@@ -49,13 +49,10 @@ const standardAlgorithms = {
4949 operations : [ 'generateKey' , 'importKey' , 'deriveBits' , 'getPublicKey' ] ,
5050 keyGenParams : { name : 'ECDH' , namedCurve : 'P-256' } ,
5151 importParams : { name : 'ECDH' , namedCurve : 'P-256' } ,
52- deriveBitsParams : {
53- name : 'ECDH' ,
54- public : crypto . subtle . generateKey (
55- { name : 'ECDH' , namedCurve : 'P-256' } ,
56- false ,
57- [ 'deriveBits' ]
58- ) ,
52+ deriveBitsParamsFactory : async ( ) => {
53+ const { publicKey} = await crypto . subtle . generateKey (
54+ { name : 'ECDH' , namedCurve : 'P-256' } , false , [ 'deriveBits' ] ) ;
55+ return { name : 'ECDH' , public : publicKey } ;
5956 } ,
6057 } ,
6158 Ed25519 : {
@@ -66,9 +63,10 @@ const standardAlgorithms = {
6663 X25519 : {
6764 operations : [ 'generateKey' , 'importKey' , 'deriveBits' , 'getPublicKey' ] ,
6865 keyGenParams : null ,
69- deriveBitsParams : {
70- name : 'X25519' ,
71- public : crypto . subtle . generateKey ( 'X25519' , false , [ 'deriveBits' ] ) ,
66+ deriveBitsParamsFactory : async ( ) => {
67+ const { publicKey} = await crypto . subtle . generateKey (
68+ 'X25519' , false , [ 'deriveBits' ] ) ;
69+ return { name : 'X25519' , public : publicKey } ;
7270 } ,
7371 } ,
7472
@@ -247,6 +245,13 @@ test(() => {
247245 tagLength : 100 ,
248246 } ) ,
249247 'Invalid tag length for AES-GCM should return false' ) ;
248+ assert_false (
249+ SubtleCrypto . supports ( 'decrypt' , {
250+ name : 'AES-GCM' ,
251+ iv : new Uint8Array ( 16 ) ,
252+ tagLength : 100 ,
253+ } ) ,
254+ 'Invalid tag length for AES-GCM should return false' ) ;
250255 assert_false (
251256 SubtleCrypto . supports ( 'generateKey' , { name : 'ECDH' , namedCurve : 'P-51' } ) ,
252257 'Invalid curve for ECDH should return false' ) ;
@@ -348,6 +353,214 @@ test(() => {
348353
349354} , 'supports returns false for algorithm objects with invalid parameters' ) ;
350355
356+ [
357+ [ 'SHA-1' , 160 ] ,
358+ [ 'SHA-256' , 256 ] ,
359+ [ 'SHA-384' , 384 ] ,
360+ [ 'SHA-512' , 512 ] ,
361+ ] . forEach ( ( [ hash , hashLength ] ) => {
362+ test ( ( ) => {
363+ const algorithm = {
364+ name : 'HKDF' ,
365+ hash,
366+ salt : new Uint8Array ( ) ,
367+ info : new Uint8Array ( ) ,
368+ } ;
369+ const maximumLength = 255 * hashLength ;
370+
371+ assert_true (
372+ SubtleCrypto . supports ( 'deriveBits' , algorithm , maximumLength ) ,
373+ `HKDF with ${ hash } supports its maximum output length`
374+ ) ;
375+ assert_false (
376+ SubtleCrypto . supports ( 'deriveBits' , algorithm , maximumLength + 8 ) ,
377+ `HKDF with ${ hash } rejects output longer than its maximum`
378+ ) ;
379+ } , `supports validates HKDF ${ hash } output length` ) ;
380+ } ) ;
381+
382+ test ( ( ) => {
383+ assert_false (
384+ SubtleCrypto . supports (
385+ 'deriveKey' ,
386+ {
387+ name : 'HKDF' ,
388+ hash : 'SHA-256' ,
389+ salt : new Uint8Array ( ) ,
390+ info : new Uint8Array ( ) ,
391+ } ,
392+ { name : 'HMAC' , hash : 'SHA-256' , length : 65288 }
393+ ) ,
394+ 'HKDF rejects a derived key longer than 255 hash blocks'
395+ ) ;
396+ } , 'supports validates HKDF output length for deriveKey' ) ;
397+
398+ test ( ( ) => {
399+ assert_false (
400+ SubtleCrypto . supports ( 'importKey' , {
401+ name : 'HMAC' ,
402+ hash : 'SHA-256' ,
403+ length : 0 ,
404+ } ) ,
405+ 'HMAC rejects an explicitly zero-length imported key'
406+ ) ;
407+ } , 'supports validates HMAC import length' ) ;
408+
409+ const invalidRsaKeyGenParameters = [
410+ {
411+ description : 'a modulus shorter than 4 bits' ,
412+ modulusLength : 3 ,
413+ publicExponent : Uint8Array . of ( 3 ) ,
414+ } ,
415+ {
416+ description : 'a public exponent less than 3' ,
417+ modulusLength : 2048 ,
418+ publicExponent : Uint8Array . of ( 1 ) ,
419+ } ,
420+ {
421+ description : 'an even public exponent' ,
422+ modulusLength : 2048 ,
423+ publicExponent : Uint8Array . of ( 4 ) ,
424+ } ,
425+ {
426+ description : 'a public exponent equal to 2^modulusLength - 1' ,
427+ modulusLength : 2048 ,
428+ publicExponent : new Uint8Array ( 256 ) . fill ( 0xff ) ,
429+ } ,
430+ ] ;
431+
432+ [
433+ 'RSASSA-PKCS1-v1_5' ,
434+ 'RSA-PSS' ,
435+ 'RSA-OAEP' ,
436+ ] . forEach ( name => {
437+ invalidRsaKeyGenParameters . forEach ( ( { description, ...parameters } ) => {
438+ test ( ( ) => {
439+ assert_false (
440+ SubtleCrypto . supports ( 'generateKey' , {
441+ name,
442+ ...parameters ,
443+ hash : 'SHA-256' ,
444+ } ) ,
445+ `${ name } rejects ${ description } `
446+ ) ;
447+ } , `supports rejects ${ name } generateKey with ${ description } ` ) ;
448+ } ) ;
449+ } ) ;
450+
451+ [ 'ECDSA' , 'ECDH' ] . forEach ( name => {
452+ test ( ( ) => {
453+ assert_false (
454+ SubtleCrypto . supports ( 'importKey' , {
455+ name,
456+ namedCurve : 'not-a-curve' ,
457+ } ) ,
458+ `${ name } rejects an unknown named curve`
459+ ) ;
460+ } , `supports validates ${ name } import namedCurve` ) ;
461+ } ) ;
462+
463+ [
464+ [ 'P-256' , 256 ] ,
465+ [ 'P-384' , 384 ] ,
466+ [ 'P-521' , 528 ] ,
467+ ] . forEach ( ( [ namedCurve , maximumLength ] ) => {
468+ promise_test ( async ( ) => {
469+ const { publicKey} = await crypto . subtle . generateKey (
470+ { name : 'ECDH' , namedCurve} , false , [ 'deriveBits' ] ) ;
471+ const algorithm = { name : 'ECDH' , public : publicKey } ;
472+
473+ assert_true (
474+ SubtleCrypto . supports ( 'deriveBits' , algorithm , maximumLength ) ,
475+ `ECDH ${ namedCurve } supports its maximum output length`
476+ ) ;
477+ assert_false (
478+ SubtleCrypto . supports ( 'deriveBits' , algorithm , maximumLength + 1 ) ,
479+ `ECDH ${ namedCurve } rejects output longer than its maximum`
480+ ) ;
481+ } , `supports validates ECDH ${ namedCurve } deriveBits length` ) ;
482+ } ) ;
483+
484+ promise_test ( async ( ) => {
485+ const { publicKey} = await crypto . subtle . generateKey (
486+ 'X25519' , false , [ 'deriveBits' ] ) ;
487+ const algorithm = { name : 'X25519' , public : publicKey } ;
488+
489+ assert_true (
490+ SubtleCrypto . supports ( 'deriveBits' , algorithm , 256 ) ,
491+ 'X25519 supports its maximum output length'
492+ ) ;
493+ assert_false (
494+ SubtleCrypto . supports ( 'deriveBits' , algorithm , 257 ) ,
495+ 'X25519 rejects output longer than its maximum'
496+ ) ;
497+ } , 'supports validates X25519 deriveBits length' ) ;
498+
499+ promise_test ( async ( ) => {
500+ const [ ecdhKeyPair , x25519KeyPair ] = await Promise . all ( [
501+ crypto . subtle . generateKey (
502+ { name : 'ECDH' , namedCurve : 'P-256' } , false , [ 'deriveBits' ] ) ,
503+ crypto . subtle . generateKey ( 'X25519' , false , [ 'deriveBits' ] ) ,
504+ ] ) ;
505+
506+ assert_false (
507+ SubtleCrypto . supports (
508+ 'deriveBits' , { name : 'ECDH' , public : ecdhKeyPair . privateKey } , 256 ) ,
509+ 'ECDH rejects a private public property'
510+ ) ;
511+ assert_false (
512+ SubtleCrypto . supports (
513+ 'deriveBits' , { name : 'ECDH' , public : x25519KeyPair . publicKey } , 256 ) ,
514+ 'ECDH rejects a public property for another algorithm'
515+ ) ;
516+ } , 'supports validates the ECDH public key' ) ;
517+
518+ promise_test ( async ( ) => {
519+ const [ x25519KeyPair , ecdhKeyPair ] = await Promise . all ( [
520+ crypto . subtle . generateKey ( 'X25519' , false , [ 'deriveBits' ] ) ,
521+ crypto . subtle . generateKey (
522+ { name : 'ECDH' , namedCurve : 'P-256' } , false , [ 'deriveBits' ] ) ,
523+ ] ) ;
524+
525+ assert_false (
526+ SubtleCrypto . supports (
527+ 'deriveBits' , { name : 'X25519' , public : x25519KeyPair . privateKey } , 256 ) ,
528+ 'X25519 rejects a private public property'
529+ ) ;
530+ assert_false (
531+ SubtleCrypto . supports (
532+ 'deriveBits' , { name : 'X25519' , public : ecdhKeyPair . publicKey } , 256 ) ,
533+ 'X25519 rejects a public property for another algorithm'
534+ ) ;
535+ } , 'supports validates the X25519 public key' ) ;
536+
537+ promise_test ( async ( ) => {
538+ const [ p256KeyPair , p521KeyPair ] = await Promise . all ( [
539+ crypto . subtle . generateKey (
540+ { name : 'ECDH' , namedCurve : 'P-256' } , false , [ 'deriveBits' ] ) ,
541+ crypto . subtle . generateKey (
542+ { name : 'ECDH' , namedCurve : 'P-521' } , false , [ 'deriveBits' ] ) ,
543+ ] ) ;
544+ const derivedKeyAlgorithm = { name : 'HMAC' , hash : 'SHA-256' } ;
545+
546+ assert_false (
547+ SubtleCrypto . supports (
548+ 'deriveKey' ,
549+ { name : 'ECDH' , public : p256KeyPair . publicKey } ,
550+ derivedKeyAlgorithm
551+ ) ,
552+ 'ECDH P-256 cannot derive a 512-bit HMAC key'
553+ ) ;
554+ assert_true (
555+ SubtleCrypto . supports (
556+ 'deriveKey' ,
557+ { name : 'ECDH' , public : p521KeyPair . publicKey } ,
558+ derivedKeyAlgorithm
559+ ) ,
560+ 'ECDH P-521 can derive a 512-bit HMAC key'
561+ ) ;
562+ } , 'supports derives the ECDH output limit from the public curve' ) ;
563+
351564// Test some specific combinations that should work
352565test ( ( ) => {
353566 // RSA algorithms
0 commit comments