mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
Exporting a key in 'raw', 'raw-public' or 'raw-seed' format when the key type does not match (e.g. an ECDSA private key as 'raw', or an ML-KEM public key as 'raw-seed') fell through to the generic NotSupportedError. The Web Crypto and modern-algos export key steps require an InvalidAccessError in these cases. Mirror exportKeySpki() and exportKeyPkcs8(): select the exporter per algorithm first, then check the key type, and drop the type guards around the call sites in exportKeySync(). Formats an algorithm does not support (e.g. 'raw' for ML-DSA) still throw NotSupportedError. This also fixes wrapKey(), which uses the same export path. Assisted-by: a closed-source coding agent Signed-off-by: koreahghg <koreahghg@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66217 Reviewed-By: Filip Skokan <panva.ip@gmail.com>
566 lines
19 KiB
JavaScript
566 lines
19 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
const fixtures = require('../common/fixtures');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const assert = require('assert');
|
|
const crypto = require('crypto');
|
|
const { subtle } = globalThis.crypto;
|
|
|
|
const curves = ['P-256', 'P-384', 'P-521'];
|
|
|
|
const keyData = {
|
|
'P-521': {
|
|
jwsAlg: 'ES512',
|
|
spki: Buffer.from(
|
|
'30819b301006072a8648ce3d020106052b8104002303818600040156f479f8df' +
|
|
'1e20a7ffc04ce420c3e154ae251996bee42f034b84d41b743f34e45f311b813a' +
|
|
'9cdec8cda59bbbbd31d460b3292521e7c1b722e5667c03db2fae753f01501736' +
|
|
'cfe247394320d8e4afc2fd39b5a9331061b81e2241282b9e17891822b5b79e05' +
|
|
'2f4597b59643fd39379c51bd5125c4f48bc3f025ce3cd36953286ccb38fb',
|
|
'hex'),
|
|
pkcs8: Buffer.from(
|
|
'3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020' +
|
|
'101044200f408758368ba930f30f76ae054fe5cd2ce7fda2c9f76a6d436cf75' +
|
|
'd66c440bfe6331c7c172a12478193c8251487bc91263fa50217f85ff636f59c' +
|
|
'd546e3ab483b4a1818903818600040156f479f8df1e20a7ffc04ce420c3e154' +
|
|
'ae251996bee42f034b84d41b743f34e45f311b813a9cdec8cda59bbbbd31d46' +
|
|
'0b3292521e7c1b722e5667c03db2fae753f01501736cfe247394320d8e4afc2' +
|
|
'fd39b5a9331061b81e2241282b9e17891822b5b79e052f4597b59643fd39379' +
|
|
'c51bd5125c4f48bc3f025ce3cd36953286ccb38fb', 'hex'),
|
|
jwk: {
|
|
kty: 'EC',
|
|
crv: 'P-521',
|
|
x: 'AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjN' +
|
|
'pZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_',
|
|
y: 'AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0W' +
|
|
'XtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7',
|
|
d: 'APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHw' +
|
|
'XKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0'
|
|
}
|
|
},
|
|
'P-384': {
|
|
jwsAlg: 'ES384',
|
|
spki: Buffer.from(
|
|
'3076301006072a8648ce3d020106052b8104002203620004219c14d66617b36e' +
|
|
'c6d8856b385b73a74d344fd8ae75ef046435dda54e3b44bd5fbdebd1d08dd69e' +
|
|
'2d7dc1dc218cb435bd28138cc778337a842f6bd61b240e74249f24667c2a5810' +
|
|
'a76bfc28e0335f88a6501dec01976da85afb00869cb6ace8', 'hex'),
|
|
pkcs8: Buffer.from(
|
|
'3081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201' +
|
|
'0104304537b5990784d3c2d22e96a8f92fa1aa492ee873e576a41582e144183c' +
|
|
'9888d10e6b9eb4ced4b2cc4012e4ac5ea84073a16403620004219c14d66617b3' +
|
|
'6ec6d8856b385b73a74d344fd8ae75ef046435dda54e3b44bd5fbdebd1d08dd6' +
|
|
'9e2d7dc1dc218cb435bd28138cc778337a842f6bd61b240e74249f24667c2a58' +
|
|
'10a76bfc28e0335f88a6501dec01976da85afb00869cb6ace8', 'hex'),
|
|
jwk: {
|
|
kty: 'EC',
|
|
crv: 'P-384',
|
|
x: 'IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1',
|
|
y: 'vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo',
|
|
d: 'RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz'
|
|
}
|
|
},
|
|
'P-256': {
|
|
jwsAlg: 'ES256',
|
|
spki: Buffer.from(
|
|
'3059301306072a8648ce3d020106082a8648ce3d03010703420004d6e8328a95' +
|
|
'fe29afcdc30977b9251efbb219022807f6b14bb34695b6b4bdb93ee6684548a4' +
|
|
'ad13c49d00433c45315e8274f3540f58f5d79ef7a1b184f4c21d17', 'hex'),
|
|
pkcs8: Buffer.from(
|
|
'308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02' +
|
|
'010104202bc2eda265e46866efa8f8f99da993175b6c85c246e15dceaed7e307' +
|
|
'0f13fbf8a14403420004d6e8328a95fe29afcdc30977b9251efbb219022807f6' +
|
|
'b14bb34695b6b4bdb93ee6684548a4ad13c49d00433c45315e8274f3540f58f5' +
|
|
'd79ef7a1b184f4c21d17', 'hex'),
|
|
jwk: {
|
|
kty: 'EC',
|
|
crv: 'P-256',
|
|
x: '1ugyipX-Ka_Nwwl3uSUe-7IZAigH9rFLs0aVtrS9uT4',
|
|
y: '5mhFSKStE8SdAEM8RTFegnTzVA9Y9dee96GxhPTCHRc',
|
|
d: 'K8LtomXkaGbvqPj5namTF1tshcJG4V3OrtfjBw8T-_g'
|
|
}
|
|
},
|
|
};
|
|
|
|
const testVectors = [
|
|
{
|
|
name: 'ECDSA',
|
|
privateUsages: ['sign'],
|
|
publicUsages: ['verify']
|
|
},
|
|
{
|
|
name: 'ECDH',
|
|
privateUsages: ['deriveKey', 'deriveBits'],
|
|
publicUsages: []
|
|
},
|
|
];
|
|
|
|
async function testImportSpki({ name, publicUsages }, namedCurve, extractable) {
|
|
const key = await subtle.importKey(
|
|
'spki',
|
|
keyData[namedCurve].spki,
|
|
{ name, namedCurve },
|
|
extractable,
|
|
publicUsages);
|
|
assert.strictEqual(key.type, 'public');
|
|
assert.strictEqual(key.extractable, extractable);
|
|
assert.deepStrictEqual(key.usages, publicUsages);
|
|
assert.deepStrictEqual(key.algorithm.name, name);
|
|
assert.deepStrictEqual(key.algorithm.namedCurve, namedCurve);
|
|
assert.strictEqual(key.algorithm, key.algorithm);
|
|
assert.strictEqual(key.usages, key.usages);
|
|
|
|
if (extractable) {
|
|
// Test the roundtrip
|
|
const spki = await subtle.exportKey('spki', key);
|
|
assert.strictEqual(
|
|
Buffer.from(spki).toString('hex'),
|
|
keyData[namedCurve].spki.toString('hex'));
|
|
|
|
await assert.rejects(
|
|
subtle.exportKey('pkcs8', key), {
|
|
message: 'Key must be a private key',
|
|
name: 'InvalidAccessError',
|
|
});
|
|
} else {
|
|
await assert.rejects(
|
|
subtle.exportKey('spki', key), {
|
|
message: /key is not extractable/,
|
|
name: 'InvalidAccessError',
|
|
});
|
|
}
|
|
|
|
// Bad usage
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'spki',
|
|
keyData[namedCurve].spki,
|
|
{ name, namedCurve },
|
|
extractable,
|
|
['wrapKey']),
|
|
{ message: /Unsupported key usage/ });
|
|
}
|
|
|
|
async function testImportPkcs8(
|
|
{ name, privateUsages },
|
|
namedCurve,
|
|
extractable) {
|
|
const key = await subtle.importKey(
|
|
'pkcs8',
|
|
keyData[namedCurve].pkcs8,
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages);
|
|
assert.strictEqual(key.type, 'private');
|
|
assert.strictEqual(key.extractable, extractable);
|
|
assert.deepStrictEqual(key.usages, privateUsages);
|
|
assert.deepStrictEqual(key.algorithm.name, name);
|
|
assert.deepStrictEqual(key.algorithm.namedCurve, namedCurve);
|
|
assert.strictEqual(key.algorithm, key.algorithm);
|
|
assert.strictEqual(key.usages, key.usages);
|
|
|
|
if (extractable) {
|
|
// Test the roundtrip
|
|
const pkcs8 = await subtle.exportKey('pkcs8', key);
|
|
assert.strictEqual(
|
|
Buffer.from(pkcs8).toString('hex'),
|
|
keyData[namedCurve].pkcs8.toString('hex'));
|
|
|
|
await assert.rejects(
|
|
subtle.exportKey('spki', key), {
|
|
message: 'Key must be a public key',
|
|
name: 'InvalidAccessError',
|
|
});
|
|
|
|
for (const format of ['raw', 'raw-public']) {
|
|
await assert.rejects(
|
|
subtle.exportKey(format, key), {
|
|
message: 'Key must be a public key',
|
|
name: 'InvalidAccessError',
|
|
});
|
|
}
|
|
} else {
|
|
await assert.rejects(
|
|
subtle.exportKey('pkcs8', key), {
|
|
message: /key is not extractable/,
|
|
name: 'InvalidAccessError',
|
|
});
|
|
}
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'pkcs8',
|
|
keyData[namedCurve].pkcs8,
|
|
{ name, namedCurve },
|
|
extractable,
|
|
[/* empty usages */]),
|
|
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
|
|
}
|
|
|
|
async function testImportJwk(
|
|
{ name, publicUsages, privateUsages },
|
|
namedCurve,
|
|
extractable) {
|
|
|
|
const jwk = keyData[namedCurve].jwk;
|
|
|
|
const [
|
|
publicKey,
|
|
privateKey,
|
|
] = await Promise.all([
|
|
subtle.importKey(
|
|
'jwk',
|
|
{
|
|
kty: jwk.kty,
|
|
crv: jwk.crv,
|
|
x: jwk.x,
|
|
y: jwk.y,
|
|
},
|
|
{ name, namedCurve },
|
|
extractable, publicUsages),
|
|
subtle.importKey(
|
|
'jwk',
|
|
jwk,
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages),
|
|
subtle.importKey(
|
|
'jwk',
|
|
{
|
|
alg: name === 'ECDSA' ? keyData[namedCurve].jwsAlg : 'ECDH-ES',
|
|
kty: jwk.kty,
|
|
crv: jwk.crv,
|
|
x: jwk.x,
|
|
y: jwk.y,
|
|
},
|
|
{ name, namedCurve },
|
|
extractable, publicUsages),
|
|
subtle.importKey(
|
|
'jwk',
|
|
{
|
|
...jwk,
|
|
alg: name === 'ECDSA' ? keyData[namedCurve].jwsAlg : 'ECDH-ES',
|
|
},
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages),
|
|
]);
|
|
|
|
assert.strictEqual(publicKey.type, 'public');
|
|
assert.strictEqual(privateKey.type, 'private');
|
|
assert.strictEqual(publicKey.extractable, extractable);
|
|
assert.strictEqual(privateKey.extractable, extractable);
|
|
assert.deepStrictEqual(publicKey.usages, publicUsages);
|
|
assert.deepStrictEqual(privateKey.usages, privateUsages);
|
|
assert.strictEqual(publicKey.algorithm.name, name);
|
|
assert.strictEqual(privateKey.algorithm.name, name);
|
|
assert.strictEqual(publicKey.algorithm.namedCurve, namedCurve);
|
|
assert.strictEqual(privateKey.algorithm.namedCurve, namedCurve);
|
|
assert.strictEqual(privateKey.algorithm, privateKey.algorithm);
|
|
assert.strictEqual(privateKey.usages, privateKey.usages);
|
|
assert.strictEqual(publicKey.algorithm, publicKey.algorithm);
|
|
assert.strictEqual(publicKey.usages, publicKey.usages);
|
|
|
|
if (extractable) {
|
|
// Test the round trip
|
|
const [
|
|
pubJwk,
|
|
pvtJwk,
|
|
] = await Promise.all([
|
|
subtle.exportKey('jwk', publicKey),
|
|
subtle.exportKey('jwk', privateKey),
|
|
]);
|
|
|
|
assert.deepStrictEqual(pubJwk.key_ops, publicUsages);
|
|
assert.strictEqual(pubJwk.ext, true);
|
|
assert.strictEqual(pubJwk.kty, 'EC');
|
|
assert.strictEqual(pubJwk.x, jwk.x);
|
|
assert.strictEqual(pubJwk.y, jwk.y);
|
|
assert.strictEqual(pubJwk.crv, jwk.crv);
|
|
|
|
assert.deepStrictEqual(pvtJwk.key_ops, privateUsages);
|
|
assert.strictEqual(pvtJwk.ext, true);
|
|
assert.strictEqual(pvtJwk.kty, 'EC');
|
|
assert.strictEqual(pvtJwk.x, jwk.x);
|
|
assert.strictEqual(pvtJwk.y, jwk.y);
|
|
assert.strictEqual(pvtJwk.crv, jwk.crv);
|
|
assert.strictEqual(pvtJwk.d, jwk.d);
|
|
} else {
|
|
await assert.rejects(
|
|
subtle.exportKey('jwk', publicKey), {
|
|
message: /key is not extractable/,
|
|
name: 'InvalidAccessError',
|
|
});
|
|
await assert.rejects(
|
|
subtle.exportKey('jwk', privateKey), {
|
|
message: /key is not extractable/,
|
|
name: 'InvalidAccessError',
|
|
});
|
|
}
|
|
|
|
{
|
|
const invalidUse = name === 'ECDH' ? 'sig' : 'enc';
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...jwk, use: invalidUse },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages),
|
|
{ message: 'Invalid JWK "use" Parameter' });
|
|
}
|
|
|
|
if (name === 'ECDSA') {
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ kty: jwk.kty, x: jwk.x, y: jwk.y, crv: jwk.crv, alg: jwk.crv === 'P-256' ? 'ES384' : 'ES256' },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
publicUsages),
|
|
{ message: 'JWK "alg" does not match the requested algorithm' });
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...jwk, alg: jwk.crv === 'P-256' ? 'ES384' : 'ES256' },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages),
|
|
{ message: 'JWK "alg" does not match the requested algorithm' });
|
|
}
|
|
|
|
for (const crv of [undefined, namedCurve === 'P-256' ? 'P-384' : 'P-256']) {
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ kty: jwk.kty, x: jwk.x, y: jwk.y, crv },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
publicUsages),
|
|
{ message: crv ? 'JWK "crv" does not match the requested algorithm' : 'Invalid keyData' });
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...jwk, crv },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
privateUsages),
|
|
{ message: crv ? 'JWK "crv" does not match the requested algorithm' : 'Invalid keyData' });
|
|
}
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...jwk },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
[/* empty usages */]),
|
|
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ kty: jwk.kty, /* missing x */ y: jwk.y, crv: jwk.crv },
|
|
{ name, namedCurve },
|
|
extractable,
|
|
publicUsages),
|
|
{ name: 'DataError', message: 'Invalid keyData' });
|
|
}
|
|
|
|
async function testImportRaw({ name, publicUsages }, namedCurve) {
|
|
const jwk = keyData[namedCurve].jwk;
|
|
|
|
const uncompressedRaw = Buffer.concat([
|
|
Buffer.alloc(1, 0x04),
|
|
Buffer.from(jwk.x, 'base64url'),
|
|
Buffer.from(jwk.y, 'base64url'),
|
|
]);
|
|
|
|
const [publicKey] = await Promise.all([
|
|
subtle.importKey(
|
|
'raw',
|
|
uncompressedRaw,
|
|
{ name, namedCurve },
|
|
true, publicUsages),
|
|
subtle.importKey(
|
|
'raw',
|
|
Buffer.concat([
|
|
Buffer.alloc(1, 0x03),
|
|
Buffer.from(jwk.x, 'base64url'),
|
|
]),
|
|
{ name, namedCurve },
|
|
true, publicUsages),
|
|
]);
|
|
|
|
assert.strictEqual(publicKey.type, 'public');
|
|
assert.deepStrictEqual(publicKey.usages, publicUsages);
|
|
assert.strictEqual(publicKey.algorithm.name, name);
|
|
assert.strictEqual(publicKey.algorithm.namedCurve, namedCurve);
|
|
assert.strictEqual(publicKey.algorithm, publicKey.algorithm);
|
|
assert.strictEqual(publicKey.usages, publicKey.usages);
|
|
|
|
// Test raw export round-trip (always uncompressed)
|
|
const exported = await subtle.exportKey('raw', publicKey);
|
|
assert.deepStrictEqual(Buffer.from(exported), uncompressedRaw);
|
|
}
|
|
|
|
(async function() {
|
|
const tests = [];
|
|
for (const vector of testVectors) {
|
|
for (const namedCurve of curves) {
|
|
for (const extractable of [true, false]) {
|
|
tests.push(testImportSpki(vector, namedCurve, extractable));
|
|
tests.push(testImportPkcs8(vector, namedCurve, extractable));
|
|
tests.push(testImportJwk(vector, namedCurve, extractable));
|
|
}
|
|
tests.push(testImportRaw(vector, namedCurve));
|
|
}
|
|
}
|
|
|
|
await Promise.all(tests);
|
|
})().then(common.mustCall());
|
|
|
|
// JWK key usage validation precedes `key_ops` validation.
|
|
(async function() {
|
|
const jwk = keyData['P-256'].jwk;
|
|
const publicJwk = {
|
|
kty: jwk.kty,
|
|
crv: jwk.crv,
|
|
x: jwk.x,
|
|
y: jwk.y,
|
|
};
|
|
|
|
for (const { name, publicUsages, privateUsages } of testVectors) {
|
|
const invalidUsage = name === 'ECDH' ?
|
|
privateUsages[0] : publicUsages[0];
|
|
const invalidJwk = name === 'ECDH' ? publicJwk : jwk;
|
|
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...invalidJwk, key_ops: [invalidUsage, invalidUsage] },
|
|
{ name, namedCurve: 'P-256' },
|
|
true,
|
|
[invalidUsage]),
|
|
{ name: 'SyntaxError', message: /Unsupported key usage/ });
|
|
|
|
const validUsage = privateUsages[0];
|
|
await assert.rejects(
|
|
subtle.importKey(
|
|
'jwk',
|
|
{ ...jwk, key_ops: [validUsage, validUsage] },
|
|
{ name, namedCurve: 'P-256' },
|
|
true,
|
|
[validUsage]),
|
|
{ name: 'DataError', message: 'Duplicate key operation' });
|
|
}
|
|
})().then(common.mustCall());
|
|
|
|
|
|
// https://github.com/nodejs/node/issues/45859
|
|
(async function() {
|
|
const compressed = Buffer.from([48, 57, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 34, 0, 2, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209]); // eslint-disable-line @stylistic/js/max-len
|
|
const uncompressed = Buffer.from([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]); // eslint-disable-line @stylistic/js/max-len
|
|
for (const name of ['ECDH', 'ECDSA']) {
|
|
const options = { name, namedCurve: 'P-256' };
|
|
const key = await subtle.importKey('spki', compressed, options, true, []);
|
|
const spki = await subtle.exportKey('spki', key);
|
|
assert.deepStrictEqual(uncompressed, Buffer.from(spki));
|
|
}
|
|
})().then(common.mustCall());
|
|
|
|
{
|
|
const rsaPublic = crypto.createPublicKey(
|
|
fixtures.readKey('rsa_public_2048.pem'));
|
|
const rsaPrivate = crypto.createPrivateKey(
|
|
fixtures.readKey('rsa_private_2048.pem'));
|
|
|
|
for (const [name, publicUsages, privateUsages] of [
|
|
['ECDSA', ['verify'], ['sign']],
|
|
['ECDH', [], ['deriveBits', 'deriveBits']],
|
|
]) {
|
|
assert.rejects(
|
|
subtle.importKey(
|
|
'spki',
|
|
rsaPublic.export({ format: 'der', type: 'spki' }),
|
|
{ name, namedCurve: 'P-256' },
|
|
true, publicUsages), { message: /Invalid key type/ },
|
|
).then(common.mustCall());
|
|
assert.rejects(
|
|
subtle.importKey(
|
|
'pkcs8',
|
|
rsaPrivate.export({ format: 'der', type: 'pkcs8' }),
|
|
{ name, namedCurve: 'P-256' },
|
|
true, privateUsages), { message: /Invalid key type/ },
|
|
).then(common.mustCall());
|
|
}
|
|
}
|
|
|
|
// Bad private keys
|
|
{
|
|
for (const { namedCurve, key: pkcs8 } of [
|
|
// The private key is exactly equal to the order, and the public key is
|
|
// private key * order.
|
|
{
|
|
namedCurve: 'P-256',
|
|
key: Buffer.from(
|
|
'3066020100301306072a8648ce3d020106082a8648ce3d030107044c304a0201' +
|
|
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc' +
|
|
'632551a12303210000ffffff00000000ffffffffffffffffbce6faada7179e84' +
|
|
'f3b9cac2fc632551', 'hex'),
|
|
},
|
|
// The private key is exactly equal to the order, and the public key is
|
|
// omitted.
|
|
{
|
|
namedCurve: 'P-256',
|
|
key: Buffer.from(
|
|
'3041020100301306072a8648ce3d020106082a8648ce3d030107042730250201' +
|
|
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc' +
|
|
'632551', 'hex'),
|
|
},
|
|
// The private key is exactly equal to the order + 11, and the public key is
|
|
// private key * order.
|
|
{
|
|
namedCurve: 'P-521',
|
|
key: Buffer.from(
|
|
'3081ee020100301006072a8648ce3d020106052b810400230481d63081d30201' +
|
|
'01044201ffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
|
|
'fffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb7' +
|
|
'1e91386414a181890381860004008a75841259fdedff546f1a39573b4315cfed' +
|
|
'5dc7ed7c17849543ef2c54f2991652f3dbc5332663da1bd19b1aebe319108501' +
|
|
'5c024fa4c9a902ecc0e02dda0cdb9a0096fb303fcbba2129849d0ca877054fb2' +
|
|
'293add566210bd0493ed2e95d4e0b9b82b1bc8a90e8b42a4ab3892331914a953' +
|
|
'36dcac80e3f4819b5d58874f92ce48c808', 'hex'),
|
|
},
|
|
// The private key is exactly equal to the order + 11, and the public key is
|
|
// omitted.
|
|
{
|
|
namedCurve: 'P-521',
|
|
key: Buffer.from(
|
|
'3060020100301006072a8648ce3d020106052b81040023044930470201010442' +
|
|
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
|
|
'fffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138' +
|
|
'6414', 'hex'),
|
|
},
|
|
]) {
|
|
for (const [name, privateUsages] of [
|
|
['ECDSA', ['sign']],
|
|
['ECDH', ['deriveBits', 'deriveBits']],
|
|
]) {
|
|
assert.rejects(
|
|
subtle.importKey(
|
|
'pkcs8',
|
|
pkcs8,
|
|
{ name, namedCurve },
|
|
true, privateUsages), { name: 'DataError', message: /Invalid keyData/ },
|
|
).then(common.mustCall());
|
|
}
|
|
}
|
|
}
|