Skip to content
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

crypto: support multiple ECDH curves and auto #15206

Closed
wants to merge 1 commit into from

Conversation

rogaps
Copy link
Contributor

@rogaps rogaps commented Sep 5, 2017

Using SSL_CTX_set1_curves_list() (OpenSSL 1.0.2+), this allows to set
colon separated ECDH curve names in SecureContext's ecdhCurve option.
The option can also be set to "auto" to select the curve automatically
from list built in OpenSSL by enabling SSL_CTX_set_ecdh_auto()
(OpenSSL 1.0.2+).
Refs: #15054

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

crypto

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. labels Sep 5, 2017
if (!SSL_CTX_set1_curves_list(sc->ctx_, *curve))
return env->ThrowError("Failed to set ECDH curve");
#else
int nid = OBJ_sn2nid(strcmp(*curve, "auto") == 0 ? "prime256v1" : *curve);
Copy link
Contributor

@mscdex mscdex Sep 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should be implicitly selecting our own hardcoded curve in this case for "auto." If the intent is to use the value of tls.DEFAULT_ECDH_CURVE, we would probably need to dynamically read that value since it could be changed by end users. However, we should probably throw an error instead when we see "auto" and the appropriate OpenSSL API is not available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was to use tls.DEFAULT_ECDH_CURVE's value but displaying error is perhaps better if auto is actually not supported the version of OpenSSL.

int nid = OBJ_sn2nid(*curve);
SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE);

#if (defined SSL_CTX_set1_curves_list || defined SSL_CTRL_SET_CURVES_LIST)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: we use defined() below but not here. I think we should be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I will update it.

@mscdex
Copy link
Contributor

mscdex commented Sep 5, 2017

/cc @nodejs/crypto

@rogaps rogaps force-pushed the multiple-curves-support branch from 1e960c6 to 9636b1c Compare September 6, 2017 13:55
@BridgeAR
Copy link
Member

PTAL @nodejs/crypto

@jasnell jasnell added the semver-minor PRs that contain new features and should be released in the next minor version. label Sep 14, 2017
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The copyright header block should not be added to new files


const options = {
key: fs.readFileSync(`${common.fixturesDir}/keys/agent2-key.pem`),
cert: fs.readFileSync(`${common.fixturesDir}/keys/agent2-cert.pem`),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make use of the new require('common/fixtures') utility here.

conn.end(reply);
}));

server.listen(0, '127.0.0.1', common.mustCall(function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 127.0.0.1 host can be omitted


server.listen(0, '127.0.0.1', common.mustCall(function() {
let cmd = `"${common.opensslCli}" s_client -cipher ${
options.ciphers} -connect 127.0.0.1:${this.address().port}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a fan of multiline template literals and we've tried to avoid their use in the past.

// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here... the copyright header should not be included.

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting closer! Left a few comments.

@tniessen
Copy link
Member

Mostly LGTM, will do a review when @jasnell's comments were addressed.

@@ -923,6 +923,22 @@ void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value curve(env->isolate(), args[0]);

SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE);

#if defined(SSL_CTX_set1_curves_list) || defined(SSL_CTRL_SET_CURVES_LIST)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you have to do this #define dance; the versions of openssl we support, support this API.

SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE);

#if defined(SSL_CTX_set1_curves_list) || defined(SSL_CTRL_SET_CURVES_LIST)
# if defined(SSL_CTX_set_ecdh_auto)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise.

if (strcmp(*curve, "auto") == 0)
return;

if (!SSL_CTX_set1_curves_list(sc->ctx_, *curve))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One (possibly academic) drawback to SSL_CTX_set1_curves_list() is that it won't let you set more than ~30 curves.

I.e., options = { ecdhCurve: crypto.getCurves().join(':') } won't work because there are over 80 different curves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supported curves are listed here. Does the documentation need to mention the lists?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that's a good idea. I was initially going to suggest to just refer readers to the relevant RFCs but on second thought, that would work okay for Brainpool (RFC 7027) but RFC 4492 is too much of a grab bag of different algorithms.

@@ -933,10 +949,10 @@ void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) {
if (ecdh == nullptr)
return env->ThrowTypeError("First argument should be a valid curve name");

SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this removed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw it was moved up

@rogaps
Copy link
Contributor Author

rogaps commented Sep 15, 2017

Thanks for the reviews. I will address them.

@rogaps rogaps force-pushed the multiple-curves-support branch from 9636b1c to a266edc Compare September 15, 2017 16:30
Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if @bnoordhuis is happy also.

@tniessen
Copy link
Member

Copy link
Member

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM.

Copy link
Member

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JS and doc LGTM

});

client.on('error', function(error) {
assert.ifError(error);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: (non blocking) assert.ifError is actually meant as callback replacement. Therefore you do not have to wrap it in a function and can use it as client.on("error", assert.ifError) instead. The same in the other test.

@BridgeAR
Copy link
Member

I am OK with this but in general - would it not be much nicer to use an Array instead of a colon separated string? And we could also allow a Boolean where false is used instead of the string "false" for deactivation and true for "auto"?

@jasnell
Copy link
Member

jasnell commented Sep 15, 2017

would it not be much nicer to use an Array

Perhaps, but using the :-delimited string is consistent with openssl in general. Perhaps as a separate PR support for an Array input can be added.

@jasnell
Copy link
Member

jasnell commented Sep 15, 2017

This is failing significantly on FIPS...

not ok 1445 parallel/test-tls-ecdh-multiple
  ---
  duration_ms: 0.412
  severity: fail
  stack: |-
    _tls_common.js:142
        c.context.setECDHCurve(options.ecdhCurve);
                  ^
    
    Error: Failed to set ECDH curve
        at Object.createSecureContext (_tls_common.js:142:15)
        at new Server (_tls_wrap.js:805:25)
        at Object.exports.createServer (_tls_wrap.js:898:10)
        at Object.<anonymous> (/home/iojs/build/workspace/node-test-commit-linux-fips/nodes/ubuntu1404-64/test/parallel/test-tls-ecdh-multiple.js:30:20)
        at Module._compile (module.js:600:30)
        at Object.Module._extensions..js (module.js:611:10)
        at Module.load (module.js:521:32)
        at tryModuleLoad (module.js:484:12)
        at Function.Module._load (module.js:476:3)
        at Function.Module.runMain (module.js:641:10)
  ...

ping @mhdawson @gibfahn

@rogaps
Copy link
Contributor Author

rogaps commented Sep 15, 2017

@jasnell I overlooked FIPS mode doesn't support brainpoolP256r1.

@rogaps rogaps force-pushed the multiple-curves-support branch from a266edc to affa214 Compare September 16, 2017 17:08
@mhdawson
Copy link
Member

mhdawson commented Sep 18, 2017

@rogaps I assume you are just going to update the tests so that they don't try to use brainpoolP256r1 when in FIPs mode. Although maybe you have already updated.

@rogaps
Copy link
Contributor Author

rogaps commented Sep 18, 2017

@mhdawson Sure. I will update the tests for some unsupported curves.

jasnell pushed a commit that referenced this pull request Sep 20, 2017
Using SSL_CTX_set1_curves_list() (OpenSSL 1.0.2+), this allows to set
colon separated ECDH curve names in SecureContext's ecdhCurve option.
The option can also be set to "auto" to select the curve automatically
from list built in OpenSSL by enabling SSL_CTX_set_ecdh_auto()
(OpenSSL 1.0.2+).

PR-URL: #15206
Ref: #15054
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
@jasnell
Copy link
Member

jasnell commented Sep 20, 2017

Landed in 873e5bd

@jasnell jasnell closed this Sep 20, 2017
jasnell pushed a commit that referenced this pull request Sep 20, 2017
Using SSL_CTX_set1_curves_list() (OpenSSL 1.0.2+), this allows to set
colon separated ECDH curve names in SecureContext's ecdhCurve option.
The option can also be set to "auto" to select the curve automatically
from list built in OpenSSL by enabling SSL_CTX_set_ecdh_auto()
(OpenSSL 1.0.2+).

PR-URL: #15206
Ref: #15054
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
jasnell added a commit that referenced this pull request Sep 20, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
jasnell added a commit that referenced this pull request Sep 21, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
Qard pushed a commit to Qard/ayo that referenced this pull request Sep 21, 2017
Using SSL_CTX_set1_curves_list() (OpenSSL 1.0.2+), this allows to set
colon separated ECDH curve names in SecureContext's ecdhCurve option.
The option can also be set to "auto" to select the curve automatically
from list built in OpenSSL by enabling SSL_CTX_set_ecdh_auto()
(OpenSSL 1.0.2+).

PR-URL: nodejs/node#15206
Ref: nodejs/node#15054
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Qard pushed a commit to Qard/ayo that referenced this pull request Sep 21, 2017
Using SSL_CTX_set1_curves_list() (OpenSSL 1.0.2+), this allows to set
colon separated ECDH curve names in SecureContext's ecdhCurve option.
The option can also be set to "auto" to select the curve automatically
from list built in OpenSSL by enabling SSL_CTX_set_ecdh_auto()
(OpenSSL 1.0.2+).

PR-URL: nodejs/node#15206
Ref: nodejs/node#15054
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
jasnell added a commit that referenced this pull request Sep 25, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
jasnell added a commit that referenced this pull request Sep 26, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
  * Custom lookup functions are now supported. [#14560](#14560)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
jasnell added a commit that referenced this pull request Sep 26, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
  * Custom lookup functions are now supported. [#14560](#14560)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
MylesBorins pushed a commit that referenced this pull request Sep 29, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](#7855)
  * Custom lookup functions are now supported. [#14560](#14560)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](#15354)
addaleax pushed a commit to addaleax/ayo that referenced this pull request Sep 30, 2017
* **crypto**
  * Support for multiple ECDH curves. [#15206](nodejs/node#15206)
* **dgram**
  * Added `setMulticastInterface()` API. [#7855](nodejs/node#7855)
  * Custom lookup functions are now supported. [#14560](nodejs/node#14560)
* **n-api**
  * The command-line flag is no longer required to use N-API. [#14902](nodejs/node#14902)
* **tls**
  * Docs-only deprecation of `parseCertString()`. [#14245](nodejs/node#14245)
* **New Contributors**
  * Welcome Sebastiaan Deckers (@sebdeckers) as a new Collaborator! [#15354](nodejs/node#15354)
@Hativ Hativ mentioned this pull request Nov 7, 2017
4 tasks
tniessen pushed a commit that referenced this pull request Nov 28, 2017
For best out-of-the-box compatibility there should not be one default
`ecdhCurve` for the tls client, OpenSSL should choose them
automatically.

See https://wiki.openssl.org/index.php/Manual:SSL_CTX_set1_curves(3)

PR-URL: #16853
Refs: #16196
Refs: #1495
Refs: #15206
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Sam Roberts <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
@rogaps rogaps deleted the multiple-curves-support branch December 23, 2017 08:46
@gibfahn
Copy link
Member

gibfahn commented Jan 19, 2018

@nodejs/lts

Post-mortem on this, it contained an accidental breaking change (which brought the code in line with the docs), changing the default curve setting from prime256v1 to auto. I think reverting at this point would do more harm than good, but it is causing problems for users. The change in default will be reverted in 10.x (as a semver-major).

One thing that would help would be @sam-github 's suggestion in #16853 (comment), which is adding aNODE_OPTIONS option that allows users to change the default back to auto without needing to change dependency code.

Quite a few people have hit this, so IMO we should prioritize getting this fixed and backported to 8.x and 6.x.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants