Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
b277776
fs: improve fsPromises readFile performance
Linkgoron Mar 5, 2021
3572299
fs: add promisified readFile benchmark
Linkgoron Mar 5, 2021
7a1de1f
tools: update ESLint to 7.21.0
lpinca Feb 28, 2021
25a5f0b
tools: update eslint-plugin-markdown configuration
cjihrig Feb 28, 2021
1c09776
domain: show falsy names as anonymous for DEP0097
cjihrig Feb 28, 2021
236ba04
domain: add name to monkey-patched emit function
cjihrig Feb 28, 2021
daa4ac5
lib: remove use of array destructuring
aduh95 Jan 6, 2021
057c6a8
tools: add ESLint rule no-array-destructuring
aduh95 Jan 6, 2021
c09bd77
test: redownload wpt fixtures with correct encoding
targos Feb 21, 2021
a44daff
test: update all Web Platform Tests
targos Feb 21, 2021
f4fd3fb
worker: allow BroadcastChannel in receiveMessageOnPort
addaleax Feb 27, 2021
8024ffb
worker: add ports property to MessageEvents
addaleax Feb 27, 2021
33436e3
src: make BaseObject::is_snapshotable virtual
addaleax Feb 27, 2021
f56a805
doc: refactor signal info in child_process.md
RaisinTen Feb 26, 2021
fd7234c
tools: make update-eslint.sh work with npm@7
lpinca Mar 2, 2021
82e78f7
tools: fix compiler warning in inspector_protocol
RaisinTen Mar 2, 2021
7042ec8
tools: update remark-preset-lint-node to 2.1.1
Trott Mar 4, 2021
267bbe3
doc: document that NODE_EXTRA_CA_CERTS is read only once
jasnell Mar 1, 2021
732d8ca
doc: clarify that columnOffset applies only to the first line
jasnell Mar 1, 2021
8e1257e
cluster: clarify construct Handle
JacksonTian Feb 15, 2021
d81b9af
crypto: improve randomUUID performance
rangoo94 Feb 5, 2021
e9028eb
cluster: restructure to same prototype for cluster child
yashLadha Dec 23, 2020
0d04b6c
test: fix flaky test-child-process-exec-abortcontroller-promisified
aduh95 Mar 2, 2021
e0e7aa1
doc: add top-level await syntax in vm.md
aduh95 Jan 26, 2021
05badcf
doc: fix small typo in 15.11.0 release
bnb Mar 4, 2021
33180fa
crypto: add separate error for INVALID_KEY_TYPE
RaisinTen Mar 1, 2021
440c944
tools: fix object name in prefer-assert-methods.js
tniessen Feb 28, 2021
7422453
deps: upgrade npm to 7.6.1
ruyadorno Mar 4, 2021
5a9196e
doc: apply sentence case to headers in pull-requests.md
marsonya Mar 4, 2021
f50db89
doc: change lang info string in fs JS snippets
aduh95 Mar 4, 2021
07fc61b
tools: add support for mjs and cjs JS snippet linting
aduh95 Feb 10, 2021
9c0ca46
tools,doc: add support for several flavors of JS code snippets
aduh95 Jan 31, 2021
ec71a0f
tools: check version number in YAML comments from changelogs
aduh95 Feb 4, 2021
366772b
doc: add return type of readline.createInterface
RaisinTen Mar 4, 2021
23d6541
crypto,test: improve hmac coverage with webcrypto tests
obi-el Mar 2, 2021
0582c51
test: fix wasi/test-return-on-exit on 32-bit systems
cjihrig Mar 1, 2021
381fb98
test: clear FLAKY designation for test-http2-pipe
Trott Mar 6, 2021
d5ff50d
test: clear flaky designation for test-stream-pipeline-http2
Trott Mar 6, 2021
d17aab1
doc: add esm examples for assert
jasnell Mar 4, 2021
044fd2f
test: remove FLAKY status for fixed test
Trott Mar 6, 2021
1f63418
test: remove FLAKY status for test-async-hooks-http-parser-destroy
Trott Mar 6, 2021
ebc6f41
doc: fix linter issue
aduh95 Mar 8, 2021
257b1ab
test: update Web Platform Tests
targos Mar 6, 2021
b7ef829
test: ignore WPT worker errors after tests finished
targos Mar 6, 2021
f7edb07
test: terminate WPT workers after test completion
targos Mar 6, 2021
e4c8c50
doc: fix typos in /doc/api/fs.md
Luntke Mar 1, 2021
6192315
doc: remove generated from dsaEncoding description
kaznovac Feb 20, 2021
b0ed1e7
test: improve error reporting in test-child-process-pipe-dataflow
Trott Mar 6, 2021
cc48816
test: fix WPT URL tests that fetch JSON data
targos Mar 6, 2021
013b3ff
test: remove unnecessary V8 flag
aduh95 Mar 9, 2021
60d8afa
doc: document that module.evaluate fulfills as undefined
jasnell Mar 9, 2021
d59c6de
src: add error formatting support
devsnek Mar 4, 2021
7c0ce17
doc: fix typo in doc/guides/collaborator-guide.md
marsonya Mar 6, 2021
e5f7179
doc: add document for http.OutgoingMessage
Ayase-252 Feb 4, 2021
705bdfb
doc: fix grammar errors in http document
Ayase-252 Feb 24, 2021
852f53e
lib: fix typo in lib/internal/bootstrap/loaders.js
marsonya Mar 6, 2021
a3abd52
doc: add localPort to http.request() options
lpinca Mar 3, 2021
4de3b84
tools: update glob-parent to 5.1.2
Trott Mar 7, 2021
55e522c
crypto: support JWK objects in create*Key
panva Feb 6, 2021
a86334f
node-api: define version 8
gabrielschulhof Mar 7, 2021
922f2f0
crypto: add optional callback to crypto.sign and crypto.verify
panva Feb 24, 2021
b2fd003
deps: V8: cherry-pick 1648e050cade
cjihrig Mar 9, 2021
ed32cd4
test: fixup flaky test-crypto-x509
panva Mar 11, 2021
e7fc7a4
doc: crypto esm examples
jasnell Mar 3, 2021
d28ce32
src: fix variable name of OnCloseReceived callback
tniessen Feb 26, 2021
e55058f
doc: use sentence case in README.md headers
marsonya Mar 6, 2021
a2d08d5
crypto: add internal error codes
RaisinTen Mar 7, 2021
ae0e76c
module: refactor NativeModule to avoid unsafe array iteration
aduh95 Feb 12, 2021
0d3cc2d
doc: fix typo in description of close event
tniessen Mar 8, 2021
4bf1f33
stream,util: fix "the the" typo in comments
lpinca Mar 9, 2021
e63a25e
lib: fix typo in lib/internal/http2/core.js
marsonya Mar 10, 2021
764aa2d
doc: fix link to googletest fixtures
tniessen Mar 10, 2021
341ee31
crypto: reconcile duplicated code
jasnell Mar 11, 2021
5731977
test,crypto: ensure promises resolve in webcrypto tests
aduh95 Mar 8, 2021
6688569
http: refactor to avoid unsafe array iteration
aduh95 Feb 12, 2021
2d9b624
tls: refactor to avoid unsafe array iteration
aduh95 Feb 12, 2021
ba91ef2
fs: improve fsPromises writeFile performance
Linkgoron Mar 5, 2021
8666d77
benchmark: add benchmark for fsPromises.writeFile
Linkgoron Mar 5, 2021
4451460
assert,util: fix commutativity edge case
BridgeAR Mar 11, 2021
3e1a46a
deps: upgrade npm to 7.6.3
ruyadorno Mar 11, 2021
e384291
events: remove return value on addEventListener
jasnell Mar 10, 2021
c737df6
http2: make res.req a normal property
cjihrig Mar 11, 2021
12fb2ff
lib: use AbortError consistently
jasnell Mar 11, 2021
1022d3d
doc: recommend checking abortSignal.aborted first
jasnell Mar 11, 2021
80af610
util: inspect __proto__ key as written in object literal
addaleax Mar 11, 2021
ede34aa
test: address flaky wpt/test-timers
Trott Mar 13, 2021
6d77b61
deps: switch openssl to quictls/openssl
jasnell Mar 4, 2021
ce357c0
deps: update archs files for OpenSSL-1.1.1+quic
jasnell Mar 4, 2021
c2cb153
test: fixup test to account for quic openssl version
jasnell Mar 4, 2021
5d79373
doc: update maintaining-openssl guide
jasnell Mar 4, 2021
0d135e8
worker: add setEnvironmentData/getEnvironmentData
jasnell Feb 23, 2021
ac2f50b
lib: implement AbortSignal.abort()
jasnell Mar 10, 2021
1b53087
test: update dom/abort tests
jasnell Mar 15, 2021
3710857
doc: add hints to http.request() options
lpinca Mar 13, 2021
5a49e31
errors: remove experimental from --enable-source-maps
Mar 13, 2021
bd62771
tools: use bundled npm in update scripts
ruyadorno Mar 4, 2021
30c62de
src,test: support dynamically linking OpenSSL 3.0
danbev Oct 26, 2020
89f3aa9
doc: add marsonya as a triager
marsonya Mar 9, 2021
72af5d9
tools: parse changelogs only in the default branch
aduh95 Mar 16, 2021
dfca2fa
deps: update to cjs-module-lexer@1.1.0
guybedford Mar 11, 2021
5011009
2021-03-17, Version 15.12.0 (Current)
danielleadams Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
crypto: support JWK objects in create*Key
PR-URL: #37254
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
panva authored and danielleadams committed Mar 16, 2021
commit 55e522ca239175299e82eba221ccc910bef9712a
25 changes: 17 additions & 8 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -2452,6 +2452,9 @@ input.on('readable', () => {
<!-- YAML
added: v11.6.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/37254
description: The key can also be a JWK object.
- version: v15.0.0
pr-url: https://github.com/nodejs/node/pull/35093
description: The key can also be an ArrayBuffer. The encoding option was
Expand All @@ -2460,11 +2463,12 @@ changes:

<!--lint disable maximum-line-length remark-lint-->
* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView}
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView} The key material,
either in PEM or DER format.
* `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`.
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView|Object} The key
material, either in PEM, DER, or JWK format.
* `format`: {string} Must be `'pem'`, `'der'`, or '`'jwk'`.
**Default:** `'pem'`.
* `type`: {string} Must be `'pkcs1'`, `'pkcs8'` or `'sec1'`. This option is
required only if the `format` is `'der'` and ignored if it is `'pem'`.
required only if the `format` is `'der'` and ignored otherwise.
* `passphrase`: {string | Buffer} The passphrase to use for decryption.
* `encoding`: {string} The string encoding to use when `key` is a string.
* Returns: {KeyObject}
Expand All @@ -2481,6 +2485,9 @@ of the passphrase is limited to 1024 bytes.
<!-- YAML
added: v11.6.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/37254
description: The key can also be a JWK object.
- version: v15.0.0
pr-url: https://github.com/nodejs/node/pull/35093
description: The key can also be an ArrayBuffer. The encoding option was
Expand All @@ -2496,10 +2503,12 @@ changes:

<!--lint disable maximum-line-length remark-lint-->
* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView}
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView}
* `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'`.
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView|Object} The key
material, either in PEM, DER, or JWK format.
* `format`: {string} Must be `'pem'`, `'der'`, or '`'jwk'`.
**Default:** `'pem'`.
* `type`: {string} Must be `'pkcs1'` or `'spki'`. This option is
required only if the `format` is `'der'` and ignored otherwise.
* `encoding` {string} The string encoding to use when `key` is a string.
* Returns: {KeyObject}
<!--lint enable maximum-line-length remark-lint-->
Expand Down
146 changes: 141 additions & 5 deletions lib/internal/crypto/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const {
const {
validateObject,
validateOneOf,
validateString,
} = require('internal/validators');

const {
Expand All @@ -38,6 +39,7 @@ const {
ERR_OPERATION_FAILED,
ERR_CRYPTO_JWK_UNSUPPORTED_CURVE,
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE,
ERR_CRYPTO_INVALID_JWK,
}
} = require('internal/errors');

Expand Down Expand Up @@ -65,6 +67,8 @@ const {

const { inspect } = require('internal/util/inspect');

const { Buffer } = require('buffer');

const kAlgorithm = Symbol('kAlgorithm');
const kExtractable = Symbol('kExtractable');
const kKeyType = Symbol('kKeyType');
Expand Down Expand Up @@ -413,6 +417,122 @@ function getKeyTypes(allowKeyObject, bufferOnly = false) {
return types;
}

function getKeyObjectHandleFromJwk(key, ctx) {
validateObject(key, 'key');
validateOneOf(
key.kty, 'key.kty', ['RSA', 'EC', 'OKP']);
const isPublic = ctx === kConsumePublic || ctx === kCreatePublic;

if (key.kty === 'OKP') {
validateString(key.crv, 'key.crv');
validateOneOf(
key.crv, 'key.crv', ['Ed25519', 'Ed448', 'X25519', 'X448']);
validateString(key.x, 'key.x');

if (!isPublic)
validateString(key.d, 'key.d');

let keyData;
if (isPublic)
keyData = Buffer.from(key.x, 'base64');
else
keyData = Buffer.from(key.d, 'base64');

switch (key.crv) {
case 'Ed25519':
case 'X25519':
if (keyData.byteLength !== 32) {
throw new ERR_CRYPTO_INVALID_JWK();
}
break;
case 'Ed448':
if (keyData.byteLength !== 57) {
throw new ERR_CRYPTO_INVALID_JWK();
}
break;
case 'X448':
if (keyData.byteLength !== 56) {
throw new ERR_CRYPTO_INVALID_JWK();
}
break;
}

const handle = new KeyObjectHandle();
if (isPublic) {
handle.initEDRaw(
`NODE-${key.crv.toUpperCase()}`,
keyData,
kKeyTypePublic);
} else {
handle.initEDRaw(
`NODE-${key.crv.toUpperCase()}`,
keyData,
kKeyTypePrivate);
}

return handle;
}

if (key.kty === 'EC') {
validateString(key.crv, 'key.crv');
validateOneOf(
key.crv, 'key.crv', ['P-256', 'secp256k1', 'P-384', 'P-521']);
validateString(key.x, 'key.x');
validateString(key.y, 'key.y');

const jwk = {
kty: key.kty,
crv: key.crv,
x: key.x,
y: key.y
};

if (!isPublic) {
validateString(key.d, 'key.d');
jwk.d = key.d;
}

const handle = new KeyObjectHandle();
const type = handle.initJwk(jwk, jwk.crv);
if (type === undefined)
throw new ERR_CRYPTO_INVALID_JWK();

return handle;
}

// RSA
validateString(key.n, 'key.n');
validateString(key.e, 'key.e');

const jwk = {
kty: key.kty,
n: key.n,
e: key.e
};

if (!isPublic) {
validateString(key.d, 'key.d');
validateString(key.p, 'key.p');
validateString(key.q, 'key.q');
validateString(key.dp, 'key.dp');
validateString(key.dq, 'key.dq');
validateString(key.qi, 'key.qi');
jwk.d = key.d;
jwk.p = key.p;
jwk.q = key.q;
jwk.dp = key.dp;
jwk.dq = key.dq;
jwk.qi = key.qi;
}

const handle = new KeyObjectHandle();
const type = handle.initJwk(jwk);
if (type === undefined)
throw new ERR_CRYPTO_INVALID_JWK();

return handle;
}

function prepareAsymmetricKey(key, ctx) {
if (isKeyObject(key)) {
// Best case: A key object, as simple as that.
Expand All @@ -423,13 +543,15 @@ function prepareAsymmetricKey(key, ctx) {
// Expect PEM by default, mostly for backward compatibility.
return { format: kKeyFormatPEM, data: getArrayBufferOrView(key, 'key') };
} else if (typeof key === 'object') {
const { key: data, encoding } = key;
const { key: data, encoding, format } = key;
// 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, ctx) };
else if (isCryptoKey(data))
return { data: getKeyObjectHandle(data[kKeyObject], ctx) };
else if (isJwk(data) && format === 'jwk')
return { data: getKeyObjectHandleFromJwk(data, ctx), format: 'jwk' };
// Either PEM or DER using PKCS#1 or SPKI.
if (!isStringOrBuffer(data)) {
throw new ERR_INVALID_ARG_TYPE(
Expand Down Expand Up @@ -494,16 +616,26 @@ function createSecretKey(key, encoding) {
function createPublicKey(key) {
const { format, type, data, passphrase } =
prepareAsymmetricKey(key, kCreatePublic);
const handle = new KeyObjectHandle();
handle.init(kKeyTypePublic, data, format, type, passphrase);
let handle;
if (format === 'jwk') {
handle = data;
} else {
handle = new KeyObjectHandle();
handle.init(kKeyTypePublic, data, format, type, passphrase);
}
return new PublicKeyObject(handle);
}

function createPrivateKey(key) {
const { format, type, data, passphrase } =
prepareAsymmetricKey(key, kCreatePrivate);
const handle = new KeyObjectHandle();
handle.init(kKeyTypePrivate, data, format, type, passphrase);
let handle;
if (format === 'jwk') {
handle = data;
} else {
handle = new KeyObjectHandle();
handle.init(kKeyTypePrivate, data, format, type, passphrase);
}
return new PrivateKeyObject(handle);
}

Expand Down Expand Up @@ -609,6 +741,10 @@ function isCryptoKey(obj) {
return obj != null && obj[kKeyObject] !== undefined;
}

function isJwk(obj) {
return obj != null && obj.kty !== undefined;
}

module.exports = {
// Public API.
createSecretKey,
Expand Down
1 change: 1 addition & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ E('ERR_CRYPTO_INCOMPATIBLE_KEY', 'Incompatible %s: %s', Error);
E('ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS', 'The selected key encoding %s %s.',
Error);
E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s', TypeError);
E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError);
E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
'Invalid key object type %s, expected %s.', TypeError);
E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error);
Expand Down
Loading