tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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();