diff options
author | Tobias Nießen <tniessen@tnie.de> | 2019-01-26 13:28:55 +0100 |
---|---|---|
committer | Tobias Nießen <tniessen@tnie.de> | 2019-03-05 16:32:19 +0100 |
commit | fe7162915e2a9de85bb550d8d50679832e46983e (patch) | |
tree | d0639862a806e942fec9ab925935eabf91c29cd8 /lib/internal/crypto | |
parent | 84ebaaa339ffc67cbada5b2ae59061c26efd39ce (diff) | |
download | android-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.js | 50 |
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); |