mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Update web-platform-tests to revision b'b728032f59a396243864b0f8584e7211e3632005'
This commit is contained in:
parent
ace9b32b1c
commit
df68c4e5d1
15632 changed files with 514865 additions and 155000 deletions
|
@ -0,0 +1,213 @@
|
|||
// META: title=WebCryptoAPI: Properties discard the context in algorithm normalization
|
||||
|
||||
let nextTest = 0;
|
||||
let tests = {};
|
||||
function closeChild(testId) {
|
||||
if (tests[testId]) {
|
||||
let {child, t} = tests[testId];
|
||||
delete tests[testId];
|
||||
document.body.removeChild(child);
|
||||
t.done();
|
||||
}
|
||||
}
|
||||
|
||||
function runInChild(t, childScript) {
|
||||
let testId = nextTest++;
|
||||
const preamble = `
|
||||
let testId = ${testId};
|
||||
function closeChildOnAccess(obj, key) {
|
||||
const oldValue = obj[key];
|
||||
Object.defineProperty(obj, key, {get: () => {
|
||||
top.closeChild(testId);
|
||||
return oldValue;
|
||||
}});
|
||||
}
|
||||
`;
|
||||
childScript = preamble + childScript;
|
||||
|
||||
let child = document.createElement("iframe");
|
||||
tests[testId] = {t, child};
|
||||
document.body.appendChild(child);
|
||||
let script = document.createElement("script");
|
||||
script.textContent = childScript;
|
||||
child.contentDocument.body.appendChild(script);
|
||||
}
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
let algorithm = {name: "AES-GCM", length: 128};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.generateKey(algorithm, true, ["encrypt", "decrypt"]);`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in generateKey");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
let algorithm = {name: "AES-GCM"};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.importKey("raw", new Uint8Array(16), algorithm, true,
|
||||
["encrypt", "decrypt"]);`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in importKey");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
|
||||
let algorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.encrypt(algorithm, key, new Uint8Array());
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in encrypt");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
|
||||
let algorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
|
||||
let encrypted = await crypto.subtle.encrypt(algorithm, key, new Uint8Array());
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.decrypt(algorithm, key, encrypted);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in decrypt");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
let algorithm = {name: "SHA-256"};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.digest(algorithm, new Uint8Array());`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in digest");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.generateKey(
|
||||
{name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
|
||||
let algorithm = {name: "ECDSA", hash: "SHA-256"};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.sign(algorithm, key.privateKey, new Uint8Array());
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in sign");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.generateKey(
|
||||
{name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
|
||||
let algorithm = {name: "ECDSA", hash: "SHA-256"};
|
||||
let data = new Uint8Array();
|
||||
let signature = await crypto.subtle.sign(algorithm, key.privateKey, data);
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.verify(algorithm, key.publicKey, signature, data);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in verify");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.importKey(
|
||||
"raw", new Uint8Array(16), "HKDF", false, ["deriveBits"]);
|
||||
let algorithm = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array(),
|
||||
};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.deriveBits(algorithm, key, 16);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in deriveBits");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.importKey(
|
||||
"raw", new Uint8Array(16), "HKDF", false, ["deriveKey"]);
|
||||
let algorithm = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array(),
|
||||
};
|
||||
let derivedAlgorithm = {name: "AES-GCM", length: 128};
|
||||
closeChildOnAccess(algorithm, "name");
|
||||
crypto.subtle.deriveKey(algorithm, key, derivedAlgorithm, true,
|
||||
["encrypt", "decrypt"]);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in deriveKey");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let key = await crypto.subtle.importKey(
|
||||
"raw", new Uint8Array(16), "HKDF", false, ["deriveKey"]);
|
||||
let algorithm = {
|
||||
name: "HKDF",
|
||||
hash: "SHA-256",
|
||||
salt: new Uint8Array(),
|
||||
info: new Uint8Array(),
|
||||
};
|
||||
let derivedAlgorithm = {name: "AES-GCM", length: 128};
|
||||
closeChildOnAccess(derivedAlgorithm, "name");
|
||||
crypto.subtle.deriveKey(algorithm, key, derivedAlgorithm, true,
|
||||
["encrypt", "decrypt"]);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in deriveKey (2)");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let wrapKey = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
|
||||
let key = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["encrypt", "decrypt"]);
|
||||
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
|
||||
closeChildOnAccess(wrapAlgorithm, "name");
|
||||
crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in wrapKey");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let wrapKey = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
|
||||
let keyAlgorithm = {name: "AES-GCM", length: 128};
|
||||
let keyUsages = ["encrypt", "decrypt"];
|
||||
let key = await crypto.subtle.generateKey(keyAlgorithm, true, keyUsages);
|
||||
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
|
||||
let wrapped = await crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
|
||||
closeChildOnAccess(wrapAlgorithm, "name");
|
||||
crypto.subtle.unwrapKey(
|
||||
"raw", wrapped, wrapKey, wrapAlgorithm, keyAlgorithm, true, keyUsages);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in unwrapKey");
|
||||
|
||||
async_test((t) => {
|
||||
const childScript = `
|
||||
(async () => {
|
||||
let wrapKey = await crypto.subtle.generateKey(
|
||||
{name: "AES-GCM", length: 128}, true, ["wrapKey", "unwrapKey"]);
|
||||
let keyAlgorithm = {name: "AES-GCM", length: 128};
|
||||
let keyUsages = ["encrypt", "decrypt"];
|
||||
let key = await crypto.subtle.generateKey(keyAlgorithm, true, keyUsages);
|
||||
let wrapAlgorithm = {name: "AES-GCM", iv: new Uint8Array(12)};
|
||||
let wrapped = await crypto.subtle.wrapKey("raw", key, wrapKey, wrapAlgorithm);
|
||||
closeChildOnAccess(keyAlgorithm, "name");
|
||||
crypto.subtle.unwrapKey(
|
||||
"raw", wrapped, wrapKey, wrapAlgorithm, keyAlgorithm, true, keyUsages);
|
||||
})();`;
|
||||
runInChild(t, childScript);
|
||||
}, "Context is discarded in unwrapKey (2)");
|
|
@ -0,0 +1,9 @@
|
|||
// META: title=WebCryptoAPI: deriveBits() Using ECDH with CFRG Elliptic Curves
|
||||
// META: script=cfrg_curves_bits.js
|
||||
|
||||
// Define subtests from a `promise_test` to ensure the harness does not
|
||||
// complete before the subtests are available. `explicit_done` cannot be used
|
||||
// for this purpose because the global `done` function is automatically invoked
|
||||
// by the WPT infrastructure in dedicated worker tests defined using the
|
||||
// "multi-global" pattern.
|
||||
promise_test(define_tests, 'setup - define tests');
|
|
@ -0,0 +1,251 @@
|
|||
|
||||
function define_tests() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
var pkcs8 = {
|
||||
"X25519": new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
|
||||
"X448": new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158])
|
||||
};
|
||||
|
||||
var spki = {
|
||||
"X25519": new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
|
||||
"X448": new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111])
|
||||
};
|
||||
|
||||
var sizes = {
|
||||
"X25519": 32,
|
||||
"X448": 56
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"X25519": new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 161, 149, 0, 8]),
|
||||
"X448": new Uint8Array([240, 246, 197, 241, 127, 148, 244, 41, 30, 171, 113, 120, 134, 109, 55, 236, 137, 6, 221, 108, 81, 65, 67, 220, 133, 190, 124, 242, 141, 239, 243, 155, 114, 110, 15, 109, 207, 129, 14, 181, 148, 220, 169, 123, 72, 130, 189, 68, 196, 62, 167, 220, 103, 244, 154, 78])
|
||||
};
|
||||
|
||||
return importKeys(pkcs8, spki, sizes)
|
||||
.then(function(results) {
|
||||
publicKeys = results.publicKeys;
|
||||
privateKeys = results.privateKeys;
|
||||
noDeriveBitsKeys = results.noDeriveBitsKeys;
|
||||
|
||||
Object.keys(sizes).forEach(function(algorithmName) {
|
||||
// Basic success case
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " good parameters");
|
||||
|
||||
// Case insensitivity check
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " mixed case parameters");
|
||||
|
||||
// Null length
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], null)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " with null length");
|
||||
|
||||
// Shorter than entire derivation per algorithm
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 32)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 32), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " short result");
|
||||
|
||||
// Non-multiple of 8
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 11)
|
||||
.then(function(derivation) {
|
||||
assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 11), "Derived correct bits");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveBits failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " non-multiple of 8 bits");
|
||||
|
||||
// Errors to test:
|
||||
|
||||
// - missing public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " missing public property");
|
||||
|
||||
// - Non CryptoKey public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " public property of algorithm is not a CryptoKey");
|
||||
|
||||
// - wrong algorithm
|
||||
promise_test(function(test) {
|
||||
publicKey = publicKeys["X25519"];
|
||||
if (algorithmName === "X25519") {
|
||||
publicKey = publicKeys["X448"];
|
||||
}
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKey}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " mismatched algorithms");
|
||||
|
||||
// - No deriveBits usage in baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveBitsKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " no deriveBits usage for base key");
|
||||
|
||||
// - Use public key for baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " base key is not a private key");
|
||||
|
||||
// - Use private key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " public property value is a private key");
|
||||
|
||||
// - Use secret key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"])
|
||||
.then(function(secretKey) {
|
||||
return subtle.deriveBits({name: algorithmName, public: secretKey}, privateKeys[algorithmName], 8 * sizes[algorithmName])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
});
|
||||
}, algorithmName + " public property value is a secret key");
|
||||
|
||||
// - Length greater than possible for particular curves OperationError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] + 8)
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with OperationError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " asking for too many bits");
|
||||
});
|
||||
});
|
||||
|
||||
function importKeys(pkcs8, spki, sizes) {
|
||||
var privateKeys = {};
|
||||
var publicKeys = {};
|
||||
var noDeriveBitsKeys = {};
|
||||
|
||||
var promises = [];
|
||||
Object.keys(pkcs8).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
privateKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(pkcs8).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, ["deriveKey"])
|
||||
.then(function(key) {
|
||||
noDeriveBitsKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
noDeriveBitsKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(spki).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("spki", spki[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
publicKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveBitsKeys: noDeriveBitsKeys}});
|
||||
}
|
||||
|
||||
// Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is
|
||||
// omitted, the two values must be the same length and have the same contents
|
||||
// in every byte. If bitCount is included, only that leading number of bits
|
||||
// have to match.
|
||||
function equalBuffers(a, b, bitCount) {
|
||||
var remainder;
|
||||
|
||||
if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
var length = a.byteLength;
|
||||
if (typeof bitCount !== "undefined") {
|
||||
length = Math.floor(bitCount / 8);
|
||||
}
|
||||
|
||||
for (var i=0; i<length; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bitCount !== "undefined") {
|
||||
remainder = bitCount % 8;
|
||||
return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves
|
||||
// META: script=cfrg_curves_keys.js
|
||||
|
||||
// Define subtests from a `promise_test` to ensure the harness does not
|
||||
// complete before the subtests are available. `explicit_done` cannot be used
|
||||
// for this purpose because the global `done` function is automatically invoked
|
||||
// by the WPT infrastructure in dedicated worker tests defined using the
|
||||
// "multi-global" pattern.
|
||||
promise_test(define_tests, 'setup - define tests');
|
|
@ -0,0 +1,219 @@
|
|||
|
||||
function define_tests() {
|
||||
// May want to test prefixed implementations.
|
||||
var subtle = self.crypto.subtle;
|
||||
|
||||
var pkcs8 = {
|
||||
"X25519": new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
|
||||
"X448": new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158])
|
||||
};
|
||||
|
||||
var spki = {
|
||||
"X25519": new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
|
||||
"X448": new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111])
|
||||
};
|
||||
|
||||
var sizes = {
|
||||
"X25519": 32,
|
||||
"X448": 56
|
||||
};
|
||||
|
||||
var derivations = {
|
||||
"X25519": new Uint8Array([39, 104, 64, 157, 250, 185, 158, 194, 59, 140, 137, 185, 63, 245, 136, 2, 149, 247, 97, 118, 8, 143, 137, 228, 61, 254, 190, 126, 161, 149, 0, 8]),
|
||||
"X448": new Uint8Array([240, 246, 197, 241, 127, 148, 244, 41, 30, 171, 113, 120, 134, 109, 55, 236, 137, 6, 221, 108, 81, 65, 67, 220, 133, 190, 124, 242, 141, 239, 243, 155, 114, 110, 15, 109, 207, 129, 14, 181, 148, 220, 169, 123, 72, 130, 189, 68, 196, 62, 167, 220, 103, 244, 154, 78])
|
||||
};
|
||||
|
||||
return importKeys(pkcs8, spki, sizes)
|
||||
.then(function(results) {
|
||||
publicKeys = results.publicKeys;
|
||||
privateKeys = results.privateKeys;
|
||||
noDeriveKeyKeys = results.noDeriveKeyKeys;
|
||||
|
||||
Object.keys(sizes).forEach(function(algorithmName) {
|
||||
// Basic success case
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_true(equalBuffers(exportedKey, derivations[algorithmName], 8 * exportedKey.length), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " good parameters");
|
||||
|
||||
// Case insensitivity check
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_true(equalBuffers(exportedKey, derivations[algorithmName], 8 * exportedKey.length), "Derived correct key");
|
||||
}, function(err) {
|
||||
assert_unreached("deriveKey failed with error " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " mixed case parameters");
|
||||
// Errors to test:
|
||||
|
||||
// - missing public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " missing public property");
|
||||
|
||||
// - Non CryptoKey public property TypeError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with TypeError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " public property of algorithm is not a CryptoKey");
|
||||
|
||||
// - wrong algorithm
|
||||
promise_test(function(test) {
|
||||
publicKey = publicKeys["X25519"];
|
||||
if (algorithmName === "X25519") {
|
||||
publicKey = publicKeys["X448"];
|
||||
}
|
||||
return subtle.deriveKey({name: algorithmName, public: publicKey}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " mismatched algorithms");
|
||||
|
||||
// - No deriveKey usage in baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveKeyKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " no deriveKey usage for base key");
|
||||
|
||||
// - Use public key for baseKey InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " base key is not a private key");
|
||||
|
||||
// - Use private key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.deriveKey({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
}, algorithmName + " public property value is a private key");
|
||||
|
||||
// - Use secret key for public property InvalidAccessError
|
||||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(secretKey) {
|
||||
return subtle.deriveKey({name: algorithmName, public: secretKey}, privateKeys[algorithmName], {name: "AES-CBC", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message);
|
||||
});
|
||||
});
|
||||
}, algorithmName + " public property value is a secret key");
|
||||
});
|
||||
});
|
||||
|
||||
function importKeys(pkcs8, spki, sizes) {
|
||||
var privateKeys = {};
|
||||
var publicKeys = {};
|
||||
var noDeriveKeyKeys = {};
|
||||
|
||||
var promises = [];
|
||||
Object.keys(pkcs8).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
privateKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(pkcs8).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("pkcs8", pkcs8[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, ["deriveBits"])
|
||||
.then(function(key) {
|
||||
noDeriveKeyKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
noDeriveKeyKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
Object.keys(spki).forEach(function(algorithmName) {
|
||||
var operation = subtle.importKey("spki", spki[algorithmName],
|
||||
{name: algorithmName},
|
||||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[algorithmName] = key;
|
||||
}, function (err) {
|
||||
publicKeys[algorithmName] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveKeyKeys: noDeriveKeyKeys}});
|
||||
}
|
||||
|
||||
// Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is
|
||||
// omitted, the two values must be the same length and have the same contents
|
||||
// in every byte. If bitCount is included, only that leading number of bits
|
||||
// have to match.
|
||||
function equalBuffers(a, b, bitCount) {
|
||||
var remainder;
|
||||
|
||||
if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var aBytes = new Uint8Array(a);
|
||||
var bBytes = new Uint8Array(b);
|
||||
|
||||
var length = a.byteLength;
|
||||
if (typeof bitCount !== "undefined") {
|
||||
length = Math.floor(bitCount / 8);
|
||||
}
|
||||
|
||||
for (var i=0; i<length; i++) {
|
||||
if (aBytes[i] !== bBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bitCount !== "undefined") {
|
||||
remainder = bitCount % 8;
|
||||
return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -165,7 +165,7 @@ function define_tests() {
|
|||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"])
|
||||
.then(function(secretKey) {
|
||||
subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
return subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve])
|
||||
.then(function(derivation) {
|
||||
assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError");
|
||||
}, function(err) {
|
||||
|
@ -199,6 +199,8 @@ function define_tests() {
|
|||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
privateKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -208,6 +210,8 @@ function define_tests() {
|
|||
false, ["deriveKey"])
|
||||
.then(function(key) {
|
||||
noDeriveBitsKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
noDeriveBitsKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -217,6 +221,8 @@ function define_tests() {
|
|||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
publicKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -224,6 +230,8 @@ function define_tests() {
|
|||
var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"])
|
||||
.then(function(keyPair) {
|
||||
ecdsaKeyPairs[namedCurve] = keyPair;
|
||||
}, function (err) {
|
||||
ecdsaKeyPairs[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
|
|
@ -143,7 +143,7 @@ function define_tests() {
|
|||
promise_test(function(test) {
|
||||
return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(secretKey) {
|
||||
subtle.deriveKey({name: "ECDH", public: secretKey}, privateKeys[namedCurve], {name: "AES-CBC", length: 256}, true, ["sign", "verify"])
|
||||
return subtle.deriveKey({name: "ECDH", public: secretKey}, privateKeys[namedCurve], {name: "AES-CBC", length: 256}, true, ["sign", "verify"])
|
||||
.then(function(key) {return crypto.subtle.exportKey("raw", key);})
|
||||
.then(function(exportedKey) {
|
||||
assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError");
|
||||
|
@ -168,6 +168,8 @@ function define_tests() {
|
|||
false, ["deriveBits", "deriveKey"])
|
||||
.then(function(key) {
|
||||
privateKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
privateKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -177,6 +179,8 @@ function define_tests() {
|
|||
false, ["deriveBits"])
|
||||
.then(function(key) {
|
||||
noDeriveKeyKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
noDeriveKeyKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -186,6 +190,8 @@ function define_tests() {
|
|||
false, [])
|
||||
.then(function(key) {
|
||||
publicKeys[namedCurve] = key;
|
||||
}, function (err) {
|
||||
publicKeys[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
@ -193,6 +199,8 @@ function define_tests() {
|
|||
var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"])
|
||||
.then(function(keyPair) {
|
||||
ecdsaKeyPairs[namedCurve] = keyPair;
|
||||
}, function (err) {
|
||||
ecdsaKeyPairs[namedCurve] = null;
|
||||
});
|
||||
promises.push(operation);
|
||||
});
|
||||
|
|
|
@ -31,7 +31,11 @@ function run_test(algorithmNames) {
|
|||
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
|
||||
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
];
|
||||
|
||||
var testVectors = [];
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// META: title=WebCryptoAPI: generateKey() for Failures
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=failures.js
|
||||
run_test(["Ed25519"]);
|
|
@ -0,0 +1,5 @@
|
|||
// META: title=WebCryptoAPI: generateKey() for Failures
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=failures.js
|
||||
run_test(["Ed448"]);
|
|
@ -0,0 +1,5 @@
|
|||
// META: title=WebCryptoAPI: generateKey() for Failures
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=failures.js
|
||||
run_test(["X25519"]);
|
|
@ -0,0 +1,5 @@
|
|||
// META: title=WebCryptoAPI: generateKey() for Failures
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=failures.js
|
||||
run_test(["X448"]);
|
|
@ -26,7 +26,11 @@ function run_test(algorithmNames, slowTest) {
|
|||
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
|
||||
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
{name: "Ed25519", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "Ed448", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "X25519", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
{name: "X448", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
|
||||
];
|
||||
|
||||
var testVectors = [];
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// META: title=WebCryptoAPI: generateKey() Successful Calls
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=/common/subset-tests.js
|
||||
// META: script=successes.js
|
||||
run_test(["Ed25519"]);
|
|
@ -0,0 +1,6 @@
|
|||
// META: title=WebCryptoAPI: generateKey() Successful Calls
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=/common/subset-tests.js
|
||||
// META: script=successes.js
|
||||
run_test(["Ed448"]);
|
|
@ -0,0 +1,6 @@
|
|||
// META: title=WebCryptoAPI: generateKey() Successful Calls
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=/common/subset-tests.js
|
||||
// META: script=successes.js
|
||||
run_test(["X25519"]);
|
|
@ -0,0 +1,6 @@
|
|||
// META: title=WebCryptoAPI: generateKey() Successful Calls
|
||||
// META: timeout=long
|
||||
// META: script=../util/helpers.js
|
||||
// META: script=/common/subset-tests.js
|
||||
// META: script=successes.js
|
||||
run_test(["X448"]);
|
|
@ -8,12 +8,24 @@ test(function() {
|
|||
}, "Float64Array")
|
||||
|
||||
assert_throws_dom("TypeMismatchError", function() {
|
||||
self.crypto.getRandomValues(new Float32Array(65537))
|
||||
const len = 65536 / Float32Array.BYTES_PER_ELEMENT + 1;
|
||||
self.crypto.getRandomValues(new Float32Array(len));
|
||||
}, "Float32Array (too long)")
|
||||
assert_throws_dom("TypeMismatchError", function() {
|
||||
self.crypto.getRandomValues(new Float64Array(65537))
|
||||
const len = 65536 / Float64Array.BYTES_PER_ELEMENT + 1;
|
||||
self.crypto.getRandomValues(new Float64Array(len))
|
||||
}, "Float64Array (too long)")
|
||||
}, "Float arrays")
|
||||
}, "Float arrays");
|
||||
|
||||
test(function() {
|
||||
assert_throws_dom("TypeMismatchError", function() {
|
||||
self.crypto.getRandomValues(new DataView(new ArrayBuffer(6)))
|
||||
}, "DataView")
|
||||
|
||||
assert_throws_dom("TypeMismatchError", function() {
|
||||
self.crypto.getRandomValues(new DataView(new ArrayBuffer(65536 + 1)))
|
||||
}, "DataView (too long)")
|
||||
}, "DataView");
|
||||
|
||||
const arrays = [
|
||||
'Int8Array',
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
// META: title=WebCryptoAPI: importKey() for OKP keys
|
||||
// META: timeout=long
|
||||
|
||||
// Test importKey and exportKey for OKP algorithms. Only "happy paths" are
|
||||
// currently tested - those where the operation should succeed.
|
||||
|
||||
var subtle = crypto.subtle;
|
||||
|
||||
var keyData = {
|
||||
"Ed25519": {
|
||||
spki: 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]),
|
||||
pkcs8: 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]),
|
||||
jwk: {
|
||||
crv: "Ed25519",
|
||||
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
|
||||
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
|
||||
kty: "OKP"
|
||||
}
|
||||
},
|
||||
|
||||
"Ed448": {
|
||||
spki: 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]),
|
||||
pkcs8: 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]),
|
||||
jwk: {
|
||||
crv: "Ed448",
|
||||
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
|
||||
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
|
||||
kty: "OKP"
|
||||
}
|
||||
},
|
||||
|
||||
"X25519": {
|
||||
spki: new Uint8Array([48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0, 28, 242, 177, 230, 2, 46, 197, 55, 55, 30, 215, 245, 62, 84, 250, 17, 84, 216, 62, 152, 235, 100, 234, 81, 250, 229, 179, 48, 124, 254, 151, 6]),
|
||||
pkcs8: new Uint8Array([48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32, 200, 131, 142, 118, 208, 87, 223, 183, 216, 201, 90, 105, 225, 56, 22, 10, 221, 99, 115, 253, 113, 164, 210, 118, 187, 86, 227, 168, 27, 100, 255, 97]),
|
||||
jwk: {
|
||||
crv: "X25519",
|
||||
d: "yIOOdtBX37fYyVpp4TgWCt1jc_1xpNJ2u1bjqBtk_2E",
|
||||
x: "HPKx5gIuxTc3Htf1PlT6EVTYPpjrZOpR-uWzMHz-lwY",
|
||||
kty: "OKP"
|
||||
}
|
||||
},
|
||||
|
||||
"X448": {
|
||||
spki: new Uint8Array([48, 66, 48, 5, 6, 3, 43, 101, 111, 3, 57, 0, 182, 4, 161, 209, 165, 205, 29, 148, 38, 213, 97, 239, 99, 10, 158, 177, 108, 190, 105, 213, 185, 202, 97, 94, 220, 83, 99, 62, 251, 82, 234, 49, 230, 230, 160, 161, 219, 172, 198, 231, 108, 188, 230, 72, 45, 126, 75, 163, 213, 93, 158, 128, 39, 101, 206, 111]),
|
||||
pkcs8: new Uint8Array([48, 70, 2, 1, 0, 48, 5, 6, 3, 43, 101, 111, 4, 58, 4, 56, 88, 199, 210, 154, 62, 181, 25, 178, 157, 0, 207, 177, 145, 187, 100, 252, 109, 138, 66, 216, 241, 113, 118, 39, 43, 137, 242, 39, 45, 24, 25, 41, 92, 101, 37, 192, 130, 150, 113, 176, 82, 239, 7, 39, 83, 15, 24, 142, 49, 208, 204, 83, 191, 38, 146, 158]),
|
||||
jwk: {
|
||||
crv: "X448",
|
||||
d: "WMfSmj61GbKdAM-xkbtk_G2KQtjxcXYnK4nyJy0YGSlcZSXAgpZxsFLvBydTDxiOMdDMU78mkp4",
|
||||
x: "tgSh0aXNHZQm1WHvYwqesWy-adW5ymFe3FNjPvtS6jHm5qCh26zG52y85kgtfkuj1V2egCdlzm8",
|
||||
kty: "OKP"
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// combinations to test
|
||||
var testVectors = [
|
||||
{name: "Ed25519", privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{name: "Ed448", privateUsages: ["sign"], publicUsages: ["verify"]},
|
||||
{name: "X25519", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
|
||||
{name: "X448", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
|
||||
];
|
||||
|
||||
// TESTS ARE HERE:
|
||||
// Test every test vector, along with all available key data
|
||||
testVectors.forEach(function(vector) {
|
||||
[true, false].forEach(function(extractable) {
|
||||
|
||||
// Test public keys first
|
||||
[[]].forEach(function(usages) { // Only valid usages argument is empty array
|
||||
['spki', 'jwk'].forEach(function(format) {
|
||||
var algorithm = {name: vector.name};
|
||||
var data = keyData[vector.name];
|
||||
if (format === "jwk") { // Not all fields used for public keys
|
||||
data = {jwk: {kty: keyData[vector.name].jwk.kty, crv: keyData[vector.name].jwk.crv, x: keyData[vector.name].jwk.x}};
|
||||
}
|
||||
|
||||
testFormat(format, algorithm, data, vector.name, usages, extractable);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Next, test private keys
|
||||
allValidUsages(vector.privateUsages, []).forEach(function(usages) {
|
||||
['pkcs8', 'jwk'].forEach(function(format) {
|
||||
var algorithm = {name: vector.name};
|
||||
var data = keyData[vector.name];
|
||||
|
||||
testFormat(format, algorithm, data, vector.name, usages, extractable);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Test importKey with a given key format and other parameters. If
|
||||
// extrable is true, export the key and verify that it matches the input.
|
||||
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
|
||||
promise_test(function(test) {
|
||||
return subtle.importKey(format, keyData[format], algorithm, extractable, usages).
|
||||
then(function(key) {
|
||||
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
|
||||
if (!extractable) {
|
||||
return;
|
||||
}
|
||||
|
||||
return subtle.exportKey(format, key).
|
||||
then(function(result) {
|
||||
if (format !== "jwk") {
|
||||
assert_true(equalBuffers(keyData[format], result), "Round trip works");
|
||||
} else {
|
||||
assert_true(equalJwk(keyData[format], result), "Round trip works");
|
||||
}
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Helper methods follow:
|
||||
|
||||
// Are two array buffers the same?
|
||||
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;
|
||||
}
|
||||
|
||||
// Are two Jwk objects "the same"? That is, does the object returned include
|
||||
// matching values for each property that was expected? It's okay if the
|
||||
// returned object has extra methods; they aren't checked.
|
||||
function equalJwk(expected, got) {
|
||||
var fields = Object.keys(expected);
|
||||
var fieldName;
|
||||
|
||||
for(var i=0; i<fields.length; i++) {
|
||||
fieldName = fields[i];
|
||||
if (!(fieldName in got)) {
|
||||
return false;
|
||||
}
|
||||
if (expected[fieldName] !== got[fieldName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build minimal Jwk objects from raw key data and algorithm specifications
|
||||
function jwkData(keyData, algorithm) {
|
||||
var result = {
|
||||
kty: "oct",
|
||||
k: byteArrayToUnpaddedBase64(keyData)
|
||||
};
|
||||
|
||||
if (algorithm.name.substring(0, 3) === "AES") {
|
||||
result.alg = "A" + (8 * keyData.byteLength).toString() + algorithm.name.substring(4);
|
||||
} else if (algorithm.name === "HMAC") {
|
||||
result.alg = "HS" + algorithm.hash.substring(4);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Jwk format wants Base 64 without the typical padding at the end.
|
||||
function byteArrayToUnpaddedBase64(byteArray){
|
||||
var binaryString = "";
|
||||
for (var i=0; i<byteArray.byteLength; i++){
|
||||
binaryString += String.fromCharCode(byteArray[i]);
|
||||
}
|
||||
var base64String = btoa(binaryString);
|
||||
|
||||
return base64String.replace(/=/g, "");
|
||||
}
|
||||
|
||||
// Want to test every valid combination of usages. Start by creating a list
|
||||
// of all non-empty subsets to possible usages.
|
||||
function allNonemptySubsetsOf(arr) {
|
||||
var results = [];
|
||||
var firstElement;
|
||||
var remainingElements;
|
||||
|
||||
for(var i=0; i<arr.length; i++) {
|
||||
firstElement = arr[i];
|
||||
remainingElements = arr.slice(i+1);
|
||||
results.push([firstElement]);
|
||||
|
||||
if (remainingElements.length > 0) {
|
||||
allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
|
||||
combination.push(firstElement);
|
||||
results.push(combination);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Return a list of all valid usage combinations, given the possible ones
|
||||
// and the ones that are required for a particular operation.
|
||||
function allValidUsages(possibleUsages, requiredUsages) {
|
||||
var allUsages = [];
|
||||
|
||||
allNonemptySubsetsOf(possibleUsages).forEach(function(usage) {
|
||||
for (var i=0; i<requiredUsages.length; i++) {
|
||||
if (!usage.includes(requiredUsages[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
allUsages.push(usage);
|
||||
});
|
||||
|
||||
return allUsages;
|
||||
}
|
||||
|
||||
// Convert method parameters to a string to uniquely name each test
|
||||
function parameterString(format, data, algorithm, extractable, usages) {
|
||||
if ("byteLength" in data) {
|
||||
data = "buffer(" + data.byteLength.toString() + ")";
|
||||
} else {
|
||||
data = "object(" + Object.keys(data).join(", ") + ")";
|
||||
}
|
||||
var result = "(" +
|
||||
objectToString(format) + ", " +
|
||||
objectToString(data) + ", " +
|
||||
objectToString(algorithm) + ", " +
|
||||
objectToString(extractable) + ", " +
|
||||
objectToString(usages) +
|
||||
")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Character representation of any object we may use as a parameter.
|
||||
function objectToString(obj) {
|
||||
var keyValuePairs = [];
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else if (typeof obj === "object") {
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
|
||||
});
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
} else if (typeof obj === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
var keyValuePairs = [];
|
||||
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
var value = obj[keyName];
|
||||
if (typeof value === "object") {
|
||||
value = objectToString(value);
|
||||
} else if (typeof value === "array") {
|
||||
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
keyValuePairs.push(keyName + ": " + value);
|
||||
});
|
||||
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
}
|
|
@ -10,6 +10,7 @@ function run_test() {
|
|||
// 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) {
|
||||
|
@ -407,6 +408,32 @@ function run_test() {
|
|||
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)
|
||||
|
|
|
@ -57,28 +57,6 @@ function getTestVectors() {
|
|||
}
|
||||
}
|
||||
|
||||
// Old ASN.1 signatures below.
|
||||
// var signatures = {
|
||||
// "P-256": {
|
||||
// "SHA-1": new Uint8Array([48, 70, 2, 33, 0, 189, 178, 29, 63, 162, 177, 41, 146, 224, 212, 75, 195, 12, 201, 193, 68, 61, 21, 122, 25, 40, 54, 22, 203, 197, 247, 160, 97, 3, 157, 35, 146, 2, 33, 0, 202, 253, 208, 131, 220, 167, 213, 121, 60, 56, 76, 111, 93, 197, 64, 54, 149, 82, 23, 255, 65, 206, 208, 154, 16, 52, 250, 3, 135, 178, 223, 248]),
|
||||
// "SHA-256": new Uint8Array([48, 68, 2, 32, 91, 78, 119, 119, 168, 102, 87, 56, 106, 33, 140, 190, 53, 232, 207, 81, 251, 156, 33, 85, 156, 6, 1, 183, 61, 254, 248, 113, 89, 191, 223, 202, 2, 32, 9, 130, 207, 194, 45, 48, 4, 134, 19, 133, 121, 124, 93, 141, 29, 63, 26, 0, 167, 132, 123, 80, 240, 184, 69, 182, 18, 111, 211, 211, 139, 209]),
|
||||
// "SHA-384": new Uint8Array([48, 69, 2, 32, 62, 124, 63, 100, 198, 132, 82, 37, 86, 53, 94, 121, 230, 167, 204, 146, 92, 56, 129, 66, 185, 242, 140, 181, 218, 239, 217, 133, 15, 166, 13, 86, 2, 33, 0, 164, 128, 5, 101, 173, 76, 227, 174, 140, 27, 28, 83, 80, 176, 202, 44, 0, 137, 37, 16, 150, 14, 29, 149, 22, 134, 1, 2, 45, 15, 91, 154]),
|
||||
// "SHA-512": new Uint8Array([48, 70, 2, 33, 0, 163, 149, 177, 250, 180, 46, 8, 35, 168, 219, 191, 25, 152, 174, 171, 100, 155, 171, 41, 170, 10, 113, 108, 160, 26, 11, 161, 69, 216, 74, 105, 155, 2, 33, 0, 236, 60, 103, 71, 26, 48, 70, 157, 54, 252, 27, 92, 152, 227, 103, 164, 153, 71, 71, 155, 103, 109, 38, 163, 158, 118, 238, 66, 50, 43, 29, 14])
|
||||
// },
|
||||
// "P-384": {
|
||||
// "SHA-1": new Uint8Array([48, 100, 2, 48, 95, 88, 156, 202, 5, 12, 93, 174, 109, 126, 105, 41, 101, 6, 111, 143, 36, 14, 7, 57, 84, 139, 59, 112, 224, 57, 250, 236, 77, 184, 59, 102, 21, 149, 236, 134, 202, 147, 140, 244, 27, 204, 55, 75, 109, 245, 40, 218, 2, 48, 25, 244, 151, 221, 217, 106, 152, 238, 40, 59, 188, 50, 235, 147, 226, 44, 121, 16, 69, 231, 204, 59, 42, 174, 23, 80, 130, 170, 204, 34, 208, 154, 135, 143, 164, 94, 62, 226, 14, 100, 213, 229, 40, 176, 31, 148, 125, 75]),
|
||||
// "SHA-256": new Uint8Array([48, 102, 2, 49, 0, 171, 16, 188, 253, 115, 108, 16, 69, 39, 187, 21, 188, 22, 86, 146, 2, 212, 145, 7, 120, 218, 186, 149, 139, 205, 55, 114, 208, 25, 183, 127, 2, 198, 234, 151, 193, 94, 12, 173, 170, 234, 130, 83, 193, 214, 110, 108, 72, 2, 49, 0, 136, 132, 142, 128, 157, 111, 141, 240, 49, 203, 203, 32, 121, 165, 57, 138, 81, 95, 64, 235, 251, 241, 59, 203, 214, 169, 17, 153, 112, 115, 91, 51, 66, 206, 172, 143, 39, 0, 217, 68, 242, 172, 86, 155, 174, 24, 39, 155]),
|
||||
// "SHA-384": new Uint8Array([48, 102, 2, 49, 0, 227, 80, 5, 74, 3, 89, 195, 243, 249, 127, 97, 9, 62, 159, 116, 170, 52, 181, 161, 160, 213, 16, 10, 137, 120, 40, 244, 151, 155, 52, 2, 111, 41, 199, 65, 146, 146, 121, 176, 101, 240, 37, 147, 163, 92, 102, 70, 79, 2, 49, 0, 223, 182, 48, 0, 17, 216, 189, 37, 249, 104, 74, 195, 177, 87, 106, 14, 127, 86, 0, 139, 238, 6, 13, 130, 146, 12, 26, 166, 204, 169, 194, 27, 81, 170, 212, 2, 128, 235, 59, 159, 120, 79, 141, 151, 188, 132, 170, 70]),
|
||||
// "SHA-512": new Uint8Array([48, 102, 2, 49, 0, 188, 136, 210, 146, 118, 251, 132, 224, 144, 121, 109, 86, 162, 216, 12, 148, 108, 169, 42, 79, 32, 152, 167, 20, 173, 176, 28, 67, 219, 93, 52, 167, 76, 140, 102, 244, 118, 146, 193, 134, 116, 26, 83, 43, 230, 241, 215, 135, 2, 49, 0, 178, 120, 154, 88, 189, 55, 9, 240, 26, 169, 201, 53, 83, 207, 11, 6, 83, 54, 194, 126, 249, 188, 189, 32, 88, 190, 228, 166, 66, 104, 103, 243, 64, 214, 153, 84, 80, 175, 20, 205, 9, 85, 74, 233, 90, 184, 240, 153])
|
||||
// },
|
||||
// "P-521": {
|
||||
// "SHA-1": new Uint8Array([48, 129, 136, 2, 66, 1, 0, 159, 229, 63, 6, 27, 187, 208, 6, 90, 246, 116, 10, 87, 207, 237, 166, 143, 68, 223, 98, 232, 90, 95, 143, 20, 240, 164, 112, 19, 199, 4, 203, 196, 231, 179, 203, 229, 64, 51, 58, 224, 124, 97, 41, 235, 202, 28, 201, 52, 61, 76, 166, 233, 197, 247, 58, 37, 115, 146, 150, 142, 108, 176, 94, 2, 66, 1, 4, 164, 11, 249, 164, 172, 86, 59, 39, 111, 61, 210, 100, 176, 168, 243, 146, 236, 28, 21, 25, 97, 28, 56, 201, 159, 24, 97, 217, 178, 5, 13, 221, 64, 6, 39, 168, 54, 129, 3, 86, 157, 104, 87, 241, 92, 158, 142, 170, 27, 126, 138, 255, 44, 33, 161, 49, 192, 230, 186, 70, 42, 189, 124, 5]),
|
||||
// "SHA-256": new Uint8Array([48, 129, 134, 2, 65, 115, 189, 109, 44, 118, 67, 34, 176, 16, 126, 246, 157, 34, 188, 209, 65, 231, 207, 180, 139, 53, 97, 110, 157, 19, 55, 35, 134, 90, 160, 20, 252, 130, 210, 179, 22, 76, 3, 142, 212, 71, 48, 251, 64, 18, 148, 199, 234, 163, 193, 120, 13, 153, 63, 174, 253, 58, 34, 130, 88, 138, 194, 248, 173, 53, 2, 65, 63, 0, 229, 139, 245, 33, 197, 245, 98, 139, 59, 87, 144, 16, 220, 183, 237, 125, 136, 134, 143, 146, 195, 0, 209, 105, 217, 20, 121, 76, 64, 87, 232, 86, 87, 136, 117, 237, 39, 83, 248, 3, 50, 236, 152, 121, 37, 116, 93, 91, 241, 235, 152, 95, 177, 217, 45, 247, 66, 193, 248, 131, 205, 132, 74]),
|
||||
// "SHA-384": new Uint8Array([48, 129, 136, 2, 66, 0, 252, 248, 24, 253, 24, 36, 120, 84, 72, 47, 246, 13, 78, 112, 200, 131, 7, 131, 73, 235, 36, 93, 54, 219, 233, 242, 85, 1, 198, 187, 17, 17, 109, 13, 47, 204, 137, 224, 17, 6, 225, 178, 133, 98, 248, 53, 151, 33, 230, 160, 42, 208, 30, 230, 154, 108, 227, 123, 216, 215, 35, 179, 17, 91, 187, 2, 66, 1, 110, 43, 180, 40, 222, 59, 177, 3, 70, 177, 175, 118, 222, 31, 1, 46, 196, 237, 187, 15, 96, 241, 216, 136, 195, 194, 45, 163, 194, 92, 159, 179, 101, 194, 90, 141, 78, 28, 31, 199, 233, 228, 180, 223, 23, 171, 62, 247, 157, 62, 126, 90, 198, 132, 197, 34, 140, 227, 79, 190, 153, 137, 225, 226, 32]),
|
||||
// "SHA-512": new Uint8Array([48, 129, 136, 2, 66, 0, 228, 69, 122, 14, 172, 82, 52, 181, 42, 214, 42, 107, 227, 154, 253, 177, 145, 236, 231, 251, 71, 46, 202, 46, 59, 63, 76, 195, 63, 130, 8, 50, 116, 179, 181, 203, 234, 27, 203, 55, 188, 239, 122, 107, 167, 163, 190, 141, 174, 35, 22, 176, 173, 157, 212, 49, 21, 69, 72, 100, 78, 131, 147, 57, 223, 2, 66, 1, 107, 241, 89, 194, 8, 164, 44, 33, 11, 173, 236, 115, 153, 16, 90, 155, 164, 247, 232, 18, 226, 223, 62, 75, 246, 178, 66, 176, 51, 74, 161, 74, 76, 14, 227, 217, 19, 114, 36, 76, 168, 151, 191, 20, 58, 179, 162, 205, 140, 156, 227, 88, 59, 161, 245, 61, 170, 211, 254, 99, 120, 17, 174, 175, 52])
|
||||
// }
|
||||
// };
|
||||
|
||||
var vectors = [];
|
||||
["P-256", "P-384", "P-521"].forEach(function(curveName) {
|
||||
["SHA-1", "SHA-256", "SHA-384", "SHA-512"].forEach(function(hashName) {
|
||||
|
@ -103,3 +81,57 @@ function getTestVectors() {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
422
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/eddsa.js
Normal file
422
tests/wpt/web-platform-tests/WebCryptoAPI/sign_verify/eddsa.js
Normal file
|
@ -0,0 +1,422 @@
|
|||
|
||||
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");
|
||||
|
||||
// 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -155,11 +155,17 @@ function run_test() {
|
|||
|
||||
// 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) {
|
||||
|
@ -173,10 +179,10 @@ function run_test() {
|
|||
// 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 ("saltLength" in vector.algorithm && vector.algorithm.saltLength > 0) {
|
||||
assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures")
|
||||
} else {
|
||||
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 + "'");
|
||||
|
|
|
@ -64,7 +64,8 @@ run_test([%s]);
|
|||
done();"""
|
||||
|
||||
names = ["AES-CTR", "AES-CBC", "AES-GCM", "AES-KW", "HMAC", "RSASSA-PKCS1-v1_5",
|
||||
"RSA-PSS", "RSA-OAEP", "ECDSA", "ECDH"]
|
||||
"RSA-PSS", "RSA-OAEP", "ECDSA", "ECDH", "Ed25519", "Ed448", "X25519",
|
||||
"X448"]
|
||||
|
||||
for filename_pattern, template in [("test_successes_%s.https.html", successes_html),
|
||||
("test_failures_%s.https.html", failures_html),
|
||||
|
|
|
@ -20,7 +20,11 @@ var registeredAlgorithmNames = [
|
|||
"SHA-384",
|
||||
"SHA-512",
|
||||
"HKDF-CTR",
|
||||
"PBKDF2"
|
||||
"PBKDF2",
|
||||
"Ed25519",
|
||||
"Ed448",
|
||||
"X25519",
|
||||
"X448"
|
||||
];
|
||||
|
||||
|
||||
|
@ -106,7 +110,22 @@ function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
|
|||
assert_equals(key.extractable, extractable, "Extractability is correct");
|
||||
|
||||
assert_equals(key.algorithm.name, registeredAlgorithmName, "Correct algorithm name");
|
||||
assert_equals(key.algorithm.length, algorithm.length, "Correct length");
|
||||
if (key.algorithm.name.toUpperCase() === "HMAC" && algorithm.length === undefined) {
|
||||
switch (key.algorithm.hash.name.toUpperCase()) {
|
||||
case 'SHA-1':
|
||||
case 'SHA-256':
|
||||
assert_equals(key.algorithm.length, 512, "Correct length");
|
||||
break;
|
||||
case 'SHA-384':
|
||||
case 'SHA-512':
|
||||
assert_equals(key.algorithm.length, 1024, "Correct length");
|
||||
break;
|
||||
default:
|
||||
assert_unreached("Unrecognized hash");
|
||||
}
|
||||
} else {
|
||||
assert_equals(key.algorithm.length, algorithm.length, "Correct length");
|
||||
}
|
||||
if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS"].includes(registeredAlgorithmName)) {
|
||||
assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function");
|
||||
}
|
||||
|
@ -162,12 +181,16 @@ function allAlgorithmSpecifiersFor(algorithmName) {
|
|||
});
|
||||
} else if (algorithmName.toUpperCase() === "HMAC") {
|
||||
[
|
||||
{name: "SHA-1", length: 160},
|
||||
{name: "SHA-256", length: 256},
|
||||
{name: "SHA-384", length: 384},
|
||||
{name: "SHA-512", length: 512}
|
||||
{hash: "SHA-1", length: 160},
|
||||
{hash: "SHA-256", length: 256},
|
||||
{hash: "SHA-384", length: 384},
|
||||
{hash: "SHA-512", length: 512},
|
||||
{hash: "SHA-1"},
|
||||
{hash: "SHA-256"},
|
||||
{hash: "SHA-384"},
|
||||
{hash: "SHA-512"},
|
||||
].forEach(function(hashAlgorithm) {
|
||||
results.push({name: algorithmName, hash: hashAlgorithm.name, length: hashAlgorithm.length});
|
||||
results.push({name: algorithmName, ...hashAlgorithm});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
|
||||
hashes.forEach(function(hashName) {
|
||||
|
@ -177,6 +200,8 @@ function allAlgorithmSpecifiersFor(algorithmName) {
|
|||
curves.forEach(function(curveName) {
|
||||
results.push({name: algorithmName, namedCurve: curveName});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 1) === "X" || algorithmName.toUpperCase().substring(0, 2) === "ED") {
|
||||
results.push({ name: algorithmName });
|
||||
}
|
||||
|
||||
return results;
|
||||
|
@ -216,6 +241,9 @@ function allValidUsages(validUsages, emptyIsValid, mandatoryUsages) {
|
|||
return okaySubsets;
|
||||
}
|
||||
|
||||
function unique(names) {
|
||||
return [...new Set(names)];
|
||||
}
|
||||
|
||||
// Algorithm name specifiers are case-insensitive. Generate several
|
||||
// case variations of a given name.
|
||||
|
@ -227,5 +255,5 @@ function allNameVariants(name, slowTest) {
|
|||
// for slow tests effectively cut the amount of work in third by only
|
||||
// returning one variation
|
||||
if (slowTest) return [mixedCaseName];
|
||||
return [upCaseName, lowCaseName, mixedCaseName];
|
||||
return unique([upCaseName, lowCaseName, mixedCaseName]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue