mirror of
https://github.com/servo/servo.git
synced 2025-06-24 09:04:33 +01:00
213 lines
9 KiB
JavaScript
213 lines
9 KiB
JavaScript
function run_test(algorithmNames) {
|
|
var subtle = crypto.subtle; // Change to test prefixed implementations
|
|
|
|
setup({explicit_timeout: true});
|
|
|
|
// These tests check that generateKey throws an error, and that
|
|
// the error is of the right type, for a wide set of incorrect parameters.
|
|
//
|
|
// Error testing occurs by setting the parameter that should trigger the
|
|
// error to an invalid value, then combining that with all valid
|
|
// parameters that should be checked earlier by generateKey, and all
|
|
// valid and invalid parameters that should be checked later by
|
|
// generateKey.
|
|
//
|
|
// There are a lot of combinations of possible parameters for both
|
|
// success and failure modes, resulting in a very large number of tests
|
|
// performed.
|
|
|
|
|
|
// Setup: define the correct behaviors that should be sought, and create
|
|
// helper functions that generate all possible test parameters for
|
|
// different situations.
|
|
|
|
var allTestVectors = [ // Parameters that should work for generateKey
|
|
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
|
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
|
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
|
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
|
|
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
|
|
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
|
{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"]}
|
|
];
|
|
|
|
var testVectors = [];
|
|
allTestVectors.forEach(function(vector) {
|
|
if (!algorithmNames || algorithmNames.includes(vector.name)) {
|
|
testVectors.push(vector);
|
|
}
|
|
});
|
|
|
|
|
|
function parameterString(algorithm, extractable, usages) {
|
|
if (typeof algorithm !== "object" && typeof algorithm !== "string") {
|
|
alert(algorithm);
|
|
}
|
|
|
|
var result = "(" +
|
|
objectToString(algorithm) + ", " +
|
|
objectToString(extractable) + ", " +
|
|
objectToString(usages) +
|
|
")";
|
|
|
|
return result;
|
|
}
|
|
|
|
// Test that a given combination of parameters results in an error,
|
|
// AND that it is the correct kind of error.
|
|
//
|
|
// Expected error is either a number, tested against the error code,
|
|
// or a string, tested against the error name.
|
|
function testError(algorithm, extractable, usages, expectedError, testTag) {
|
|
promise_test(function(test) {
|
|
return crypto.subtle.generateKey(algorithm, extractable, usages)
|
|
.then(function(result) {
|
|
assert_unreached("Operation succeeded, but should not have");
|
|
}, function(err) {
|
|
if (typeof expectedError === "number") {
|
|
assert_equals(err.code, expectedError, testTag + " not supported");
|
|
} else {
|
|
assert_equals(err.name, expectedError, testTag + " not supported");
|
|
}
|
|
});
|
|
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
|
|
}
|
|
|
|
|
|
// Given an algorithm name, create several invalid parameters.
|
|
function badAlgorithmPropertySpecifiersFor(algorithmName) {
|
|
var results = [];
|
|
|
|
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
|
|
// Specifier properties are name and length
|
|
[64, 127, 129, 255, 257, 512].forEach(function(length) {
|
|
results.push({name: algorithmName, length: length});
|
|
});
|
|
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
|
|
[new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
|
|
results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
|
|
});
|
|
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
|
|
["P-512", "Curve25519"].forEach(function(curveName) {
|
|
results.push({name: algorithmName, namedCurve: curveName});
|
|
});
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
// Don't create an exhaustive list of all invalid usages,
|
|
// because there would usually be nearly 2**8 of them,
|
|
// way too many to test. Instead, create every singleton
|
|
// of an illegal usage, and "poison" every valid usage
|
|
// with an illegal one.
|
|
function invalidUsages(validUsages, mandatoryUsages) {
|
|
var results = [];
|
|
|
|
var illegalUsages = [];
|
|
["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
|
|
if (!validUsages.includes(usage)) {
|
|
illegalUsages.push(usage);
|
|
}
|
|
});
|
|
|
|
var goodUsageCombinations = allValidUsages(validUsages, false, mandatoryUsages);
|
|
|
|
illegalUsages.forEach(function(illegalUsage) {
|
|
results.push([illegalUsage]);
|
|
goodUsageCombinations.forEach(function(usageCombination) {
|
|
results.push(usageCombination.concat([illegalUsage]));
|
|
});
|
|
});
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
// Now test for properly handling errors
|
|
// - Unsupported algorithm
|
|
// - Bad usages for algorithm
|
|
// - Bad key lengths
|
|
|
|
// Algorithm normalization should fail with "Not supported"
|
|
var badAlgorithmNames = [
|
|
"AES",
|
|
{name: "AES"},
|
|
{name: "AES", length: 128},
|
|
{name: "AES-CMAC", length: 128}, // Removed after CR
|
|
{name: "AES-CFB", length: 128}, // Removed after CR
|
|
{name: "HMAC", hash: "MD5"},
|
|
{name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
|
|
{name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
|
|
{name: "EC", namedCurve: "P521"}
|
|
];
|
|
|
|
|
|
// Algorithm normalization failures should be found first
|
|
// - all other parameters can be good or bad, should fail
|
|
// due to NotSupportedError.
|
|
badAlgorithmNames.forEach(function(algorithm) {
|
|
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
|
|
.forEach(function(usages) {
|
|
[false, true, "RED", 7].forEach(function(extractable){
|
|
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
// Algorithms normalize okay, but usages bad (though not empty).
|
|
// It shouldn't matter what other extractable is. Should fail
|
|
// due to SyntaxError
|
|
testVectors.forEach(function(vector) {
|
|
var name = vector.name;
|
|
|
|
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
|
|
invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
|
|
[true].forEach(function(extractable) {
|
|
testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
// Other algorithm properties should be checked next, so try good
|
|
// algorithm names and usages, but bad algorithm properties next.
|
|
// - Special case: normally bad usage [] isn't checked until after properties,
|
|
// so it's included in this test case. It should NOT cause an error.
|
|
testVectors.forEach(function(vector) {
|
|
var name = vector.name;
|
|
badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
|
|
allValidUsages(vector.usages, true, vector.mandatoryUsages)
|
|
.forEach(function(usages) {
|
|
[false, true].forEach(function(extractable) {
|
|
if (name.substring(0,2) === "EC") {
|
|
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
|
|
} else {
|
|
testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
// The last thing that should be checked is an empty usages (for secret keys).
|
|
testVectors.forEach(function(vector) {
|
|
var name = vector.name;
|
|
|
|
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
|
|
var usages = [];
|
|
[false, true].forEach(function(extractable) {
|
|
testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
}
|