From 2359a6caa6e711c495765376ed4a266b88b9bfb8 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Thu, 29 Aug 2024 18:46:40 +0200 Subject: [PATCH] test,crypto: update WebCryptoAPI WPT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: #54572 Refs: #54468 PR-URL: https://github.com/nodejs/node/pull/54593 Refs: https://github.com/nodejs/node/issues/54572 Refs: https://github.com/nodejs/node/pull/54468 Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum Reviewed-By: Michaƫl Zasso Reviewed-By: Yagiz Nizipli Reviewed-By: Luigi Pinca --- test/common/wpt.js | 12 +- test/fixtures/wpt/README.md | 2 +- .../derive_bits_keys/cfrg_curves_bits.js | 25 +- .../derived_bits_length.https.any.js | 11 + .../derive_bits_keys/derived_bits_length.js | 36 ++ .../derived_bits_length_testcases.js | 30 + .../derived_bits_length_vectors.js | 33 + .../derive_bits_keys/ecdh_bits.js | 19 - .../wpt/WebCryptoAPI/derive_bits_keys/hkdf.js | 19 - .../WebCryptoAPI/derive_bits_keys/pbkdf2.js | 20 - .../wpt/WebCryptoAPI/getRandomValues.any.js | 17 + .../importKey-unsettled-promise.https.any.js | 17 + .../wpt/WebCryptoAPI/sign_verify/eddsa.js | 590 ++++++------------ .../eddsa_small_order_points.https.any.js | 6 + .../sign_verify/eddsa_small_order_points.js | 26 + .../WebCryptoAPI/sign_verify/eddsa_vectors.js | 141 ++++- test/fixtures/wpt/versions.json | 2 +- test/wpt/README.md | 10 +- test/wpt/status/WebCryptoAPI.cjs | 37 ++ test/wpt/status/WebCryptoAPI.json | 8 - 20 files changed, 568 insertions(+), 493 deletions(-) create mode 100644 test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_testcases.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_vectors.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/import_export/crashtests/importKey-unsettled-promise.https.any.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.js create mode 100644 test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.js create mode 100644 test/wpt/status/WebCryptoAPI.cjs delete mode 100644 test/wpt/status/WebCryptoAPI.json diff --git a/test/common/wpt.js b/test/common/wpt.js index 7917e17729c7ee..0c8805d541286e 100644 --- a/test/common/wpt.js +++ b/test/common/wpt.js @@ -458,8 +458,16 @@ class StatusLoader { load() { const dir = path.join(__dirname, '..', 'wpt'); - const statusFile = path.join(dir, 'status', `${this.path}.json`); - const result = JSON.parse(fs.readFileSync(statusFile, 'utf8')); + let statusFile = path.join(dir, 'status', `${this.path}.json`); + let result; + + if (fs.existsSync(statusFile)) { + result = JSON.parse(fs.readFileSync(statusFile, 'utf8')); + } else { + statusFile = path.join(dir, 'status', `${this.path}.cjs`); + result = require(statusFile); + } + this.rules.addRules(result); const subDir = fixtures.path('wpt', this.path); diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index e5565462a12029..118bb456a8eecd 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -32,7 +32,7 @@ Last update: - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi - wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/5e042cbc4e/WebCryptoAPI +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/6748a0a246/WebCryptoAPI - webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions - webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/e97fac4791/webmessaging/broadcastchannel - webstorage: https://github.com/web-platform-tests/wpt/tree/9dafa89214/webstorage diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js index ef6905e574c158..da809278a87aa5 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js @@ -6,8 +6,6 @@ function define_tests() { // Verify the derive functions perform checks against the all-zero value results, // ensuring small-order points are rejected. // https://www.rfc-editor.org/rfc/rfc7748#section-6.1 - // TODO: The spec states that the check must be done on use, but there is discussion about doing it on import. - // https://github.com/WICG/webcrypto-secure-curves/pull/13 Object.keys(kSmallOrderPoint).forEach(function(algorithmName) { kSmallOrderPoint[algorithmName].forEach(function(test) { promise_test(async() => { @@ -23,8 +21,8 @@ function define_tests() { false, []) derived = await subtle.deriveBits({name: algorithmName, public: publicKey}, privateKey, 8 * sizes[algorithmName]); } catch (err) { - assert_false(privateKey === undefined, "Private key should be valid."); - assert_false(publicKey === undefined, "Public key should be valid."); + assert_true(privateKey !== undefined, "Private key should be valid."); + assert_true(publicKey !== undefined, "Public key should be valid."); assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + "."); } assert_equals(derived, undefined, "Operation succeeded, but should not have."); @@ -59,25 +57,6 @@ function define_tests() { }); }, algorithmName + " mixed case parameters"); - // Null length - // "Null" is not valid per the current spec - // - https://github.com/w3c/webcrypto/issues/322 - // - https://github.com/w3c/webcrypto/issues/329 - // - // Proposal for a spec change: - // - https://github.com/w3c/webcrypto/pull/345 - // - // This test case may be replaced by these new tests: - // - https://github.com/web-platform-tests/wpt/pull/43400 - promise_test(function(test) { - return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], null) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, algorithmName + " with null length"); - // Shorter than entire derivation per algorithm promise_test(function(test) { return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 32) diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js new file mode 100644 index 00000000000000..0aee2e3c172d30 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js @@ -0,0 +1,11 @@ +// META: title=WebCryptoAPI: deriveBits() tests for the 'length' parameter +// META: script=derived_bits_length.js +// META: script=derived_bits_length_vectors.js +// META: script=derived_bits_length_testcases.js + +// Define subtests from a `promise_test` to ensure the harness does not +// complete before the subtests are available. `explicit_done` cannot be used +// for this purpose because the global `done` function is automatically invoked +// by the WPT infrastructure in dedicated worker tests defined using the +// "multi-global" pattern. +promise_test(define_tests, 'setup - define tests'); diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.js new file mode 100644 index 00000000000000..5a7ed7eb50a0a0 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.js @@ -0,0 +1,36 @@ +function define_tests() { + // May want to test prefixed implementations. + var subtle = self.crypto.subtle; + + Object.keys(testCases).forEach(algorithm => { + let testData = algorithms[algorithm]; + testCases[algorithm].forEach(testParam => { + promise_test(async() => { + let derivedBits, privateKey, publicKey; + try { + privateKey = await subtle.importKey(testData.privateKey.format, testData.privateKey.data, testData.importAlg, false, ["deriveBits"]); + if (testData.deriveAlg.public !== undefined) { + publicKey = await subtle.importKey(testData.publicKey.format, testData.publicKey.data, testData.importAlg, false, []); + testData.deriveAlg.public = publicKey; + } + if (testParam.length === "omitted") + derivedBits = await subtle.deriveBits(testData.deriveAlg, privateKey); + else + derivedBits = await subtle.deriveBits(testData.deriveAlg, privateKey, testParam.length); + if (testParam.expected === undefined) { + assert_unreached("deriveBits should have thrown an OperationError exception."); + } + assert_array_equals(new Uint8Array(derivedBits), testParam.expected, "Derived bits do not match the expected result."); + } catch (err) { + if (err instanceof AssertionError || testParam.expected !== undefined) { + throw err; + } + assert_true(privateKey !== undefined, "Key should be valid."); + assert_equals(err.name, "OperationError", "deriveBits correctly threw OperationError: " + err.message); + } + }, algorithm + " derivation with " + testParam.length + " as 'length' parameter"); + }); + }); + + return Promise.resolve("define_tests"); +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_testcases.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_testcases.js new file mode 100644 index 00000000000000..1bd7fbc2c85989 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_testcases.js @@ -0,0 +1,30 @@ +var testCases = { + "HKDF": [ + {length: 256, expected: algorithms["HKDF"].derivation}, + {length: 0, expected: undefined}, // explicitly disallowed, so should throw + {length: null, expected: undefined }, // should throw an exception + {length: undefined, expected: undefined }, // should throw an exception + {length: "omitted", expected: undefined }, // default value is null, so should throw + ], + "PBKDF2": [ + {length: 256, expected: algorithms["PBKDF2"].derivation}, + {length: 0, expected: undefined}, // explicitly disallowed, so should throw + {length: null, expected: undefined }, // should throw an exception + {length: undefined, expected: undefined }, // should throw an exception + {length: "omitted", expected: undefined }, // default value is null, so should throw + ], + "ECDH": [ + {length: 256, expected: algorithms["ECDH"].derivation}, + {length: 0, expected: emptyArray}, + {length: null, expected: algorithms["ECDH"].derivation}, + {length: undefined, expected: algorithms["ECDH"].derivation}, + {length: "omitted", expected: algorithms["ECDH"].derivation }, // default value is null + ], + "X25519": [ + {length: 256, expected: algorithms["X25519"].derivation}, + {length: 0, expected: emptyArray}, + {length: null, expected: algorithms["X25519"].derivation}, + {length: undefined, expected: algorithms["X25519"].derivation}, + {length: "omitted", expected: algorithms["X25519"].derivation }, // default value is null + ], +} diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_vectors.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_vectors.js new file mode 100644 index 00000000000000..fa51f7d3f2b195 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length_vectors.js @@ -0,0 +1,33 @@ +const emptyArray = new Uint8Array([]); +const rawKey = new Uint8Array([85, 115, 101, 114, 115, 32, 115, 104, 111, 117, 108, 100, 32, 112, 105, 99, 107, 32, 108, 111, 110, 103, 32, 112, 97, 115, 115, 112, 104, 114, 97, 115, 101, 115, 32, 40, 110, 111, 116, 32, 117, 115, 101, 32, 115, 104, 111, 114, 116, 32, 112, 97, 115, 115, 119, 111, 114, 100, 115, 41, 33]); +const salt = new Uint8Array([83, 111, 100, 105, 117, 109, 32, 67, 104, 108, 111, 114, 105, 100, 101, 32, 99, 111, 109, 112, 111, 117, 110, 100]); +const info = new Uint8Array([72, 75, 68, 70, 32, 101, 120, 116, 114, 97, 32, 105, 110, 102, 111]); + +var algorithms = { + "HKDF": { + importAlg: {name: "HKDF"}, + privateKey: {format: "raw", data: rawKey}, + deriveAlg: {name: "HKDF", salt: salt, hash: "SHA-256", info: info}, + derivation: new Uint8Array([49, 183, 214, 133, 48, 168, 99, 231, 23, 192, 129, 202, 105, 23, 182, 134, 80, 179, 221, 154, 41, 243, 6, 6, 226, 202, 209, 153, 190, 193, 77, 19]), + }, + "PBKDF2": { + importAlg: {name: "PBKDF2"}, + privateKey: {format: "raw", data: rawKey}, + deriveAlg: {name: "PBKDF2", salt: salt, hash: "SHA-256", iterations: 100000}, + derivation: new Uint8Array([17, 153, 45, 139, 129, 51, 17, 36, 76, 84, 75, 98, 41, 41, 69, 226, 8, 212, 3, 206, 189, 107, 149, 82, 161, 165, 98, 6, 93, 153, 88, 234]), + }, + "ECDH": { + importAlg: {name: "ECDH", namedCurve: "P-256"}, + privateKey: {format: "pkcs8", data: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47])}, + publicKey: {format: "spki", data: new Uint8Array([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, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61])}, + deriveAlg: {name: "ECDH", public: new Uint8Array ([])}, + derivation: new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), + }, + "X25519": { + importAlg: {name: "X25519"}, + privateKey: {format: "pkcs8", data: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97])}, + publicKey: {format: "spki", data: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6])}, + deriveAlg: {name: "X25519", public: new Uint8Array ([])}, + derivation: new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 161, 149, 0, 8]), + } +}; diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js index cb9747a529fd53..36b29c20a282ab 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js @@ -55,25 +55,6 @@ function define_tests() { }); }, namedCurve + " mixed case parameters"); - // Null length - // "Null" is not valid per the current spec - // - https://github.com/w3c/webcrypto/issues/322 - // - https://github.com/w3c/webcrypto/issues/329 - // - // Proposal for a spec change: - // - https://github.com/w3c/webcrypto/pull/345 - // - // This test case may be replaced by these new tests: - // - https://github.com/web-platform-tests/wpt/pull/43400 - promise_test(function(test) { - return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], null) - .then(function(derivation) { - assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); - }, function(err) { - assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); - }); - }, namedCurve + " with null length"); - // Shorter than entire derivation per algorithm promise_test(function(test) { return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 32) diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js index 3903da5cddff94..b2dfda0257bc81 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js @@ -139,25 +139,6 @@ function define_tests() { }); }, testName + " with missing info"); - // length null (OperationError) - // "Null" is not valid per the current spec - // - https://github.com/w3c/webcrypto/issues/322 - // - https://github.com/w3c/webcrypto/issues/329 - // - // Proposal for a spec change: - // - https://github.com/w3c/webcrypto/pull/345 - // - // This test case may be replaced by these new tests: - // - https://github.com/web-platform-tests/wpt/pull/43400 - subsetTest(promise_test, function(test) { - return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], null) - .then(function(derivation) { - assert_unreached("null length should have thrown an OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "deriveBits with null length correctly threw OperationError: " + err.message); - }); - }, testName + " with null length"); - // length not multiple of 8 (OperationError) subsetTest(promise_test, function(test) { return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 44) diff --git a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js index 4e4ae79d800a40..090806ceb6b3ea 100644 --- a/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js +++ b/test/fixtures/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js @@ -103,26 +103,6 @@ function define_tests() { }); - // Test various error conditions for deriveBits below: - // length null (OperationError) - // "Null" is not valid per the current spec - // - https://github.com/w3c/webcrypto/issues/322 - // - https://github.com/w3c/webcrypto/issues/329 - // - // Proposal for a spec change: - // - https://github.com/w3c/webcrypto/pull/345 - // - // This test case may be replaced by these new tests: - // - https://github.com/web-platform-tests/wpt/pull/43400 - subsetTest(promise_test, function(test) { - return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], null) - .then(function(derivation) { - assert_unreached("null length should have thrown an OperationError"); - }, function(err) { - assert_equals(err.name, "OperationError", "deriveBits with null length correctly threw OperationError: " + err.message); - }); - }, testName + " with null length"); - // 0 length (OperationError) subsetTest(promise_test, function(test) { return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0) diff --git a/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js b/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js index 1a3370ea13d2c0..574134eb76dcd8 100644 --- a/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js +++ b/test/fixtures/wpt/WebCryptoAPI/getRandomValues.any.js @@ -1,4 +1,15 @@ // Step 1. +test(function() { + assert_throws_dom("TypeMismatchError", function() { + self.crypto.getRandomValues(new Float16Array(6)) + }, "Float16Array") + + assert_throws_dom("TypeMismatchError", function() { + const len = 65536 / Float16Array.BYTES_PER_ELEMENT + 1; + self.crypto.getRandomValues(new Float16Array(len)); + }, "Float16Array (too long)") +}, "Float16 arrays"); + test(function() { assert_throws_dom("TypeMismatchError", function() { self.crypto.getRandomValues(new Float32Array(6)) @@ -57,4 +68,10 @@ for (const array of arrays) { test(function() { assert_true(self.crypto.getRandomValues(new ctor(0)).length == 0) }, "Null arrays: " + array); + + test(function() { + class Buffer extends ctor {} + // Must not throw for the test to pass + self.crypto.getRandomValues(new Buffer(256)); + }, "Subclass of " + array); } diff --git a/test/fixtures/wpt/WebCryptoAPI/import_export/crashtests/importKey-unsettled-promise.https.any.js b/test/fixtures/wpt/WebCryptoAPI/import_export/crashtests/importKey-unsettled-promise.https.any.js new file mode 100644 index 00000000000000..0ceeea390ebf97 --- /dev/null +++ b/test/fixtures/wpt/WebCryptoAPI/import_export/crashtests/importKey-unsettled-promise.https.any.js @@ -0,0 +1,17 @@ +// META: title=WebCryptoAPI: Assure promise returned by importKey is settled. +// META: timeout=long +// META: script=/common/gc.js + +'use strict'; + +promise_test(async () => { + const jwkKey = {}; + const extractable = true; + crypto.subtle.importKey("jwk", jwkKey, {name: "UNSUPPORTED", hash: "SHA-224"}, extractable, []).then( + () => { assert_unreached("Unsupported algorithm should cause promise rejection")}, + (err) => { + assert_equals(err.name, "NotSupportedError"); + }); + await garbageCollect(); +}) + diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js index d77a8808831176..de9a5268827d75 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js @@ -1,363 +1,214 @@ function run_test() { - setup({explicit_done: true}); - var subtle = self.crypto.subtle; // Change to test prefixed implementations - // When are all these tests really done? When all the promises they use have resolved. - var all_promises = []; - // Source file [algorithm_name]_vectors.js provides the getTestVectors method // for the algorithm that drives these tests. var testVectors = getTestVectors(); - // Test verification first, because signing tests rely on that working testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.data) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - return operation; - }, vector.name + " verification"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification"); - }); - - all_promises.push(promise); - }); + var algorithm = {name: vector.algorithmName}; - // Test verification with an altered buffer after call - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { + // Test verification first, because signing tests rely on that working + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_true(isVerified, "Signature verified"); + }, vector.name + " verification"); + + // Test verification with an altered buffer after call + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); var signature = copyBuffer(vector.signature); - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.data) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - signature[0] = 255 - signature[0]; - return operation; - }, vector.name + " verification with altered signature after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); - }); - - all_promises.push(promise); - }); - - // Check for successful verification even if data is altered after call. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { + [isVerified] = await Promise.all([ + subtle.verify(algorithm, key, signature, vector.data), + signature[0] = 255 - signature[0] + ]); + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_true(isVerified, "Signature verified"); + }, vector.name + " verification with altered signature after call"); + + // Check for successful verification even if data is altered after call. + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); var data = copyBuffer(vector.data); - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, data) - .then(function(is_verified) { - assert_true(is_verified, "Signature verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - data[0] = 255 - data[0]; - return operation; - }, vector.name + " with altered data after call"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " with altered data after call"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using privateKey to verify. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.data) - .then(function(data) { - assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": " + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using privateKey to verify"); - - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using privateKey to verify"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to using publicKey to sign. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - return subtle.sign(algorithm, vector.publicKey, vector.data) - .then(function(signature) { - assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": " + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " using publicKey to sign"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " using publicKey to sign"); - }); - - all_promises.push(promise); - }); - - // Check for failures due to no "verify" usage. - testVectors.forEach(function(originalVector) { - var vector = Object.assign({}, originalVector); - - var promise = importVectorKeys(vector, [], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.data) - .then(function(data) { - assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'"); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); - }); - }, vector.name + " no verify usage"); - }, function(err) { - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " no verify usage"); - }); - - all_promises.push(promise); - }); - - // Check for successful signing and verification. - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - return subtle.sign(algorithm, vector.privateKey, vector.data) - .then(function(signature) { - assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); - // Can we verify the signature? - return subtle.verify(algorithm, vector.publicKey, signature, vector.data) - .then(function(is_verified) { - assert_true(is_verified, "Round trip verification works"); - return signature; - }, function(err) { - assert_unreached("verify error for test " + vector.name + ": " + err.message + "'"); - }); - }, function(err) { - assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); - }); - }, vector.name + " round trip"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested signing or verifying - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " round trip"); - }); - - all_promises.push(promise); - }); - - // Test signing with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - var algorithm = {name: vector.algorithmName}; - return importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - promise_test(function(test) { - var operation = subtle.sign(algorithm, wrongKey, vector.data) - .then(function(signature) { - assert_unreached("Signing should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " signing with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification with the wrong algorithm - testVectors.forEach(function(vector) { - // Want to get the key for the wrong algorithm - var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) - .then(function(wrongKey) { - return importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; - promise_test(function(test) { - var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.data) - .then(function(signature) { - assert_unreached("Verifying should not have succeeded for " + vector.name); - }, function(err) { - assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); - }); - - return operation; - }, vector.name + " verifying with wrong algorithm name"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); - }); - }, function(err) { - promise_test(function(test) { - assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); - }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with wrong signature - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; + [isVerified] = await Promise.all([ + subtle.verify(algorithm, key, vector.signature, data), + data[0] = 255 - data[0] + ]); + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_true(isVerified, "Signature verified"); + }, vector.name + " with altered data after call"); + + // Check for failures due to using privateKey to verify. + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]); + isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) + assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name); + } catch (err) { + if (err instanceof AssertionError) + throw err; + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }; + assert_false(isVerified, "Signature verified"); + }, vector.name + " using privateKey to verify"); + + // Check for failures due to using publicKey to sign. + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + let signature = await subtle.sign(algorithm, key, vector.data); + assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name); + } catch (err) { + if (err instanceof AssertionError) + throw err; + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }; + }, vector.name + " using publicKey to sign"); + + // Check for failures due to no "verify" usage. + promise_test(async() => { + let isVerified = false; + let key; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, []); + isVerified = await subtle.verify(algorithm, key, vector.signature, vector.data) + assert_unreached("Should have thrown error for no verify usage in " + vector.name); + } catch (err) { + if (err instanceof AssertionError) + throw err; + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }; + assert_false(isVerified, "Signature verified"); + }, vector.name + " no verify usage"); + + // Check for successful signing and verification. + var algorithm = {name: vector.algorithmName}; + promise_test(async() => { + let isVerified = false; + let privateKey, publicKey; + let signature; + try { + privateKey = await subtle.importKey("pkcs8", vector.privateKeyBuffer, algorithm, false, ["sign"]); + publicKey = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + signature = await subtle.sign(algorithm, privateKey, vector.data); + isVerified = await subtle.verify(algorithm, publicKey, vector.signature, vector.data) + } catch (err) { + assert_false(publicKey === undefined || privateKey === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_false(signature === undefined, "sign error for test " + vector.name + ": '" + err.message + "'"); + assert_unreached("verify error for test " + vector.name + ": " + err.message + "'"); + }; + assert_true(isVerified, "Round trip verification works"); + }, vector.name + " round trip"); + + // Test signing with the wrong algorithm + var algorithm = {name: vector.algorithmName}; + promise_test(async() => { + let wrongKey; + try { + wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + let signature = await subtle.sign(algorithm, wrongKey, vector.data); + assert_unreached("Signing should not have succeeded for " + vector.name); + } catch (err) { + if (err instanceof AssertionError) + throw err; + assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }; + }, vector.name + " signing with wrong algorithm name"); + + // Test verification with the wrong algorithm + var algorithm = {name: vector.algorithmName}; + promise_test(async() => { + let wrongKey; + try { + wrongKey = await subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + let isVerified = await subtle.verify(algorithm, wrongKey, vector.signature, vector.data) + assert_unreached("Verifying should not have succeeded for " + vector.name); + } catch (err) { + if (err instanceof AssertionError) + throw err; + assert_false(wrongKey === undefined, "Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }; + }, vector.name + " verifying with wrong algorithm name"); + + // Test verification fails with wrong signature + var algorithm = {name: vector.algorithmName}; + promise_test(async() => { + let key; + let isVerified = true; var signature = copyBuffer(vector.signature); signature[0] = 255 - signature[0]; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.data) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to altered signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to altered signature"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with short (odd length) signature - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + isVerified = await subtle.verify(algorithm, key, signature, vector.data) + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_false(isVerified, "Signature verified"); + }, vector.name + " verification failure due to altered signature"); + + // Test verification fails with short (odd length) signature + promise_test(async() => { + let key; + let isVerified = true; var signature = vector.signature.slice(1); // Skip the first byte - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.data) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to shortened signature"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to shortened signature"); - }); - - all_promises.push(promise); - }); - - // Test verification fails with wrong data - testVectors.forEach(function(vector) { - var promise = importVectorKeys(vector, ["verify"], ["sign"]) - .then(function(vectors) { - var algorithm = {name: vector.algorithmName}; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + isVerified = await subtle.verify(algorithm, key, signature, vector.data) + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_false(isVerified, "Signature verified"); + }, vector.name + " verification failure due to shortened signature"); + + // Test verification fails with wrong data + promise_test(async() => { + let key; + let isVerified = true; var data = copyBuffer(vector.data); data[0] = 255 - data[0]; - promise_test(function(test) { - var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, data) - .then(function(is_verified) { - assert_false(is_verified, "Signature NOT verified"); - }, function(err) { - assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); - }); - - return operation; - }, vector.name + " verification failure due to altered data"); - - }, function(err) { - // We need a failed test if the importVectorKey operation fails, so - // we know we never tested verification. - promise_test(function(test) { - assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); - }, "importVectorKeys step: " + vector.name + " verification failure due to altered data"); - }); - - all_promises.push(promise); - }); - - - promise_test(function() { - return Promise.all(all_promises) - .then(function() {done();}) - .catch(function() {done();}) - }, "setup"); - - // Test that generated keys are valid for signing and verifying. - testVectors.forEach(function(vector) { - var algorithm = {name: vector.algorithmName}; + try { + key = await subtle.importKey("spki", vector.publicKeyBuffer, algorithm, false, ["verify"]); + isVerified = await subtle.verify(algorithm, key, vector.signature, data) + } catch (err) { + assert_false(key === undefined, "importKey failed for " + vector.name + ". Message: ''" + err.message + "''"); + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }; + assert_false(isVerified, "Signature verified"); + }, vector.name + " verification failure due to altered data"); + + // Test that generated keys are valid for signing and verifying. promise_test(async() => { let key = await subtle.generateKey(algorithm, false, ["sign", "verify"]); let signature = await subtle.sign(algorithm, key.privateKey, vector.data); @@ -366,42 +217,6 @@ function run_test() { }, "Sign and verify using generated " + vector.algorithmName + " keys."); }); - - // A test vector has all needed fields for signing and verifying, EXCEPT that the - // key field may be null. This function replaces that null with the Correct - // CryptoKey object. - // - // Returns a Promise that yields an updated vector on success. - function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { - var publicPromise, privatePromise; - - if (vector.publicKey !== null) { - publicPromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithmName}, false, publicKeyUsages) - .then(function(key) { - vector.publicKey = key; - return vector; - }); // Returns a copy of the sourceBuffer it is sent. - } - - if (vector.privateKey !== null) { - privatePromise = new Promise(function(resolve, reject) { - resolve(vector); - }); - } else { - privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithmName}, false, privateKeyUsages) - .then(function(key) { - vector.privateKey = key; - return vector; - }); - } - - return Promise.all([publicPromise, privatePromise]); - } - // Returns a copy of the sourceBuffer it is sent. function copyBuffer(sourceBuffer) { var source = new Uint8Array(sourceBuffer); @@ -414,22 +229,5 @@ function run_test() { return copy; } - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i { + let isVerified = true; + let publicKey; + try { + publicKey = await subtle.importKey("raw", test.keyData, algorithm, false, ["verify"]) + isVerified = await subtle.verify(algorithm, publicKey, test.signature, test.message); + } catch (err) { + assert_true(publicKey !== undefined, "Public key should be valid."); + assert_unreached("The operation shouldn't fail, but it thown this error: " + err.name + ": " + err.message + "."); + } + assert_equals(isVerified, test.verified, "Signature verification result."); + }, algorithmName + " Verification checks with small-order key of order - Test " + test.id); + }); + }); + + return; +} diff --git a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_vectors.js b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_vectors.js index 96ec2b01af96f2..ce80e0ea7e2626 100644 --- a/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_vectors.js +++ b/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa_vectors.js @@ -53,6 +53,145 @@ function getTestVectors() { vectors.push(vector); }); - return vectors; } + +// https://eprint.iacr.org/2020/1244.pdf#table.caption.3 +var kSmallOrderPoints = [ + // Canonical serializations + [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // #0 - Order 1 + [0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F], // #1 - Order 2 + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80], // #2 - Order 4 + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // #3 - Order 4 + [0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F, 0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F, 0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6, 0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0x7A], // #4 - Order 8 + [0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F, 0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F, 0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6, 0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0xFA], // #5 - Order 8 + [0x26, 0xE8, 0x95, 0x8F, 0xC2, 0xB2, 0x27, 0xB0, 0x45, 0xC3, 0xF4, 0x89, 0xF2, 0xEF, 0x98, 0xF0, 0xD5, 0xDF, 0xAC, 0x05, 0xD3, 0xC6, 0x33, 0x39, 0xB1, 0x38, 0x02, 0x88, 0x6D, 0x53, 0xFC, 0x05], // #6 - Order 8 + [0x26, 0xE8, 0x95, 0x8F, 0xC2, 0xB2, 0x27, 0xB0, 0x45, 0xC3, 0xF4, 0x89, 0xF2, 0xEF, 0x98, 0xF0, 0xD5, 0xDF, 0xAC, 0x05, 0xD3, 0xC6, 0x33, 0x39, 0xB1, 0x38, 0x02, 0x88, 0x6D, 0x53, 0xFC, 0x85], // #7 - Order 8 + + // Non-canonical serializatons + [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80], // #8 - Order 1 + [0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], // #9 - Order 2 + [0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F], // #10 - Order 1 + [0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], // #11 - Order 1 + [0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], // #12 - Order 4 + [0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F], // #13 - Order 4 +]; + + +var pubKeys = [ + [0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa], // kSmallOrderPoints #5 + [0xf7, 0xba, 0xde, 0xc5, 0xb8, 0xab, 0xea, 0xf6, 0x99, 0x58, 0x39, 0x92, 0x21, 0x9b, 0x7b, 0x22, 0x3f, 0x1d, 0xf3, 0xfb, 0xbe, 0xa9, 0x19, 0x84, 0x4e, 0x3f, 0x7c, 0x55, 0x4a, 0x43, 0xdd, 0x43], // highest 32 bytes of case "1" signature + [0xcd, 0xb2, 0x67, 0xce, 0x40, 0xc5, 0xcd, 0x45, 0x30, 0x6f, 0xa5, 0xd2, 0xf2, 0x97, 0x31, 0x45, 0x93, 0x87, 0xdb, 0xf9, 0xeb, 0x93, 0x3b, 0x7b, 0xd5, 0xae, 0xd9, 0xa7, 0x65, 0xb8, 0x8d, 0x4d], + [0x44, 0x2a, 0xad, 0x9f, 0x08, 0x9a, 0xd9, 0xe1, 0x46, 0x47, 0xb1, 0xef, 0x90, 0x99, 0xa1, 0xff, 0x47, 0x98, 0xd7, 0x85, 0x89, 0xe6, 0x6f, 0x28, 0xec, 0xa6, 0x9c, 0x11, 0xf5, 0x82, 0xa6, 0x23], + [0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // kSmallOrderPoints #9 + [0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F], // kSmallOrderPoints #1 +] + +// https://eprint.iacr.org/2020/1244.pdf +// signature = (R, S); public key A, h = SHA512(R||A||M ) +// 8(SB) = 8R + 8(hA) => (1) +// SB = R + hA => (2) +var kSmallOrderTestCases = { + "Ed25519": [ + { + id: "0", // S = 0 | A's order = small | R's order = small | (1) = pass | (2) = pass + message : Uint8Array.from([0x8c, 0x93, 0x25, 0x5d, 0x71, 0xdc, 0xab, 0x10, 0xe8, 0xf3, 0x79, 0xc2, 0x62, 0x00, 0xf3, 0xc7, 0xbd, 0x5f, 0x09, 0xd9, 0xbc, 0x30, 0x68, 0xd3, 0xef, 0x4e, 0xde, 0xb4, 0x85, 0x30, 0x22, 0xb6]), + keyData : Uint8Array.from(pubKeys[0]), + signature : Uint8Array.from([0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), + verified: false, // small-order signature's R fail in the verification. + }, + { + id: "1", // 0 < S < L | A's order = small | R's order = mixed | (1) = pass | (2) = pass + message : Uint8Array.from([0x9b, 0xd9, 0xf4, 0x4f, 0x4d, 0xcc, 0x75, 0xbd, 0x53, 0x1b, 0x56, 0xb2, 0xcd, 0x28, 0x0b, 0x0b, 0xb3, 0x8f, 0xc1, 0xcd, 0x6d, 0x12, 0x30, 0xe1, 0x48, 0x61, 0xd8, 0x61, 0xde, 0x09, 0x2e, 0x79]), + keyData : Uint8Array.from(pubKeys[0]), + signature : Uint8Array.from([0xf7, 0xba, 0xde, 0xc5, 0xb8, 0xab, 0xea, 0xf6, 0x99, 0x58, 0x39, 0x92, 0x21, 0x9b, 0x7b, 0x22, 0x3f, 0x1d, 0xf3, 0xfb, 0xbe, 0xa9, 0x19, 0x84, 0x4e, 0x3f, 0x7c, 0x55, 0x4a, 0x43, 0xdd, 0x43, 0xa5, 0xbb, 0x70, 0x47, 0x86, 0xbe, 0x79, 0xfc, 0x47, 0x6f, 0x91, 0xd3, 0xf3, 0xf8, 0x9b, 0x03, 0x98, 0x4d, 0x80, 0x68, 0xdc, 0xf1, 0xbb, 0x7d, 0xfc, 0x66, 0x37, 0xb4, 0x54, 0x50, 0xac, 0x04]), + verified: false, // small-order key's data fail in the verification. + }, + { + id: "2", // 0 < S < L | A's order = mixed | R's order = small | (1) = pass | (2) = pass + message : Uint8Array.from([0xae, 0xbf, 0x3f, 0x26, 0x01, 0xa0, 0xc8, 0xc5, 0xd3, 0x9c, 0xc7, 0xd8, 0x91, 0x16, 0x42, 0xf7, 0x40, 0xb7, 0x81, 0x68, 0x21, 0x8d, 0xa8, 0x47, 0x17, 0x72, 0xb3, 0x5f, 0x9d, 0x35, 0xb9, 0xab]), + keyData : Uint8Array.from(pubKeys[1]), + signature : Uint8Array.from([0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa, 0x8c, 0x4b, 0xd4, 0x5a, 0xec, 0xac, 0xa5, 0xb2, 0x4f, 0xb9, 0x7b, 0xc1, 0x0a, 0xc2, 0x7a, 0xc8, 0x75, 0x1a, 0x7d, 0xfe, 0x1b, 0xaf, 0xf8, 0xb9, 0x53, 0xec, 0x9f, 0x58, 0x33, 0xca, 0x26, 0x0e]), + verified: false, // small-order signature's R fail in the verification. + }, + { + id: "3", // 0 < S < L | A's order = mixed | R's order = mixed | (1) = pass | (2) = pass + message : Uint8Array.from([0x9b, 0xd9, 0xf4, 0x4f, 0x4d, 0xcc, 0x75, 0xbd, 0x53, 0x1b, 0x56, 0xb2, 0xcd, 0x28, 0x0b, 0x0b, 0xb3, 0x8f, 0xc1, 0xcd, 0x6d, 0x12, 0x30, 0xe1, 0x48, 0x61, 0xd8, 0x61, 0xde, 0x09, 0x2e, 0x79]), + keyData : Uint8Array.from(pubKeys[2]), + signature : Uint8Array.from([0x90, 0x46, 0xa6, 0x47, 0x50, 0x44, 0x49, 0x38, 0xde, 0x19, 0xf2, 0x27, 0xbb, 0x80, 0x48, 0x5e, 0x92, 0xb8, 0x3f, 0xdb, 0x4b, 0x65, 0x06, 0xc1, 0x60, 0x48, 0x4c, 0x01, 0x6c, 0xc1, 0x85, 0x2f, 0x87, 0x90, 0x9e, 0x14, 0x42, 0x8a, 0x7a, 0x1d, 0x62, 0xe9, 0xf2, 0x2f, 0x3d, 0x3a, 0xd7, 0x80, 0x2d, 0xb0, 0x2e, 0xb2, 0xe6, 0x88, 0xb6, 0xc5, 0x2f, 0xcd, 0x66, 0x48, 0xa9, 0x8b, 0xd0, 0x09]), + verified: true, // mixed-order points are not checked. + }, + { + id: "4", // 0 < S < L | A's order = mixed | R's order = mixed | (1) = pass | (2) = fail + message : Uint8Array.from([0xe4, 0x7d, 0x62, 0xc6, 0x3f, 0x83, 0x0d, 0xc7, 0xa6, 0x85, 0x1a, 0x0b, 0x1f, 0x33, 0xae, 0x4b, 0xb2, 0xf5, 0x07, 0xfb, 0x6c, 0xff, 0xec, 0x40, 0x11, 0xea, 0xcc, 0xd5, 0x5b, 0x53, 0xf5, 0x6c]), + keyData : Uint8Array.from(pubKeys[2]), + signature : Uint8Array.from([0x16, 0x0a, 0x1c, 0xb0, 0xdc, 0x9c, 0x02, 0x58, 0xcd, 0x0a, 0x7d, 0x23, 0xe9, 0x4d, 0x8f, 0xa8, 0x78, 0xbc, 0xb1, 0x92, 0x5f, 0x2c, 0x64, 0x24, 0x6b, 0x2d, 0xee, 0x17, 0x96, 0xbe, 0xd5, 0x12, 0x5e, 0xc6, 0xbc, 0x98, 0x2a, 0x26, 0x9b, 0x72, 0x3e, 0x06, 0x68, 0xe5, 0x40, 0x91, 0x1a, 0x9a, 0x6a, 0x58, 0x92, 0x1d, 0x69, 0x25, 0xe4, 0x34, 0xab, 0x10, 0xaa, 0x79, 0x40, 0x55, 0x1a, 0x09]), + verified: false, // expect a cofactorless verification algorithm. + }, + { + id: "5", // 0 < S < L | A's order = mixed | R's order = L | (1) = pass | (2) = fail + message : Uint8Array.from([0xe4, 0x7d, 0x62, 0xc6, 0x3f, 0x83, 0x0d, 0xc7, 0xa6, 0x85, 0x1a, 0x0b, 0x1f, 0x33, 0xae, 0x4b, 0xb2, 0xf5, 0x07, 0xfb, 0x6c, 0xff, 0xec, 0x40, 0x11, 0xea, 0xcc, 0xd5, 0x5b, 0x53, 0xf5, 0x6c]), + keyData : Uint8Array.from(pubKeys[2]), + signature : Uint8Array.from([0x21, 0x12, 0x2a, 0x84, 0xe0, 0xb5, 0xfc, 0xa4, 0x05, 0x2f, 0x5b, 0x12, 0x35, 0xc8, 0x0a, 0x53, 0x78, 0x78, 0xb3, 0x8f, 0x31, 0x42, 0x35, 0x6b, 0x2c, 0x23, 0x84, 0xeb, 0xad, 0x46, 0x68, 0xb7, 0xe4, 0x0b, 0xc8, 0x36, 0xda, 0xc0, 0xf7, 0x10, 0x76, 0xf9, 0xab, 0xe3, 0xa5, 0x3f, 0x9c, 0x03, 0xc1, 0xce, 0xee, 0xdd, 0xb6, 0x58, 0xd0, 0x03, 0x04, 0x94, 0xac, 0xe5, 0x86, 0x68, 0x74, 0x05]), + verified: false, // expect a cofactorless verification algorithm. + }, + { + id: "6", // S > L | A's order = L | R's order = L | (1) = pass | (2) = pass + message : Uint8Array.from([0x85, 0xe2, 0x41, 0xa0, 0x7d, 0x14, 0x8b, 0x41, 0xe4, 0x7d, 0x62, 0xc6, 0x3f, 0x83, 0x0d, 0xc7, 0xa6, 0x85, 0x1a, 0x0b, 0x1f, 0x33, 0xae, 0x4b, 0xb2, 0xf5, 0x07, 0xfb, 0x6c, 0xff, 0xec, 0x40]), + keyData : Uint8Array.from(pubKeys[3]), + signature : Uint8Array.from([0xe9, 0x6f, 0x66, 0xbe, 0x97, 0x6d, 0x82, 0xe6, 0x01, 0x50, 0xba, 0xec, 0xff, 0x99, 0x06, 0x68, 0x4a, 0xeb, 0xb1, 0xef, 0x18, 0x1f, 0x67, 0xa7, 0x18, 0x9a, 0xc7, 0x8e, 0xa2, 0x3b, 0x6c, 0x0e, 0x54, 0x7f, 0x76, 0x90, 0xa0, 0xe2, 0xdd, 0xcd, 0x04, 0xd8, 0x7d, 0xbc, 0x34, 0x90, 0xdc, 0x19, 0xb3, 0xb3, 0x05, 0x2f, 0x7f, 0xf0, 0x53, 0x8c, 0xb6, 0x8a, 0xfb, 0x36, 0x9b, 0xa3, 0xa5, 0x14]), + verified: false, // S out of bounds + }, + { + id: "7", // S >> L | A's order = L | R's order = L | (1) = pass | (2) = pass + message : Uint8Array.from([0x85, 0xe2, 0x41, 0xa0, 0x7d, 0x14, 0x8b, 0x41, 0xe4, 0x7d, 0x62, 0xc6, 0x3f, 0x83, 0x0d, 0xc7, 0xa6, 0x85, 0x1a, 0x0b, 0x1f, 0x33, 0xae, 0x4b, 0xb2, 0xf5, 0x07, 0xfb, 0x6c, 0xff, 0xec, 0x40]), + keyData : Uint8Array.from(pubKeys[3]), + signature : Uint8Array.from([0x8c, 0xe5, 0xb9, 0x6c, 0x8f, 0x26, 0xd0, 0xab, 0x6c, 0x47, 0x95, 0x8c, 0x9e, 0x68, 0xb9, 0x37, 0x10, 0x4c, 0xd3, 0x6e, 0x13, 0xc3, 0x35, 0x66, 0xac, 0xd2, 0xfe, 0x8d, 0x38, 0xaa, 0x19, 0x42, 0x7e, 0x71, 0xf9, 0x8a, 0x47, 0x34, 0xe7, 0x4f, 0x2f, 0x13, 0xf0, 0x6f, 0x97, 0xc2, 0x0d, 0x58, 0xcc, 0x3f, 0x54, 0xb8, 0xbd, 0x0d, 0x27, 0x2f, 0x42, 0xb6, 0x95, 0xdd, 0x7e, 0x89, 0xa8, 0xc2, 0x02]), + verified: false, // S out of bounds + }, + { + id: "8", // 0 < S < L | A's order = mixed | R's order = small (non-canonical) | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #8 and accept #9, and viceversa + message : Uint8Array.from([0x9b, 0xed, 0xc2, 0x67, 0x42, 0x37, 0x25, 0xd4, 0x73, 0x88, 0x86, 0x31, 0xeb, 0xf4, 0x59, 0x88, 0xba, 0xd3, 0xdb, 0x83, 0x85, 0x1e, 0xe8, 0x5c, 0x85, 0xe2, 0x41, 0xa0, 0x7d, 0x14, 0x8b, 0x41]), + keyData : Uint8Array.from(pubKeys[1]), + signature : Uint8Array.from([0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xbe, 0x96, 0x78, 0xac, 0x10, 0x2e, 0xdc, 0xd9, 0x2b, 0x02, 0x10, 0xbb, 0x34, 0xd7, 0x42, 0x8d, 0x12, 0xff, 0xc5, 0xdf, 0x5f, 0x37, 0xe3, 0x59, 0x94, 0x12, 0x66, 0xa4, 0xe3, 0x5f, 0x0f]), + verified: false, // non-canonical point should fail in the verificaton (RFC8032) + }, + { + id: "9", // 0 < S < L | A's order = mixed | R's order = small (non-canonical) | (1) = ? | (2) = ? + message : Uint8Array.from([0x9b, 0xed, 0xc2, 0x67, 0x42, 0x37, 0x25, 0xd4, 0x73, 0x88, 0x86, 0x31, 0xeb, 0xf4, 0x59, 0x88, 0xba, 0xd3, 0xdb, 0x83, 0x85, 0x1e, 0xe8, 0x5c, 0x85, 0xe2, 0x41, 0xa0, 0x7d, 0x14, 0x8b, 0x41]), + keyData : Uint8Array.from(pubKeys[1]), + signature : Uint8Array.from([0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0x8c, 0x5b, 0x64, 0xcd, 0x20, 0x89, 0x82, 0xaa, 0x38, 0xd4, 0x93, 0x66, 0x21, 0xa4, 0x77, 0x5a, 0xa2, 0x33, 0xaa, 0x05, 0x05, 0x71, 0x1d, 0x8f, 0xdc, 0xfd, 0xaa, 0x94, 0x3d, 0x49, 0x08]), + verified: false, // non-canonical point should fail in the verificaton (RFC8032) + }, + { + id: "10", // 0 < S < L | A's order = small (non-canonical) | R's order = mixed | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #10 and accept #11, and viceversa + message : Uint8Array.from([0xe9, 0x6b, 0x70, 0x21, 0xeb, 0x39, 0xc1, 0xa1, 0x63, 0xb6, 0xda, 0x4e, 0x30, 0x93, 0xdc, 0xd3, 0xf2, 0x13, 0x87, 0xda, 0x4c, 0xc4, 0x57, 0x2b, 0xe5, 0x88, 0xfa, 0xfa, 0xe2, 0x3c, 0x15, 0x5b]), + keyData : Uint8Array.from(pubKeys[4]), + signature : Uint8Array.from([0xa9, 0xd5, 0x52, 0x60, 0xf7, 0x65, 0x26, 0x1e, 0xb9, 0xb8, 0x4e, 0x10, 0x6f, 0x66, 0x5e, 0x00, 0xb8, 0x67, 0x28, 0x7a, 0x76, 0x19, 0x90, 0xd7, 0x13, 0x59, 0x63, 0xee, 0x0a, 0x7d, 0x59, 0xdc, 0xa5, 0xbb, 0x70, 0x47, 0x86, 0xbe, 0x79, 0xfc, 0x47, 0x6f, 0x91, 0xd3, 0xf3, 0xf8, 0x9b, 0x03, 0x98, 0x4d, 0x80, 0x68, 0xdc, 0xf1, 0xbb, 0x7d, 0xfc, 0x66, 0x37, 0xb4, 0x54, 0x50, 0xac, 0x04]), + verified: false, // non-canonical point should fail in the verificaton (RFC8032) + }, + { + id: "11", // 0 < S < L | A's order = small (non-canonical) | R's order = mixed | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #10 and accept #11, and viceversa + message : Uint8Array.from([0x39, 0xa5, 0x91, 0xf5, 0x32, 0x1b, 0xbe, 0x07, 0xfd, 0x5a, 0x23, 0xdc, 0x2f, 0x39, 0xd0, 0x25, 0xd7, 0x45, 0x26, 0x61, 0x57, 0x46, 0x72, 0x7c, 0xee, 0xfd, 0x6e, 0x82, 0xae, 0x65, 0xc0, 0x6f]), + keyData : Uint8Array.from(pubKeys[4]), + signature : Uint8Array.from([0xa9, 0xd5, 0x52, 0x60, 0xf7, 0x65, 0x26, 0x1e, 0xb9, 0xb8, 0x4e, 0x10, 0x6f, 0x66, 0x5e, 0x00, 0xb8, 0x67, 0x28, 0x7a, 0x76, 0x19, 0x90, 0xd7, 0x13, 0x59, 0x63, 0xee, 0x0a, 0x7d, 0x59, 0xdc, 0xa5, 0xbb, 0x70, 0x47, 0x86, 0xbe, 0x79, 0xfc, 0x47, 0x6f, 0x91, 0xd3, 0xf3, 0xf8, 0x9b, 0x03, 0x98, 0x4d, 0x80, 0x68, 0xdc, 0xf1, 0xbb, 0x7d, 0xfc, 0x66, 0x37, 0xb4, 0x54, 0x50, 0xac, 0x04]), + verified: false, // non-canonical point should fail in the verificaton (RFC8032) + }, + // https://eprint.iacr.org/2020/1244.pdf#section.A.2 + // cases breaking non-repudiation + { + id: "12", // 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ? + message : Uint8Array.from([0x53, 0x65, 0x6e, 0x64, 0x20, 0x31, 0x30, 0x30, 0x20, 0x55, 0x53, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x41, 0x6c, 0x69, 0x63, 0x65]), + keyData : Uint8Array.from(pubKeys[5]), + signature : Uint8Array.from([0xa9, 0xd5, 0x52, 0x60, 0xf7, 0x65, 0x26, 0x1e, 0xb9, 0xb8, 0x4e, 0x10, 0x6f, 0x66, 0x5e, 0x00, 0xb8, 0x67, 0x28, 0x7a, 0x76, 0x19, 0x90, 0xd7, 0x13, 0x59, 0x63, 0xee, 0x0a, 0x7d, 0x59, 0xdc, 0xa5, 0xbb, 0x70, 0x47, 0x86, 0xbe, 0x79, 0xfc, 0x47, 0x6f, 0x91, 0xd3, 0xf3, 0xf8, 0x9b, 0x03, 0x98, 0x4d, 0x80, 0x68, 0xdc, 0xf1, 0xbb, 0x7d, 0xfc, 0x66, 0x37, 0xb4, 0x54, 0x50, 0xac, 0x04]), + verified: false, + }, + { + id: "13", // 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ? + message : Uint8Array.from([0x53, 0x65, 0x6e, 0x64, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x55, 0x53, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x41, 0x6c, 0x69, 0x63, 0x65]), + keyData : Uint8Array.from(pubKeys[5]), + signature : Uint8Array.from([0xa9, 0xd5, 0x52, 0x60, 0xf7, 0x65, 0x26, 0x1e, 0xb9, 0xb8, 0x4e, 0x10, 0x6f, 0x66, 0x5e, 0x00, 0xb8, 0x67, 0x28, 0x7a, 0x76, 0x19, 0x90, 0xd7, 0x13, 0x59, 0x63, 0xee, 0x0a, 0x7d, 0x59, 0xdc, 0xa5, 0xbb, 0x70, 0x47, 0x86, 0xbe, 0x79, 0xfc, 0x47, 0x6f, 0x91, 0xd3, 0xf3, 0xf8, 0x9b, 0x03, 0x98, 0x4d, 0x80, 0x68, 0xdc, 0xf1, 0xbb, 0x7d, 0xfc, 0x66, 0x37, 0xb4, 0x54, 0x50, 0xac, 0x04]), + verified: false, + } + ] +}; diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index c9320269a28f2a..43b1f480d1f18c 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -88,7 +88,7 @@ "path": "wasm/webapi" }, "WebCryptoAPI": { - "commit": "5e042cbc4ecab7b2279a5fd411c6daa24ca886c6", + "commit": "6748a0a24614b01ce6527493a19ef846738bee3a", "path": "WebCryptoAPI" }, "webidl/ecmascript-binding/es-exceptions": { diff --git a/test/wpt/README.md b/test/wpt/README.md index 0f73062e289a47..df890d5d832ee0 100644 --- a/test/wpt/README.md +++ b/test/wpt/README.md @@ -27,7 +27,7 @@ it's not yet clear how compliant the implementation is, the requirements and expected failures can be figured out in a later step when the tests are run for the first time. -See [Format of a status JSON file](#status-format) for details. +See [Format of a status file](#status-format) for details. ### 2. Pull the WPT files @@ -98,7 +98,7 @@ add this to `test/wpt/status/url.json`: } ``` -See [Format of a status JSON file](#status-format) for details. +See [Format of a status file](#status-format) for details. ### 5. Commit the changes and submit a Pull Request @@ -147,7 +147,7 @@ expected failures. -## Format of a status JSON file +## Format of a status file ```json { @@ -177,6 +177,10 @@ A test may have to be skipped because it depends on another irrelevant Web API, or certain harness has not been ported in our test runner yet. In that case it needs to be marked with `skip` instead of `fail`. +The status file may optionally also be a CJS module that exports the object. +This allows for more complex logic to be used to determine the expected status +of a test. + [Web Platform Tests]: https://github.com/web-platform-tests/wpt [`test/fixtures/wpt/README.md`]: ../fixtures/wpt/README.md [git node wpt]: https://github.com/nodejs/node-core-utils/blob/HEAD/docs/git-node.md#git-node-wpt diff --git a/test/wpt/status/WebCryptoAPI.cjs b/test/wpt/status/WebCryptoAPI.cjs new file mode 100644 index 00000000000000..0057d5f72cc937 --- /dev/null +++ b/test/wpt/status/WebCryptoAPI.cjs @@ -0,0 +1,37 @@ +'use strict'; + +const os = require('node:os'); + +const s390x = os.arch() === 's390x'; + +module.exports = { + 'algorithm-discards-context.https.window.js': { + 'skip': 'Not relevant in Node.js context', + }, + 'historical.any.js': { + 'skip': 'Not relevant in Node.js context', + }, + 'getRandomValues.any.js': { + 'fail': { + 'note': 'Node.js does not support Float16Array', + 'expected': [ + 'Float16 arrays', + ], + }, + }, + 'sign_verify/eddsa_small_order_points.https.any.js': { + 'fail': { + 'note': 'see https://github.com/nodejs/node/issues/54572', + 'expected': [ + 'Ed25519 Verification checks with small-order key of order - Test 1', + 'Ed25519 Verification checks with small-order key of order - Test 2', + 'Ed25519 Verification checks with small-order key of order - Test 12', + 'Ed25519 Verification checks with small-order key of order - Test 13', + ...(s390x ? [] : [ + 'Ed25519 Verification checks with small-order key of order - Test 0', + 'Ed25519 Verification checks with small-order key of order - Test 11', + ]), + ], + }, + }, +}; diff --git a/test/wpt/status/WebCryptoAPI.json b/test/wpt/status/WebCryptoAPI.json deleted file mode 100644 index 9f9ba93240be25..00000000000000 --- a/test/wpt/status/WebCryptoAPI.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "algorithm-discards-context.https.window.js": { - "skip": "Not relevant in Node.js context" - }, - "historical.any.js": { - "skip": "Not relevant in Node.js context" - } -}