Skip to content

Commit

Permalink
test,crypto: update WebCryptoAPI WPT
Browse files Browse the repository at this point in the history
PR-URL: #45569
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
  • Loading branch information
panva authored and targos committed Dec 12, 2022
1 parent 7892e23 commit 358e2fe
Show file tree
Hide file tree
Showing 13 changed files with 847 additions and 30 deletions.
2 changes: 1 addition & 1 deletion test/fixtures/wpt/README.md
Expand Up @@ -32,7 +32,7 @@ Last update:
- user-timing: https://github.com/web-platform-tests/wpt/tree/df24fb604e/user-timing
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/d8dbe6990b/wasm/jsapi
- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/0042d42ee6/WebCryptoAPI
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/21ccdcd814/WebCryptoAPI
- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions

[Web Platform Tests]: https://github.com/web-platform-tests/wpt
Expand Down
176 changes: 176 additions & 0 deletions test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js
@@ -0,0 +1,176 @@
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') 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, 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");
});
});
});
});
});
}
@@ -0,0 +1,102 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures.js

// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var validKeyData = [
{
format: "spki",
data: 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])
},
{
format: "pkcs8",
data: 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])
},
{
format: "jwk",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed25519",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
},
},
];

// Removed just the last byte.
var badKeyLengthData = [
{
format: "spki",
data: 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])
},
{
format: "pkcs8",
data: 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])
},
{
format: "jwk",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPcw",
kty: "OKP"
}
},
{
format: "jwk",
data: {
crv: "Ed25519",
x: "2OGJY9gJ1IfZVJrMrsZ0Ln7rok2KDTsUt-PK6gaJPc",
kty: "OKP"
}
},
];

var missingJWKFieldKeyData = [
{
param: "x",
data: {
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
kty: "OKP"
},
},
{
param: "kty",
data: {
crv: "Ed25519",
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
},
},
{
param: "crv",
data: {
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
kty: "OKP"
},
}
];

// The public key doesn't match the private key.
var invalidJWKKeyData = [
{
crv: "Ed25519",
d: "88j0xI34eBRujNO_bfTlDjibpwdOFcI1Lc1dMI1MqB8",
x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
kty: "OKP"
},
];

run_test(["Ed25519"]);
@@ -0,0 +1,103 @@
// META: title=WebCryptoAPI: importKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=okp_importKey_failures.js

// Setup: define the correct behaviors that should be sought, and create
// helper functions that generate all possible test parameters for
// different situations.
var validKeyData = [
{
format: "spki",
data: 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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed448",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
];

// Removed just the last byte.
var badKeyLengthData = [
{
format: "spki",
data: 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]),
},
{
format: "pkcs8",
data: 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]),
},
{
format: "jwk",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
},
},
{
format: "jwk",
data: {
crv: "Ed448",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalq",
kty: "OKP"
},
},
];

var missingJWKFieldKeyData = [
{
param: "x",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
kty: "OKP"
}
},
{
param: "kty",
data: {
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
}
},
{
param: "crv",
data: {
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "q0u4hf19LFryToNxDP-gx0pX4nSAHbIFewvcXqAytv5rx4uARTZa6ybobh8U_TSdB8SElfWkalqA",
kty: "OKP"
}
}
];

// The public key doesn't match the private key.
var invalidJWKKeyData = [
{
crv: "Ed448",
d: "Dv8DRYwo4BecUh3jEslpt4NDSOyrmRpg47Lpp55M2eSA7ykXEtLIPQRyctXJ9ChmT2ltJnBFjx0u",
x: "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA",
kty: "OKP"
},
];

run_test(["Ed448"]);

0 comments on commit 358e2fe

Please sign in to comment.