summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/WebCryptoAPI/sign_verify
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/WebCryptoAPI/sign_verify')
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.https.any.js6
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js509
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa_vectors.js137
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.https.any.js6
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.js434
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa_vectors.js58
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.https.any.js6
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.js350
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac_vectors.js39
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa.js409
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js6
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js92
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss.https.any.js6
-rw-r--r--testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss_vectors.js147
14 files changed, 2205 insertions, 0 deletions
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.https.any.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.https.any.js
new file mode 100644
index 0000000000..9764cc3354
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.https.any.js
@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: sign() and verify() Using ECDSA
+// META: script=ecdsa_vectors.js
+// META: script=ecdsa.js
+// META: timeout=long
+
+run_test();
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js
new file mode 100644
index 0000000000..6bf662adcc
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js
@@ -0,0 +1,509 @@
+
+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();
+ var invalidTestVectors = getInvalidTestVectors();
+
+ // 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, hash: vector.hashName};
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .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, hash: vector.hashName};
+ promise_test(function(test) {
+ var signature = copyBuffer(vector.signature);
+ var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
+ .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 plaintext is altered after call.
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ var algorithm = {name: vector.algorithmName, hash: vector.hashName};
+ promise_test(function(test) {
+ var plaintext = copyBuffer(vector.plaintext);
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Signature verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ plaintext[0] = 255 - plaintext[0];
+ return operation;
+ }, vector.name + " with altered plaintext after call");
+ }, function(err) {
+ promise_test(function(test) {
+ assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
+ }, "importVectorKeys step: " + vector.name + " with altered plaintext 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, hash: vector.hashName};
+ promise_test(function(test) {
+ return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.plaintext)
+ .then(function(plaintext) {
+ 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, hash: vector.hashName};
+ promise_test(function(test) {
+ return subtle.sign(algorithm, vector.publicKey, vector.plaintext)
+ .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, hash: vector.hashName};
+ promise_test(function(test) {
+ return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .then(function(plaintext) {
+ 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, hash: vector.hashName};
+ promise_test(function(test) {
+ return subtle.sign(algorithm, vector.privateKey, vector.plaintext)
+ .then(function(signature) {
+ // Can we verify the signature?
+ return subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
+ .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, hash: vector.hashName};
+ return importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var operation = subtle.sign(algorithm, wrongKey, vector.plaintext)
+ .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, hash: vector.hashName};
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.plaintext)
+ .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, hash: vector.hashName};
+ var signature = copyBuffer(vector.signature);
+ signature[0] = 255 - signature[0];
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
+ .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 wrong hash
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ var hashName = "SHA-1";
+ if (vector.hashName === "SHA-1") {
+ hashName = "SHA-256"
+ }
+ var algorithm = {name: vector.algorithmName, hash: hashName};
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .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 wrong hash");
+
+ }, 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 wrong hash");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Test verification fails with bad hash name
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ // use the wrong name for the hash
+ var hashName = vector.hashName.substring(0, 3) + vector.hashName.substring(4);
+ var algorithm = {name: vector.algorithmName, hash: hashName};
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_unreached("Verification should throw an error");
+ }, function(err) {
+ assert_equals(err.name, "NotSupportedError", "Correctly throws NotSupportedError for illegal hash name")
+ });
+
+ return operation;
+ }, vector.name + " verification failure due to bad hash 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 + " verification failure due to bad hash name");
+ });
+
+ 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, hash: vector.hashName};
+ var signature = vector.signature.slice(1); // Skip the first byte
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext)
+ .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 plaintext
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ var algorithm = {name: vector.algorithmName, hash: vector.hashName};
+ var plaintext = copyBuffer(vector.plaintext);
+ plaintext[0] = 255 - plaintext[0];
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext)
+ .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 plaintext");
+
+ }, 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 plaintext");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Test invalid signatures
+ invalidTestVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ var algorithm = {name: vector.algorithmName, hash: vector.hashName};
+ promise_test(function(test) {
+ var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_false(is_verified, "Signature unexpectedly 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);
+ });
+
+ promise_test(function() {
+ return Promise.all(all_promises)
+ .then(function() {done();})
+ .catch(function() {done();})
+ }, "setup");
+
+ // 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, namedCurve: vector.namedCurve}, 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, namedCurve: vector.namedCurve}, 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);
+ var copy = new Uint8Array(sourceBuffer.byteLength)
+
+ for (var i=0; i<source.byteLength; i++) {
+ copy[i] = source[i];
+ }
+
+ 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;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa_vectors.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa_vectors.js
new file mode 100644
index 0000000000..2d1fb6d5c9
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa_vectors.js
@@ -0,0 +1,137 @@
+
+// ecdsa_vectors.js
+
+// Data for testing ECDSA with every curve currently in the WebCryptoAPI recommendation.
+
+// The following function returns an array of test vectors
+// for the subtleCrypto encrypt method.
+//
+// Each test vector has the following fields:
+// name - a unique name for this vector
+// publicKeyBuffer - an arrayBuffer with the key data
+// publicKeyFormat - "spki" "jwk"
+// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// privateKeyBuffer - an arrayBuffer with the key data
+// privateKeyFormat - "pkcs8" or "jwk"
+// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// algorithmName - the name of the AlgorithmIdentifier parameter to provide to encrypt
+// namedCurve - the curve used
+// hashName - the hash function to sign with
+// plaintext - the text to encrypt
+// signature - the expected signature
+function getTestVectors() {
+ var pkcs8 = {
+ "P-256": 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, 230, 238, 207, 158, 98, 108, 202, 142, 24, 7, 155, 146, 197, 238, 38, 158, 84, 202, 18, 142, 175, 212, 137, 71, 255, 81, 171, 160, 10, 192, 229, 214, 161, 68, 3, 66, 0, 4, 10, 5, 30, 56, 111, 103, 196, 166, 225, 229, 203, 238, 125, 55, 116, 91, 88, 142, 190, 114, 15, 117, 89, 22, 40, 111, 150, 41, 105, 122, 57, 23, 17, 216, 106, 234, 201, 103, 8, 210, 58, 38, 35, 216, 198, 237, 187, 84, 217, 164, 63, 100, 6, 105, 49, 128, 15, 53, 29, 158, 117, 235, 238, 30]),
+ "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 2, 169, 160, 216, 153, 239, 168, 126, 117, 100, 17, 9, 7, 233, 216, 44, 33, 189, 98, 101, 163, 122, 189, 154, 111, 219, 15, 128, 236, 132, 77, 211, 161, 66, 83, 32, 214, 125, 220, 48, 245, 219, 116, 239, 185, 162, 230, 97, 161, 100, 3, 98, 0, 4, 29, 49, 157, 105, 45, 202, 95, 87, 84, 186, 123, 50, 193, 22, 66, 198, 216, 210, 180, 251, 130, 73, 195, 242, 20, 215, 30, 144, 181, 37, 41, 102, 217, 127, 123, 235, 31, 170, 177, 228, 243, 226, 96, 85, 73, 194, 238, 219, 82, 3, 41, 179, 190, 166, 181, 229, 86, 36, 161, 81, 80, 161, 105, 102, 99, 95, 25, 22, 239, 4, 221, 117, 142, 105, 64, 157, 6, 51, 203, 75, 37, 153, 65, 121, 178, 42, 118, 156, 116, 52, 54, 145, 14, 121, 153, 81]),
+ "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 83, 62, 97, 143, 152, 234, 209, 181, 19, 236, 136, 120, 200, 130, 13, 55, 122, 54, 216, 240, 63, 43, 160, 70, 201, 49, 130, 90, 61, 53, 135, 48, 192, 178, 96, 51, 219, 183, 247, 228, 163, 212, 67, 74, 3, 94, 36, 183, 7, 249, 18, 71, 102, 23, 110, 26, 240, 184, 93, 242, 46, 170, 186, 156, 37, 161, 129, 137, 3, 129, 134, 0, 4, 0, 166, 222, 236, 251, 72, 145, 23, 241, 228, 28, 196, 160, 100, 7, 61, 134, 115, 8, 110, 81, 219, 37, 8, 110, 141, 183, 100, 212, 239, 246, 10, 173, 99, 88, 253, 207, 150, 122, 198, 132, 89, 39, 94, 42, 128, 79, 142, 238, 183, 228, 196, 40, 75, 20, 81, 192, 165, 234, 118, 254, 112, 7, 172, 5, 71, 1, 197, 237, 218, 249, 168, 158, 124, 79, 220, 201, 36, 199, 55, 216, 245, 133, 218, 151, 3, 169, 84, 194, 59, 231, 193, 74, 175, 166, 102, 84, 178, 86, 119, 10, 147, 142, 127, 38, 231, 0, 198, 3, 147, 28, 123, 208, 189, 181, 208, 99, 44, 125, 30, 171, 70, 111, 9, 217, 118, 194, 74, 50, 62, 27, 124])
+ };
+
+ var spki = {
+ "P-256": 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, 10, 5, 30, 56, 111, 103, 196, 166, 225, 229, 203, 238, 125, 55, 116, 91, 88, 142, 190, 114, 15, 117, 89, 22, 40, 111, 150, 41, 105, 122, 57, 23, 17, 216, 106, 234, 201, 103, 8, 210, 58, 38, 35, 216, 198, 237, 187, 84, 217, 164, 63, 100, 6, 105, 49, 128, 15, 53, 29, 158, 117, 235, 238, 30]),
+ "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 29, 49, 157, 105, 45, 202, 95, 87, 84, 186, 123, 50, 193, 22, 66, 198, 216, 210, 180, 251, 130, 73, 195, 242, 20, 215, 30, 144, 181, 37, 41, 102, 217, 127, 123, 235, 31, 170, 177, 228, 243, 226, 96, 85, 73, 194, 238, 219, 82, 3, 41, 179, 190, 166, 181, 229, 86, 36, 161, 81, 80, 161, 105, 102, 99, 95, 25, 22, 239, 4, 221, 117, 142, 105, 64, 157, 6, 51, 203, 75, 37, 153, 65, 121, 178, 42, 118, 156, 116, 52, 54, 145, 14, 121, 153, 81]),
+ "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 166, 222, 236, 251, 72, 145, 23, 241, 228, 28, 196, 160, 100, 7, 61, 134, 115, 8, 110, 81, 219, 37, 8, 110, 141, 183, 100, 212, 239, 246, 10, 173, 99, 88, 253, 207, 150, 122, 198, 132, 89, 39, 94, 42, 128, 79, 142, 238, 183, 228, 196, 40, 75, 20, 81, 192, 165, 234, 118, 254, 112, 7, 172, 5, 71, 1, 197, 237, 218, 249, 168, 158, 124, 79, 220, 201, 36, 199, 55, 216, 245, 133, 218, 151, 3, 169, 84, 194, 59, 231, 193, 74, 175, 166, 102, 84, 178, 86, 119, 10, 147, 142, 127, 38, 231, 0, 198, 3, 147, 28, 123, 208, 189, 181, 208, 99, 44, 125, 30, 171, 70, 111, 9, 217, 118, 194, 74, 50, 62, 27, 124])
+ };
+
+ // plaintext
+ var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
+
+ // For verification tests.
+ var signatures = {
+ "P-256": {
+ "SHA-1": new Uint8Array([172, 224, 125, 170, 52, 83, 158, 179, 85, 149, 130, 217, 59, 201, 0, 251, 237, 196, 51, 243, 218, 231, 211, 136, 157, 249, 219, 16, 140, 178, 145, 16, 177, 104, 68, 179, 88, 49, 219, 184, 212, 202, 109, 248, 110, 64, 202, 129, 7, 173, 226, 88, 194, 69, 164, 158, 120, 120, 128, 3, 115, 14, 181, 197]),
+ "SHA-256": new Uint8Array([83, 223, 63, 226, 42, 29, 106, 105, 225, 145, 197, 180, 118, 154, 109, 110, 66, 67, 47, 251, 53, 190, 203, 65, 207, 36, 19, 57, 49, 122, 124, 118, 59, 74, 222, 134, 42, 235, 180, 229, 134, 24, 205, 81, 171, 156, 100, 218, 127, 242, 126, 53, 27, 77, 249, 101, 157, 132, 244, 30, 67, 30, 64, 12]),
+ "SHA-384": new Uint8Array([235, 111, 173, 249, 151, 252, 218, 129, 123, 117, 136, 26, 162, 115, 247, 110, 169, 145, 95, 189, 228, 98, 32, 82, 34, 94, 154, 197, 47, 83, 124, 137, 215, 71, 222, 247, 135, 22, 221, 238, 77, 247, 223, 194, 42, 158, 175, 224, 76, 182, 56, 138, 97, 196, 238, 109, 42, 102, 13, 71, 1, 43, 56, 92]),
+ "SHA-512": new Uint8Array([74, 201, 175, 173, 69, 107, 160, 142, 203, 41, 225, 5, 73, 146, 6, 40, 93, 130, 129, 35, 156, 171, 190, 161, 12, 10, 234, 123, 7, 5, 112, 97, 57, 183, 15, 52, 94, 215, 79, 255, 175, 222, 66, 234, 253, 180, 62, 161, 7, 11, 249, 37, 118, 185, 13, 102, 67, 84, 101, 189, 73, 132, 110, 206])
+ },
+ "P-384": {
+ "SHA-1": new Uint8Array([101, 254, 7, 14, 195, 234, 195, 82, 80, 208, 11, 158, 230, 219, 77, 45, 173, 213, 243, 187, 185, 196, 149, 200, 103, 29, 42, 13, 43, 153, 20, 159, 178, 79, 136, 175, 7, 78, 11, 144, 50, 104, 179, 208, 237, 95, 14, 20, 104, 87, 150, 178, 143, 227, 75, 45, 142, 220, 223, 16, 132, 91, 36, 207, 121, 179, 54, 39, 216, 189, 44, 129, 98, 28, 181, 30, 3, 12, 33, 164, 58, 187, 10, 135, 64, 250, 194, 111, 133, 34, 230, 131, 195, 103, 172, 150]),
+ "SHA-256": new Uint8Array([75, 194, 223, 234, 59, 205, 164, 251, 180, 253, 146, 123, 3, 15, 155, 128, 177, 245, 210, 173, 155, 183, 170, 6, 41, 56, 105, 87, 113, 32, 178, 177, 208, 239, 17, 204, 217, 254, 208, 113, 74, 171, 54, 190, 246, 57, 40, 247, 132, 245, 60, 126, 9, 223, 147, 233, 179, 229, 176, 200, 131, 207, 114, 9, 81, 180, 254, 35, 130, 199, 132, 46, 220, 252, 212, 93, 149, 106, 114, 210, 154, 64, 48, 160, 56, 169, 0, 230, 247, 221, 133, 122, 86, 80, 211, 232]),
+ "SHA-384": new Uint8Array([13, 217, 194, 199, 240, 182, 244, 217, 50, 130, 84, 169, 2, 232, 115, 116, 179, 192, 146, 25, 94, 107, 226, 26, 161, 166, 220, 216, 235, 166, 15, 123, 11, 56, 196, 0, 109, 250, 33, 70, 212, 233, 253, 35, 220, 51, 97, 121, 151, 64, 23, 73, 58, 31, 79, 116, 238, 207, 228, 85, 190, 61, 169, 237, 153, 100, 29, 129, 97, 13, 254, 180, 104, 182, 7, 218, 148, 29, 87, 20, 231, 181, 26, 238, 44, 69, 170, 14, 156, 77, 160, 33, 178, 55, 0, 144]),
+ "SHA-512": new Uint8Array([114, 251, 219, 54, 159, 211, 76, 28, 84, 38, 77, 7, 244, 250, 205, 105, 176, 46, 66, 6, 248, 168, 187, 37, 155, 136, 42, 48, 92, 86, 253, 226, 211, 81, 7, 228, 147, 197, 60, 214, 180, 175, 11, 49, 48, 111, 77, 3, 253, 67, 207, 199, 98, 161, 3, 14, 23, 163, 215, 117, 69, 58, 18, 18, 177, 66, 159, 123, 61, 147, 6, 106, 95, 66, 161, 11, 19, 140, 209, 119, 220, 9, 97, 110, 130, 125, 89, 136, 34, 215, 141, 70, 39, 183, 84, 230])
+ },
+ "P-521": {
+ "SHA-1": new Uint8Array([1, 120, 26, 23, 166, 14, 67, 18, 105, 96, 253, 57, 110, 18, 16, 145, 108, 33, 21, 202, 68, 40, 217, 104, 56, 156, 75, 70, 193, 85, 54, 116, 206, 147, 123, 142, 33, 112, 12, 230, 9, 50, 174, 15, 87, 92, 161, 135, 221, 89, 119, 32, 219, 131, 158, 177, 242, 12, 126, 51, 148, 120, 117, 89, 220, 213, 0, 32, 126, 87, 13, 245, 199, 228, 173, 159, 192, 165, 247, 32, 101, 233, 206, 28, 158, 61, 18, 202, 94, 109, 217, 244, 79, 225, 40, 86, 27, 117, 244, 34, 108, 79, 173, 242, 61, 131, 83, 108, 198, 105, 234, 64, 152, 227, 115, 182, 203, 145, 156, 139, 92, 252, 5, 5, 166, 125, 150, 178, 118, 164, 106, 61]),
+ "SHA-256": new Uint8Array([1, 116, 219, 167, 123, 20, 215, 63, 102, 245, 113, 103, 134, 163, 229, 168, 215, 201, 49, 68, 94, 109, 50, 10, 146, 41, 217, 97, 216, 161, 179, 239, 209, 26, 94, 163, 60, 121, 73, 90, 197, 153, 187, 182, 138, 100, 26, 132, 157, 88, 216, 62, 248, 84, 204, 38, 95, 166, 201, 23, 223, 246, 238, 67, 90, 103, 1, 179, 213, 82, 125, 172, 32, 251, 10, 112, 51, 195, 254, 121, 116, 78, 172, 239, 123, 63, 252, 39, 182, 77, 200, 99, 248, 111, 66, 152, 44, 178, 34, 146, 69, 254, 157, 228, 138, 165, 158, 182, 83, 212, 73, 112, 134, 217, 17, 165, 189, 39, 14, 149, 197, 30, 126, 152, 247, 165, 134, 63, 199, 251, 6, 92]),
+ "SHA-384": new Uint8Array([1, 247, 125, 177, 229, 19, 120, 225, 23, 197, 184, 190, 200, 160, 63, 150, 87, 210, 68, 197, 78, 131, 121, 8, 191, 113, 1, 37, 95, 65, 81, 82, 93, 158, 137, 207, 127, 84, 99, 27, 51, 104, 145, 157, 56, 36, 255, 159, 127, 120, 254, 129, 35, 154, 26, 159, 222, 43, 122, 131, 233, 92, 166, 160, 202, 17, 1, 185, 139, 29, 164, 237, 0, 236, 118, 147, 103, 233, 149, 139, 128, 71, 212, 127, 146, 171, 139, 255, 150, 241, 51, 11, 249, 72, 201, 34, 9, 1, 27, 140, 219, 180, 150, 212, 100, 219, 185, 22, 114, 14, 183, 2, 189, 173, 146, 140, 153, 185, 128, 183, 101, 4, 224, 173, 28, 18, 180, 168, 87, 49, 199, 12]),
+ "SHA-512": new Uint8Array([0, 178, 202, 175, 103, 152, 81, 154, 157, 54, 219, 250, 254, 120, 107, 47, 186, 28, 194, 172, 185, 149, 147, 193, 119, 179, 110, 58, 28, 238, 183, 2, 39, 90, 226, 60, 252, 202, 10, 173, 120, 246, 182, 222, 230, 180, 113, 139, 149, 208, 209, 167, 21, 170, 51, 120, 71, 14, 80, 181, 22, 193, 142, 15, 51, 5, 1, 240, 7, 30, 106, 50, 134, 127, 167, 15, 105, 92, 211, 156, 78, 135, 225, 66, 185, 228, 19, 77, 56, 116, 11, 214, 254, 227, 84, 165, 117, 22, 126, 19, 82, 78, 148, 131, 38, 55, 145, 15, 225, 30, 83, 168, 95, 178, 27, 145, 173, 184, 27, 177, 119, 156, 78, 43, 139, 200, 124, 113, 125, 195, 80, 132])
+ }
+ }
+
+ var vectors = [];
+ ["P-256", "P-384", "P-521"].forEach(function(curveName) {
+ ["SHA-1", "SHA-256", "SHA-384", "SHA-512"].forEach(function(hashName) {
+ var vector = {
+ name: "ECDSA " + curveName + " with " + hashName,
+ publicKeyBuffer: spki[curveName],
+ publicKeyFormat: "spki",
+ publicKey: null,
+ privateKeyBuffer: pkcs8[curveName],
+ privateKeyFormat: "pkcs8",
+ privateKey: null,
+ algorithmName: "ECDSA",
+ namedCurve: curveName,
+ hashName: hashName,
+ plaintext: plaintext,
+ signature: signatures[curveName][hashName]
+ };
+
+ vectors.push(vector);
+ })
+ });
+
+ return vectors;
+}
+
+// Additional test vectors, using the same format as getTestVectors, but the
+// signatures are invalid.
+function getInvalidTestVectors() {
+ var vectors = [
+ {
+ name: "The signature was truncated by 1 byte",
+ publicKeyBuffer: 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, 156, 176, 207, 105, 48, 61, 175, 199, 97, 212, 228, 104, 123, 78, 207, 3, 158, 109, 52, 171, 150, 74, 248, 8, 16, 216, 213, 88, 164, 168, 214, 247, 45, 81, 35, 58, 23, 136, 146, 10, 134, 238, 8, 161, 150, 44, 121, 239, 163, 23, 251, 120, 121, 226, 151, 218, 210, 20, 109, 185, 149, 250, 28, 120]),
+ publicKeyFormat: "spki",
+ publicKey: null,
+ algorithmName: "ECDSA",
+ namedCurve: "P-256",
+ hashName: "SHA-512",
+ plaintext: new Uint8Array([110, 41, 50, 21, 51, 1, 164, 238, 246, 128, 230, 66, 137, 41, 173, 174, 152, 140, 16, 141, 102, 138, 49, 255, 85, 208, 72, 153, 71, 215, 95, 248, 26, 70, 191, 137, 232, 77, 100, 1, 240, 35, 190, 110, 135, 104, 143, 188, 215, 132, 215, 133, 202, 132, 103, 53, 82, 74, 203, 82, 208, 4, 82, 200, 64, 64, 164, 121, 231, 204, 51, 9, 54, 68, 29, 147, 187, 231, 34, 169, 67, 42, 110, 29, 177, 18, 181, 201, 64, 59, 16, 39, 44, 177, 52, 127, 214, 25, 212, 99, 247, 169, 210, 35, 173, 118, 253, 224, 109, 138, 104, 131, 80, 15, 184, 67, 35, 90, 191, 249, 142, 36, 27, 223, 181, 83, 140, 62]),
+ signature: new Uint8Array([75, 159, 145, 228, 40, 82, 135, 38, 26, 29, 28, 146, 60, 246, 25, 205, 82, 193, 117, 207, 231, 241, 190, 96, 165, 37, 140, 97, 3, 72, 186, 61, 40, 196, 95, 144, 29, 113, 196, 27, 41, 134, 56, 236, 13, 106, 133, 215, 252, 176, 195, 59, 191, 236, 90, 156, 129, 8, 70, 182, 57, 40, 154]),
+ },
+ {
+ name: "The signature was made using SHA-512, however verification is being done using SHA-1.",
+ publicKeyBuffer: 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, 156, 176, 207, 105, 48, 61, 175, 199, 97, 212, 228, 104, 123, 78, 207, 3, 158, 109, 52, 171, 150, 74, 248, 8, 16, 216, 213, 88, 164, 168, 214, 247, 45, 81, 35, 58, 23, 136, 146, 10, 134, 238, 8, 161, 150, 44, 121, 239, 163, 23, 251, 120, 121, 226, 151, 218, 210, 20, 109, 185, 149, 250, 28, 120]),
+ publicKeyFormat: "spki",
+ publicKey: null,
+ algorithmName: "ECDSA",
+ namedCurve: "P-256",
+ hashName: "SHA-1",
+ plaintext: new Uint8Array([110, 41, 50, 21, 51, 1, 164, 238, 246, 128, 230, 66, 137, 41, 173, 174, 152, 140, 16, 141, 102, 138, 49, 255, 85, 208, 72, 153, 71, 215, 95, 248, 26, 70, 191, 137, 232, 77, 100, 1, 240, 35, 190, 110, 135, 104, 143, 188, 215, 132, 215, 133, 202, 132, 103, 53, 82, 74, 203, 82, 208, 4, 82, 200, 64, 64, 164, 121, 231, 204, 51, 9, 54, 68, 29, 147, 187, 231, 34, 169, 67, 42, 110, 29, 177, 18, 181, 201, 64, 59, 16, 39, 44, 177, 52, 127, 214, 25, 212, 99, 247, 169, 210, 35, 173, 118, 253, 224, 109, 138, 104, 131, 80, 15, 184, 67, 35, 90, 191, 249, 142, 36, 27, 223, 181, 83, 140, 62]),
+ signature: new Uint8Array([75, 159, 145, 228, 40, 82, 135, 38, 26, 29, 28, 146, 60, 246, 25, 205, 82, 193, 117, 207, 231, 241, 190, 96, 165, 37, 140, 97, 3, 72, 186, 61, 40, 196, 95, 144, 29, 113, 196, 27, 41, 134, 56, 236, 13, 106, 133, 215, 252, 176, 195, 59, 191, 236, 90, 156, 129, 8, 70, 182, 57, 40, 154, 132]),
+ },
+ {
+ name: "Excess padding",
+ publicKeyBuffer: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 8, 116, 162, 224, 184, 255, 68, 143, 14, 84, 50, 30, 39, 244, 241, 230, 77, 6, 76, 222, 183, 210, 111, 69, 140, 50, 233, 48, 18, 15, 78, 87, 220, 133, 194, 105, 63, 151, 126, 237, 74, 142, 204, 141, 185, 129, 180, 217, 31, 105, 68, 109, 244, 244, 198, 245, 222, 25, 0, 63, 69, 248, 145, 208, 235, 205, 47, 255, 219, 92, 129, 192, 64, 232, 214, 153, 76, 67, 199, 254, 237, 185, 138, 74, 49, 237, 251, 53, 232, 154, 48, 1, 60, 59, 146, 103]),
+ publicKeyFormat: "spki",
+ publicKey: null,
+ algorithmName: "ECDSA",
+ namedCurve: "P-384",
+ hashName: "SHA-1",
+ plaintext: new Uint8Array([63, 7, 131, 165, 142, 102, 243, 210, 192, 204, 251, 95, 172, 63, 9, 219, 111, 134, 9, 208, 89, 43, 199, 127, 223, 254, 217, 207, 14, 19, 125, 38, 168, 103, 5, 118, 101, 243, 173, 129, 190, 235, 187, 219, 114, 61, 90, 71, 197, 128, 130, 143, 16, 247, 52, 122, 184, 169, 194, 77, 25, 95, 115, 109, 250, 230, 234, 227, 125, 136, 254, 59, 71, 53, 231, 198, 105, 168, 10, 193, 145, 62, 92, 36, 200, 193, 213, 205, 177, 95, 153, 79, 62, 194, 241, 199, 116, 117, 46, 20, 245, 150, 179, 140, 47, 191, 3, 118, 22, 214, 8, 36, 77, 61, 167, 212, 186, 223, 53, 19, 48, 249, 71, 224, 76, 195, 80, 231]),
+ // Each of r and s in this input is padded up to one extra byte.
+ signature: new Uint8Array([0, 141, 157, 62, 61, 11, 43, 40, 113, 234, 47, 3, 242, 123, 168, 105, 159, 33, 75, 232, 216, 117, 192, 215, 112, 176, 255, 241, 196, 206, 52, 31, 12, 131, 74, 193, 31, 158, 193, 43, 253, 184, 50, 11, 23, 36, 200, 194, 32, 0, 98, 21, 13, 251, 168, 230, 92, 12, 123, 231, 239, 129, 200, 114, 65, 210, 195, 122, 131, 194, 126, 179, 28, 204, 43, 60, 57, 87, 103, 10, 116, 76, 129, 190, 109, 116, 19, 64, 181, 24, 156, 192, 197, 71, 223, 129, 176, 210]),
+ },
+ {
+ name: "Empty signature",
+ publicKeyBuffer: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 8, 116, 162, 224, 184, 255, 68, 143, 14, 84, 50, 30, 39, 244, 241, 230, 77, 6, 76, 222, 183, 210, 111, 69, 140, 50, 233, 48, 18, 15, 78, 87, 220, 133, 194, 105, 63, 151, 126, 237, 74, 142, 204, 141, 185, 129, 180, 217, 31, 105, 68, 109, 244, 244, 198, 245, 222, 25, 0, 63, 69, 248, 145, 208, 235, 205, 47, 255, 219, 92, 129, 192, 64, 232, 214, 153, 76, 67, 199, 254, 237, 185, 138, 74, 49, 237, 251, 53, 232, 154, 48, 1, 60, 59, 146, 103]),
+ publicKeyFormat: "spki",
+ publicKey: null,
+ algorithmName: "ECDSA",
+ namedCurve: "P-384",
+ hashName: "SHA-1",
+ plaintext: new Uint8Array([63, 7, 131, 165, 142, 102, 243, 210, 192, 204, 251, 95, 172, 63, 9, 219, 111, 134, 9, 208, 89, 43, 199, 127, 223, 254, 217, 207, 14, 19, 125, 38, 168, 103, 5, 118, 101, 243, 173, 129, 190, 235, 187, 219, 114, 61, 90, 71, 197, 128, 130, 143, 16, 247, 52, 122, 184, 169, 194, 77, 25, 95, 115, 109, 250, 230, 234, 227, 125, 136, 254, 59, 71, 53, 231, 198, 105, 168, 10, 193, 145, 62, 92, 36, 200, 193, 213, 205, 177, 95, 153, 79, 62, 194, 241, 199, 116, 117, 46, 20, 245, 150, 179, 140, 47, 191, 3, 118, 22, 214, 8, 36, 77, 61, 167, 212, 186, 223, 53, 19, 48, 249, 71, 224, 76, 195, 80, 231]),
+ signature: new Uint8Array([]),
+ },
+ ];
+
+ return vectors;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.https.any.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.https.any.js
new file mode 100644
index 0000000000..85993a48b9
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.https.any.js
@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: sign() and verify() Using EdDSA
+// META: script=eddsa_vectors.js
+// META: script=eddsa.js
+// META: timeout=long
+
+run_test();
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.js
new file mode 100644
index 0000000000..d425fec2dc
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa.js
@@ -0,0 +1,434 @@
+
+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) {
+ // 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};
+ promise_test(async() => {
+ let key = await subtle.generateKey(algorithm, false, ["sign", "verify"]);
+ let signature = await subtle.sign(algorithm, key.privateKey, vector.data);
+ let isVerified = await subtle.verify(algorithm, key.publicKey, signature, vector.data);
+ assert_true(isVerified, "Verificaton failed.");
+ }, "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);
+ var copy = new Uint8Array(sourceBuffer.byteLength)
+
+ for (var i=0; i<source.byteLength; i++) {
+ copy[i] = source[i];
+ }
+
+ 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;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa_vectors.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa_vectors.js
new file mode 100644
index 0000000000..96ec2b01af
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/eddsa_vectors.js
@@ -0,0 +1,58 @@
+// eddsa_vectors.js
+
+// Data for testing Ed25519 and Ed448.
+
+// The following function returns an array of test vectors
+// for the subtleCrypto sign method.
+//
+// Each test vector has the following fields:
+// name - a unique name for this vector
+// publicKeyBuffer - an arrayBuffer with the key data
+// publicKeyFormat - "spki" "jwk"
+// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// privateKeyBuffer - an arrayBuffer with the key data
+// privateKeyFormat - "pkcs8" or "jwk"
+// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// algorithmName - the name of the AlgorithmIdentifier parameter to provide to sign
+// data - the text to sign
+// signature - the expected signature
+function getTestVectors() {
+ var pkcs8 = {
+ "Ed25519": new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 243, 200, 244, 196, 141, 248, 120, 20, 110, 140, 211, 191, 109, 244, 229, 14, 56, 155, 167, 7, 78, 21, 194, 53, 45, 205, 93, 48, 141, 76, 168, 31]),
+ "Ed448": new Uint8Array([48, 71, 2, 1, 0, 48, 5, 6, 3, 43, 101, 113, 4, 59, 4, 57, 14, 255, 3, 69, 140, 40, 224, 23, 156, 82, 29, 227, 18, 201, 105, 183, 131, 67, 72, 236, 171, 153, 26, 96, 227, 178, 233, 167, 158, 76, 217, 228, 128, 239, 41, 23, 18, 210, 200, 61, 4, 114, 114, 213, 201, 244, 40, 102, 79, 105, 109, 38, 112, 69, 143, 29, 46]),
+ };
+
+ var spki = {
+ "Ed25519": new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 216, 225, 137, 99, 216, 9, 212, 135, 217, 84, 154, 204, 174, 198, 116, 46, 126, 235, 162, 77, 138, 13, 59, 20, 183, 227, 202, 234, 6, 137, 61, 204]),
+ "Ed448": new Uint8Array([48, 67, 48, 5, 6, 3, 43, 101, 113, 3, 58, 0, 171, 75, 184, 133, 253, 125, 44, 90, 242, 78, 131, 113, 12, 255, 160, 199, 74, 87, 226, 116, 128, 29, 178, 5, 123, 11, 220, 94, 160, 50, 182, 254, 107, 199, 139, 128, 69, 54, 90, 235, 38, 232, 110, 31, 20, 253, 52, 157, 7, 196, 132, 149, 245, 164, 106, 90, 128]),
+ };
+
+ // data
+ var data = new Uint8Array([43, 126, 208, 188, 119, 149, 105, 74, 180, 172, 211, 89, 3, 254, 140, 215, 216, 15, 106, 28, 134, 136, 166, 195, 65, 68, 9, 69, 117, 20, 161, 69, 120, 85, 187, 178, 25, 227, 10, 27, 238, 168, 254, 134, 144, 130, 217, 159, 200, 40, 47, 144, 80, 208, 36, 229, 158, 175, 7, 48, 186, 157, 183, 10]);
+
+ // For verification tests.
+ var signatures = {
+ "Ed25519": new Uint8Array([61, 144, 222, 94, 87, 67, 223, 194, 130, 37, 191, 173, 179, 65, 177, 22, 203, 248, 163, 241, 206, 237, 191, 74, 220, 53, 14, 245, 211, 71, 24, 67, 164, 24, 97, 77, 203, 110, 97, 72, 98, 97, 76, 247, 175, 20, 150, 249, 52, 11, 60, 132, 78, 164, 220, 234, 177, 211, 209, 85, 235, 126, 204, 0]),
+ "Ed448": new Uint8Array([118, 137, 126, 140, 80, 172, 107, 17, 50, 115, 92, 9, 197, 95, 80, 108, 1, 73, 210, 103, 124, 117, 102, 79, 139, 193, 11, 130, 111, 189, 157, 240, 160, 60, 217, 134, 188, 232, 51, 158, 100, 199, 209, 114, 14, 169, 54, 23, 132, 220, 115, 131, 119, 101, 172, 41, 128, 192, 218, 192, 129, 74, 139, 193, 135, 209, 201, 201, 7, 197, 220, 192, 121, 86, 248, 91, 112, 147, 15, 228, 45, 231, 100, 23, 114, 23, 203, 45, 82, 186, 183, 193, 222, 190, 12, 168, 156, 206, 203, 205, 99, 247, 2, 90, 42, 90, 87, 43, 157, 35, 176, 100, 47, 0]),
+ }
+
+ var vectors = [];
+ ["Ed25519", "Ed448"].forEach(function(algorithmName) {
+ var vector = {
+ name: "EdDSA " + algorithmName,
+ publicKeyBuffer: spki[algorithmName],
+ publicKeyFormat: "spki",
+ publicKey: null,
+ privateKeyBuffer: pkcs8[algorithmName],
+ privateKeyFormat: "pkcs8",
+ privateKey: null,
+ algorithmName: algorithmName,
+ data: data,
+ signature: signatures[algorithmName]
+ };
+
+ vectors.push(vector);
+ });
+
+ return vectors;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.https.any.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.https.any.js
new file mode 100644
index 0000000000..419bab0506
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.https.any.js
@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: sign() and verify() Using HMAC
+// META: script=hmac_vectors.js
+// META: script=hmac.js
+// META: timeout=long
+
+run_test();
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.js
new file mode 100644
index 0000000000..8df4b042f5
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.js
@@ -0,0 +1,350 @@
+
+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 hmac_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(vector) {
+ promise_test(function(test) {
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext)
+ .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(vector) {
+ promise_test(function(test) {
+ var signature = copyBuffer(vector.signature);
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Signature is not 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 plaintext is altered after call.
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vector) {
+ promise_test(function(test) {
+ var plaintext = copyBuffer(vector.plaintext);
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Signature verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ plaintext[0] = 255 - plaintext[0];
+ return operation;
+ }, vector.name + " with altered plaintext after call");
+ }, function(err) {
+ promise_test(function(test) {
+ assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
+ }, "importVectorKeys step: " + vector.name + " with altered plaintext");
+ });
+
+ 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(vector) {
+ promise_test(function(test) {
+ return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, vector.plaintext)
+ .then(function(plaintext) {
+ 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) {
+ promise_test(function(test) {
+ return subtle.sign({name: "HMAC", hash: vector.hash}, vector.key, vector.plaintext)
+ .then(function(signature) {
+ // Can we get the verify the new signature?
+ return subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Round trip verifies");
+ return signature;
+ }, function(err) {
+ assert_unreached("verify 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: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"])
+ .then(function(wrongKey) {
+ return importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var operation = subtle.sign({name: "HMAC", hash: vector.hash}, wrongKey.privateKey, vector.plaintext)
+ .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: "ECDSA", namedCurve: "P-256", hash: "SHA-256"}, false, ["sign", "verify"])
+ .then(function(wrongKey) {
+ return importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vector) {
+ promise_test(function(test) {
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, wrongKey.publicKey, vector.signature, vector.plaintext)
+ .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);
+ });
+
+ // Verification should fail if the plaintext is changed
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vector) {
+ var plaintext = copyBuffer(vector.plaintext);
+ plaintext[0] = 255 - plaintext[0];
+ promise_test(function(test) {
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, vector.signature, plaintext)
+ .then(function(is_verified) {
+ assert_false(is_verified, "Signature is NOT verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ return operation;
+ }, vector.name + " verification failure due to wrong plaintext");
+
+ }, 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 wrong plaintext");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Verification should fail if the signature is changed
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vector) {
+ var signature = copyBuffer(vector.signature);
+ signature[0] = 255 - signature[0];
+ promise_test(function(test) {
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_false(is_verified, "Signature is NOT verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ return operation;
+ }, vector.name + " verification failure due to wrong 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 wrong signature");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Verification should fail if the signature is wrong length
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify", "sign"])
+ .then(function(vector) {
+ var signature = vector.signature.slice(1); // Drop first byte
+ promise_test(function(test) {
+ var operation = subtle.verify({name: "HMAC", hash: vector.hash}, vector.key, signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_false(is_verified, "Signature is NOT verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ return operation;
+ }, vector.name + " verification failure due to short 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 short signature");
+ });
+
+ all_promises.push(promise);
+ });
+
+
+
+ promise_test(function() {
+ return Promise.all(all_promises)
+ .then(function() {done();})
+ .catch(function() {done();})
+ }, "setup");
+
+ // 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, keyUsages) {
+ if (vector.key !== null) {
+ return new Promise(function(resolve, reject) {
+ resolve(vector);
+ });
+ } else {
+ return subtle.importKey("raw", vector.keyBuffer, {name: "HMAC", hash: vector.hash}, false, keyUsages)
+ .then(function(key) {
+ vector.key = key;
+ return vector;
+ });
+ }
+ }
+
+ // Returns a copy of the sourceBuffer it is sent.
+ function copyBuffer(sourceBuffer) {
+ var source = new Uint8Array(sourceBuffer);
+ var copy = new Uint8Array(sourceBuffer.byteLength)
+
+ for (var i=0; i<source.byteLength; i++) {
+ copy[i] = source[i];
+ }
+
+ 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;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac_vectors.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac_vectors.js
new file mode 100644
index 0000000000..de9642b181
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac_vectors.js
@@ -0,0 +1,39 @@
+
+function getTestVectors() {
+ var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
+
+ var raw = {
+ "SHA-1": new Uint8Array([71, 162, 7, 70, 209, 113, 121, 219, 101, 224, 167, 157, 237, 255, 199, 253, 241, 129, 8, 27]),
+ "SHA-256": new Uint8Array([229, 136, 236, 8, 17, 70, 61, 118, 114, 65, 223, 16, 116, 180, 122, 228, 7, 27, 81, 242, 206, 54, 83, 123, 166, 156, 205, 195, 253, 194, 183, 168]),
+ "SHA-384": new Uint8Array([107, 29, 162, 142, 171, 31, 88, 42, 217, 113, 142, 255, 224, 94, 35, 213, 253, 44, 152, 119, 162, 217, 68, 63, 144, 190, 192, 147, 190, 206, 46, 167, 210, 53, 76, 208, 189, 197, 225, 71, 210, 233, 0, 147, 115, 73, 68, 136]),
+ "SHA-512": new Uint8Array([93, 204, 53, 148, 67, 170, 246, 82, 250, 19, 117, 214, 179, 230, 31, 220, 242, 155, 180, 162, 139, 213, 211, 220, 250, 64, 248, 47, 144, 107, 178, 128, 4, 85, 219, 3, 181, 211, 31, 185, 114, 161, 90, 109, 1, 3, 162, 78, 86, 209, 86, 161, 25, 192, 229, 161, 233, 42, 68, 195, 197, 101, 124, 249])
+ };
+
+ var signatures = {
+ "SHA-1": new Uint8Array([5, 51, 144, 42, 153, 248, 82, 78, 229, 10, 240, 29, 56, 222, 220, 225, 51, 217, 140, 160]),
+ "SHA-256": new Uint8Array([133, 164, 12, 234, 46, 7, 140, 40, 39, 163, 149, 63, 251, 102, 194, 123, 41, 26, 71, 43, 13, 112, 160, 0, 11, 69, 216, 35, 128, 62, 235, 84]),
+ "SHA-384": new Uint8Array([33, 124, 61, 80, 240, 186, 154, 109, 110, 174, 30, 253, 215, 165, 24, 254, 46, 56, 128, 181, 130, 164, 13, 6, 30, 144, 153, 193, 224, 38, 239, 88, 130, 84, 139, 93, 92, 236, 221, 85, 152, 217, 155, 107, 111, 48, 87, 255]),
+ "SHA-512": new Uint8Array([97, 251, 39, 140, 63, 251, 12, 206, 43, 241, 207, 114, 61, 223, 216, 239, 31, 147, 28, 12, 97, 140, 37, 144, 115, 36, 96, 89, 57, 227, 249, 162, 198, 244, 175, 105, 11, 218, 52, 7, 220, 47, 87, 112, 246, 160, 164, 75, 149, 77, 100, 163, 50, 227, 238, 8, 33, 171, 248, 43, 127, 62, 153, 193])
+ };
+
+ // Each test vector has the following fields:
+ // name - a unique name for this vector
+ // keyBuffer - an arrayBuffer with the key data
+ // key - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+ // hashName - the hash function to sign with
+ // plaintext - the text to encrypt
+ // signature - the expected signature
+ var vectors = [];
+ Object.keys(raw).forEach(function(hashName) {
+ vectors.push({
+ name: "HMAC with " + hashName,
+ hash: hashName,
+ keyBuffer: raw[hashName],
+ key: null,
+ plaintext: plaintext,
+ signature: signatures[hashName]
+ });
+ });
+
+ return vectors;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa.js
new file mode 100644
index 0000000000..3eb79fb013
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa.js
@@ -0,0 +1,409 @@
+
+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) {
+ promise_test(function(test) {
+ var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .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) {
+ promise_test(function(test) {
+ var signature = copyBuffer(vector.signature);
+ var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
+ .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 plaintext is altered after call.
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var plaintext = copyBuffer(vector.plaintext);
+ var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Signature verified");
+ }, function(err) {
+ assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
+ });
+
+ plaintext[0] = 255 - plaintext[0];
+ return operation;
+ }, vector.name + " with altered plaintext after call");
+ }, function(err) {
+ promise_test(function(test) {
+ assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
+ }, "importVectorKeys step: " + vector.name + " with altered plaintext 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) {
+ promise_test(function(test) {
+ return subtle.verify(vector.algorithm, vector.privateKey, vector.signature, vector.plaintext)
+ .then(function(plaintext) {
+ 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) {
+ promise_test(function(test) {
+ return subtle.sign(vector.algorithm, vector.publicKey, vector.plaintext)
+ .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) {
+ promise_test(function(test) {
+ return subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext)
+ .then(function(plaintext) {
+ 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) {
+ // RSA signing is deterministic with PKCS#1 v1.5, or PSS with zero-length salts.
+ const isDeterministic = !("saltLength" in vector.algorithm) || vector.algorithm.saltLength == 0;
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext)
+ .then(function(signature) {
+ if (isDeterministic) {
+ // If deterministic, we can check the output matches. Otherwise, we can only check it verifies.
+ assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output");
+ }
+ // Can we verify the new signature?
+ return subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_true(is_verified, "Round trip verifies");
+ return signature;
+ }, function(err) {
+ assert_unreached("verify error for test " + vector.name + ": " + err.message + "'");
+ });
+ })
+ .then(function(priorSignature) {
+ // Will a second signing give us different signature? It should for PSS with non-empty salt
+ return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext)
+ .then(function(signature) {
+ if (isDeterministic) {
+ assert_true(equalBuffers(priorSignature, signature), "Two signings with empty salt give same signature")
+ } else {
+ assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures")
+ }
+ }, function(err) {
+ assert_unreached("second time 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 alteredVector = Object.assign({}, vector);
+ alteredVector.algorithm = Object.assign({}, vector.algorithm);
+ if (vector.algorithm.name === "RSA-PSS") {
+ alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5";
+ } else {
+ alteredVector.algorithm.name = "RSA-PSS";
+ }
+
+ var promise = importVectorKeys(alteredVector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var operation = subtle.sign(vector.algorithm, alteredVector.privateKey, vector.plaintext)
+ .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");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Test verification with the wrong algorithm
+ testVectors.forEach(function(vector) {
+ // Want to get the key for the wrong algorithm
+ var alteredVector = Object.assign({}, vector);
+ alteredVector.algorithm = Object.assign({}, vector.algorithm);
+ if (vector.algorithm.name === "RSA-PSS") {
+ alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5";
+ } else {
+ alteredVector.algorithm.name = "RSA-PSS";
+ }
+
+ var promise = importVectorKeys(alteredVector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ // Some tests are sign only
+ if (!("signature" in vector)) {
+ return;
+ }
+ promise_test(function(test) {
+ var operation = subtle.verify(vector.algorithm, alteredVector.publicKey, vector.signature, vector.plaintext)
+ .then(function(is_verified) {
+ assert_unreached("Verification 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 + " verification 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 + " verification with wrong algorithm name");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Verification should fail with wrong signature
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var signature = copyBuffer(vector.signature);
+ signature[0] = 255 - signature[0];
+ var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)
+ .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 with 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 with altered signature");
+ });
+
+ all_promises.push(promise);
+ });
+
+ // Verification should fail with wrong plaintext
+ testVectors.forEach(function(vector) {
+ var promise = importVectorKeys(vector, ["verify"], ["sign"])
+ .then(function(vectors) {
+ promise_test(function(test) {
+ var plaintext = copyBuffer(vector.plaintext);
+ plaintext[0] = 255 - plaintext[0];
+ var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)
+ .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 with altered plaintext");
+
+ }, 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 with altered plaintext");
+ });
+
+ all_promises.push(promise);
+ });
+
+
+ promise_test(function() {
+ return Promise.all(all_promises)
+ .then(function() {done();})
+ .catch(function() {done();})
+ }, "setup");
+
+ // 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.algorithm.name, hash: vector.hash}, 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.algorithm.name, hash: vector.hash}, 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);
+ var copy = new Uint8Array(sourceBuffer.byteLength)
+
+ for (var i=0; i<source.byteLength; i++) {
+ copy[i] = source[i];
+ }
+
+ 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;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js
new file mode 100644
index 0000000000..d930a715ac
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js
@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: sign() and verify() Using RSASSA-PKCS1-v1_5
+// META: script=rsa_pkcs_vectors.js
+// META: script=rsa.js
+// META: timeout=long
+
+run_test();
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js
new file mode 100644
index 0000000000..71e5d8571b
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js
@@ -0,0 +1,92 @@
+
+// rsa_pkcs_vectors.js
+
+// Data for testing RSASSA-PKCS1-v1_5 with a 2048-bit modulus and 65537 public exponent.
+
+// The following function returns an array of test vectors
+// for the subtleCrypto encrypt method.
+//
+// Each test vector has the following fields:
+// name - a unique name for this vector
+// publicKeyBuffer - an arrayBuffer with the key data
+// publicKeyFormat - "spki" "jwk"
+// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// privateKeyBuffer - an arrayBuffer with the key data
+// privateKeyFormat - "pkcs8" or "jwk"
+// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt
+// plaintext - the text to encrypt
+// signature - the expected signature
+function getTestVectors() {
+ var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]);
+ var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]);
+
+ // plaintext
+ var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
+
+ // For verification tests.
+ var signatures = {
+ "sha-1": new Uint8Array([83, 46, 47, 27, 105, 204, 46, 232, 71, 46, 242, 143, 127, 54, 168, 26, 36, 205, 228, 238, 131, 133, 138, 125, 23, 5, 74, 195, 96, 44, 152, 221, 67, 46, 59, 54, 144, 68, 9, 53, 7, 43, 183, 192, 49, 230, 128, 112, 29, 25, 185, 124, 181, 81, 13, 134, 201, 190, 219, 231, 209, 192, 104, 57, 206, 237, 138, 59, 106, 201, 86, 65, 49, 196, 81, 43, 187, 171, 222, 35, 123, 77, 170, 41, 250, 13, 60, 151, 72, 123, 72, 168, 254, 233, 214, 59, 80, 86, 157, 198, 183, 209, 8, 80, 200, 50, 5, 89, 52, 59, 133, 55, 182, 18, 20, 167, 228, 84, 58, 113, 77, 101, 226, 28, 78, 71, 130, 148, 235, 66, 70, 206, 166, 104, 227, 81, 252, 224, 180, 225, 24, 199, 88, 190, 79, 220, 70, 199, 179, 34, 107, 191, 64, 181, 179, 149, 13, 98, 184, 189, 170, 79, 107, 183, 106, 48, 34, 43, 163, 39, 52, 237, 93, 244, 172, 141, 79, 255, 167, 85, 113, 5, 8, 122, 106, 207, 186, 91, 72, 81, 97, 99, 187, 145, 104, 100, 232, 44, 184, 97, 235, 145, 13, 207, 111, 26, 219, 173, 83, 153, 175, 212, 151, 251, 122, 251, 127, 117, 218, 131, 200, 5, 146, 234, 26, 222, 62, 56, 3, 180, 187, 104, 49, 185, 51, 41, 124, 15, 204, 195, 105, 55, 228, 96, 24, 121, 127, 202, 133, 148, 125, 41, 198, 162, 122, 129]),
+ "sha-256": new Uint8Array([19, 48, 106, 186, 37, 29, 238, 82, 100, 89, 194, 131, 82, 164, 41, 205, 216, 85, 84, 199, 228, 166, 121, 10, 44, 110, 68, 180, 94, 187, 196, 160, 10, 10, 85, 36, 77, 98, 166, 13, 223, 14, 215, 212, 45, 119, 20, 241, 47, 120, 58, 198, 112, 157, 14, 39, 2, 219, 38, 146, 174, 170, 204, 90, 92, 219, 190, 193, 115, 25, 140, 170, 176, 209, 79, 232, 133, 208, 168, 218, 31, 22, 106, 150, 92, 158, 37, 212, 132, 112, 180, 136, 77, 92, 146, 164, 216, 68, 23, 68, 5, 86, 143, 74, 192, 52, 13, 246, 196, 16, 252, 68, 207, 126, 230, 213, 155, 166, 52, 249, 198, 36, 12, 150, 181, 154, 6, 252, 238, 255, 77, 210, 150, 34, 231, 249, 131, 174, 191, 0, 236, 242, 65, 241, 201, 18, 207, 213, 220, 110, 238, 185, 79, 157, 145, 97, 19, 232, 67, 169, 133, 85, 194, 66, 87, 248, 195, 237, 171, 31, 39, 131, 159, 140, 201, 169, 99, 232, 184, 84, 101, 165, 110, 193, 216, 118, 34, 90, 224, 1, 251, 212, 36, 71, 1, 226, 228, 125, 129, 181, 87, 132, 126, 56, 39, 227, 59, 54, 243, 245, 232, 254, 223, 164, 154, 13, 52, 208, 29, 189, 175, 132, 250, 92, 117, 47, 2, 2, 168, 202, 178, 196, 204, 44, 181, 7, 111, 101, 55, 217, 194, 45, 53, 55, 56, 233, 179, 156, 151, 2, 107, 5, 156, 233, 93, 137]),
+ "sha-384": new Uint8Array([53, 79, 205, 28, 98, 226, 54, 45, 78, 139, 206, 223, 81, 80, 247, 178, 123, 236, 51, 171, 50, 162, 121, 117, 52, 90, 76, 140, 254, 178, 52, 102, 155, 196, 171, 175, 129, 231, 25, 221, 244, 193, 175, 174, 69, 67, 44, 183, 174, 185, 19, 60, 189, 135, 141, 231, 102, 232, 114, 98, 129, 120, 163, 58, 194, 10, 2, 138, 125, 140, 43, 100, 26, 92, 82, 59, 22, 187, 230, 94, 178, 11, 171, 51, 28, 152, 58, 150, 27, 174, 109, 230, 78, 107, 144, 119, 170, 137, 200, 70, 184, 214, 157, 207, 113, 1, 71, 141, 16, 117, 26, 59, 135, 178, 165, 222, 44, 166, 206, 113, 160, 191, 237, 127, 88, 122, 33, 110, 5, 58, 30, 83, 196, 162, 172, 233, 60, 38, 27, 68, 15, 236, 212, 51, 13, 215, 203, 215, 146, 184, 57, 133, 2, 178, 162, 8, 69, 164, 194, 145, 141, 135, 42, 172, 245, 11, 48, 39, 19, 87, 1, 154, 88, 174, 24, 129, 158, 117, 196, 142, 158, 248, 8, 16, 134, 15, 160, 73, 100, 119, 108, 160, 75, 32, 3, 41, 103, 77, 202, 83, 32, 180, 0, 245, 23, 134, 78, 113, 224, 135, 182, 139, 129, 223, 97, 62, 226, 75, 172, 52, 220, 242, 230, 69, 149, 225, 44, 121, 144, 112, 243, 247, 25, 217, 61, 120, 67, 182, 149, 146, 52, 108, 252, 32, 198, 187, 249, 49, 7, 242, 121, 214, 32, 126, 198, 87]),
+ "sha-512": new Uint8Array([98, 41, 183, 8, 151, 248, 98, 11, 99, 84, 135, 205, 74, 169, 150, 38, 152, 49, 255, 41, 49, 210, 135, 20, 240, 30, 88, 177, 101, 241, 8, 44, 49, 152, 184, 244, 81, 120, 140, 253, 62, 213, 154, 120, 248, 52, 209, 28, 226, 133, 209, 5, 28, 66, 165, 206, 160, 34, 127, 222, 254, 41, 52, 68, 194, 81, 142, 190, 92, 176, 5, 91, 234, 75, 88, 6, 240, 235, 161, 182, 101, 2, 42, 99, 190, 68, 192, 136, 254, 154, 210, 99, 37, 215, 159, 124, 65, 237, 151, 249, 9, 205, 76, 162, 131, 40, 228, 196, 169, 222, 141, 166, 124, 53, 220, 28, 133, 183, 30, 214, 255, 170, 249, 157, 116, 178, 184, 142, 159, 95, 5, 167, 50, 246, 104, 140, 153, 59, 88, 160, 237, 53, 232, 240, 161, 6, 212, 232, 177, 179, 96, 227, 52, 65, 92, 116, 46, 148, 103, 88, 35, 219, 15, 210, 94, 34, 207, 247, 166, 51, 92, 112, 225, 147, 35, 93, 205, 164, 138, 221, 104, 88, 98, 107, 217, 99, 17, 230, 15, 126, 94, 164, 73, 27, 108, 30, 98, 72, 175, 225, 43, 187, 213, 79, 136, 105, 176, 67, 165, 176, 68, 69, 98, 129, 63, 10, 152, 179, 0, 53, 111, 48, 110, 107, 120, 58, 41, 243, 190, 201, 124, 164, 14, 162, 0, 98, 202, 184, 146, 110, 197, 217, 106, 163, 135, 204, 132, 130, 26, 109, 114, 184, 234, 18, 110, 125])
+ };
+
+ var vectors = [
+ {
+ name: "RSASSA-PKCS1-v1_5 with SHA-1",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSASSA-PKCS1-v1_5"},
+ hash: "SHA-1",
+ plaintext: plaintext,
+ signature: signatures["sha-1"]
+ },
+ {
+ name: "RSASSA-PKCS1-v1_5 with SHA-256",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSASSA-PKCS1-v1_5"},
+ hash: "SHA-256",
+ plaintext: plaintext,
+ signature: signatures["sha-256"]
+ },
+ {
+ name: "RSASSA-PKCS1-v1_5 with SHA-384",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSASSA-PKCS1-v1_5"},
+ hash: "SHA-384",
+ plaintext: plaintext,
+ signature: signatures["sha-384"]
+ },
+ {
+ name: "RSASSA-PKCS1-v1_5 with SHA-512",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSASSA-PKCS1-v1_5"},
+ hash: "SHA-512",
+ plaintext: plaintext,
+ signature: signatures["sha-512"]
+ }
+ ];
+
+
+ return vectors;
+}
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss.https.any.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss.https.any.js
new file mode 100644
index 0000000000..f02ba2096b
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss.https.any.js
@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: sign() and verify() Using RSA-PSS
+// META: script=rsa_pss_vectors.js
+// META: script=rsa.js
+// META: timeout=long
+
+run_test();
diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss_vectors.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss_vectors.js
new file mode 100644
index 0000000000..c3ce779606
--- /dev/null
+++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss_vectors.js
@@ -0,0 +1,147 @@
+
+// rsa_pss_vectors.js
+
+// Data for testing RSA-PSS with a 2048-bit modulus and 65537 public exponent.
+
+// The following function returns an array of test vectors
+// for the subtleCrypto encrypt method.
+//
+// Each test vector has the following fields:
+// name - a unique name for this vector
+// publicKeyBuffer - an arrayBuffer with the key data
+// publicKeyFormat - "spki" "jwk"
+// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// privateKeyBuffer - an arrayBuffer with the key data
+// privateKeyFormat - "pkcs8" or "jwk"
+// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it!
+// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt
+// plaintext - the text to encrypt
+// signature - the expected signature
+function getTestVectors() {
+ var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]);
+ var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]);
+
+ // plaintext for RSA-PSS
+ var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
+
+ // For verification tests. Note that "salted" signatures use a salt length equal to the hash size
+ var signatures = {
+ "sha-1, no salt": new Uint8Array([31, 28, 216, 30, 203, 59, 179, 29, 242, 229, 240, 246, 76, 92, 10, 49, 12, 124, 248, 141, 25, 235, 81, 42, 80, 120, 225, 86, 216, 35, 114, 122, 248, 134, 138, 18, 229, 223, 191, 169, 118, 56, 103, 132, 186, 152, 44, 57, 146, 135, 137, 177, 52, 149, 42, 74, 40, 198, 36, 17, 119, 188, 242, 36, 143, 42, 219, 96, 7, 127, 84, 93, 209, 126, 79, 128, 155, 59, 133, 159, 212, 48, 209, 104, 30, 128, 71, 18, 109, 119, 54, 149, 25, 238, 213, 182, 24, 243, 41, 122, 87, 80, 133, 240, 201, 49, 237, 36, 140, 246, 11, 189, 126, 255, 250, 10, 140, 43, 135, 75, 167, 248, 30, 205, 107, 243, 145, 208, 31, 30, 136, 29, 130, 122, 123, 149, 223, 135, 77, 154, 218, 187, 123, 7, 241, 49, 171, 51, 20, 42, 139, 11, 109, 92, 169, 104, 86, 113, 212, 155, 152, 43, 103, 101, 25, 9, 234, 161, 123, 150, 179, 147, 224, 79, 179, 109, 151, 47, 155, 37, 143, 27, 121, 18, 61, 242, 18, 211, 153, 36, 164, 222, 174, 197, 6, 207, 100, 15, 29, 237, 208, 45, 40, 132, 95, 53, 72, 216, 72, 134, 82, 120, 142, 46, 33, 70, 243, 206, 138, 134, 165, 86, 216, 75, 69, 120, 241, 13, 162, 154, 189, 177, 118, 166, 135, 24, 204, 27, 34, 112, 176, 115, 92, 46, 92, 166, 198, 187, 10, 250, 194, 58, 91, 250, 129, 122]),
+ "sha-256, no salt": new Uint8Array([97, 87, 214, 104, 237, 101, 93, 151, 139, 76, 21, 140, 132, 25, 235, 128, 113, 141, 253, 252, 125, 75, 52, 53, 127, 153, 23, 233, 225, 22, 182, 243, 182, 80, 64, 201, 209, 97, 85, 192, 129, 214, 136, 122, 188, 179, 186, 79, 250, 1, 145, 228, 128, 126, 226, 6, 104, 26, 161, 212, 128, 158, 162, 13, 229, 24, 107, 119, 227, 202, 206, 208, 127, 201, 179, 215, 27, 157, 240, 172, 129, 181, 195, 39, 63, 243, 247, 79, 50, 167, 173, 52, 198, 80, 98, 163, 21, 64, 206, 211, 5, 39, 239, 164, 183, 170, 45, 39, 255, 127, 128, 83, 95, 62, 101, 206, 53, 46, 185, 225, 139, 80, 84, 65, 109, 233, 89, 53, 74, 77, 204, 203, 37, 66, 227, 58, 131, 88, 237, 166, 32, 168, 101, 61, 214, 69, 143, 86, 171, 148, 254, 225, 220, 1, 239, 66, 251, 137, 88, 170, 19, 72, 16, 228, 216, 254, 29, 212, 254, 238, 106, 240, 71, 66, 248, 13, 165, 121, 56, 117, 167, 138, 42, 76, 192, 141, 78, 10, 104, 171, 3, 241, 192, 34, 160, 232, 167, 211, 9, 96, 137, 146, 210, 78, 205, 215, 232, 241, 137, 94, 62, 92, 211, 110, 73, 144, 107, 83, 25, 50, 217, 255, 149, 134, 24, 177, 165, 15, 152, 69, 95, 81, 94, 12, 99, 16, 61, 46, 78, 22, 81, 175, 197, 102, 235, 156, 173, 30, 126, 250, 225, 169, 117, 12, 56, 128]),
+ "sha-384, no salt": new Uint8Array([123, 149, 170, 182, 179, 76, 9, 98, 210, 40, 64, 158, 48, 223, 155, 4, 60, 27, 11, 170, 218, 8, 231, 61, 136, 116, 34, 85, 43, 143, 21, 34, 226, 228, 43, 242, 185, 255, 44, 108, 154, 163, 235, 12, 210, 55, 6, 24, 232, 241, 163, 104, 115, 89, 94, 0, 189, 231, 90, 156, 224, 98, 236, 50, 181, 246, 57, 79, 34, 103, 163, 245, 193, 24, 64, 255, 146, 230, 225, 91, 243, 28, 197, 62, 145, 124, 168, 239, 192, 137, 95, 177, 18, 194, 239, 143, 104, 28, 187, 106, 65, 1, 82, 246, 233, 48, 202, 255, 31, 38, 14, 49, 249, 131, 84, 46, 104, 205, 21, 222, 161, 126, 211, 19, 156, 172, 115, 81, 6, 251, 5, 252, 22, 59, 46, 208, 90, 13, 237, 147, 144, 89, 161, 12, 92, 215, 97, 158, 33, 178, 210, 6, 144, 121, 148, 39, 75, 52, 164, 218, 239, 161, 206, 89, 182, 179, 25, 247, 57, 85, 160, 145, 138, 94, 35, 126, 27, 191, 218, 219, 69, 201, 7, 165, 0, 131, 87, 126, 113, 146, 129, 136, 69, 153, 91, 74, 109, 63, 241, 151, 142, 15, 154, 66, 105, 88, 83, 40, 46, 53, 195, 183, 129, 51, 179, 224, 198, 36, 18, 90, 255, 20, 161, 135, 61, 25, 143, 99, 4, 255, 236, 127, 193, 207, 42, 222, 204, 108, 209, 75, 31, 137, 177, 166, 55, 247, 46, 209, 255, 93, 231, 198, 180, 217, 101, 153]),
+ "sha-512, no salt": new Uint8Array([175, 27, 192, 127, 167, 10, 221, 25, 243, 206, 31, 27, 239, 141, 252, 110, 36, 175, 67, 103, 28, 251, 151, 230, 184, 105, 232, 107, 126, 240, 53, 80, 166, 88, 19, 24, 255, 246, 68, 154, 250, 139, 103, 231, 62, 42, 106, 20, 226, 6, 119, 216, 176, 103, 20, 90, 132, 66, 37, 116, 174, 12, 253, 42, 93, 255, 112, 198, 215, 233, 127, 106, 14, 22, 101, 5, 7, 158, 180, 38, 74, 67, 196, 147, 242, 235, 63, 176, 111, 172, 192, 27, 230, 7, 116, 194, 119, 100, 106, 40, 8, 18, 71, 103, 150, 34, 178, 32, 34, 126, 146, 73, 117, 72, 103, 170, 143, 225, 128, 64, 21, 196, 249, 135, 0, 152, 46, 218, 64, 232, 77, 11, 160, 51, 108, 244, 79, 88, 47, 184, 120, 19, 116, 128, 78, 143, 180, 62, 185, 213, 119, 172, 244, 114, 53, 135, 163, 154, 43, 74, 158, 22, 139, 118, 118, 50, 183, 165, 84, 247, 123, 197, 39, 40, 33, 201, 56, 192, 153, 75, 22, 47, 116, 130, 99, 111, 127, 250, 197, 100, 161, 155, 215, 51, 244, 135, 120, 1, 220, 50, 77, 196, 113, 150, 239, 18, 202, 154, 143, 73, 33, 165, 73, 108, 214, 115, 121, 53, 202, 85, 91, 115, 70, 109, 221, 129, 126, 175, 240, 63, 237, 160, 235, 45, 97, 46, 60, 219, 89, 177, 152, 158, 239, 253, 193, 129, 1, 212, 110, 86, 185, 255, 92, 145, 249, 93]),
+ "sha-1, salted": new Uint8Array([31, 96, 138, 113, 209, 136, 76, 254, 33, 131, 180, 144, 55, 170, 133, 85, 176, 19, 154, 138, 18, 103, 165, 197, 185, 204, 226, 7, 1, 242, 173, 75, 189, 91, 50, 151, 64, 191, 243, 26, 204, 195, 75, 249, 175, 209, 67, 154, 5, 54, 187, 50, 182, 212, 39, 210, 105, 104, 219, 201, 233, 200, 13, 33, 17, 217, 72, 196, 129, 203, 23, 49, 119, 138, 205, 49, 16, 70, 50, 65, 196, 242, 59, 62, 19, 184, 85, 209, 98, 203, 21, 56, 81, 41, 15, 217, 95, 120, 21, 25, 226, 206, 249, 55, 69, 164, 19, 207, 238, 200, 233, 79, 186, 120, 34, 183, 37, 212, 116, 67, 24, 69, 140, 246, 180, 169, 23, 182, 91, 21, 238, 111, 84, 185, 195, 145, 246, 6, 74, 158, 3, 31, 112, 9, 245, 146, 68, 156, 11, 70, 213, 69, 122, 39, 153, 203, 14, 189, 120, 161, 2, 160, 85, 238, 4, 112, 178, 96, 194, 179, 216, 255, 189, 238, 15, 212, 118, 68, 130, 32, 144, 236, 85, 174, 98, 51, 190, 16, 98, 244, 65, 196, 50, 237, 60, 39, 94, 116, 214, 32, 19, 38, 129, 236, 46, 128, 30, 155, 91, 106, 204, 26, 215, 31, 137, 53, 56, 143, 126, 44, 3, 55, 13, 18, 233, 68, 227, 65, 140, 42, 182, 59, 180, 42, 190, 27, 185, 230, 149, 48, 240, 36, 88, 186, 40, 64, 11, 54, 128, 111, 247, 141, 165, 121, 26, 206]),
+ "sha-256, salted": new Uint8Array([140, 61, 3, 189, 232, 196, 45, 148, 83, 99, 27, 11, 170, 200, 158, 98, 150, 218, 32, 84, 55, 19, 192, 4, 223, 53, 188, 26, 111, 174, 32, 90, 178, 191, 88, 83, 105, 104, 144, 115, 205, 238, 52, 90, 214, 226, 120, 59, 45, 218, 24, 123, 73, 121, 234, 4, 87, 70, 55, 88, 21, 110, 16, 62, 237, 208, 239, 24, 52, 211, 91, 214, 173, 84, 13, 155, 139, 34, 95, 209, 119, 14, 81, 78, 160, 175, 53, 247, 7, 242, 231, 160, 56, 43, 230, 245, 237, 157, 107, 89, 29, 83, 108, 225, 33, 91, 23, 239, 62, 235, 69, 11, 180, 138, 0, 23, 73, 124, 103, 190, 2, 64, 71, 10, 221, 210, 137, 26, 129, 168, 241, 207, 110, 128, 227, 248, 55, 254, 66, 55, 98, 146, 223, 85, 91, 139, 5, 147, 27, 105, 83, 5, 151, 250, 227, 109, 205, 1, 177, 200, 23, 103, 212, 236, 212, 202, 240, 107, 239, 192, 53, 34, 75, 221, 42, 94, 107, 137, 213, 21, 57, 35, 90, 201, 85, 112, 231, 87, 219, 215, 15, 220, 21, 4, 0, 1, 176, 123, 147, 123, 240, 20, 140, 204, 0, 95, 76, 39, 42, 207, 95, 143, 192, 150, 163, 125, 38, 32, 142, 150, 172, 52, 28, 45, 29, 33, 44, 68, 214, 213, 21, 108, 147, 79, 102, 239, 66, 253, 186, 199, 122, 32, 134, 129, 85, 11, 4, 139, 70, 110, 50, 199, 108, 122, 123, 7]),
+ "sha-384, salted": new Uint8Array([121, 247, 40, 75, 180, 33, 109, 230, 132, 41, 133, 78, 219, 66, 24, 239, 120, 173, 23, 64, 132, 133, 103, 55, 115, 21, 219, 136, 103, 161, 87, 51, 199, 4, 46, 139, 249, 7, 98, 230, 115, 201, 12, 14, 44, 88, 198, 197, 206, 244, 151, 86, 139, 217, 42, 109, 33, 150, 18, 196, 117, 108, 85, 250, 196, 85, 7, 248, 22, 8, 188, 39, 32, 218, 78, 237, 213, 178, 62, 31, 60, 135, 64, 198, 180, 205, 126, 76, 240, 224, 67, 66, 177, 132, 193, 17, 1, 153, 230, 80, 128, 215, 59, 152, 94, 97, 29, 102, 248, 233, 121, 144, 129, 110, 73, 23, 186, 219, 176, 66, 93, 217, 67, 131, 137, 46, 42, 169, 109, 228, 219, 13, 224, 147, 106, 238, 132, 213, 72, 42, 61, 163, 27, 39, 49, 159, 67, 131, 15, 196, 135, 3, 204, 125, 78, 174, 219, 32, 253, 48, 50, 61, 191, 63, 34, 96, 141, 181, 22, 55, 211, 179, 5, 179, 25, 121, 98, 101, 141, 128, 147, 92, 38, 109, 51, 204, 251, 41, 117, 144, 98, 31, 74, 150, 124, 114, 69, 233, 43, 1, 88, 192, 220, 234, 148, 62, 42, 206, 113, 158, 189, 177, 150, 169, 186, 231, 223, 62, 217, 204, 98, 118, 94, 39, 182, 53, 113, 116, 62, 40, 160, 83, 141, 176, 130, 92, 173, 37, 57, 235, 93, 229, 230, 163, 32, 168, 139, 87, 62, 193, 151, 44, 38, 64, 21, 48]),
+ "sha-512, salted": new Uint8Array([183, 79, 48, 153, 216, 7, 135, 17, 139, 31, 157, 231, 159, 194, 7, 137, 62, 13, 45, 117, 196, 17, 15, 75, 21, 155, 133, 186, 7, 214, 58, 2, 86, 252, 60, 208, 246, 108, 232, 217, 162, 227, 207, 122, 61, 90, 123, 156, 11, 239, 172, 102, 56, 137, 74, 62, 54, 206, 117, 230, 73, 238, 6, 157, 216, 221, 152, 170, 139, 96, 36, 116, 201, 139, 20, 187, 3, 73, 45, 229, 81, 169, 232, 231, 121, 52, 239, 155, 104, 69, 131, 147, 79, 33, 141, 149, 118, 190, 36, 11, 92, 79, 54, 46, 175, 94, 1, 64, 200, 234, 146, 99, 144, 133, 166, 38, 150, 83, 80, 93, 207, 160, 4, 34, 109, 185, 246, 50, 119, 101, 58, 100, 161, 130, 110, 75, 171, 177, 122, 181, 77, 216, 84, 61, 207, 28, 232, 9, 112, 109, 104, 22, 230, 167, 95, 248, 70, 163, 212, 193, 141, 17, 189, 235, 31, 49, 177, 13, 85, 163, 121, 91, 100, 150, 49, 158, 110, 117, 21, 4, 216, 106, 78, 123, 182, 83, 91, 159, 4, 21, 232, 21, 216, 199, 137, 197, 177, 227, 135, 242, 168, 192, 15, 239, 110, 50, 116, 98, 203, 126, 82, 91, 143, 148, 91, 229, 177, 114, 72, 224, 224, 164, 216, 85, 211, 151, 226, 45, 6, 124, 228, 83, 147, 115, 223, 186, 70, 209, 121, 146, 80, 175, 199, 15, 83, 80, 6, 202, 205, 39, 102, 245, 221, 207, 143, 145])
+ };
+
+ var vectors = [
+ {
+ name: "RSA-PSS with SHA-1 and no salt",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 0},
+ hash: "SHA-1",
+ plaintext: plaintext,
+ signature: signatures["sha-1, no salt"]
+ },
+ {
+ name: "RSA-PSS with SHA-256 and no salt",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 0},
+ hash: "SHA-256",
+ plaintext: plaintext,
+ signature: signatures["sha-256, no salt"]
+ },
+ {
+ name: "RSA-PSS with SHA-384 and no salt",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 0},
+ hash: "SHA-384",
+ plaintext: plaintext,
+ signature: signatures["sha-384, no salt"]
+ },
+ {
+ name: "RSA-PSS with SHA-512 and no salt",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 0},
+ hash: "SHA-512",
+ plaintext: plaintext,
+ signature: signatures["sha-512, no salt"]
+ },
+ {
+ name: "RSA-PSS with SHA-1, salted",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 20},
+ hash: "SHA-1",
+ plaintext: plaintext,
+ signature: signatures["sha-1, salted"]
+ },
+ {
+ name: "RSA-PSS with SHA-256, salted",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 32},
+ hash: "SHA-256",
+ plaintext: plaintext,
+ signature: signatures["sha-256, salted"]
+ },
+ {
+ name: "RSA-PSS with SHA-384, salted",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 48},
+ hash: "SHA-384",
+ plaintext: plaintext,
+ signature: signatures["sha-384, salted"]
+ },
+ {
+ name: "RSA-PSS with SHA-512, salted",
+ publicKeyBuffer: spki,
+ publicKeyFormat: "spki",
+ privateKey: null,
+ privateKeyBuffer: pkcs8,
+ privateKeyFormat: "pkcs8",
+ publicKey: null,
+ algorithm: {name: "RSA-PSS", saltLength: 64},
+ hash: "SHA-512",
+ plaintext: plaintext,
+ signature: signatures["sha-512, salted"]
+ }
+ ];
+
+ return vectors;
+}