mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: https://github.com/nodejs/node/pull/64960 Fixes: https://github.com/nodejs/node/issues/48379 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
'use strict';
|
|
|
|
// KeyObject instances must survive structured cloning with their
|
|
// native backing data and hidden JS slot semantics preserved.
|
|
|
|
const common = require('../common');
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const assert = require('node:assert');
|
|
const { once } = require('node:events');
|
|
const {
|
|
createHmac,
|
|
createSecretKey,
|
|
generateKeyPairSync,
|
|
sign,
|
|
verify,
|
|
} = require('node:crypto');
|
|
const { hasFIPS } = require('../common/crypto');
|
|
const { MessageChannel, Worker } = require('node:worker_threads');
|
|
const { types: { isKeyObject } } = require('node:util');
|
|
|
|
function assertNoOwnKeys(key) {
|
|
assert.deepStrictEqual(Object.getOwnPropertySymbols(key), []);
|
|
assert.deepStrictEqual(Object.getOwnPropertyNames(key), []);
|
|
assert.deepStrictEqual(Reflect.ownKeys(key), []);
|
|
}
|
|
|
|
function assertSameKeyObject(original, clone) {
|
|
assert.notStrictEqual(original, clone);
|
|
assert.strictEqual(isKeyObject(clone), true);
|
|
assert.strictEqual(original.type, clone.type);
|
|
assert.strictEqual(original.equals(clone), true);
|
|
assert.deepStrictEqual(original, clone);
|
|
if (clone.type === 'secret') {
|
|
assert.strictEqual(original.symmetricKeySize, clone.symmetricKeySize);
|
|
} else {
|
|
assert.strictEqual(original.asymmetricKeyType, clone.asymmetricKeyType);
|
|
assert.deepStrictEqual(
|
|
original.asymmetricKeyDetails,
|
|
clone.asymmetricKeyDetails);
|
|
}
|
|
assertNoOwnKeys(original);
|
|
assertNoOwnKeys(clone);
|
|
}
|
|
|
|
async function roundTripViaMessageChannel(key) {
|
|
const { port1, port2 } = new MessageChannel();
|
|
port1.postMessage(key);
|
|
const [received] = await once(port2, 'message');
|
|
port1.close();
|
|
port2.close();
|
|
return received;
|
|
}
|
|
|
|
async function roundTripViaWorker(key) {
|
|
const worker = new Worker(`
|
|
'use strict';
|
|
const { parentPort } = require('node:worker_threads');
|
|
const { types: { isKeyObject } } = require('node:util');
|
|
|
|
parentPort.once('message', ({ key, expectedType }) => {
|
|
try {
|
|
if (!isKeyObject(key) || key.type !== expectedType) {
|
|
throw new Error('KeyObject slot mismatch in worker');
|
|
}
|
|
parentPort.postMessage({ key });
|
|
} catch (err) {
|
|
parentPort.postMessage({ error: err.stack || err.message });
|
|
}
|
|
});
|
|
`, { eval: true });
|
|
|
|
worker.postMessage({ key, expectedType: key.type });
|
|
const [msg] = await once(worker, 'message');
|
|
await worker.terminate();
|
|
|
|
assert.strictEqual(msg.error, undefined, msg.error);
|
|
return msg.key;
|
|
}
|
|
|
|
function hmacDigest(key) {
|
|
return createHmac('sha256', key).update('payload').digest('hex');
|
|
}
|
|
|
|
(async () => {
|
|
const secret = createSecretKey(Buffer.alloc(16));
|
|
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
|
modulusLength: hasFIPS(3) ? 2048 : 1024,
|
|
});
|
|
|
|
for (const key of [secret, publicKey, privateKey]) {
|
|
const cloned = structuredClone(key);
|
|
assertSameKeyObject(key, cloned);
|
|
|
|
const viaPort = await roundTripViaMessageChannel(key);
|
|
assertSameKeyObject(key, viaPort);
|
|
|
|
const clonedAgain = structuredClone(viaPort);
|
|
assertSameKeyObject(key, clonedAgain);
|
|
|
|
const viaWorker = await roundTripViaWorker(key);
|
|
assertSameKeyObject(key, viaWorker);
|
|
}
|
|
|
|
const secretClones = [
|
|
secret,
|
|
structuredClone(secret),
|
|
await roundTripViaMessageChannel(secret),
|
|
await roundTripViaWorker(secret),
|
|
];
|
|
const digest = hmacDigest(secret);
|
|
for (const key of secretClones) {
|
|
assert.strictEqual(hmacDigest(key), digest);
|
|
}
|
|
|
|
const data = Buffer.from('payload');
|
|
const publicClones = [
|
|
publicKey,
|
|
structuredClone(publicKey),
|
|
await roundTripViaMessageChannel(publicKey),
|
|
await roundTripViaWorker(publicKey),
|
|
];
|
|
const privateClones = [
|
|
privateKey,
|
|
structuredClone(privateKey),
|
|
await roundTripViaMessageChannel(privateKey),
|
|
await roundTripViaWorker(privateKey),
|
|
];
|
|
|
|
const signature = sign('sha256', data, privateKey);
|
|
for (const key of publicClones) {
|
|
assert.strictEqual(verify('sha256', data, key, signature), true);
|
|
}
|
|
for (const key of privateClones) {
|
|
const clonedSignature = sign('sha256', data, key);
|
|
assert.strictEqual(verify('sha256', data, publicKey, clonedSignature), true);
|
|
}
|
|
})().then(common.mustCall());
|