test,crypto: update WebCryptoAPI WPT

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 <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
Filip Skokan 2024-08-29 18:46:40 +02:00 committed by GitHub
parent beabcec41c
commit fc02b88f89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 575 additions and 500 deletions

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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');

View File

@ -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");
}

View File

@ -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
],
}

View File

@ -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]),
}
};

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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();
})

View File

@ -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);
});
// 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) {
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) {
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};
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};
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};
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};
// 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);
[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);
[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];
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
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];
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<a.byteLength; i++) {
if (aBytes[i] !== bBytes[i]) {
return false;
}
}
return true;
}
return;
}

View File

@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: verify() Using EdDSA with small-order points
// META: script=eddsa_vectors.js
// META: script=eddsa_small_order_points.js
// META: timeout=long
run_test();

View File

@ -0,0 +1,26 @@
function run_test() {
var subtle = self.crypto.subtle; // Change to test prefixed implementations
// When verifying an Ed25519 or Ed448 signature, if the public key or the first half of the signature (R) is
// an invalid or small-order element, return false.
Object.keys(kSmallOrderTestCases).forEach(function (algorithmName) {
var algorithm = {name: algorithmName};
kSmallOrderTestCases[algorithmName].forEach(function(test) {
promise_test(async() => {
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;
}

View File

@ -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,
}
]
};

View File

@ -88,7 +88,7 @@
"path": "wasm/webapi"
},
"WebCryptoAPI": {
"commit": "5e042cbc4ecab7b2279a5fd411c6daa24ca886c6",
"commit": "6748a0a24614b01ce6527493a19ef846738bee3a",
"path": "WebCryptoAPI"
},
"webidl/ecmascript-binding/es-exceptions": {

View File

@ -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.
<a id="status-format"></a>
## 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

View File

@ -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',
]),
],
},
},
};

View File

@ -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"
}
}