function run_test(algorithmNames) { var subtle = crypto.subtle; // Change to test prefixed implementations setup({explicit_timeout: true}); // These tests check that importKey and exportKey throw 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 importKey, and all // valid and invalid parameters that should be checked later by // importKey. // // There are a lot of combinations of possible parameters for both // success and failure modes, resulting in a very large number of tests // performed. var allTestVectors = [ // Parameters that should work for importKey / exportKey {name: "Ed25519", privateUsages: ["sign"], publicUsages: ["verify"]}, {name: "Ed448", privateUsages: ["sign"], publicUsages: ["verify"]}, {name: "X25519", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}, {name: "X448", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []}, ]; var testVectors = []; if (algorithmNames && !Array.isArray(algorithmNames)) { algorithmNames = [algorithmNames]; }; allTestVectors.forEach(function(vector) { if (!algorithmNames || algorithmNames.includes(vector.name)) { testVectors.push(vector); } }); function parameterString(format, algorithm, extractable, usages, data) { if (typeof algorithm !== "object" && typeof algorithm !== "string") { alert(algorithm); } var jwk_label = ""; if (format === "jwk") jwk_label = data.d === undefined ? " (public) " : "(private)"; var result = "(" + objectToString(format) + jwk_label + ", " + 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(format, algorithm, keyData, keySize, usages, extractable, expectedError, testTag) { promise_test(async() => { let key; try { key = await subtle.importKey(format, keyData, algorithm, extractable, usages); } catch(err) { let actualError = typeof expectedError === "number" ? err.code : err.name; assert_equals(actualError, expectedError, testTag + " not supported."); } assert_equals(key, undefined, "Operation succeeded, but should not have."); }, testTag + ": importKey" + parameterString(format, algorithm, extractable, usages, keyData)); } // 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 = validUsages.length === 0 ? [] : allValidUsages(validUsages, false, mandatoryUsages); illegalUsages.forEach(function(illegalUsage) { results.push([illegalUsage]); goodUsageCombinations.forEach(function(usageCombination) { results.push(usageCombination.concat([illegalUsage])); }); }); return results; } function validUsages(usages, format, data) { if (format === 'spki' || format === 'raw') return usages.publicUsages if (format === 'pkcs8') return usages.privateUsages if (format === 'jwk') { if (data === undefined) return []; return data.d === undefined ? usages.publicUsages : usages.privateUsages; } return []; } // Now test for properly handling errors // - Unsupported algorithm // - Bad usages for algorithm // - Bad key lengths // - Lack of a mandatory format field // - Incompatible keys pair // 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; validKeyData.forEach(function(test) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { invalidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, usages, extractable, "SyntaxError", "Bad usages"); }); }); }); }); }); // Algorithms normalize okay, but usages bad (empty). // Should fail due to SyntaxError testVectors.forEach(function(vector) { var name = vector.name; validKeyData.filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && test.data.d)).forEach(function(test) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, [/* Empty usages */], extractable, "SyntaxError", "Empty usages"); }); }); }); }); // Algorithms normalize okay, usages ok. The length of the key must thouw a DataError exception. testVectors.forEach(function(vector) { var name = vector.name; badKeyLengthData.forEach(function(test) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { allValidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError(test.format, algorithm, test.data, name, usages, extractable, "DataError", "Bad key length"); }); }); }); }); }); // Algorithms normalize okay, usages ok and valid key. The lack of the mandatory JWK parameter must throw a syntax error. testVectors.forEach(function(vector) { var name = vector.name; missingJWKFieldKeyData.forEach(function(test) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { allValidUsages(validUsages(vector, 'jwk', test.data)).forEach(function(usages) { [true, false].forEach(function(extractable) { testError('jwk', algorithm, test.data, name, usages, extractable, "DataError", "Missing JWK '" + test.param + "' parameter"); }); }); }); }); }); // Algorithms normalize okay, usages ok and valid key. The public key is not compatible with the private key. testVectors.forEach(function(vector) { var name = vector.name; invalidJWKKeyData.forEach(function(data) { allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { allValidUsages(vector.privateUsages).forEach(function(usages) { [true].forEach(function(extractable) { testError('jwk', algorithm, data, name, usages, extractable, "DataError", "Invalid key pair"); }); }); }); }); }); }