From d7e7008c1f4318e2ebd375fed75362711ebdbb2c Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 24 Nov 2014 16:17:13 +0300 Subject: [PATCH] crypto: throw if the key doesn't match cert fix joyent/node#8770 Reviewed-By: Ben Noordhuis PR-URL: https://github.com/node-forward/node/pull/66 --- lib/_tls_common.js | 42 +++++++++++++++------------- src/node_crypto.cc | 9 +++++- test/simple/test-tls-key-mismatch.js | 42 ++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 20 deletions(-) create mode 100644 test/simple/test-tls-key-mismatch.js diff --git a/lib/_tls_common.js b/lib/_tls_common.js index e66ae662fe..a3309ead0a 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -65,25 +65,6 @@ exports.createSecureContext = function createSecureContext(options, context) { if (context) return c; - if (options.key) { - if (Array.isArray(options.key)) { - for (var i = 0; i < options.key.length; i++) { - var key = options.key[i]; - - if (key.passphrase) - c.context.setKey(key.pem, key.passphrase); - else - c.context.setKey(key); - } - } else { - if (options.passphrase) { - c.context.setKey(options.key, options.passphrase); - } else { - c.context.setKey(options.key); - } - } - } - // NOTE: It's important to add CA before the cert to be able to load // cert's issuer in C++ code. if (options.ca) { @@ -107,6 +88,29 @@ exports.createSecureContext = function createSecureContext(options, context) { } } + // NOTE: It is important to set the key after the cert. + // `ssl_set_pkey` returns `0` when the key does not much the cert, but + // `ssl_set_cert` returns `1` and nullifies the key in the SSL structure + // which leads to the crash later on. + if (options.key) { + if (Array.isArray(options.key)) { + for (var i = 0; i < options.key.length; i++) { + var key = options.key[i]; + + if (key.passphrase) + c.context.setKey(key.pem, key.passphrase); + else + c.context.setKey(key); + } + } else { + if (options.passphrase) { + c.context.setKey(options.key, options.passphrase); + } else { + c.context.setKey(options.key); + } + } + } + if (options.ciphers) c.context.setCiphers(options.ciphers); else diff --git a/src/node_crypto.cc b/src/node_crypto.cc index bbc2b95c7a..31b2b0175f 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -456,9 +456,16 @@ void SecureContext::SetKey(const FunctionCallbackInfo& args) { return ThrowCryptoError(env, err); } - SSL_CTX_use_PrivateKey(sc->ctx_, key); + int rv = SSL_CTX_use_PrivateKey(sc->ctx_, key); EVP_PKEY_free(key); BIO_free_all(bio); + + if (!rv) { + unsigned long err = ERR_get_error(); + if (!err) + return env->ThrowError("SSL_CTX_use_PrivateKey"); + return ThrowCryptoError(env, err); + } } diff --git a/test/simple/test-tls-key-mismatch.js b/test/simple/test-tls-key-mismatch.js new file mode 100644 index 0000000000..f99e9471fd --- /dev/null +++ b/test/simple/test-tls-key-mismatch.js @@ -0,0 +1,42 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// 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. + +if (!process.versions.openssl) { + console.error('Skipping because node compiled without OpenSSL.'); + process.exit(0); +} + +var common = require('../common'); +var assert = require('assert'); +var tls = require('tls'); +var fs = require('fs'); +var fs = require('fs'); + +var options = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem') +}; + +var cert = null; + +assert.throws(function() { + tls.createSecureContext(options); +});