summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/tls.md13
-rw-r--r--lib/_tls_common.js12
-rw-r--r--src/node_crypto.cc5
-rw-r--r--test/parallel/test-tls-passphrase.js97
4 files changed, 97 insertions, 30 deletions
diff --git a/doc/api/tls.md b/doc/api/tls.md
index 85fcfc35b4..08996fdff2 100644
--- a/doc/api/tls.md
+++ b/doc/api/tls.md
@@ -893,12 +893,13 @@ added: v0.11.13
individually. PFX is usually encrypted, if it is, `passphrase` will be used
to decrypt it.
* `key` {string|string[]|Buffer|Buffer[]|Object[]} Optional private keys in
- PEM format. Single keys will be decrypted with `passphrase` if necessary.
- Multiple keys, probably using different algorithms, can be provided either
- as an array of unencrypted key strings or buffers, or an array of objects in
- the form `{pem: <string|buffer>, passphrase: <string>}`. The object form can
- only occur in an array, and it _must_ include a passphrase, even if key is
- not encrypted.
+ PEM format. PEM allows the option of private keys being encrypted. Encrypted
+ keys will be decrypted with `options.passphrase`. Multiple keys using
+ different algorithms can be provided either as an array of unencrypted key
+ strings or buffers, or an array of objects in the form `{pem:
+ <string|buffer>[, passphrase: <string>]}`. The object form can only occur in
+ an array. `object.passphrase` is optional. Encrypted keys will be decrypted
+ with `object.passphrase` if provided, or `options.passphrase` if it is not.
* `passphrase` {string} Optional shared passphrase used for a single private
key and/or a PFX.
* `cert` {string|string[]|Buffer|Buffer[]} Optional cert chains in PEM format.
diff --git a/lib/_tls_common.js b/lib/_tls_common.js
index 9cb7045386..85ae71f8d1 100644
--- a/lib/_tls_common.js
+++ b/lib/_tls_common.js
@@ -78,17 +78,11 @@ exports.createSecureContext = function createSecureContext(options, context) {
if (Array.isArray(options.key)) {
for (i = 0; i < options.key.length; i++) {
const key = options.key[i];
- if (key.passphrase)
- c.context.setKey(key.pem, key.passphrase);
- else
- c.context.setKey(key);
+ const passphrase = key.passphrase || options.passphrase;
+ c.context.setKey(key.pem || key, passphrase);
}
} else {
- if (options.passphrase) {
- c.context.setKey(options.key, options.passphrase);
- } else {
- c.context.setKey(options.key);
- }
+ c.context.setKey(options.key, options.passphrase);
}
}
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index abfa8c585f..7b3bc40609 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -442,7 +442,10 @@ void SecureContext::SetKey(const FunctionCallbackInfo<Value>& args) {
}
if (len == 2) {
- THROW_AND_RETURN_IF_NOT_STRING(args[1], "Pass phrase");
+ if (args[1]->IsUndefined() || args[1]->IsNull())
+ len = 1;
+ else
+ THROW_AND_RETURN_IF_NOT_STRING(args[1], "Pass phrase");
}
BIO *bio = LoadBIO(env, args[0]);
diff --git a/test/parallel/test-tls-passphrase.js b/test/parallel/test-tls-passphrase.js
index 319c3511dc..4630fe236d 100644
--- a/test/parallel/test-tls-passphrase.js
+++ b/test/parallel/test-tls-passphrase.js
@@ -51,13 +51,12 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
key: rawKey,
- passphrase: 'passphrase', // Ignored.
+ passphrase: 'ignored',
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
// Buffer[]
- /* XXX(sam) Should work, but its unimplemented ATM.
tls.connect({
port: this.address().port,
key: [passKey],
@@ -65,7 +64,6 @@ server.listen(0, common.mustCall(function() {
cert: [cert],
rejectUnauthorized: false
}, common.mustCall(function() {}));
- */
tls.connect({
port: this.address().port,
@@ -77,7 +75,7 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
key: [rawKey],
- passphrase: 'passphrase', // Ignored.
+ passphrase: 'ignored',
cert: [cert],
rejectUnauthorized: false
}, common.mustCall(function() {}));
@@ -101,13 +99,12 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
key: rawKey.toString(),
- passphrase: 'passphrase', // Ignored.
+ passphrase: 'ignored',
cert: cert.toString(),
rejectUnauthorized: false
}, common.mustCall(function() {}));
// String[]
- /* XXX(sam) Should work, but its unimplemented ATM.
tls.connect({
port: this.address().port,
key: [passKey.toString()],
@@ -115,7 +112,6 @@ server.listen(0, common.mustCall(function() {
cert: [cert.toString()],
rejectUnauthorized: false
}, common.mustCall(function() {}));
- */
tls.connect({
port: this.address().port,
@@ -127,7 +123,7 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
key: [rawKey.toString()],
- passphrase: 'passphrase', // Ignored.
+ passphrase: 'ignored',
cert: [cert.toString()],
rejectUnauthorized: false
}, common.mustCall(function() {}));
@@ -142,6 +138,22 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
+ key: [{pem: passKey, passphrase: 'passphrase'}],
+ passphrase: 'ignored',
+ cert: cert,
+ rejectUnauthorized: false
+ }, common.mustCall(function() {}));
+
+ tls.connect({
+ port: this.address().port,
+ key: [{pem: passKey}],
+ passphrase: 'passphrase',
+ cert: cert,
+ rejectUnauthorized: false
+ }, common.mustCall(function() {}));
+
+ tls.connect({
+ port: this.address().port,
key: [{pem: passKey.toString(), passphrase: 'passphrase'}],
cert: cert,
rejectUnauthorized: false
@@ -149,23 +161,22 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
- key: [{pem: rawKey, passphrase: 'passphrase'}],
+ key: [{pem: rawKey, passphrase: 'ignored'}],
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
tls.connect({
port: this.address().port,
- key: [{pem: rawKey.toString(), passphrase: 'passphrase'}],
+ key: [{pem: rawKey.toString(), passphrase: 'ignored'}],
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
- /* XXX(sam) Should work, but unimplemented ATM
tls.connect({
port: this.address().port,
key: [{pem: rawKey}],
- passphrase: 'passphrase',
+ passphrase: 'ignored',
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
@@ -173,7 +184,7 @@ server.listen(0, common.mustCall(function() {
tls.connect({
port: this.address().port,
key: [{pem: rawKey.toString()}],
- passphrase: 'passphrase',
+ passphrase: 'ignored',
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
@@ -191,9 +202,37 @@ server.listen(0, common.mustCall(function() {
cert: cert,
rejectUnauthorized: false
}, common.mustCall(function() {}));
- */
})).unref();
+// Missing passphrase
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: passKey,
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad password read/);
+
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: [passKey],
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad password read/);
+
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: [{pem: passKey}],
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad password read/);
+
+// Invalid passphrase
assert.throws(function() {
tls.connect({
port: server.address().port,
@@ -203,3 +242,33 @@ assert.throws(function() {
rejectUnauthorized: false
});
}, /bad decrypt/);
+
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: [passKey],
+ passphrase: 'invalid',
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad decrypt/);
+
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: [{pem: passKey}],
+ passphrase: 'invalid',
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad decrypt/);
+
+assert.throws(function() {
+ tls.connect({
+ port: server.address().port,
+ key: [{pem: passKey, passphrase: 'invalid'}],
+ passphrase: 'passphrase', // Valid but unused
+ cert: cert,
+ rejectUnauthorized: false
+ });
+}, /bad decrypt/);