| 'use strict'; |
| |
| const common = require('../common'); |
| |
| if (!common.hasCrypto) |
| common.skip('missing crypto'); |
| |
| const assert = require('assert'); |
| const { subtle } = globalThis.crypto; |
| |
| const rsa_pkcs = require('../fixtures/crypto/rsa_pkcs'); |
| const rsa_pss = require('../fixtures/crypto/rsa_pss'); |
| |
| async function testVerify({ |
| algorithm, |
| hash, |
| publicKeyBuffer, |
| privateKeyBuffer, |
| signature, |
| plaintext, |
| }) { |
| const [ |
| publicKey, |
| noVerifyPublicKey, |
| privateKey, |
| hmacKey, |
| ecdsaKeys, |
| ] = await Promise.all([ |
| subtle.importKey( |
| 'spki', |
| publicKeyBuffer, |
| { name: algorithm.name, hash }, |
| false, |
| ['verify']), |
| subtle.importKey( |
| 'spki', |
| publicKeyBuffer, |
| { name: algorithm.name, hash }, |
| false, |
| [ /* No usages */ ]), |
| subtle.importKey( |
| 'pkcs8', |
| privateKeyBuffer, |
| { name: algorithm.name, hash }, |
| false, |
| ['sign']), |
| subtle.generateKey( |
| { name: 'HMAC', hash: 'SHA-256' }, |
| false, |
| ['sign']), |
| subtle.generateKey( |
| { |
| name: 'ECDSA', |
| namedCurve: 'P-521', |
| hash: 'SHA-256', |
| }, |
| false, |
| ['sign']), |
| ]); |
| |
| assert(await subtle.verify(algorithm, publicKey, signature, plaintext)); |
| |
| // Test verification with altered buffers |
| const copy = Buffer.from(plaintext); |
| const sigcopy = Buffer.from(signature); |
| const p = subtle.verify(algorithm, publicKey, sigcopy, copy); |
| copy[0] = 255 - copy[0]; |
| sigcopy[0] = 255 - sigcopy[0]; |
| assert(await p); |
| |
| // Test failure when using wrong key |
| await assert.rejects( |
| subtle.verify(algorithm, privateKey, signature, plaintext), { |
| message: /Unable to use this key to verify/ |
| }); |
| |
| await assert.rejects( |
| subtle.verify(algorithm, noVerifyPublicKey, signature, plaintext), { |
| message: /Unable to use this key to verify/ |
| }); |
| |
| // Test failure when using the wrong algorithms |
| await assert.rejects( |
| subtle.verify(algorithm, hmacKey, signature, plaintext), { |
| message: /Unable to use this key to verify/ |
| }); |
| |
| await assert.rejects( |
| subtle.verify(algorithm, ecdsaKeys.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(algorithm, publicKey, copy, plaintext))); |
| assert(!(await subtle.verify( |
| algorithm, |
| publicKey, |
| copy.slice(1), |
| plaintext))); |
| } |
| |
| // Test failure when data is altered |
| { |
| const copy = Buffer.from(plaintext); |
| copy[0] = 255 - copy[0]; |
| assert(!(await subtle.verify(algorithm, publicKey, signature, copy))); |
| } |
| |
| // Test failure when wrong hash is used |
| { |
| const otherhash = hash === 'SHA-1' ? 'SHA-256' : 'SHA-1'; |
| const keyWithOtherHash = await subtle.importKey( |
| 'spki', |
| publicKeyBuffer, |
| { name: algorithm.name, hash: otherhash }, |
| false, |
| ['verify']); |
| assert(!(await subtle.verify(algorithm, keyWithOtherHash, signature, plaintext))); |
| } |
| } |
| |
| async function testSign({ |
| algorithm, |
| hash, |
| publicKeyBuffer, |
| privateKeyBuffer, |
| signature, |
| plaintext, |
| }) { |
| const [ |
| publicKey, |
| privateKey, |
| hmacKey, |
| ecdsaKeys, |
| ] = await Promise.all([ |
| subtle.importKey( |
| 'spki', |
| publicKeyBuffer, |
| { name: algorithm.name, hash }, |
| false, |
| ['verify']), |
| subtle.importKey( |
| 'pkcs8', |
| privateKeyBuffer, |
| { name: algorithm.name, hash }, |
| false, |
| ['sign']), |
| subtle.generateKey( |
| { name: 'HMAC', hash: 'SHA-256' }, |
| false, |
| ['sign']), |
| subtle.generateKey( |
| { |
| name: 'ECDSA', |
| namedCurve: 'P-521', |
| hash: 'SHA-256', |
| }, |
| false, |
| ['sign']), |
| ]); |
| |
| { |
| const sig = await subtle.sign(algorithm, privateKey, plaintext); |
| assert.strictEqual(sig.byteLength, signature.byteLength); |
| assert(await subtle.verify(algorithm, publicKey, sig, plaintext)); |
| } |
| |
| { |
| const copy = Buffer.from(plaintext); |
| const p = subtle.sign(algorithm, privateKey, copy); |
| copy[0] = 255 - copy[0]; |
| const sig = await p; |
| assert(await subtle.verify(algorithm, publicKey, sig, plaintext)); |
| } |
| |
| // Test failure when using wrong key |
| await assert.rejects( |
| subtle.sign(algorithm, publicKey, plaintext), { |
| message: /Unable to use this key to sign/ |
| }); |
| |
| // Test failure when using the wrong algorithms |
| await assert.rejects( |
| subtle.sign(algorithm, hmacKey, plaintext), { |
| message: /Unable to use this key to sign/ |
| }); |
| |
| await assert.rejects( |
| subtle.sign(algorithm, ecdsaKeys.privateKey, plaintext), { |
| message: /Unable to use this key to sign/ |
| }); |
| } |
| |
| async function testSaltLength(keyLength, hash, hLen) { |
| const { publicKey, privateKey } = await subtle.generateKey({ |
| name: 'RSA-PSS', |
| modulusLength: keyLength, |
| publicExponent: new Uint8Array([1, 0, 1]), |
| hash, |
| }, false, ['sign', 'verify']); |
| |
| const data = Buffer.from('Hello, world!'); |
| const max = keyLength / 8 - hLen - 2; |
| |
| const signature = await subtle.sign({ name: 'RSA-PSS', saltLength: max }, privateKey, data); |
| await assert.rejects( |
| subtle.sign({ name: 'RSA-PSS', saltLength: max + 1 }, privateKey, data), (err) => { |
| assert.strictEqual(err.name, 'OperationError'); |
| assert.strictEqual(err.cause?.code, 'ERR_OUT_OF_RANGE'); |
| assert.strictEqual(err.cause?.message, `The value of "algorithm.saltLength" is out of range. It must be >= 0 && <= ${max}. Received ${max + 1}`); |
| return true; |
| }); |
| await subtle.verify({ name: 'RSA-PSS', saltLength: max }, publicKey, signature, data); |
| await assert.rejects( |
| subtle.verify({ name: 'RSA-PSS', saltLength: max + 1 }, publicKey, signature, data), (err) => { |
| assert.strictEqual(err.name, 'OperationError'); |
| assert.strictEqual(err.cause?.code, 'ERR_OUT_OF_RANGE'); |
| assert.strictEqual(err.cause?.message, `The value of "algorithm.saltLength" is out of range. It must be >= 0 && <= ${max}. Received ${max + 1}`); |
| return true; |
| }); |
| } |
| |
| (async function() { |
| const variations = []; |
| |
| rsa_pkcs().forEach((vector) => { |
| variations.push(testVerify(vector)); |
| variations.push(testSign(vector)); |
| }); |
| rsa_pss().forEach((vector) => { |
| variations.push(testVerify(vector)); |
| variations.push(testSign(vector)); |
| }); |
| |
| for (const keyLength of [1024, 2048]) { |
| for (const [hash, hLen] of [['SHA-1', 20], ['SHA-256', 32], ['SHA-384', 48], ['SHA-512', 64]]) { |
| variations.push(testSaltLength(keyLength, hash, hLen)); |
| } |
| } |
| |
| await Promise.all(variations); |
| })().then(common.mustCall()); |