Skip to content

Commit 892a5df

Browse files
committed
fixup! crypto: improve accuracy of SubtleCrypto.supports
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent cc76732 commit 892a5df

4 files changed

Lines changed: 337 additions & 2 deletions

File tree

test/fixtures/wpt/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Last update:
3434
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/65a2134d50/wasm/jsapi
3535
- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi
3636
- web-locks: https://github.com/web-platform-tests/wpt/tree/10a122a6bc/web-locks
37-
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/2cb332d710/WebCryptoAPI
37+
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/8b5cd267b4/WebCryptoAPI
3838
- webidl: https://github.com/web-platform-tests/wpt/tree/63ca529a02/webidl
3939
- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/2f96fa1996/webidl/ecmascript-binding/es-exceptions
4040
- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/6495c91853/webmessaging/broadcastchannel
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// META: title=WebCrypto API: supports method tests for algorithms in https://wicg.github.io/webcrypto-modern-algos/
2+
// META: script=util/helpers.js
3+
4+
'use strict';
5+
6+
const modernAlgorithms = {
7+
// Asymmetric algorithms
8+
'ML-DSA-44': {
9+
operations: ['generateKey', 'importKey', 'sign', 'verify'],
10+
},
11+
'ML-DSA-65': {
12+
operations: ['generateKey', 'importKey', 'sign', 'verify'],
13+
},
14+
'ML-DSA-87': {
15+
operations: ['generateKey', 'importKey', 'sign', 'verify'],
16+
},
17+
'ML-KEM-512': {
18+
operations: [
19+
'generateKey', 'importKey', 'encapsulateKey', 'encapsulateBits',
20+
'decapsulateKey', 'decapsulateBits'
21+
],
22+
},
23+
'ML-KEM-768': {
24+
operations: [
25+
'generateKey', 'importKey', 'encapsulateKey', 'encapsulateBits',
26+
'decapsulateKey', 'decapsulateBits'
27+
],
28+
},
29+
'ML-KEM-1024': {
30+
operations: [
31+
'generateKey', 'importKey', 'encapsulateKey', 'encapsulateBits',
32+
'decapsulateKey', 'decapsulateBits'
33+
],
34+
},
35+
36+
// Symmetric algorithms
37+
'ChaCha20-Poly1305': {
38+
operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'],
39+
encryptParams: {name: 'ChaCha20-Poly1305', iv: new Uint8Array(12)},
40+
},
41+
42+
};
43+
44+
const operations = [
45+
'generateKey',
46+
'importKey',
47+
'sign',
48+
'verify',
49+
'encrypt',
50+
'decrypt',
51+
'deriveBits',
52+
'digest',
53+
'encapsulateKey',
54+
'encapsulateBits',
55+
'decapsulateKey',
56+
'decapsulateBits',
57+
];
58+
59+
// Test that supports method exists and is a static method
60+
test(() => {
61+
assert_true(
62+
typeof SubtleCrypto.supports === 'function',
63+
'SubtleCrypto.supports should be a function');
64+
}, 'SubtleCrypto.supports method exists');
65+
66+
67+
// Test standard WebCrypto algorithms for requested operations
68+
for (const [algorithmName, algorithmInfo] of Object.entries(modernAlgorithms)) {
69+
for (const operation of operations) {
70+
promise_test(async (t) => {
71+
const isSupported = algorithmInfo.operations.includes(operation);
72+
73+
// Use appropriate algorithm parameters for each operation
74+
let algorithm;
75+
let lengthOrAdditionalAlgorithm;
76+
switch (operation) {
77+
case 'generateKey':
78+
algorithm = algorithmInfo.keyGenParams || algorithmName;
79+
break;
80+
case 'importKey':
81+
algorithm = algorithmInfo.importParams || algorithmName;
82+
break;
83+
case 'sign':
84+
case 'verify':
85+
algorithm = algorithmInfo.signParams || algorithmName;
86+
break;
87+
case 'encrypt':
88+
case 'decrypt':
89+
algorithm = algorithmInfo.encryptParams || algorithmName;
90+
break;
91+
case 'deriveBits':
92+
algorithm = algorithmInfo.deriveBitsParams || algorithmName;
93+
if (algorithm?.public instanceof Promise) {
94+
algorithm.public = (await algorithm.public).publicKey;
95+
}
96+
if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') {
97+
lengthOrAdditionalAlgorithm = 256;
98+
}
99+
break;
100+
case 'digest':
101+
algorithm = algorithmName;
102+
break;
103+
case 'encapsulateKey':
104+
case 'encapsulateBits':
105+
case 'decapsulateKey':
106+
case 'decapsulateBits':
107+
algorithm = algorithmName;
108+
if (operation === 'encapsulateKey' || operation === 'decapsulateKey') {
109+
lengthOrAdditionalAlgorithm = { name: 'AES-GCM', length: 256 };
110+
}
111+
break;
112+
default:
113+
algorithm = algorithmName;
114+
}
115+
116+
const result = SubtleCrypto.supports(operation, algorithm, lengthOrAdditionalAlgorithm);
117+
118+
if (isSupported) {
119+
assert_true(result, `${algorithmName} should support ${operation}`);
120+
} else {
121+
assert_false(
122+
result, `${algorithmName} should not support ${operation}`);
123+
}
124+
}, `supports(${operation}, ${algorithmName})`);
125+
}
126+
}
127+
128+
// Test some algorithm objects with valid parameters
129+
test(() => {
130+
assert_true(
131+
SubtleCrypto.supports('encrypt', {
132+
name: 'ChaCha20-Poly1305',
133+
iv: new Uint8Array(12),
134+
tagLength: 128,
135+
}),
136+
'ChaCha20-Poly1305 encrypt with valid tagLength');
137+
}, 'supports returns true for algorithm objects with valid parameters');
138+
139+
// Test some algorithm objects with invalid parameters
140+
test(() => {
141+
assert_false(
142+
SubtleCrypto.supports('encrypt', {
143+
name: 'ChaCha20-Poly1305',
144+
iv: new Uint8Array(12),
145+
tagLength: 100,
146+
}),
147+
'ChaCha20-Poly1305 encrypt with invalid tagLength');
148+
149+
assert_false(
150+
SubtleCrypto.supports('encrypt', {
151+
name: 'ChaCha20-Poly1305',
152+
iv: new Uint8Array(10),
153+
tagLength: 128,
154+
}),
155+
'ChaCha20-Poly1305 encrypt with invalid iv');
156+
}, 'supports returns false for algorithm objects with invalid parameters');
157+
158+
159+
done();

test/fixtures/wpt/WebCryptoAPI/supports.tentative.https.any.js

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,137 @@ test(() => {
268268
}),
269269
'Invalid hash parameter should return false'
270270
);
271+
assert_false(
272+
SubtleCrypto.supports(
273+
'encrypt', {name: 'AES-CBC', iv: new Uint8Array(10)}),
274+
'Invalid IV for AES-CBC should return false');
275+
assert_false(
276+
SubtleCrypto.supports('encrypt', {
277+
name: 'AES-CTR',
278+
counter: new Uint8Array(10),
279+
length: 128,
280+
}),
281+
'Invalid IV for AES-CTR should return false');
282+
assert_false(
283+
SubtleCrypto.supports('encrypt', {
284+
name: 'AES-CTR',
285+
counter: new Uint8Array(16),
286+
length: 0,
287+
}),
288+
'Invalid length=0 for AES-CTR should return false');
289+
assert_false(
290+
SubtleCrypto.supports('encrypt', {
291+
name: 'AES-CTR',
292+
counter: new Uint8Array(16),
293+
length: 129,
294+
}),
295+
'Invalid length=129 for AES-CTR should return false');
296+
assert_false(
297+
SubtleCrypto.supports('encrypt', {
298+
name: 'AES-GCM',
299+
iv: new Uint8Array(16),
300+
tagLength: 100,
301+
}),
302+
'Invalid tag length for AES-GCM should return false');
303+
assert_false(
304+
SubtleCrypto.supports('generateKey', {name: 'ECDH', namedCurve: 'P-51'}),
305+
'Invalid curve for ECDH should return false');
306+
assert_false(
307+
SubtleCrypto.supports(
308+
'deriveBits', {
309+
name: 'HKDF',
310+
hash: 'SHA-25',
311+
salt: new Uint8Array(16),
312+
info: new Uint8Array(0),
313+
},
314+
8),
315+
'Invalid hash for HKDF should return false');
316+
assert_false(
317+
SubtleCrypto.supports(
318+
'deriveBits', {
319+
name: 'HKDF',
320+
hash: 'SHA-256',
321+
salt: new Uint8Array(16),
322+
info: new Uint8Array(0),
323+
},
324+
11),
325+
'Invalid length for HKDF should return false');
326+
assert_false(
327+
SubtleCrypto.supports(
328+
'deriveBits', {
329+
name: 'HKDF',
330+
hash: 'SHA-256',
331+
salt: new Uint8Array(16),
332+
info: new Uint8Array(0),
333+
}),
334+
'null length for HKDF should return false');
335+
assert_false(
336+
SubtleCrypto.supports('generateKey', {
337+
name: 'HMAC',
338+
hash: 'SHA-25',
339+
}),
340+
'Invalid hash for HMAC should return false');
341+
assert_false(
342+
SubtleCrypto.supports('generateKey', {
343+
name: 'HMAC',
344+
hash: 'SHA-256',
345+
length: 0,
346+
}),
347+
'Invalid length for HMAC should return false');
348+
assert_false(
349+
SubtleCrypto.supports(
350+
'deriveBits', {
351+
name: 'PBKDF2',
352+
hash: 'SHA-25',
353+
salt: new Uint8Array(16),
354+
iterations: 100000,
355+
},
356+
8),
357+
'Invalid hash for PBKDF2 should return false');
358+
assert_false(
359+
SubtleCrypto.supports(
360+
'deriveBits', {
361+
name: 'PBKDF2',
362+
hash: 'SHA-256',
363+
salt: new Uint8Array(16),
364+
iterations: 100000,
365+
},
366+
11),
367+
'Invalid length for PBKDF2 should return false');
368+
assert_false(
369+
SubtleCrypto.supports(
370+
'deriveBits', {
371+
name: 'PBKDF2',
372+
hash: 'SHA-256',
373+
salt: new Uint8Array(16),
374+
iterations: 100000,
375+
}),
376+
'null length for PBKDF2 should return false');
377+
assert_false(
378+
SubtleCrypto.supports('generateKey', {
379+
name: 'RSASSA-PKCS1-v1_5',
380+
modulusLength: 2048,
381+
publicExponent: new Uint8Array([1, 0, 1]),
382+
hash: 'SHA-56',
383+
}),
384+
'Invalid hash for RSA PKCS1 should return false');
385+
assert_false(
386+
SubtleCrypto.supports('generateKey', {
387+
name: 'RSA-PSS',
388+
modulusLength: 2048,
389+
publicExponent: new Uint8Array([1, 0, 1]),
390+
hash: 'SHA-56',
391+
}),
392+
'Invalid hash for RSA PSS should return false');
393+
assert_false(
394+
SubtleCrypto.supports('generateKey', {
395+
name: 'RSA-OAEP',
396+
modulusLength: 2048,
397+
publicExponent: new Uint8Array([1, 0, 1]),
398+
hash: 'SHA-26',
399+
}),
400+
'Invalid hash for RSA OAEP should return false');
401+
271402
}, 'supports returns false for algorithm objects with invalid parameters');
272403

273404
// Test some specific combinations that should work
@@ -394,4 +525,49 @@ test(() => {
394525
);
395526
}, 'Invalid algorithm and operation combinations fail');
396527

528+
// Test supports for deriveKey op
529+
test(() => {
530+
assert_true(
531+
SubtleCrypto.supports(
532+
'deriveKey', {
533+
name: 'HKDF',
534+
hash: 'SHA-256',
535+
salt: new Uint8Array(16),
536+
info: new Uint8Array(0),
537+
},
538+
{name: 'HMAC', hash: 'SHA-256'}),
539+
540+
'deriveKey HKDF-HMAC should pass');
541+
}, 'deriveKey tests');
542+
543+
promise_test(async (t) => {
544+
let keypair = await crypto.subtle.generateKey(
545+
{
546+
name: 'X25519',
547+
},
548+
false, ['deriveKey', 'deriveBits']);
549+
550+
assert_true(
551+
SubtleCrypto.supports(
552+
'deriveKey', {
553+
name: 'X25519',
554+
public: keypair.publicKey,
555+
},
556+
{name: 'AES-GCM', length: 256}),
557+
558+
'deriveKey X25519-AES-GCM-256 should pass');
559+
560+
assert_false(
561+
SubtleCrypto.supports(
562+
'deriveKey', {
563+
name: 'X25519',
564+
public: keypair.publicKey,
565+
},
566+
{name: 'HMAC', hash: 'SHA-256'}),
567+
568+
'deriveKey X25519-HMAC-SHA-256 should fail');
569+
}, 'deriveKey promise tests');
570+
571+
572+
397573
done();

test/fixtures/wpt/versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
"path": "web-locks"
9797
},
9898
"WebCryptoAPI": {
99-
"commit": "2cb332d71030ba0200610d72b94bb1badf447418",
99+
"commit": "8b5cd267b480d75bce41aa306bebbd07ce414fa5",
100100
"path": "WebCryptoAPI"
101101
},
102102
"webidl": {

0 commit comments

Comments
 (0)