supports.tentative.https.any.js (10974B)
1 // META: title=WebCrypto API: supports method tests 2 // META: script=util/helpers.js 3 4 'use strict'; 5 6 const standardAlgorithms = { 7 // Asymmetric algorithms 8 'RSASSA-PKCS1-v1_5': { 9 operations: ['generateKey', 'importKey', 'sign', 'verify'], 10 keyGenParams: { 11 name: 'RSASSA-PKCS1-v1_5', 12 modulusLength: 2048, 13 publicExponent: new Uint8Array([1, 0, 1]), 14 hash: 'SHA-256', 15 }, 16 importParams: { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, 17 signParams: { name: 'RSASSA-PKCS1-v1_5' }, 18 }, 19 'RSA-PSS': { 20 operations: ['generateKey', 'importKey', 'sign', 'verify'], 21 keyGenParams: { 22 name: 'RSA-PSS', 23 modulusLength: 2048, 24 publicExponent: new Uint8Array([1, 0, 1]), 25 hash: 'SHA-256', 26 }, 27 importParams: { name: 'RSA-PSS', hash: 'SHA-256' }, 28 signParams: { name: 'RSA-PSS', saltLength: 32 }, 29 }, 30 'RSA-OAEP': { 31 operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'], 32 keyGenParams: { 33 name: 'RSA-OAEP', 34 modulusLength: 2048, 35 publicExponent: new Uint8Array([1, 0, 1]), 36 hash: 'SHA-256', 37 }, 38 importParams: { name: 'RSA-OAEP', hash: 'SHA-256' }, 39 encryptParams: { name: 'RSA-OAEP' }, 40 }, 41 ECDSA: { 42 operations: ['generateKey', 'importKey', 'sign', 'verify'], 43 keyGenParams: { name: 'ECDSA', namedCurve: 'P-256' }, 44 importParams: { name: 'ECDSA', namedCurve: 'P-256' }, 45 signParams: { name: 'ECDSA', hash: 'SHA-256' }, 46 }, 47 ECDH: { 48 operations: ['generateKey', 'importKey', 'deriveBits'], 49 keyGenParams: { name: 'ECDH', namedCurve: 'P-256' }, 50 importParams: { name: 'ECDH', namedCurve: 'P-256' }, 51 deriveBitsParams: { 52 name: 'ECDH', 53 public: crypto.subtle.generateKey( 54 { name: 'ECDH', namedCurve: 'P-256' }, 55 false, 56 ['deriveBits'] 57 ), 58 }, 59 }, 60 Ed25519: { 61 operations: ['generateKey', 'importKey', 'sign', 'verify'], 62 keyGenParams: null, 63 signParams: { name: 'Ed25519' }, 64 }, 65 X25519: { 66 operations: ['generateKey', 'importKey', 'deriveBits'], 67 keyGenParams: null, 68 deriveBitsParams: { 69 name: 'X25519', 70 public: crypto.subtle.generateKey('X25519', false, ['deriveBits']), 71 }, 72 }, 73 74 // Symmetric algorithms 75 'AES-CBC': { 76 operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'], 77 keyGenParams: { name: 'AES-CBC', length: 256 }, 78 encryptParams: { name: 'AES-CBC', iv: new Uint8Array(16) }, 79 }, 80 'AES-CTR': { 81 operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'], 82 keyGenParams: { name: 'AES-CTR', length: 256 }, 83 encryptParams: { 84 name: 'AES-CTR', 85 counter: new Uint8Array(16), 86 length: 128, 87 }, 88 }, 89 'AES-GCM': { 90 operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'], 91 keyGenParams: { name: 'AES-GCM', length: 256 }, 92 encryptParams: { name: 'AES-GCM', iv: new Uint8Array(12) }, 93 }, 94 'AES-KW': { 95 operations: ['generateKey', 'importKey'], // wrapKey/unwrapKey not in requested operations 96 keyGenParams: { name: 'AES-KW', length: 256 }, 97 }, 98 HMAC: { 99 operations: ['generateKey', 'importKey', 'sign', 'verify'], 100 keyGenParams: { name: 'HMAC', hash: 'SHA-256' }, 101 importParams: { name: 'HMAC', hash: 'SHA-256' }, 102 signParams: { name: 'HMAC' }, 103 }, 104 105 // Hash algorithms 106 'SHA-1': { 107 operations: ['digest'], 108 keyGenParams: null, 109 }, 110 'SHA-256': { 111 operations: ['digest'], 112 keyGenParams: null, 113 }, 114 'SHA-384': { 115 operations: ['digest'], 116 keyGenParams: null, 117 }, 118 'SHA-512': { 119 operations: ['digest'], 120 keyGenParams: null, 121 }, 122 123 // Key derivation algorithms 124 HKDF: { 125 operations: ['importKey', 'deriveBits'], 126 keyGenParams: null, 127 deriveBitsParams: { 128 name: 'HKDF', 129 hash: 'SHA-256', 130 salt: new Uint8Array(16), 131 info: new Uint8Array(0), 132 }, 133 }, 134 PBKDF2: { 135 operations: ['importKey', 'deriveBits'], 136 keyGenParams: null, 137 deriveBitsParams: { 138 name: 'PBKDF2', 139 hash: 'SHA-256', 140 salt: new Uint8Array(16), 141 iterations: 100000, 142 }, 143 }, 144 }; 145 146 const operations = [ 147 'generateKey', 148 'importKey', 149 'sign', 150 'verify', 151 'encrypt', 152 'decrypt', 153 'deriveBits', 154 'digest', 155 ]; 156 157 // Test that supports method exists and is a static method 158 test(() => { 159 assert_true( 160 typeof SubtleCrypto.supports === 'function', 161 'SubtleCrypto.supports should be a function' 162 ); 163 }, 'SubtleCrypto.supports method exists'); 164 165 // Test invalid operation names 166 test(() => { 167 assert_false( 168 SubtleCrypto.supports('invalidOperation', 'AES-GCM'), 169 'Invalid operation should return false' 170 ); 171 assert_false( 172 SubtleCrypto.supports('', 'AES-GCM'), 173 'Empty operation should return false' 174 ); 175 assert_false( 176 SubtleCrypto.supports('GENERATEKEY', 'AES-GCM'), 177 'Case-sensitive operation check' 178 ); 179 }, 'supports returns false for invalid operations'); 180 181 // Test invalid algorithm identifiers 182 test(() => { 183 assert_false( 184 SubtleCrypto.supports('generateKey', 'InvalidAlgorithm'), 185 'Invalid algorithm should return false' 186 ); 187 assert_false( 188 SubtleCrypto.supports('generateKey', ''), 189 'Empty algorithm should return false' 190 ); 191 }, 'supports returns false for invalid algorithms'); 192 193 // Test standard WebCrypto algorithms for requested operations 194 for (const [algorithmName, algorithmInfo] of Object.entries( 195 standardAlgorithms 196 )) { 197 for (const operation of operations) { 198 promise_test(async (t) => { 199 const isSupported = algorithmInfo.operations.includes(operation); 200 201 // Use appropriate algorithm parameters for each operation 202 let algorithm; 203 let length; 204 switch (operation) { 205 case 'generateKey': 206 algorithm = algorithmInfo.keyGenParams || algorithmName; 207 break; 208 case 'importKey': 209 algorithm = algorithmInfo.importParams || algorithmName; 210 break; 211 case 'sign': 212 case 'verify': 213 algorithm = algorithmInfo.signParams || algorithmName; 214 break; 215 case 'encrypt': 216 case 'decrypt': 217 algorithm = algorithmInfo.encryptParams || algorithmName; 218 break; 219 case 'deriveBits': 220 algorithm = algorithmInfo.deriveBitsParams || algorithmName; 221 if (algorithm?.public instanceof Promise) { 222 algorithm.public = (await algorithm.public).publicKey; 223 } 224 if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') { 225 length = 256; 226 } 227 break; 228 case 'digest': 229 algorithm = algorithmName; 230 break; 231 default: 232 algorithm = algorithmName; 233 } 234 235 const result = SubtleCrypto.supports(operation, algorithm, length); 236 237 if (isSupported) { 238 assert_true(result, `${algorithmName} should support ${operation}`); 239 } else { 240 assert_false(result, `${algorithmName} should not support ${operation}`); 241 } 242 }, `supports(${operation}, ${algorithmName})`); 243 } 244 } 245 246 // Test algorithm objects (not just strings) 247 test(() => { 248 assert_true( 249 SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 256 }), 250 'Algorithm object should be supported' 251 ); 252 assert_true( 253 SubtleCrypto.supports('generateKey', { name: 'HMAC', hash: 'SHA-256' }), 254 'Algorithm object with parameters should be supported' 255 ); 256 }, 'supports works with algorithm objects'); 257 258 // Test with algorithm objects that have invalid parameters 259 test(() => { 260 assert_false( 261 SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 100 }), 262 'Invalid key length should return false' 263 ); 264 assert_false( 265 SubtleCrypto.supports('generateKey', { 266 name: 'HMAC', 267 hash: 'INVALID-HASH', 268 }), 269 'Invalid hash parameter should return false' 270 ); 271 }, 'supports returns false for algorithm objects with invalid parameters'); 272 273 // Test some specific combinations that should work 274 test(() => { 275 // RSA algorithms 276 assert_true( 277 SubtleCrypto.supports('generateKey', { 278 name: 'RSASSA-PKCS1-v1_5', 279 modulusLength: 2048, 280 publicExponent: new Uint8Array([1, 0, 1]), 281 hash: 'SHA-256', 282 }), 283 'RSASSA-PKCS1-v1_5 generateKey' 284 ); 285 assert_true( 286 SubtleCrypto.supports('sign', { name: 'RSASSA-PKCS1-v1_5' }), 287 'RSASSA-PKCS1-v1_5 sign' 288 ); 289 assert_true( 290 SubtleCrypto.supports('verify', { name: 'RSASSA-PKCS1-v1_5' }), 291 'RSASSA-PKCS1-v1_5 verify' 292 ); 293 294 // ECDSA 295 assert_true( 296 SubtleCrypto.supports('generateKey', { 297 name: 'ECDSA', 298 namedCurve: 'P-256', 299 }), 300 'ECDSA generateKey' 301 ); 302 assert_true( 303 SubtleCrypto.supports('sign', { name: 'ECDSA', hash: 'SHA-256' }), 304 'ECDSA sign' 305 ); 306 assert_true( 307 SubtleCrypto.supports('verify', { name: 'ECDSA', hash: 'SHA-256' }), 308 'ECDSA verify' 309 ); 310 311 // AES-GCM 312 assert_true( 313 SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 256 }), 314 'AES-GCM generateKey' 315 ); 316 assert_true( 317 SubtleCrypto.supports('encrypt', { 318 name: 'AES-GCM', 319 iv: new Uint8Array(12), 320 }), 321 'AES-GCM encrypt' 322 ); 323 assert_true( 324 SubtleCrypto.supports('decrypt', { 325 name: 'AES-GCM', 326 iv: new Uint8Array(12), 327 }), 328 'AES-GCM decrypt' 329 ); 330 331 // HMAC 332 assert_true( 333 SubtleCrypto.supports('generateKey', { name: 'HMAC', hash: 'SHA-256' }), 334 'HMAC generateKey' 335 ); 336 assert_true(SubtleCrypto.supports('sign', { name: 'HMAC' }), 'HMAC sign'); 337 assert_true(SubtleCrypto.supports('verify', { name: 'HMAC' }), 'HMAC verify'); 338 }, 'Common algorithm and operation combinations work'); 339 340 // Test some specific combinations that should not work 341 test(() => { 342 // Hash algorithms don't support key operations 343 assert_false( 344 SubtleCrypto.supports('generateKey', 'SHA-256'), 345 'SHA-256 generateKey should fail' 346 ); 347 assert_false( 348 SubtleCrypto.supports('sign', 'SHA-256'), 349 'SHA-256 sign should fail' 350 ); 351 352 // AES can't sign/verify (these require algorithm parameters due to normalization) 353 assert_false( 354 SubtleCrypto.supports('sign', 'AES-GCM'), 355 'AES-GCM sign should fail' 356 ); 357 assert_false( 358 SubtleCrypto.supports('verify', 'AES-GCM'), 359 'AES-GCM verify should fail' 360 ); 361 362 // ECDSA can't encrypt/decrypt 363 assert_false( 364 SubtleCrypto.supports('encrypt', 'ECDSA'), 365 'ECDSA encrypt should fail' 366 ); 367 assert_false( 368 SubtleCrypto.supports('decrypt', 'ECDSA'), 369 'ECDSA decrypt should fail' 370 ); 371 372 // HMAC can't encrypt/decrypt 373 assert_false( 374 SubtleCrypto.supports('encrypt', 'HMAC'), 375 'HMAC encrypt should fail' 376 ); 377 assert_false( 378 SubtleCrypto.supports('decrypt', 'HMAC'), 379 'HMAC decrypt should fail' 380 ); 381 382 // Non-hash algorithms can't digest 383 assert_false( 384 SubtleCrypto.supports('digest', 'AES-GCM'), 385 'AES-GCM digest should fail' 386 ); 387 assert_false( 388 SubtleCrypto.supports('digest', 'ECDSA'), 389 'ECDSA digest should fail' 390 ); 391 assert_false( 392 SubtleCrypto.supports('digest', 'HMAC'), 393 'HMAC digest should fail' 394 ); 395 }, 'Invalid algorithm and operation combinations fail'); 396 397 done();