Skip to content

Commit 99bfbed

Browse files
panvadanielleadams
authored andcommittedApr 3, 2023
test,crypto: update WebCryptoAPI WPT
PR-URL: #46575 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent c60816a commit 99bfbed

File tree

10 files changed

+125
-62
lines changed

10 files changed

+125
-62
lines changed
 

‎test/fixtures/wpt/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Last update:
3131
- user-timing: https://github.com/web-platform-tests/wpt/tree/df24fb604e/user-timing
3232
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/d8dbe6990b/wasm/jsapi
3333
- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi
34-
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/450f829d25/WebCryptoAPI
34+
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/238d9d9bac/WebCryptoAPI
3535
- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions
3636

3737
[Web Platform Tests]: https://github.com/web-platform-tests/wpt

‎test/fixtures/wpt/WebCryptoAPI/generateKey/successes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function run_test(algorithmNames, slowTest) {
6464
.then(function(result) {
6565
if (resultType === "CryptoKeyPair") {
6666
assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
67-
assert_goodCryptoKey(result.publicKey, algorithm, extractable, usages, "public");
67+
assert_goodCryptoKey(result.publicKey, algorithm, true, usages, "public");
6868
} else {
6969
assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
7070
}

‎test/fixtures/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// META: title=WebCryptoAPI: importKey() for EC keys
22
// META: timeout=long
3+
// META: script=../util/helpers.js
34

45
// Test importKey and exportKey for EC algorithms. Only "happy paths" are
56
// currently tested - those where the operation should succeed.
@@ -110,6 +111,7 @@
110111
return subtle.importKey(format, keyData, algorithm, extractable, usages).
111112
then(function(key) {
112113
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
114+
assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData.d)) ? 'private' : 'public');
113115
if (!extractable) {
114116
return;
115117
}

‎test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey.https.any.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// META: title=WebCryptoAPI: importKey() for OKP keys
22
// META: timeout=long
3+
// META: script=../util/helpers.js
34

45
// Test importKey and exportKey for OKP algorithms. Only "happy paths" are
56
// currently tested - those where the operation should succeed.
@@ -104,6 +105,7 @@
104105
return subtle.importKey(format, keyData[format], algorithm, extractable, usages).
105106
then(function(key) {
106107
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
108+
assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData[format].d)) ? 'private' : 'public');
107109
if (!extractable) {
108110
return;
109111
}

‎test/fixtures/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// META: title=WebCryptoAPI: importKey() for symmetric keys
22
// META: timeout=long
3+
// META: script=../util/helpers.js
34

45
// Test importKey and exportKey for non-PKC algorithms. Only "happy paths" are
56
// currently tested - those where the operation should succeed.
@@ -57,13 +58,18 @@
5758
});
5859
});
5960

61+
function hasLength(algorithm) {
62+
return algorithm.name === 'HMAC' || algorithm.name.startsWith('AES');
63+
}
64+
6065
// Test importKey with a given key format and other parameters. If
6166
// extrable is true, export the key and verify that it matches the input.
6267
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
6368
promise_test(function(test) {
6469
return subtle.importKey(format, keyData, algorithm, extractable, usages).
6570
then(function(key) {
6671
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
72+
assert_goodCryptoKey(key, hasLength(key.algorithm) ? { length: keySize, ...algorithm } : algorithm, extractable, usages, 'secret');
6773
if (!extractable) {
6874
return;
6975
}

‎test/fixtures/wpt/WebCryptoAPI/sign_verify/rsa.js

+29
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,35 @@ function run_test() {
306306
all_promises.push(promise);
307307
});
308308

309+
// [RSA-PSS] Verification should fail with wrong saltLength
310+
testVectors.forEach(function(vector) {
311+
if (vector.algorithm.name === "RSA-PSS") {
312+
var promise = importVectorKeys(vector, ["verify"], ["sign"])
313+
.then(function(vectors) {
314+
promise_test(function(test) {
315+
const saltLength = vector.algorithm.saltLength === 32 ? 48 : 32;
316+
var operation = subtle.verify({ ...vector.algorithm, saltLength }, vector.publicKey, vector.signature, vector.plaintext)
317+
.then(function(is_verified) {
318+
assert_false(is_verified, "Signature NOT verified");
319+
}, function(err) {
320+
assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'");
321+
});
322+
323+
return operation;
324+
}, vector.name + " verification failure with wrong saltLength");
325+
326+
}, function(err) {
327+
// We need a failed test if the importVectorKey operation fails, so
328+
// we know we never tested verification.
329+
promise_test(function(test) {
330+
assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''");
331+
}, "importVectorKeys step: " + vector.name + " verification failure with wrong saltLength");
332+
});
333+
334+
all_promises.push(promise);
335+
}
336+
});
337+
309338
// Verification should fail with wrong plaintext
310339
testVectors.forEach(function(vector) {
311340
var promise = importVectorKeys(vector, ["verify"], ["sign"])

‎test/fixtures/wpt/WebCryptoAPI/util/helpers.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var registeredAlgorithmNames = [
1919
"SHA-256",
2020
"SHA-384",
2121
"SHA-512",
22-
"HKDF-CTR",
22+
"HKDF",
2323
"PBKDF2",
2424
"Ed25519",
2525
"Ed448",
@@ -104,9 +104,6 @@ function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
104104

105105
assert_equals(key.constructor, CryptoKey, "Is a CryptoKey");
106106
assert_equals(key.type, kind, "Is a " + kind + " key");
107-
if (key.type === "public") {
108-
extractable = true; // public keys are always extractable
109-
}
110107
assert_equals(key.extractable, extractable, "Extractability is correct");
111108

112109
assert_equals(key.algorithm.name, registeredAlgorithmName, "Correct algorithm name");
@@ -130,6 +127,10 @@ function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
130127
assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function");
131128
}
132129

130+
if (/^(?:Ed|X)(?:25519|448)$/.test(key.algorithm.name)) {
131+
assert_false('namedCurve' in key.algorithm, "Does not have a namedCurve property");
132+
}
133+
133134
// usages is expected to be provided for a key pair, but we are checking
134135
// only a single key. The publicKey and privateKey portions of a key pair
135136
// recognize only some of the usages appropriate for a key pair.

‎test/fixtures/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js

+76-55
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77

88
var wrappers = []; // Things we wrap (and upwrap) keys with
99
var keys = []; // Things to wrap and unwrap
10-
var ecdhPeerKey; // ECDH peer public key needed for non-extractable ECDH key comparison
1110

1211
// Generate all the keys needed, then iterate over all combinations
1312
// to test wrapping and unwrapping.
1413
promise_test(function() {
15-
return Promise.all([generateWrappingKeys(), generateKeysToWrap(), generateEcdhPeerKey()])
14+
return Promise.all([generateWrappingKeys(), generateKeysToWrap()])
1615
.then(function(results) {
1716
var promises = [];
1817
wrappers.forEach(function(wrapper) {
@@ -83,6 +82,9 @@
8382
{algorithm: {name: "ECDSA", namedCurve: "P-256"}, privateUsages: ["sign"], publicUsages: ["verify"]},
8483
{algorithm: {name: "ECDH", namedCurve: "P-256"}, privateUsages: ["deriveBits"], publicUsages: []},
8584
{algorithm: {name: "Ed25519" }, privateUsages: ["sign"], publicUsages: ["verify"]},
85+
{algorithm: {name: "Ed448" }, privateUsages: ["sign"], publicUsages: ["verify"]},
86+
{algorithm: {name: "X25519" }, privateUsages: ["deriveBits"], publicUsages: []},
87+
{algorithm: {name: "X448" }, privateUsages: ["deriveBits"], publicUsages: []},
8688
{algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]},
8789
{algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]},
8890
{algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]},
@@ -112,13 +114,6 @@
112114
}));
113115
}
114116

115-
function generateEcdhPeerKey() {
116-
return subtle.generateKey({name: "ECDH", namedCurve: "P-256"},true,["deriveBits"])
117-
.then(function(result){
118-
ecdhPeerKey = result.publicKey;
119-
});
120-
}
121-
122117
// Can we successfully "round-trip" (wrap, then unwrap, a key)?
123118
function testWrapping(wrapper, toWrap) {
124119
var formats;
@@ -135,58 +130,72 @@
135130
var originalExport;
136131
return subtle.exportKey(fmt, toWrap.key).then(function(exportedKey) {
137132
originalExport = exportedKey;
138-
if (wrappingIsPossible(originalExport, wrapper.parameters.name)) {
139-
promise_test(function(test) {
133+
const isPossible = wrappingIsPossible(originalExport, wrapper.parameters.name);
134+
promise_test(function(test) {
135+
if (!isPossible) {
136+
return Promise.resolve().then(() => {
137+
assert_false(false, "Wrapping is not possible");
138+
})
139+
}
140+
return subtle.wrapKey(fmt, toWrap.key, wrapper.wrappingKey, wrapper.parameters.wrapParameters)
141+
.then(function(wrappedResult) {
142+
return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages);
143+
}).then(function(unwrappedResult) {
144+
assert_true(unwrappedResult.extractable, "Unwrapped result is extractable");
145+
return subtle.exportKey(fmt, unwrappedResult)
146+
}).then(function(roundTripExport) {
147+
assert_true(equalExport(originalExport, roundTripExport), "Post-wrap export matches original export");
148+
}, function(err) {
149+
assert_unreached("Round trip for extractable key threw an error - " + err.name + ': "' + err.message + '"');
150+
});
151+
}, "Can wrap and unwrap " + toWrap.name + " keys using " + fmt + " and " + wrapper.parameters.name);
152+
153+
if (canCompareNonExtractableKeys(toWrap.key)) {
154+
promise_test(function(test){
155+
if (!isPossible) {
156+
return Promise.resolve().then(() => {
157+
assert_false(false, "Wrapping is not possible");
158+
})
159+
}
140160
return subtle.wrapKey(fmt, toWrap.key, wrapper.wrappingKey, wrapper.parameters.wrapParameters)
141161
.then(function(wrappedResult) {
142-
return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages);
143-
}).then(function(unwrappedResult) {
144-
assert_true(unwrappedResult.extractable, "Unwrapped result is extractable");
145-
return subtle.exportKey(fmt, unwrappedResult)
146-
}).then(function(roundTripExport) {
147-
assert_true(equalExport(originalExport, roundTripExport), "Post-wrap export matches original export");
148-
}, function(err) {
149-
assert_unreached("Round trip for extractable key threw an error - " + err.name + ': "' + err.message + '"');
162+
return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, false, toWrap.usages);
163+
}).then(function(unwrappedResult){
164+
assert_false(unwrappedResult.extractable, "Unwrapped result is non-extractable");
165+
return equalKeys(toWrap.key, unwrappedResult);
166+
}).then(function(result){
167+
assert_true(result, "Unwrapped key matches original");
168+
}).catch(function(err){
169+
assert_unreached("Round trip for key unwrapped non-extractable threw an error - " + err.name + ': "' + err.message + '"');
150170
});
151-
}, "Can wrap and unwrap " + toWrap.name + " keys using " + fmt + " and " + wrapper.parameters.name);
171+
}, "Can wrap and unwrap " + toWrap.name + " keys as non-extractable using " + fmt + " and " + wrapper.parameters.name);
152172

153-
if (canCompareNonExtractableKeys(toWrap.key)) {
173+
if (fmt === "jwk") {
154174
promise_test(function(test){
155-
return subtle.wrapKey(fmt, toWrap.key, wrapper.wrappingKey, wrapper.parameters.wrapParameters)
156-
.then(function(wrappedResult) {
157-
return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, false, toWrap.usages);
175+
if (!isPossible) {
176+
return Promise.resolve().then(() => {
177+
assert_false(false, "Wrapping is not possible");
178+
})
179+
}
180+
var wrappedKey;
181+
return wrapAsNonExtractableJwk(toWrap.key,wrapper).then(function(wrappedResult){
182+
wrappedKey = wrappedResult;
183+
return subtle.unwrapKey("jwk", wrappedKey, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, false, toWrap.usages);
158184
}).then(function(unwrappedResult){
159-
assert_false(unwrappedResult.extractable, "Unwrapped result is non-extractable");
160-
return equalKeys(toWrap.key, unwrappedResult);
185+
assert_false(unwrappedResult.extractable, "Unwrapped key is non-extractable");
186+
return equalKeys(toWrap.key,unwrappedResult);
161187
}).then(function(result){
162188
assert_true(result, "Unwrapped key matches original");
163189
}).catch(function(err){
164-
assert_unreached("Round trip for key unwrapped non-extractable threw an error - " + err.name + ': "' + err.message + '"');
190+
assert_unreached("Round trip for non-extractable key threw an error - " + err.name + ': "' + err.message + '"');
191+
}).then(function(){
192+
return subtle.unwrapKey("jwk", wrappedKey, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages);
193+
}).then(function(unwrappedResult){
194+
assert_unreached("Unwrapping a non-extractable JWK as extractable should fail");
195+
}).catch(function(err){
196+
assert_equals(err.name, "DataError", "Unwrapping a non-extractable JWK as extractable fails with DataError");
165197
});
166-
}, "Can wrap and unwrap " + toWrap.name + " keys as non-extractable using " + fmt + " and " + wrapper.parameters.name);
167-
168-
if (fmt === "jwk") {
169-
promise_test(function(test){
170-
var wrappedKey;
171-
return wrapAsNonExtractableJwk(toWrap.key,wrapper).then(function(wrappedResult){
172-
wrappedKey = wrappedResult;
173-
return subtle.unwrapKey("jwk", wrappedKey, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, false, toWrap.usages);
174-
}).then(function(unwrappedResult){
175-
assert_false(unwrappedResult.extractable, "Unwrapped key is non-extractable");
176-
return equalKeys(toWrap.key,unwrappedResult);
177-
}).then(function(result){
178-
assert_true(result, "Unwrapped key matches original");
179-
}).catch(function(err){
180-
assert_unreached("Round trip for non-extractable key threw an error - " + err.name + ': "' + err.message + '"');
181-
}).then(function(){
182-
return subtle.unwrapKey("jwk", wrappedKey, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages);
183-
}).then(function(unwrappedResult){
184-
assert_unreached("Unwrapping a non-extractable JWK as extractable should fail");
185-
}).catch(function(err){
186-
assert_equals(err.name, "DataError", "Unwrapping a non-extractable JWK as extractable fails with DataError");
187-
});
188-
}, "Can unwrap " + toWrap.name + " non-extractable keys using jwk and " + wrapper.parameters.name);
189-
}
198+
}, "Can unwrap " + toWrap.name + " non-extractable keys using jwk and " + wrapper.parameters.name);
190199
}
191200
}
192201
});
@@ -386,14 +395,23 @@
386395
case "Ed25519" :
387396
signParams = {name: "Ed25519"};
388397
break;
398+
case "Ed448" :
399+
signParams = {name: "Ed448"};
400+
break;
401+
case "X25519" :
402+
deriveParams = {name: "X25519"};
403+
break;
404+
case "X448" :
405+
deriveParams = {name: "X448"};
406+
break;
389407
case "HMAC" :
390408
signParams = {name: "HMAC"};
391409
break;
392410
case "AES-KW" :
393411
wrapParams = {name: "AES-KW"};
394412
break;
395413
case "ECDH" :
396-
deriveParams = {name: "ECDH", public: ecdhPeerKey};
414+
deriveParams = {name: "ECDH"};
397415
break;
398416
default:
399417
throw new Error("Unsupported algorithm for key comparison");
@@ -422,7 +440,7 @@
422440
if (expected.algorithm.name === "RSA-PSS" || expected.algorithm.name === "RSASSA-PKCS1-v1_5") {
423441
["d","p","q","dp","dq","qi","oth"].forEach(function(field){ delete jwkExpectedKey[field]; });
424442
}
425-
if (expected.algorithm.name === "ECDSA" || expected.algorithm.name === "Ed25519") {
443+
if (expected.algorithm.name === "ECDSA" || expected.algorithm.name.startsWith("Ed")) {
426444
delete jwkExpectedKey["d"];
427445
}
428446
jwkExpectedKey.key_ops = ["verify"];
@@ -446,9 +464,12 @@
446464
var wrappedWithGot = Array.from((new Uint8Array(wrapResult)).values());
447465
return wrappedWithGot.every((x,i) => x === wrappedWithExpected[i]);
448466
});
449-
} else {
467+
} else if (deriveParams) {
450468
var expectedDerivedBits;
451-
return subtle.deriveBits(deriveParams, expected, 128)
469+
return subtle.generateKey(expected.algorithm, true, ['deriveBits']).then(({ publicKey }) => {
470+
deriveParams.public = publicKey;
471+
return subtle.deriveBits(deriveParams, expected, 128)
472+
})
452473
.then(function(result){
453474
expectedDerivedBits = Array.from((new Uint8Array(result)).values());
454475
return subtle.deriveBits(deriveParams, got, 128);

‎test/fixtures/wpt/versions.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
"path": "wasm/webapi"
8585
},
8686
"WebCryptoAPI": {
87-
"commit": "450f829d2567ed9c44bd9b10f7e8f34a2ad15315",
87+
"commit": "238d9d9bac54d4f1ae8844fc8dd4389b1ad99b4e",
8888
"path": "WebCryptoAPI"
8989
},
9090
"webidl/ecmascript-binding/es-exceptions": {

0 commit comments

Comments
 (0)
Please sign in to comment.