-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Upgrade openssl-1.1.0e for Node-v8 (DO NOT LAND THIS) #11828
Conversation
I agree with @shigeki's recommendation to stick with 1.0.2 in Node version 8. I'd prefer we have more time for the update to settle in master before it goes into a release and we are not that far from cutting version 8. |
I agree on this too. It seems that 1.1.0 is getting more security updates than 1.0.2 at the moment, I'd say that it should make Node 8 safer too. |
This extracts and adds all source files of openssl-1.1.0e.tar.gz into deps/openssl/openssl110.
This is a floating patch against openssl-1.1.0 in order to have asm files of *.S which are before pre-processed. Node.js needs them in its repository because pre-processing is to be made in the build of Node binaries on each architecture platforms. This patch should be submitted to the upstream.
This commit has a new binding scheme in builing OpenSSL-1.1.0 library with Node. OpenSSL-1.1.0 uses a new build system with perl for various supported platforms. See `Configurations/README` and `Configurations/README.design` in the OpenSSL source for details. In order to build OpenSSL library without perl in the build of Node for various supported platforms, platform dependent files (e.g. asm and header files ) are pre-generated and stored into the `config/arch` directory. - Makefile and generate.pl Makefile has supported platform list and generates and copies platform dependent files (e.g. asm files) into arch directory with generate.pl. Platform dependent gypi files also created obtaining build information from `configdata.pm` that is generated with `Configure` in the OpenSSL build system. For Windows, `Configure` generates makefile that is only available to nmake command. `Makefile_VC-WIN32` and `Makefile_VC-WIN64A` are made created by hand for the use of GNU make. If make rules or targets are changed in the version up of OpenSSL, they should be also updated. Theses are usually used in upgrading openssl-1.1.0. - gyp and gypi files openssl.gyp has two targets of openssl and openssl-cli referred from node.gyp. They includes asm and no_asm gypi files with arch dependent gypi according to its build options and platforms . The gyp data which is common with asm and no_asm are stored in openssl_common.gypi. - header files bn_conf.h, dso_conf.h and opensslconf.h are platform dependent in the OpenSSL sources. They are replaced with *.h.tmpl files to include the file in the `../../../config/` and referred to each arch files that depends on asm and no-asm option.
This updates all platform dependent files for OpenSSL-1-1.0e with using `make` command in the config directory.
This adds a new option to build Node with OpenSSL-1.1.0. The configure also check build evnviroments if asm features are supported.
Fix lint errors in nodejs#8491 and add more fixes of build failures due to API changes in OpenSSL-1.1.0.
This add a new rules to install header files of OpenSSL-1.1.0 in case of use-openssl110 option. This also includes the fix of mkssldef.py due to the change of a format of ordinal files.
This fixes that tests can run and pass on both built with OpenSSL-1.0.2 and 1.1.0. Only the test of `test/parallel/test-tls-econnreset.js` is skipped because there are no way to leads TLS handshake failure and send ECONNRESET from the tls client to tls server with using OpenSSL-1.1.0.
This always enables use_openssl110 flag true. It has fallback to add no_asm option on Windows when nasm is not installed. This is a tentative fix for running on CI.
642d992
to
45dc7f7
Compare
A few concerns I will note:
|
@sgallagher See @shigeki's comment about ending support for Node 8 when its OpenSSL support ends:
|
As Node.js goes to semver-major everybody should expect breaking changes, deprecations would not work anymore and etc. If not, they should stick to previous LTS versions until they update their projects. |
@gibfahn I would like ask you to use Node in your package with our builtin openssl library not using a shared library to meet our support policy. For example, It is shown in CVE-2016-7056 of outdated openssl-1.0.1 that the distributor will not fix it. See it in https://access.redhat.com/security/cve/cve-2016-7056 and https://bugzilla.redhat.com/show_bug.cgi?id=1412120 . Even if it is a moderate severity, we do not accept its risk. That is why we follow the upstream support policy. |
@sgallagher I replied to your comment. Sorry for @gibfahn. |
@shigeki That leaves us with two options:
The latter is unrealistic in a volunteer project like Fedora. I should also note that Fedora follows OpenSSL upstream's recommendations. We generally carry the latest upstream releases within 24 hours. Red Hat Enterprise Linux makes its own decisions about which patches to carry, weighing the costs of maintenance, testing, certification and customer inconvenience. Since I (and my fellow co-maintainers) do not have the resources to maintain our own embedded version of OpenSSL, our only option is to trust that Red Hat makes reasonable decisions on which patches to backport on those platforms. |
@shigeki BTW, for Red Hat, an issue of "moderate" severity usually translates to "It's not worth the hassle to customers to push out a fix solely for this, but it will usually be included the next time an update for a more severe issue is released." |
@sgallagher Thanks for clarification. I understand your situation. Crypto libraries have a long history against patents and government laws to meet local legal restrictions. We currently make a high priority on the upstream's support policy. |
@nodejs/lts would like this to get discussed again so we commit if possible to the major that will contain the updated openssl, so we don't get stuck on an unsupported Openssl in LTS, see meeting notes for nodejs/Release#201 |
I think that the most issue is that we have to support both 1.0.2 and 1.1.x as long as fips is needed. |
Why not just stick with OpenSSL 1.1.x ❓ |
|
I wrote it in the comment above as
In this PR, both openssl-1.0.2 and 1.1.0 are included and + if options.openssl_fips:
+ warn('openssl-1.1.0 does not support FIPS. Use 1.0.2 instead.')
+ variables['use_openssl110'] = 'false' Another idea I wrote in the above for the target of Node-v9 or v10 is
This also can be workable for Node-v8. |
I'm wondering why this is on the agenda. I think we agreed to stick with 1.0.2 for Node version 8 and then upgrade in Node version 9. Is this to get consensus on upgrading in Node version 9 or something else ? |
This was discussed in the last CTC meeting but it was unclear why it was on the agenda. @shigeki, @sam-github I took the action to get us to clarify the recommendation so that we can take that back to the CTC. I'd suggest that we upgrade to openssl v1.1 for Node version 9. This means that if you need FIPs support before the cert for v1.1 completes you would have to stick with Node version 8. My rational would be:
|
@shigeki sorry to ping you again, but it would be great if we had your feedback in time for the CTC meeting tomorrow. |
Sorry, I missed this. I think it does not need more discussion to stick OpenSSL-1.0.2 in Node-v8. I will remove the ctc-agenda tag and close this. If anyone has any new issues to discuss on upgrading openssl in Node-v8. Please open a new issue. |
@shigeki now that 8.0.0 is out, do you plan to reopen this PR, or raise a new one? It probably makes sense to get OpenSSL 1.1 into master well before Node 9. |
@gibfahn I'm planning to open a new PR after releasing OpenSSL-1.1.1. It is expected be released soon after TLS1.3 is finalized. |
src/node_crypto.cc
Outdated
return 1; | ||
} | ||
|
||
static const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this one is no longer needed.
src/node_crypto.cc
Outdated
*tick = s->tlsext_tick; | ||
} | ||
|
||
static int SSL_SESSION_has_ticket(const SSL_SESSION *s) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
src/node_crypto.cc
Outdated
|
||
#define SSL_get_tlsext_status_type(ssl) (ssl->tlsext_status_type) | ||
|
||
// It doesn't do exactly the same, but works. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not do the same thing and leaks memory. HMAC_CTX_cleanup followed by HMAC_CTX_init would probably work. But, see comment later on...
src/node_crypto.h
Outdated
@@ -496,7 +491,11 @@ class Hmac : public BaseObject { | |||
~Hmac() override { | |||
if (!initialised_) | |||
return; | |||
HMAC_CTX_cleanup(&ctx_); | |||
#if OPENSSL_VERSION_NUMBER < 0x10100000L | |||
free(ctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This leaks memory. It does not call HMAC_CTX_cleanup
.
src/node_crypto.h
Outdated
@@ -515,10 +514,15 @@ class Hmac : public BaseObject { | |||
: BaseObject(env, wrap), | |||
initialised_(false) { | |||
MakeWeak<Hmac>(this); | |||
#if OPENSSL_VERSION_NUMBER < 0x10100000L | |||
ctx_ = reinterpret_cast<HMAC_CTX *>(malloc(sizeof(HMAC_CTX))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will break 1.0.2. It needs to call HMAC_CTX_init(ctx_)
to zero-initialize everything.
src/node_crypto.h
Outdated
} | ||
|
||
~SignBase() override { | ||
if (!initialised_) | ||
return; | ||
EVP_MD_CTX_cleanup(&mdctx_); | ||
#if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
free(mdctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
src/node_crypto.cc
Outdated
@@ -3708,11 +3822,11 @@ void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) { | |||
if (md == nullptr) { | |||
return env()->ThrowError("Unknown message digest"); | |||
} | |||
HMAC_CTX_init(&ctx_); | |||
HMAC_CTX_reset(ctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is pretty much redundant with the one at line 3985. The state here is really confusing. Since you're paying for a heap-allocated EVP_MD_CTX
anyway, simpler would be to merge the initialised_
bit into whether ctx_
is null. That is:
HmacInit
has aCHECK_EQ(nullptr, ctx_)
. It then setsctx_ = HMAC_CTX_new()
beforeHMAC_Init_ex
. (TBH, OpenSSL didn't do a great job of cleaning up the API while they were opaquifying.HMAC_CTX_new
andHMAC_Init_ex
should have been the same operation.- All the
if (!initialised_)
checks beforeif (!ctx_)
- In
HmacDigest
, rather than reset and clearinginitialised_
, doHMAC_CTX_free(ctx_);
andctx_ = nullptr;
.
src/node_crypto.cc
Outdated
@@ -3849,8 +3963,8 @@ bool Hash::HashInit(const char* hash_type) { | |||
const EVP_MD* md = EVP_get_digestbyname(hash_type); | |||
if (md == nullptr) | |||
return false; | |||
EVP_MD_CTX_init(&mdctx_); | |||
if (EVP_DigestInit_ex(&mdctx_, md, nullptr) <= 0) { | |||
EVP_MD_CTX_init(mdctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
src/node_crypto.cc
Outdated
@@ -4001,8 +4115,8 @@ SignBase::Error Sign::SignInit(const char* sign_type) { | |||
if (md == nullptr) | |||
return kSignUnknownDigest; | |||
|
|||
EVP_MD_CTX_init(&mdctx_); | |||
if (!EVP_SignInit_ex(&mdctx_, md, nullptr)) | |||
EVP_MD_CTX_init(mdctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
src/node_crypto.cc
Outdated
@@ -4207,8 +4321,8 @@ SignBase::Error Verify::VerifyInit(const char* verify_type) { | |||
if (md == nullptr) | |||
return kSignUnknownDigest; | |||
|
|||
EVP_MD_CTX_init(&mdctx_); | |||
if (!EVP_VerifyInit_ex(&mdctx_, md, nullptr)) | |||
EVP_MD_CTX_init(mdctx_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
(I ended up here from #14761. Although I missed this PR was actually closed already? I'm a little confused which PR is the plan for making Node work with 1.1.0 since the other one is out of date. Anyway, I've left some comments on this one since it seems to be the most up-to-date version of the original PR.) |
@davidben Thanks for reviewing. Yes, this was old PR and still in WIP and it was closed as we wait for FIPS support of OpenSSL-1.1.x. But it is good to have preparations for the future upgrading so I will submit a new WIP PR against 1.1.0f with including your comments after next week. |
Sounds good. Sorry about the confusion. I'm happy to review it or even put it together myself if it's helpful. |
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passestests and/or benchmarks are included
documentation is changed or added
commit message follows commit guidelines
Affected core subsystem(s)
crypto, tls
This PR is a big patch and please don't review this immediately.
It is time to make a decision if we upgrade OpenSSL-1.1.0 in Node-v8. It breaks API/ABI compatibilities with 1.0.2 so that it needs semver-major in this upgrade.
I submit this patch for intending to show and demonstrate that upgrading to 1.1.0 can be done in all platforms. CI results has already shown in https://ci.nodejs.org/job/node-test-commit/8424/ and they are green except FreeBSD failure due to Jenkins error.
Before we make the decision, I think that the following three major issues should be discussed.
Support end difference between Node LTS and OpenSSL
Node-v8 LTS Maintenance End will be in 2020-04. According to the current support policy of OpenSSL of https://www.openssl.org/policies/releasestrat.html , it says that
If we continue to use openssl-1.0.2, Node-v8 LTS support should be end on 2019-12-31 about 3 months earlier than our plan as we did in v0.12.
1.1.0 will be support end in the next year. A new OpenSSL-1.1.1 is now under development and expected to be released near future with new feature of TLS1.3. It is API/ABI compatible with 1.1.0 so we can deploy it with semver-minor. A new OpenSSL release will be supported at least two years. If LTS is specified to it, it will be five years support.
If we deployed 1.1.0 in Node-v8, we need to make semver-minor upgrade of OpenSSL until to meet its support end of 2020-04.
FIPS Support
The current FIPS support is provided only for 1.0.2. There was an announcement of a sponsor to support FIPS compliance with OpenSSL 1.1 in
https://www.openssl.org/blog/blog/2016/07/20/fips/ but it is not yet to known when new FIPS support is released.
If FIPS support is required in Node, we have to continue to use 1.0.2 until new FIPS support is released.
New Build Requirement (nasm) on Windows
In order to build OpenSSL in Windows with asm support, NASM is officially required. https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/NOTES.WIN#L20-L23
It was noted even in 1.0.2 and we have been ignoring this requirement. 1.1.0 begins to checks its requirement during build. We can avoid it with our own risk but I don't think it is a good way to go. As it is inevitable, we should decide when and what version of Node the new requirement starts.
This PR adds an experimental support of OpenSSL-1.1.0e with a new flag
--use-openssl11
in configure and contines to use 1.0.2 by default. I think that it leads API complexities when we add a new feature specific to 1.1.0 and agree that it is not a good solution.My preference is that we stay on 1.0.2 in Node-v8 and deploy 1.1.0 or 1.1.1 someday later in v9 or v10 with replacing 1.0.2. If FIPS support is not released at that time. we separate a new branch with 1.0.2 only to have FIPS support.
CC @nodejs/crypto , @nodejs/lts