Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 36.4k
crypto: allow deriving public from private keys#26278
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
Closed
tniessen
wants to merge
2
commits into
nodejs:master
from
tniessen:crypto-allow-deriving-public-from-private-key
Uh oh!
There was an error while loading. Please reload this page.
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1813,28 +1813,35 @@ must be an object with the properties described above. | ||
| <!-- YAML | ||
| added: v11.6.0 | ||
| changes: | ||
| - version: REPLACEME | ||
| pr-url: https://github.com/nodejs/node/pull/26278 | ||
| description: The `key` argument can now be a `KeyObject` with type | ||
| `private`. | ||
| - version: v11.7.0 | ||
| pr-url: https://github.com/nodejs/node/pull/25217 | ||
| description: The `key` argument can now be a private key. | ||
| --> | ||
| * `key` {Object | string | Buffer} | ||
| * `key` {Object | string | Buffer | KeyObject} | ||
| - `key`: {string | Buffer} | ||
| - `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`. | ||
| - `type`: {string} Must be `'pkcs1'` or `'spki'`. This option is required | ||
| only if the `format` is `'der'`. | ||
| * Returns: {KeyObject} | ||
| Creates and returns a new key object containing a public key. If `key` is a | ||
| string or `Buffer`, `format` is assumed to be `'pem'`; otherwise, `key` | ||
| must be an object with the properties described above. | ||
| string or `Buffer`, `format` is assumed to be `'pem'`; if `key` is a `KeyObject` | ||
| with type `'private'`, the public key is derived from the given private key; | ||
| otherwise, `key` must be an object with the properties described above. | ||
| If the format is `'pem'`, the `'key'` may also be an X.509 certificate. | ||
| Because public keys can be derived from private keys, a private key may be | ||
| passed instead of a public key. In that case, this function behaves as if | ||
| [`crypto.createPrivateKey()`][] had been called, except that the type of the | ||
| returned `KeyObject` will be `public` and that the private key cannot be | ||
| extracted from the returned `KeyObject`. | ||
| returned `KeyObject` will be `'public'` and that the private key cannot be | ||
| extracted from the returned `KeyObject`. Similarly, if a `KeyObject` with type | ||
| `'private'` is given, a new `KeyObject` with type `'public'` will be returned | ||
sam-github marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| and it will be impossible to extract the private key from the returned object. | ||
| ### crypto.createSecretKey(key) | ||
| <!-- YAML | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
sam-github marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| // 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); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.