Skip to content
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

test: migrate tests to use node:test module for better test structure for webcrypto #56030

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
70 changes: 36 additions & 34 deletions test/parallel/test-webcrypto-cryptokey-workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,55 @@
// sent to a Worker via postMessage.

const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const assert = require('node:assert');
const { test } = require('node:test');
const { subtle } = globalThis.crypto;
const { once } = require('events');
const { once } = require('node:events');
const { Worker, parentPort } = require('node:worker_threads');

const {
Worker,
parentPort,
} = require('worker_threads');

const keyData =
Buffer.from(
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex');
// Skip the test if crypto is not available
if (!common.hasCrypto) common.skip('missing crypto');

const keyData = Buffer.from(
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', 'hex'
);
const sig = '13691a79fb55a0417e4d6699a32f91ad29283fa2c1439865cc0632931f4f48dc';

async function doSig(key) {
const signature = await subtle.sign({
name: 'HMAC'
}, key, Buffer.from('some data'));
const signature = await subtle.sign({ name: 'HMAC' }, key, Buffer.from('some data'));
assert.strictEqual(Buffer.from(signature).toString('hex'), sig);
}

if (process.env.HAS_STARTED_WORKER) {
return parentPort.once('message', (key) => {
assert.strictEqual(key.algorithm.name, 'HMAC');
doSig(key).then(common.mustCall());
});
}
// Main test logic
test('CryptoKey instances can be sent to a Worker via postMessage', async (t) => {
await t.test('should process signature in Worker and main thread', async () => {
if (process.env.HAS_STARTED_WORKER) {
return parentPort.once('message', (key) => {
assert.strictEqual(key.algorithm.name, 'HMAC');
doSig(key).then(common.mustCall());
});
}

// Don't use isMainThread to allow running this test inside a worker.
process.env.HAS_STARTED_WORKER = 1;
// Set environment variable to trigger worker process
process.env.HAS_STARTED_WORKER = 1;

(async function() {
const worker = new Worker(__filename);
const worker = new Worker(__filename);

await once(worker, 'online');
// Wait for the worker to start
await once(worker, 'online');

const key = await subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
true, ['sign', 'verify']);
// Create and send the CryptoKey to the worker
const key = await subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
true, ['sign', 'verify']
);

worker.postMessage(key);
worker.postMessage(key);

await doSig(key);
})().then(common.mustCall());
// Perform the signature in the main thread
await doSig(key);
});
});
189 changes: 43 additions & 146 deletions test/parallel/test-webcrypto-export-import-rsa.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
'use strict';

const common = require('../common');
const fixtures = require('../common/fixtures');

if (!common.hasCrypto)
common.skip('missing crypto');
require('../common');

const assert = require('assert');
const crypto = require('crypto');
const { subtle } = globalThis.crypto;

const sizes = [1024, 2048, 4096];

const hashes = [
'SHA-1',
'SHA-256',
'SHA-384',
'SHA-512',
];
const hashes = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];

const keyData = {
1024: {
Expand Down Expand Up @@ -305,61 +294,59 @@ async function testImportSpki({ name, publicUsages }, size, hash, extractable) {
keyData[size].spki,
{ name, hash },
extractable,
publicUsages);
publicUsages
);

assert.strictEqual(key.type, 'public');
assert.strictEqual(key.extractable, extractable);
assert.deepStrictEqual(key.usages, publicUsages);
assert.strictEqual(key.algorithm.name, name);
assert.strictEqual(key.algorithm.modulusLength, size);
assert.deepStrictEqual(key.algorithm.publicExponent,
new Uint8Array([1, 0, 1]));
assert.deepStrictEqual(key.algorithm.publicExponent, new Uint8Array([1, 0, 1]));
assert.strictEqual(key.algorithm.hash.name, hash);

if (extractable) {
const spki = await subtle.exportKey('spki', key);
assert.strictEqual(
Buffer.from(spki).toString('hex'),
keyData[size].spki.toString('hex'));
keyData[size].spki.toString('hex')
);
} else {
await assert.rejects(
subtle.exportKey('spki', key), {
message: /key is not extractable/
});
subtle.exportKey('spki', key),
{ message: /key is not extractable/ }
);
}
}

async function testImportPkcs8(
{ name, privateUsages },
size,
hash,
extractable) {
async function testImportPkcs8({ name, privateUsages }, size, hash, extractable) {
const key = await subtle.importKey(
'pkcs8',
keyData[size].pkcs8,
{ name, hash },
extractable,
privateUsages);
privateUsages
);

assert.strictEqual(key.type, 'private');
assert.strictEqual(key.extractable, extractable);
assert.deepStrictEqual(key.usages, privateUsages);
assert.strictEqual(key.algorithm.name, name);
assert.strictEqual(key.algorithm.modulusLength, size);
assert.deepStrictEqual(key.algorithm.publicExponent,
new Uint8Array([1, 0, 1]));
assert.deepStrictEqual(key.algorithm.publicExponent, new Uint8Array([1, 0, 1]));
assert.strictEqual(key.algorithm.hash.name, hash);

if (extractable) {
const pkcs8 = await subtle.exportKey('pkcs8', key);
assert.strictEqual(
Buffer.from(pkcs8).toString('hex'),
keyData[size].pkcs8.toString('hex'));
keyData[size].pkcs8.toString('hex')
);
} else {
await assert.rejects(
subtle.exportKey('pkcs8', key), {
message: /key is not extractable/
});
subtle.exportKey('pkcs8', key),
{ message: /key is not extractable/ }
);
}

await assert.rejects(
Expand All @@ -368,16 +355,13 @@ async function testImportPkcs8(
keyData[size].pkcs8,
{ name, hash },
extractable,
[/* empty usages */]),
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
[]
),
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' }
);
}

async function testImportJwk(
{ name, publicUsages, privateUsages },
size,
hash,
extractable) {

async function testImportJwk({ name, publicUsages, privateUsages }, size, hash, extractable) {
const jwk = keyData[size].jwk;

const [
Expand All @@ -394,13 +378,15 @@ async function testImportJwk(
},
{ name, hash },
extractable,
publicUsages),
publicUsages
),
subtle.importKey(
'jwk',
{ ...jwk, alg: `PS${hash.substring(4)}` },
{ name, hash },
extractable,
privateUsages),
privateUsages
),
]);

assert.strictEqual(publicKey.type, 'public');
Expand All @@ -411,10 +397,8 @@ async function testImportJwk(
assert.strictEqual(privateKey.algorithm.name, name);
assert.strictEqual(publicKey.algorithm.modulusLength, size);
assert.strictEqual(privateKey.algorithm.modulusLength, size);
assert.deepStrictEqual(publicKey.algorithm.publicExponent,
new Uint8Array([1, 0, 1]));
assert.deepStrictEqual(publicKey.algorithm.publicExponent,
privateKey.algorithm.publicExponent);
assert.deepStrictEqual(publicKey.algorithm.publicExponent, new Uint8Array([1, 0, 1]));
assert.deepStrictEqual(publicKey.algorithm.publicExponent, privateKey.algorithm.publicExponent);

if (extractable) {
const [
Expand Down Expand Up @@ -445,83 +429,14 @@ async function testImportJwk(
assert.strictEqual(pubJwk.qi, undefined);
} else {
await assert.rejects(
subtle.exportKey('jwk', publicKey), {
message: /key is not extractable/
});
await assert.rejects(
subtle.exportKey('jwk', privateKey), {
message: /key is not extractable/
});
}

{
const invalidUse = name === 'RSA-OAEP' ? 'sig' : 'enc';
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, n: jwk.n, e: jwk.e, use: invalidUse },
{ name, hash },
extractable,
publicUsages),
{ message: 'Invalid JWK "use" Parameter' });
await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk, use: invalidUse },
{ name, hash },
extractable,
privateUsages),
{ message: 'Invalid JWK "use" Parameter' });
}

{
let invalidAlg = name === 'RSA-OAEP' ? name : name === 'RSA-PSS' ? 'PS' : 'RS';
switch (name) {
case 'RSA-OAEP':
if (hash === 'SHA-1')
invalidAlg += '-256';
break;
default:
if (hash === 'SHA-256')
invalidAlg += '384';
else
invalidAlg += '256';
}
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, n: jwk.n, e: jwk.e, alg: invalidAlg },
{ name, hash },
extractable,
publicUsages),
{ message: 'JWK "alg" does not match the requested algorithm' });
subtle.exportKey('jwk', publicKey),
{ message: /key is not extractable/ }
);
await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk, alg: invalidAlg },
{ name, hash },
extractable,
privateUsages),
{ message: 'JWK "alg" does not match the requested algorithm' });
subtle.exportKey('jwk', privateKey),
{ message: /key is not extractable/ }
);
}

await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk },
{ name, hash },
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 e */ n: jwk.n },
{ name, hash },
extractable,
publicUsages),
{ name: 'DataError', message: 'Invalid keyData' });
}

// combinations to test
Expand All @@ -543,7 +458,7 @@ const testVectors = [
},
];

(async function() {
const runTests = async () => {
const variations = [];
sizes.forEach((size) => {
hashes.forEach((hash) => {
Expand All @@ -556,29 +471,11 @@ const testVectors = [
});
});
});
await Promise.all(variations);
})().then(common.mustCall());

{
const ecPublic = crypto.createPublicKey(
fixtures.readKey('ec_p256_public.pem'));
const ecPrivate = crypto.createPrivateKey(
fixtures.readKey('ec_p256_private.pem'));
await Promise.all(variations);
};

for (const [name, [publicUsage, privateUsage]] of Object.entries({
'RSA-PSS': ['verify', 'sign'],
'RSASSA-PKCS1-v1_5': ['verify', 'sign'],
'RSA-OAEP': ['encrypt', 'decrypt'],
})) {
assert.rejects(subtle.importKey(
'spki',
ecPublic.export({ format: 'der', type: 'spki' }),
{ name, hash: 'SHA-256' },
true, [publicUsage]), { message: /Invalid key type/ }).then(common.mustCall());
assert.rejects(subtle.importKey(
'pkcs8',
ecPrivate.export({ format: 'der', type: 'pkcs8' }),
{ name, hash: 'SHA-256' },
true, [privateUsage]), { message: /Invalid key type/ }).then(common.mustCall());
}
}
// Export tests
require('node:test').test('Crypto Key Import Tests', async (t) => {
await runTests();
});
Loading
Loading