summaryrefslogtreecommitdiff
path: root/lib/internal/crypto
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2019-01-26 13:28:55 +0100
committerTobias Nießen <tniessen@tnie.de>2019-03-05 16:32:19 +0100
commitfe7162915e2a9de85bb550d8d50679832e46983e (patch)
treed0639862a806e942fec9ab925935eabf91c29cd8 /lib/internal/crypto
parent84ebaaa339ffc67cbada5b2ae59061c26efd39ce (diff)
downloadandroid-node-v8-fe7162915e2a9de85bb550d8d50679832e46983e.tar.gz
android-node-v8-fe7162915e2a9de85bb550d8d50679832e46983e.tar.bz2
android-node-v8-fe7162915e2a9de85bb550d8d50679832e46983e.zip
crypto: allow deriving public from private keys
This change allows passing private key objects to crypto.createPublicKey, resulting in a key object that represents a valid public key for the given private key. The returned public key object can be used and exported safely without revealing information about the private key. PR-URL: https://github.com/nodejs/node/pull/26278 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Diffstat (limited to 'lib/internal/crypto')
-rw-r--r--lib/internal/crypto/keys.js50
1 files changed, 31 insertions, 19 deletions
diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js
index ecd747d947..2e23d76671 100644
--- a/lib/internal/crypto/keys.js
+++ b/lib/internal/crypto/keys.js
@@ -26,6 +26,12 @@ const { isArrayBufferView } = require('internal/util/types');
const kKeyType = Symbol('kKeyType');
+// Key input contexts.
+const kConsumePublic = 0;
+const kConsumePrivate = 1;
+const kCreatePublic = 2;
+const kCreatePrivate = 3;
+
const encodingNames = [];
for (const m of [[kKeyEncodingPKCS1, 'pkcs1'], [kKeyEncodingPKCS8, 'pkcs8'],
[kKeyEncodingSPKI, 'spki'], [kKeyEncodingSEC1, 'sec1']])
@@ -203,7 +209,7 @@ function parseKeyEncoding(enc, keyType, isPublic, objName) {
// when this is used to parse an input encoding and must be a valid key type if
// used to parse an output encoding.
function parsePublicKeyEncoding(enc, keyType, objName) {
- return parseKeyFormatAndType(enc, keyType, true, objName);
+ return parseKeyEncoding(enc, keyType, keyType ? true : undefined, objName);
}
// Parses the private key encoding based on an object. keyType must be undefined
@@ -213,26 +219,31 @@ function parsePrivateKeyEncoding(enc, keyType, objName) {
return parseKeyEncoding(enc, keyType, false, objName);
}
-function getKeyObjectHandle(key, isPublic, allowKeyObject) {
- if (!allowKeyObject) {
+function getKeyObjectHandle(key, ctx) {
+ if (ctx === kCreatePrivate) {
throw new ERR_INVALID_ARG_TYPE(
'key',
['string', 'Buffer', 'TypedArray', 'DataView'],
key
);
}
- if (isPublic != null) {
- const expectedType = isPublic ? 'public' : 'private';
- if (key.type !== expectedType)
- throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, expectedType);
+
+ if (key.type !== 'private') {
+ if (ctx === kConsumePrivate || ctx === kCreatePublic)
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'private');
+ if (key.type !== 'public') {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type,
+ 'private or public');
+ }
}
+
return key[kHandle];
}
-function prepareAsymmetricKey(key, isPublic, allowKeyObject = true) {
+function prepareAsymmetricKey(key, ctx) {
if (isKeyObject(key)) {
// Best case: A key object, as simple as that.
- return { data: getKeyObjectHandle(key, isPublic, allowKeyObject) };
+ return { data: getKeyObjectHandle(key, ctx) };
} else if (typeof key === 'string' || isArrayBufferView(key)) {
// Expect PEM by default, mostly for backward compatibility.
return { format: kKeyFormatPEM, data: key };
@@ -241,32 +252,32 @@ function prepareAsymmetricKey(key, isPublic, allowKeyObject = true) {
// The 'key' property can be a KeyObject as well to allow specifying
// additional options such as padding along with the key.
if (isKeyObject(data))
- return { data: getKeyObjectHandle(data, isPublic, allowKeyObject) };
+ return { data: getKeyObjectHandle(data, ctx) };
// Either PEM or DER using PKCS#1 or SPKI.
if (!isStringOrBuffer(data)) {
throw new ERR_INVALID_ARG_TYPE(
'key',
['string', 'Buffer', 'TypedArray', 'DataView',
- ...(allowKeyObject ? ['KeyObject'] : [])],
+ ...(ctx !== kCreatePrivate ? ['KeyObject'] : [])],
key);
}
- return { data, ...parseKeyEncoding(key, undefined, isPublic) };
+ return { data, ...parseKeyEncoding(key, undefined) };
} else {
throw new ERR_INVALID_ARG_TYPE(
'key',
['string', 'Buffer', 'TypedArray', 'DataView',
- ...(allowKeyObject ? ['KeyObject'] : [])],
+ ...(ctx !== kCreatePrivate ? ['KeyObject'] : [])],
key
);
}
}
-function preparePrivateKey(key, allowKeyObject) {
- return prepareAsymmetricKey(key, false, allowKeyObject);
+function preparePrivateKey(key) {
+ return prepareAsymmetricKey(key, kConsumePrivate);
}
-function preparePublicOrPrivateKey(key, allowKeyObject) {
- return prepareAsymmetricKey(key, undefined, allowKeyObject);
+function preparePublicOrPrivateKey(key) {
+ return prepareAsymmetricKey(key, kConsumePublic);
}
function prepareSecretKey(key, bufferOnly = false) {
@@ -296,14 +307,15 @@ function createSecretKey(key) {
}
function createPublicKey(key) {
- const { format, type, data } = preparePublicOrPrivateKey(key, false);
+ const { format, type, data } = prepareAsymmetricKey(key, kCreatePublic);
const handle = new KeyObjectHandle(kKeyTypePublic);
handle.init(data, format, type);
return new PublicKeyObject(handle);
}
function createPrivateKey(key) {
- const { format, type, data, passphrase } = preparePrivateKey(key, false);
+ const { format, type, data, passphrase } =
+ prepareAsymmetricKey(key, kCreatePrivate);
const handle = new KeyObjectHandle(kKeyTypePrivate);
handle.init(data, format, type, passphrase);
return new PrivateKeyObject(handle);