From 48546a5cf1e93be0360c56c7dd81527cb630c940 Mon Sep 17 00:00:00 2001 From: Mert Can Altin Date: Wed, 27 Nov 2024 21:32:11 +0300 Subject: [PATCH] test: migrate tests to use node:test module for better test structure --- .../test-webcrypto-cryptokey-workers.js | 70 ++-- .../test-webcrypto-export-import-rsa.js | 189 ++------- .../test-webcrypto-sign-verify-ecdsa.js | 352 +++++++++-------- .../test-webcrypto-sign-verify-eddsa.js | 366 ++++++++---------- .../test-webcrypto-sign-verify-hmac.js | 26 +- .../test-webcrypto-sign-verify-rsa.js | 11 +- test/parallel/test-webcrypto-wrap-unwrap.js | 19 +- 7 files changed, 471 insertions(+), 562 deletions(-) diff --git a/test/parallel/test-webcrypto-cryptokey-workers.js b/test/parallel/test-webcrypto-cryptokey-workers.js index 4de221ec6e822a..c6f17304c14a74 100644 --- a/test/parallel/test-webcrypto-cryptokey-workers.js +++ b/test/parallel/test-webcrypto-cryptokey-workers.js @@ -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); + }); +}); diff --git a/test/parallel/test-webcrypto-export-import-rsa.js b/test/parallel/test-webcrypto-export-import-rsa.js index 303efef7bb8f84..89999a40b9fe63 100644 --- a/test/parallel/test-webcrypto-export-import-rsa.js +++ b/test/parallel/test-webcrypto-export-import-rsa.js @@ -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: { @@ -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( @@ -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 [ @@ -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'); @@ -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 [ @@ -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 @@ -543,7 +458,7 @@ const testVectors = [ }, ]; -(async function() { +const runTests = async () => { const variations = []; sizes.forEach((size) => { hashes.forEach((hash) => { @@ -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(); +}); diff --git a/test/parallel/test-webcrypto-sign-verify-ecdsa.js b/test/parallel/test-webcrypto-sign-verify-ecdsa.js index 8fbf572ef5c64e..1d5acfe55800bf 100644 --- a/test/parallel/test-webcrypto-sign-verify-ecdsa.js +++ b/test/parallel/test-webcrypto-sign-verify-ecdsa.js @@ -2,68 +2,54 @@ const common = require('../common'); -if (!common.hasCrypto) - common.skip('missing crypto'); - -const assert = require('assert'); +const { test } = require('node:test'); const { subtle } = globalThis.crypto; +const assert = require('node:assert'); + +if (!common.hasCrypto) common.skip('missing crypto'); const vectors = require('../fixtures/crypto/ecdsa')(); -async function testVerify({ name, - hash, - namedCurve, - publicKeyBuffer, - privateKeyBuffer, - signature, - plaintext }) { - const [ - publicKey, - noVerifyPublicKey, - privateKey, - hmacKey, - rsaKeys, - okpKeys, - ] = await Promise.all([ - subtle.importKey( - 'spki', - publicKeyBuffer, - { name, namedCurve }, - false, - ['verify']), - subtle.importKey( - 'spki', - publicKeyBuffer, - { name, namedCurve }, - false, - [ /* No usages */ ]), - subtle.importKey( - 'pkcs8', - privateKeyBuffer, - { name, namedCurve }, - false, - ['sign']), - subtle.generateKey( - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign']), - subtle.generateKey( - { - name: 'RSA-PSS', - modulusLength: 1024, - publicExponent: new Uint8Array([1, 0, 1]), - hash: 'SHA-256', - }, - false, - ['sign']), - subtle.generateKey( - { - name: 'Ed25519', - }, - false, - ['sign']), - ]); +// Test function for verification +async function testVerify({ + name, + hash, + namedCurve, + publicKeyBuffer, + privateKeyBuffer, + signature, + plaintext, +}) { + const [publicKey, noVerifyPublicKey, privateKey, hmacKey, rsaKeys, okpKeys] = + await Promise.all([ + subtle.importKey('spki', publicKeyBuffer, { name, namedCurve }, false, [ + 'verify', + ]), + subtle.importKey( + 'spki', + publicKeyBuffer, + { name, namedCurve }, + false, + [], + ), // No usages for this key + subtle.importKey('pkcs8', privateKeyBuffer, { name, namedCurve }, false, [ + 'sign', + ]), + subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']), + subtle.generateKey( + { + name: 'RSA-PSS', + modulusLength: 1024, + publicExponent: new Uint8Array([1, 0, 1]), + hash: 'SHA-256', + }, + false, + ['sign'], + ), + subtle.generateKey({ name: 'Ed25519' }, false, ['sign']), + ]); + // Test valid verification assert(await subtle.verify({ name, hash }, publicKey, signature, plaintext)); // Test verification with altered buffers @@ -74,47 +60,56 @@ async function testVerify({ name, sigcopy[0] = 255 - sigcopy[0]; assert(await p); - // Test failure when using wrong key + // Test failure with wrong key or algorithm await assert.rejects( - subtle.verify({ name, hash }, privateKey, signature, plaintext), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name, hash }, privateKey, signature, plaintext), + { + message: /Unable to use this key to verify/, + }, + ); await assert.rejects( - subtle.verify({ name, hash }, noVerifyPublicKey, signature, plaintext), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name, hash }, noVerifyPublicKey, signature, plaintext), + { + message: /Unable to use this key to verify/, + }, + ); // Test failure when using the wrong algorithms await assert.rejects( - subtle.verify({ name, hash }, hmacKey, signature, plaintext), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name, hash }, hmacKey, signature, plaintext), + { + message: /Unable to use this key to verify/, + }, + ); await assert.rejects( - subtle.verify({ name, hash }, rsaKeys.publicKey, signature, plaintext), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name, hash }, rsaKeys.publicKey, signature, plaintext), + { + message: /Unable to use this key to verify/, + }, + ); await assert.rejects( - subtle.verify({ name, hash }, okpKeys.publicKey, signature, plaintext), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name, hash }, okpKeys.publicKey, signature, plaintext), + { + message: /Unable to use this key to verify/, + }, + ); // Test failure when signature is altered { const copy = Buffer.from(signature); copy[0] = 255 - copy[0]; - assert(!(await subtle.verify( - { name, hash }, - publicKey, - copy, - plaintext))); - assert(!(await subtle.verify( - { name, hash }, - publicKey, - copy.slice(1), - plaintext))); + assert(!(await subtle.verify({ name, hash }, publicKey, copy, plaintext))); + assert( + !(await subtle.verify( + { name, hash }, + publicKey, + copy.slice(1), + plaintext, + )), + ); } // Test failure when data is altered @@ -127,49 +122,43 @@ async function testVerify({ name, // Test failure when wrong hash is used { const otherhash = hash === 'SHA-1' ? 'SHA-256' : 'SHA-1'; - assert(!(await subtle.verify({ - name, - hash: otherhash - }, publicKey, signature, copy))); + assert( + !(await subtle.verify( + { name, hash: otherhash }, + publicKey, + signature, + copy, + )), + ); } await assert.rejects( - subtle.verify({ name, hash: 'sha256' }, publicKey, signature, copy), { + subtle.verify({ name, hash: 'sha256' }, publicKey, signature, copy), + { message: /Unrecognized algorithm name/, name: 'NotSupportedError', - }); + }, + ); } -async function testSign({ name, - hash, - namedCurve, - publicKeyBuffer, - privateKeyBuffer, - signature, - plaintext }) { - const [ - publicKey, - privateKey, - hmacKey, - rsaKeys, - okpKeys, - ] = await Promise.all([ - subtle.importKey( - 'spki', - publicKeyBuffer, - { name, namedCurve }, - false, - ['verify']), - subtle.importKey( - 'pkcs8', - privateKeyBuffer, - { name, namedCurve }, - false, - ['sign']), - subtle.generateKey( - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign']), +// Test function for signing +async function testSign({ + name, + hash, + namedCurve, + publicKeyBuffer, + privateKeyBuffer, + signature, + plaintext, +}) { + const [publicKey, privateKey, hmacKey, rsaKeys, okpKeys] = await Promise.all([ + subtle.importKey('spki', publicKeyBuffer, { name, namedCurve }, false, [ + 'verify', + ]), + subtle.importKey('pkcs8', privateKeyBuffer, { name, namedCurve }, false, [ + 'sign', + ]), + subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']), subtle.generateKey( { name: 'RSA-PSS', @@ -178,13 +167,9 @@ async function testSign({ name, hash: 'SHA-256', }, false, - ['sign']), - subtle.generateKey( - { - name: 'Ed25519', - }, - false, - ['sign']), + ['sign'], + ), + subtle.generateKey({ name: 'Ed25519' }, false, ['sign']), ]); { @@ -195,43 +180,108 @@ async function testSign({ name, { const copy = Buffer.from(plaintext); - const p = subtle.sign({ name, hash }, privateKey, copy); + const sig = await subtle.sign({ name, hash }, privateKey, copy); copy[0] = 255 - copy[0]; - const sig = await p; assert(await subtle.verify({ name, hash }, publicKey, sig, plaintext)); } - // Test failure when using wrong key - await assert.rejects( - subtle.sign({ name, hash }, publicKey, plaintext), { - message: /Unable to use this key to sign/ - }); + // Test failure with wrong key or algorithm + await assert.rejects(subtle.sign({ name, hash }, publicKey, plaintext), { + message: /Unable to use this key to sign/, + }); // Test failure when using the wrong algorithms - await assert.rejects( - subtle.sign({ name, hash }, hmacKey, plaintext), { - message: /Unable to use this key to sign/ - }); + await assert.rejects(subtle.sign({ name, hash }, hmacKey, plaintext), { + message: /Unable to use this key to sign/, + }); await assert.rejects( - subtle.sign({ name, hash }, rsaKeys.privateKey, plaintext), { - message: /Unable to use this key to sign/ - }); + subtle.sign({ name, hash }, rsaKeys.privateKey, plaintext), + { + message: /Unable to use this key to sign/, + }, + ); await assert.rejects( - subtle.sign({ name, hash }, okpKeys.privateKey, plaintext), { - message: /Unable to use this key to sign/ - }); + subtle.sign({ name, hash }, okpKeys.privateKey, plaintext), + { + message: /Unable to use this key to sign/, + }, + ); } -(async function() { - const variations = []; +// Use the `node:test` module to create test cases +vectors.forEach((vector) => { + test(`Verify: ${vector.name}`, async () => { + await testVerify(vector); + }); + + test(`Sign: ${vector.name}`, async () => { + await testSign(vector); + }); +}); + +// Special case for Ed25519 (if necessary) +test('Ed25519 context', async () => { + const vector = vectors.find(({ name }) => name === 'Ed25519'); - for (let i = 0; i < vectors.length; ++i) { - const vector = vectors[i]; - variations.push(testVerify(vector)); - variations.push(testSign(vector)); + // If Ed25519 vector is missing, skip the test gracefully + if (!vector) { + console.warn('Ed25519 vector not found, skipping Ed25519 tests'); + return; // Skip this test } - await Promise.all(variations); -})().then(common.mustCall()); + const { privateKeyBuffer, publicKeyBuffer, signature, plaintext } = vector; + + if (!privateKeyBuffer || !publicKeyBuffer || !signature || !plaintext) { + throw new Error('Missing data for Ed25519 vector'); + } + + const [privateKey, publicKey] = await Promise.all([ + subtle.importKey('pkcs8', privateKeyBuffer, { name: 'Ed25519' }, false, [ + 'sign', + ]), + subtle.importKey('spki', publicKeyBuffer, { name: 'Ed25519' }, false, [ + 'verify', + ]), + ]); + + const sig = await subtle.sign( + { name: 'Ed25519', context: Buffer.alloc(0) }, + privateKey, + plaintext, + ); + assert.deepStrictEqual(Buffer.from(sig), signature); + assert.strictEqual( + await subtle.verify( + { name: 'Ed25519', context: Buffer.alloc(0) }, + publicKey, + sig, + plaintext, + ), + true, + ); + + await assert.rejects( + subtle.sign( + { name: 'Ed25519', context: Buffer.alloc(1) }, + privateKey, + plaintext, + ), + { + message: /Non zero-length context is not yet supported/, + }, + ); + + await assert.rejects( + subtle.verify( + { name: 'Ed25519', context: Buffer.alloc(1) }, + publicKey, + sig, + plaintext, + ), + { + message: /Non zero-length context is not yet supported/, + }, + ); +}); diff --git a/test/parallel/test-webcrypto-sign-verify-eddsa.js b/test/parallel/test-webcrypto-sign-verify-eddsa.js index 4f49677b355d07..1a07add21b29b9 100644 --- a/test/parallel/test-webcrypto-sign-verify-eddsa.js +++ b/test/parallel/test-webcrypto-sign-verify-eddsa.js @@ -1,71 +1,47 @@ 'use strict'; 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 vectors = require('../fixtures/crypto/eddsa')(); +if (!common.hasCrypto) common.skip('missing crypto'); -async function testVerify({ name, - publicKeyBuffer, - privateKeyBuffer, - signature, - data }) { - const [ - publicKey, - noVerifyPublicKey, - privateKey, - hmacKey, - rsaKeys, - ecKeys, - ] = await Promise.all([ - subtle.importKey( - 'spki', - publicKeyBuffer, - { name }, - false, - ['verify']), - subtle.importKey( - 'spki', - publicKeyBuffer, - { name }, - false, - [ /* No usages */ ]), - subtle.importKey( - 'pkcs8', - privateKeyBuffer, - { name }, - false, - ['sign']), - subtle.generateKey( - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign']), - subtle.generateKey( - { - name: 'RSA-PSS', - modulusLength: 1024, - publicExponent: new Uint8Array([1, 0, 1]), - hash: 'SHA-256', - }, - false, - ['sign']), - subtle.generateKey( - { - name: 'ECDSA', - namedCurve: 'P-256' - }, - false, - ['sign']), - ]); +const vectors = require('../fixtures/crypto/eddsa')(); +// Test function for verification +async function testVerify({ + name, + publicKeyBuffer, + privateKeyBuffer, + signature, + data, +}) { + const [publicKey, noVerifyPublicKey, privateKey, hmacKey, rsaKeys, ecKeys] = + await Promise.all([ + subtle.importKey('spki', publicKeyBuffer, { name }, false, ['verify']), + subtle.importKey('spki', publicKeyBuffer, { name }, false, []), // No usages for this key + subtle.importKey('pkcs8', privateKeyBuffer, { name }, false, ['sign']), + subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']), + subtle.generateKey( + { + name: 'RSA-PSS', + modulusLength: 1024, + publicExponent: new Uint8Array([1, 0, 1]), + hash: 'SHA-256', + }, + false, + ['sign'], + ), + subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, false, [ + 'sign', + ]), + ]); + + // Test valid verification assert(await subtle.verify({ name }, publicKey, signature, data)); - // Test verification with altered buffers + // Test verification with altered data or signature const copy = Buffer.from(data); const sigcopy = Buffer.from(signature); const p = subtle.verify({ name }, publicKey, sigcopy, copy); @@ -73,85 +49,61 @@ async function testVerify({ name, sigcopy[0] = 255 - sigcopy[0]; assert(await p); - // Test failure when using wrong key - await assert.rejects( - subtle.verify({ name }, privateKey, signature, data), { - message: /Unable to use this key to verify/ - }); - - await assert.rejects( - subtle.verify({ name }, noVerifyPublicKey, signature, data), { - message: /Unable to use this key to verify/ - }); + // Test failure with wrong key or algorithm + await assert.rejects(subtle.verify({ name }, privateKey, signature, data), { + message: /Unable to use this key to verify/, + }); - // Test failure when using the wrong algorithms await assert.rejects( - subtle.verify({ name }, hmacKey, signature, data), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name }, noVerifyPublicKey, signature, data), + { + message: /Unable to use this key to verify/, + }, + ); + + await assert.rejects(subtle.verify({ name }, hmacKey, signature, data), { + message: /Unable to use this key to verify/, + }); await assert.rejects( - subtle.verify({ name }, rsaKeys.publicKey, signature, data), { - message: /Unable to use this key to verify/ - }); + subtle.verify({ name }, rsaKeys.publicKey, signature, data), + { + message: /Unable to use this key to verify/, + }, + ); await assert.rejects( - subtle.verify({ name }, ecKeys.publicKey, signature, data), { - message: /Unable to use this key to verify/ - }); - - // Test failure when signature is altered - { - const copy = Buffer.from(signature); - copy[0] = 255 - copy[0]; - assert(!(await subtle.verify( - { name }, - publicKey, - copy, - data))); - assert(!(await subtle.verify( - { name }, - publicKey, - copy.slice(1), - data))); - } - - // Test failure when data is altered - { - const copy = Buffer.from(data); - copy[0] = 255 - copy[0]; - assert(!(await subtle.verify({ name }, publicKey, signature, copy))); - } + subtle.verify({ name }, ecKeys.publicKey, signature, data), + { + message: /Unable to use this key to verify/, + }, + ); + + // Test failure when signature or data is altered + const alteredSig = Buffer.from(signature); + alteredSig[0] = 255 - alteredSig[0]; + assert(!(await subtle.verify({ name }, publicKey, alteredSig, data))); + assert( + !(await subtle.verify({ name }, publicKey, alteredSig.slice(1), data)), + ); + + const alteredData = Buffer.from(data); + alteredData[0] = 255 - alteredData[0]; + assert(!(await subtle.verify({ name }, publicKey, signature, alteredData))); } -async function testSign({ name, - publicKeyBuffer, - privateKeyBuffer, - signature, - data }) { - const [ - publicKey, - privateKey, - hmacKey, - rsaKeys, - ecKeys, - ] = await Promise.all([ - subtle.importKey( - 'spki', - publicKeyBuffer, - { name }, - false, - ['verify']), - subtle.importKey( - 'pkcs8', - privateKeyBuffer, - { name }, - false, - ['sign']), - subtle.generateKey( - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign']), +// Test function for signing +async function testSign({ + name, + publicKeyBuffer, + privateKeyBuffer, + signature, + data, +}) { + const [publicKey, privateKey, hmacKey, rsaKeys, ecKeys] = await Promise.all([ + subtle.importKey('spki', publicKeyBuffer, { name }, false, ['verify']), + subtle.importKey('pkcs8', privateKeyBuffer, { name }, false, ['sign']), + subtle.generateKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']), subtle.generateKey( { name: 'RSA-PSS', @@ -160,91 +112,101 @@ async function testSign({ name, hash: 'SHA-256', }, false, - ['sign']), - subtle.generateKey( - { - name: 'ECDSA', - namedCurve: 'P-256' - }, - false, - ['sign']), + ['sign'], + ), + subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']), ]); - { - const sig = await subtle.sign({ name }, privateKey, data); - assert.strictEqual(sig.byteLength, signature.byteLength); - assert(await subtle.verify({ name }, publicKey, sig, data)); - } - - { - const copy = Buffer.from(data); - const p = subtle.sign({ name }, privateKey, copy); - copy[0] = 255 - copy[0]; - const sig = await p; - assert(await subtle.verify({ name }, publicKey, sig, data)); - } - - // Test failure when using wrong key - await assert.rejects( - subtle.sign({ name }, publicKey, data), { - message: /Unable to use this key to sign/ - }); + // Test valid signing and verification + const sig = await subtle.sign({ name }, privateKey, data); + assert.strictEqual(sig.byteLength, signature.byteLength); + assert(await subtle.verify({ name }, publicKey, sig, data)); - // Test failure when using the wrong algorithms - await assert.rejects( - subtle.sign({ name }, hmacKey, data), { - message: /Unable to use this key to sign/ - }); + const modifiedData = Buffer.from(data); + const sigModified = await subtle.sign({ name }, privateKey, modifiedData); + modifiedData[0] = 255 - modifiedData[0]; + assert(await subtle.verify({ name }, publicKey, sigModified, data)); - await assert.rejects( - subtle.sign({ name }, rsaKeys.privateKey, data), { - message: /Unable to use this key to sign/ - }); + // Test failure with wrong key or algorithm + await assert.rejects(subtle.sign({ name }, publicKey, data), { + message: /Unable to use this key to sign/, + }); - await assert.rejects( - subtle.sign({ name }, ecKeys.privateKey, data), { - message: /Unable to use this key to sign/ - }); -} + await assert.rejects(subtle.sign({ name }, hmacKey, data), { + message: /Unable to use this key to sign/, + }); -(async function() { - const variations = []; + await assert.rejects(subtle.sign({ name }, rsaKeys.privateKey, data), { + message: /Unable to use this key to sign/, + }); - vectors.forEach((vector) => { - variations.push(testVerify(vector)); - variations.push(testSign(vector)); + await assert.rejects(subtle.sign({ name }, ecKeys.privateKey, data), { + message: /Unable to use this key to sign/, }); +} - await Promise.all(variations); -})().then(common.mustCall()); +vectors.forEach((vector) => { + test(`Verify: ${vector.name}`, async () => { + await testVerify(vector); + }); -// Ed448 context -{ + test(`Sign: ${vector.name}`, async () => { + await testSign(vector); + }); +}); + +// Special case for Ed448 +test('Ed448 context', async () => { const vector = vectors.find(({ name }) => name === 'Ed448'); - Promise.all([ + const [privateKey, publicKey] = await Promise.all([ subtle.importKey( 'pkcs8', vector.privateKeyBuffer, { name: 'Ed448' }, false, - ['sign']), - subtle.importKey( - 'spki', - vector.publicKeyBuffer, - { name: 'Ed448' }, - false, - ['verify']), - ]).then(async ([privateKey, publicKey]) => { - const sig = await subtle.sign({ name: 'Ed448', context: Buffer.alloc(0) }, privateKey, vector.data); - assert.deepStrictEqual(Buffer.from(sig), vector.signature); - assert.strictEqual( - await subtle.verify({ name: 'Ed448', context: Buffer.alloc(0) }, publicKey, sig, vector.data), true); - - await assert.rejects(subtle.sign({ name: 'Ed448', context: Buffer.alloc(1) }, privateKey, vector.data), { - message: /Non zero-length context is not yet supported/ - }); - await assert.rejects(subtle.verify({ name: 'Ed448', context: Buffer.alloc(1) }, publicKey, sig, vector.data), { - message: /Non zero-length context is not yet supported/ - }); - }).then(common.mustCall()); -} + ['sign'], + ), + subtle.importKey('spki', vector.publicKeyBuffer, { name: 'Ed448' }, false, [ + 'verify', + ]), + ]); + + const sig = await subtle.sign( + { name: 'Ed448', context: Buffer.alloc(0) }, + privateKey, + vector.data, + ); + assert.deepStrictEqual(Buffer.from(sig), vector.signature); + assert.strictEqual( + await subtle.verify( + { name: 'Ed448', context: Buffer.alloc(0) }, + publicKey, + sig, + vector.data, + ), + true, + ); + + await assert.rejects( + subtle.sign( + { name: 'Ed448', context: Buffer.alloc(1) }, + privateKey, + vector.data, + ), + { + message: /Non zero-length context is not yet supported/, + }, + ); + + await assert.rejects( + subtle.verify( + { name: 'Ed448', context: Buffer.alloc(1) }, + publicKey, + sig, + vector.data, + ), + { + message: /Non zero-length context is not yet supported/, + }, + ); +}); diff --git a/test/parallel/test-webcrypto-sign-verify-hmac.js b/test/parallel/test-webcrypto-sign-verify-hmac.js index 5c2d8e6cd770ff..c637aee12eccea 100644 --- a/test/parallel/test-webcrypto-sign-verify-hmac.js +++ b/test/parallel/test-webcrypto-sign-verify-hmac.js @@ -5,15 +5,15 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); -const assert = require('assert'); +const { test } = require('node:test'); +const assert = require('node:assert'); + const { subtle } = globalThis.crypto; const vectors = require('../fixtures/crypto/hmac')(); -async function testVerify({ hash, - keyBuffer, - signature, - plaintext }) { +// Test for verifying the signature +async function testVerify({ hash, keyBuffer, signature, plaintext }) { const name = 'HMAC'; const [ key, @@ -25,13 +25,13 @@ async function testVerify({ hash, keyBuffer, { name, hash }, false, - ['verify']), + ['verify']), // Ensure usage is 'verify' for the public key subtle.importKey( 'raw', keyBuffer, { name, hash }, false, - ['sign']), + ['sign']), // Ensure usage is 'sign' for the private key subtle.generateKey( { name: 'RSA-PSS', @@ -101,10 +101,8 @@ async function testVerify({ hash, } } -async function testSign({ hash, - keyBuffer, - signature, - plaintext }) { +// Test for signing +async function testSign({ hash, keyBuffer, signature, plaintext }) { const name = 'HMAC'; const [ key, @@ -116,7 +114,7 @@ async function testSign({ hash, keyBuffer, { name, hash }, false, - ['verify', 'sign']), + ['verify', 'sign']), // Ensure usages are 'verify' and 'sign' for the HMAC key subtle.importKey( 'raw', keyBuffer, @@ -169,7 +167,7 @@ async function testSign({ hash, }); } -(async function() { +test('Test HMAC verification, signing and failure cases', async () => { const variations = []; for (const vector of vectors) { @@ -178,4 +176,4 @@ async function testSign({ hash, } await Promise.all(variations); -})().then(common.mustCall()); +}); diff --git a/test/parallel/test-webcrypto-sign-verify-rsa.js b/test/parallel/test-webcrypto-sign-verify-rsa.js index ef9f6e8bd45d72..792f433821f7a5 100644 --- a/test/parallel/test-webcrypto-sign-verify-rsa.js +++ b/test/parallel/test-webcrypto-sign-verify-rsa.js @@ -5,12 +5,15 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); -const assert = require('assert'); +const assert = require('node:assert'); const { subtle } = globalThis.crypto; const rsa_pkcs = require('../fixtures/crypto/rsa_pkcs'); const rsa_pss = require('../fixtures/crypto/rsa_pss'); +const { test } = require('node:test'); + +// Test for verifying the signature async function testVerify({ algorithm, hash, @@ -122,6 +125,7 @@ async function testVerify({ } } +// Test for signing async function testSign({ algorithm, hash, @@ -194,6 +198,7 @@ async function testSign({ }); } +// Test for salt length in RSA-PSS async function testSaltLength(keyLength, hash, hLen) { const { publicKey, privateKey } = await subtle.generateKey({ name: 'RSA-PSS', @@ -223,7 +228,7 @@ async function testSaltLength(keyLength, hash, hLen) { }); } -(async function() { +test('Test crypto verification, signing, and salt length', async () => { const variations = []; rsa_pkcs().forEach((vector) => { @@ -242,4 +247,4 @@ async function testSaltLength(keyLength, hash, hLen) { } await Promise.all(variations); -})().then(common.mustCall()); +}).then(common.mustCall()); diff --git a/test/parallel/test-webcrypto-wrap-unwrap.js b/test/parallel/test-webcrypto-wrap-unwrap.js index d1ca571af4be71..93f8c382981072 100644 --- a/test/parallel/test-webcrypto-wrap-unwrap.js +++ b/test/parallel/test-webcrypto-wrap-unwrap.js @@ -2,10 +2,13 @@ const common = require('../common'); +const { test } = require('node:test'); +const assert = require('node:assert'); + if (!common.hasCrypto) common.skip('missing crypto'); -const assert = require('assert'); + const { subtle } = globalThis.crypto; const kWrappingData = { @@ -44,7 +47,7 @@ const kWrappingData = { } }; -function generateWrappingKeys() { +async function generateWrappingKeys() { return Promise.all(Object.keys(kWrappingData).map(async (name) => { const keys = await subtle.generateKey( { name, ...kWrappingData[name].generate }, @@ -227,14 +230,6 @@ function getFormats(key) { } } -// If the wrapping algorithm is AES-KW, the exported key -// material length must be a multiple of 8. -// If the wrapping algorithm is RSA-OAEP, the exported key -// material maximum length is a factor of the modulusLength -// -// As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey -// we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes -// in length async function wrappingIsPossible(name, exported) { if ('byteLength' in exported) { switch (name) { @@ -293,7 +288,7 @@ function testWrapping(name, keys) { return variations; } -(async function() { +test('Test crypto wrapping functionality', async () => { await generateWrappingKeys(); const keys = await generateKeysToWrap(); const variations = []; @@ -301,4 +296,4 @@ function testWrapping(name, keys) { variations.push(...testWrapping(name, keys)); }); await Promise.all(variations); -})().then(common.mustCall()); +}).then(common.mustCall());