tor-browser

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

test_WebCrypto.html (34001B)


      1 <!DOCTYPE html>
      2 <html>
      3 
      4 <head>
      5 <title>WebCrypto Test Suite</title>
      6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      7 <link rel="stylesheet" href="./test_WebCrypto.css"/>
      8 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      9 
     10 <!-- Utilities for manipulating ABVs -->
     11 <script src="util.js"></script>
     12 
     13 <!-- A simple wrapper around IndexedDB -->
     14 <script src="simpledb.js"></script>
     15 
     16 <!-- Test vectors drawn from the literature -->
     17 <script src="./test-vectors.js"></script>
     18 
     19 <!-- General testing framework -->
     20 <script src="./test-array.js"></script>
     21 
     22 <script>/* <![CDATA[*/
     23 "use strict";
     24 
     25 // -----------------------------------------------------------------------------
     26 TestArray.addTest(
     27  "Test for presence of WebCrypto API methods",
     28  function() {
     29    this.complete(
     30      exists(window.crypto.subtle) &&
     31      exists(window.crypto.subtle.encrypt) &&
     32      exists(window.crypto.subtle.decrypt) &&
     33      exists(window.crypto.subtle.sign) &&
     34      exists(window.crypto.subtle.verify) &&
     35      exists(window.crypto.subtle.digest) &&
     36      exists(window.crypto.subtle.importKey) &&
     37      exists(window.crypto.subtle.exportKey) &&
     38      exists(window.crypto.subtle.generateKey) &&
     39      exists(window.crypto.subtle.deriveKey) &&
     40      exists(window.crypto.subtle.deriveBits)
     41    );
     42  }
     43 );
     44 
     45 // -----------------------------------------------------------------------------
     46 TestArray.addTest(
     47  "Clean failure on a mal-formed algorithm",
     48  function() {
     49    var that = this;
     50    var alg = {
     51      get name() {
     52        throw new Error("Oh no, no name!");
     53      },
     54    };
     55 
     56    crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"])
     57      .then(
     58        error(that),
     59        complete(that, function() { return true; })
     60      );
     61  }
     62 );
     63 
     64 // -----------------------------------------------------------------------------
     65 TestArray.addTest(
     66  "Import / export round-trip with 'raw'",
     67  function() {
     68    var that = this;
     69    var alg = "AES-GCM";
     70 
     71    function doExport(x) {
     72      if (!hasKeyFields(x)) {
     73        throw new Error("Invalid key; missing field(s)");
     74      } else if ((x.algorithm.name != alg) ||
     75        (x.algorithm.length != 8 * tv.raw.length) ||
     76        (x.type != "secret") ||
     77        (!x.extractable) ||
     78        (x.usages.length != 1) ||
     79        (x.usages[0] != "encrypt")) {
     80        throw new Error("Invalid key: incorrect key data");
     81      }
     82      return crypto.subtle.exportKey("raw", x);
     83    }
     84 
     85    crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"])
     86      .then(doExport)
     87      .then(
     88        memcmp_complete(that, tv.raw),
     89        error(that)
     90      );
     91  }
     92 );
     93 
     94 // -----------------------------------------------------------------------------
     95 TestArray.addTest(
     96  "Import failure with format 'raw'",
     97  function() {
     98    var that = this;
     99    var alg = "AES-GCM";
    100 
    101    crypto.subtle.importKey("raw", tv.negative_raw, alg, true, ["encrypt"])
    102      .then(error(that), complete(that));
    103  }
    104 );
    105 
    106 // -----------------------------------------------------------------------------
    107 TestArray.addTest(
    108  "Proper handling of an ABV representing part of a buffer",
    109  function() {
    110    var that = this;
    111    var alg = "AES-GCM";
    112 
    113    var u8 = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    114                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    115                             0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    116                             0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f]);
    117    var u32 = new Uint32Array(u8.buffer, 8, 4);
    118    var out = u8.subarray(8, 24);
    119 
    120    function doExport(x) {
    121      return crypto.subtle.exportKey("raw", x);
    122    }
    123 
    124    crypto.subtle.importKey("raw", u32, alg, true, ["encrypt"])
    125      .then(doExport, error(that))
    126      .then(memcmp_complete(that, out), error(that));
    127  }
    128 );
    129 
    130 // -----------------------------------------------------------------------------
    131 TestArray.addTest(
    132  "Import / export round-trip with 'pkcs8'",
    133  function() {
    134    var that = this;
    135    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
    136 
    137    function doExport(x) {
    138      if (!hasKeyFields(x)) {
    139        throw new Error("Invalid key; missing field(s)");
    140      } else if ((x.algorithm.name != alg.name) ||
    141        (x.algorithm.hash.name != alg.hash) ||
    142        (x.algorithm.modulusLength != 512) ||
    143        (x.algorithm.publicExponent.byteLength != 3) ||
    144        (x.type != "private") ||
    145        (!x.extractable) ||
    146        (x.usages.length != 1) ||
    147        (x.usages[0] != "sign")) {
    148        throw new Error("Invalid key: incorrect key data");
    149      }
    150      return crypto.subtle.exportKey("pkcs8", x);
    151    }
    152 
    153    crypto.subtle.importKey("pkcs8", tv.pkcs8, alg, true, ["sign"])
    154      .then(doExport)
    155      .then(
    156        memcmp_complete(that, tv.pkcs8),
    157        error(that)
    158      );
    159  }
    160 );
    161 
    162 // -----------------------------------------------------------------------------
    163 TestArray.addTest(
    164  "Import failure with format 'pkcs8'",
    165  function() {
    166    var that = this;
    167    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
    168 
    169    crypto.subtle.importKey("pkcs8", tv.negative_pkcs8, alg, true, ["encrypt"])
    170      .then(error(that), complete(that));
    171  }
    172 );
    173 
    174 // -----------------------------------------------------------------------------
    175 TestArray.addTest(
    176  "Import / export round-trip with 'spki'",
    177  function() {
    178    var that = this;
    179    var alg = {
    180      name: "RSASSA-PKCS1-v1_5",
    181      hash: "SHA-256",
    182    };
    183 
    184    function doExport(x) {
    185      if (!hasKeyFields(x)) {
    186        throw new Error("Invalid key; missing field(s)");
    187      } else if ((x.algorithm.name != alg.name) ||
    188        (x.algorithm.modulusLength != 1024) ||
    189        (x.algorithm.publicExponent.byteLength != 3) ||
    190        (x.type != "public") ||
    191        (!x.extractable) ||
    192        (x.usages.length != 1) ||
    193        (x.usages[0] != "verify")) {
    194        throw new Error("Invalid key: incorrect key data");
    195      }
    196      return crypto.subtle.exportKey("spki", x);
    197    }
    198 
    199    crypto.subtle.importKey("spki", tv.spki, alg, true, ["verify"])
    200      .then(doExport, error(that))
    201      .then(
    202        memcmp_complete(that, tv.spki),
    203        error(that)
    204      );
    205  }
    206 );
    207 
    208 // -----------------------------------------------------------------------------
    209 TestArray.addTest(
    210  "Import failure with format 'spki'",
    211  function() {
    212    var that = this;
    213    var alg = {
    214      name: "RSASSA-PKCS1-v1_5",
    215      hash: "SHA-256",
    216    };
    217 
    218    crypto.subtle.importKey("spki", tv.negative_spki, alg, true, ["encrypt"])
    219      .then(error(that), complete(that));
    220  }
    221 );
    222 
    223 // -----------------------------------------------------------------------------
    224 TestArray.addTest(
    225  "Importing an ECDSA key as an RSA key should fail",
    226  function() {
    227    var that = this;
    228    var alg = {
    229      name: "RSASSA-PKCS1-v1_5",
    230      hash: "SHA-256",
    231    };
    232 
    233    crypto.subtle.importKey("spki", tv.ecdh_p256.spki, alg, true, ["verify"])
    234      .then(error(that), complete(that));
    235  }
    236 );
    237 
    238 // -----------------------------------------------------------------------------
    239 TestArray.addTest(
    240  "Refuse to export non-extractable key",
    241  function() {
    242    var that = this;
    243    var alg = "AES-GCM";
    244 
    245    function doExport(x) {
    246      return crypto.subtle.exportKey("raw", x);
    247    }
    248 
    249    crypto.subtle.importKey("raw", tv.raw, alg, false, ["encrypt"])
    250      .then(doExport, error(that))
    251      .then(
    252        error(that),
    253        complete(that)
    254      );
    255  }
    256 );
    257 
    258 // -----------------------------------------------------------------------------
    259 TestArray.addTest(
    260  "IndexedDB store / retrieve round-trip",
    261  function() {
    262    var that = this;
    263    var alg = "AES-GCM";
    264    var importedKey;
    265    var dbname = "keyDB";
    266    var dbstore = "keystore";
    267    var dbversion = 1;
    268    var dbkey = 0;
    269    var db;
    270 
    271    function doIndexedDB(x) {
    272      importedKey = x;
    273      var req = indexedDB.deleteDatabase(dbname);
    274      req.onerror = error(that);
    275      req.onsuccess = doCreateDB;
    276    }
    277 
    278    function doCreateDB() {
    279      var req = indexedDB.open(dbname, dbversion);
    280      req.onerror = error(that);
    281      req.onupgradeneeded = function(e) {
    282        db = e.target.result;
    283        db.createObjectStore(dbstore, {keyPath: "id"});
    284      };
    285 
    286      req.onsuccess = doPut;
    287    }
    288 
    289    function doPut() {
    290      var req = db.transaction([dbstore], "readwrite")
    291                  .objectStore(dbstore)
    292                  .add({id: dbkey, val: importedKey});
    293      req.onerror = error(that);
    294      req.onsuccess = doGet;
    295    }
    296 
    297    function doGet() {
    298      var req = db.transaction([dbstore], "readwrite")
    299                  .objectStore(dbstore)
    300                  .get(dbkey);
    301      req.onerror = error(that);
    302      req.onsuccess = complete(that, function(e) {
    303        db.close();
    304        return hasKeyFields(e.target.result.val);
    305      });
    306    }
    307 
    308    crypto.subtle.importKey("raw", tv.raw, alg, false, ["encrypt"])
    309      .then(doIndexedDB, error(that));
    310  }
    311 );
    312 
    313 // -----------------------------------------------------------------------------
    314 TestArray.addTest(
    315  "Generate a 256-bit HMAC-SHA-256 key",
    316  function() {
    317    var that = this;
    318    var alg = { name: "HMAC", length: 256, hash: {name: "SHA-256"} };
    319    crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then(
    320      complete(that, function(x) {
    321        return hasKeyFields(x) && x.algorithm.length == 256;
    322      }),
    323      error(that)
    324    );
    325  }
    326 );
    327 
    328 // -----------------------------------------------------------------------------
    329 TestArray.addTest(
    330  "Generate a 256-bit HMAC-SHA-256 key without specifying a key length",
    331  function() {
    332    var that = this;
    333    var alg = { name: "HMAC", hash: {name: "SHA-256"} };
    334    crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then(
    335      complete(that, function(x) {
    336        return hasKeyFields(x) && x.algorithm.length == 512;
    337      }),
    338      error(that)
    339    );
    340  }
    341 );
    342 
    343 // -----------------------------------------------------------------------------
    344 TestArray.addTest(
    345  "Generate a 256-bit HMAC-SHA-512 key without specifying a key length",
    346  function() {
    347    var that = this;
    348    var alg = { name: "HMAC", hash: {name: "SHA-512"} };
    349    crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then(
    350      complete(that, function(x) {
    351        return hasKeyFields(x) && x.algorithm.length == 1024;
    352      }),
    353      error(that)
    354    );
    355  }
    356 );
    357 
    358 // -----------------------------------------------------------------------------
    359 TestArray.addTest(
    360  "Fail generating an HMAC key when specifying an invalid hash algorithm",
    361  function() {
    362    var that = this;
    363    var alg = { name: "HMAC", hash: {name: "SHA-123"} };
    364    crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then(
    365      error(that),
    366      complete(that, function() { return true; })
    367    );
    368  }
    369 );
    370 
    371 // -----------------------------------------------------------------------------
    372 TestArray.addTest(
    373  "Fail generating an HMAC key when specifying a zero length",
    374  function() {
    375    var that = this;
    376    var alg = { name: "HMAC", hash: {name: "SHA-256"}, length: 0 };
    377    crypto.subtle.generateKey(alg, true, ["sign", "verify"]).then(
    378      error(that),
    379      complete(that, function() { return true; })
    380    );
    381  }
    382 );
    383 
    384 // -----------------------------------------------------------------------------
    385 TestArray.addTest(
    386  "Generate a 192-bit AES key",
    387  function() {
    388    var that = this;
    389    var alg = { name: "AES-GCM", length: 192 };
    390    crypto.subtle.generateKey(alg, true, ["encrypt"]).then(
    391      complete(that, function(x) {
    392        return hasKeyFields(x);
    393      }),
    394      error(that)
    395    );
    396  }
    397 );
    398 
    399 // -----------------------------------------------------------------------------
    400 TestArray.addTest(
    401  "Fail generating an AES key of wrong length",
    402  function() {
    403    var that = this;
    404    var alg = { name: "AES-CBC", length: 64 };
    405    crypto.subtle.generateKey(alg, false, ["encrypt"]).then(
    406      error(that),
    407      complete(that, function(e) {
    408        return e.name == "OperationError";
    409      })
    410    );
    411  }
    412 );
    413 
    414 // -----------------------------------------------------------------------------
    415 TestArray.addTest(
    416  "Fail generating a key with bad algorithm argument",
    417  function() {
    418    var that = this;
    419    var alg = { name: "AES", length: 128 };
    420    crypto.subtle.generateKey(alg, false, ["encrypt"]).then(
    421      error(that),
    422      complete(that, function(e) {
    423        return e.name == "NotSupportedError";
    424      })
    425    );
    426  }
    427 );
    428 
    429 // -----------------------------------------------------------------------------
    430 TestArray.addTest(  "Generate a 1024-bit RSA key",
    431  function() {
    432    var that = this;
    433    var alg = {
    434      name: "RSASSA-PKCS1-v1_5",
    435      hash: "SHA-256",
    436      modulusLength: 1024,
    437      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    438    };
    439    crypto.subtle.generateKey(alg, false, ["sign", "verify"]).then(
    440      complete(that, function(x) {
    441        return exists(x.publicKey) &&
    442               (x.publicKey.algorithm.name == alg.name) &&
    443               (x.publicKey.algorithm.modulusLength == alg.modulusLength) &&
    444               (x.publicKey.type == "public") &&
    445               x.publicKey.extractable &&
    446               (x.publicKey.usages.length == 1) &&
    447               (x.publicKey.usages[0] == "verify") &&
    448               exists(x.privateKey) &&
    449               (x.privateKey.algorithm.name == alg.name) &&
    450               (x.privateKey.algorithm.modulusLength == alg.modulusLength) &&
    451               (x.privateKey.type == "private") &&
    452               !x.privateKey.extractable &&
    453               (x.privateKey.usages.length == 1) &&
    454               (x.privateKey.usages[0] == "sign");
    455      }),
    456      error(that)
    457    );
    458  }
    459 );
    460 
    461 // -----------------------------------------------------------------------------
    462 TestArray.addTest(
    463  "Fail cleanly when NSS refuses to generate a key pair",
    464  function() {
    465    var that = this;
    466    var alg = {
    467      name: "RSASSA-PKCS1-v1_5",
    468      hash: "SHA-256",
    469      modulusLength: 2299, // NSS does not like this key length
    470      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    471    };
    472 
    473    crypto.subtle.generateKey(alg, false, ["sign"])
    474      .then( error(that), complete(that) );
    475  }
    476 );
    477 
    478 // -----------------------------------------------------------------------------
    479 TestArray.addTest(
    480  "SHA-256 digest",
    481  function() {
    482    var that = this;
    483    crypto.subtle.digest("SHA-256", tv.sha256.data).then(
    484      memcmp_complete(that, tv.sha256.result),
    485      error(that)
    486    );
    487  }
    488 );
    489 
    490 // -----------------------------------------------------------------------------
    491 TestArray.addTest(
    492  "Fail cleanly on unknown hash algorithm",
    493  function() {
    494    var that = this;
    495    crypto.subtle.digest("GOST-34_311-95", tv.sha256.data).then(
    496      error(that),
    497      complete(that, function() { return true; })
    498    );
    499  }
    500 );
    501 
    502 // -----------------------------------------------------------------------------
    503 TestArray.addTest(
    504  "AES-CBC encrypt",
    505  function() {
    506    var that = this;
    507 
    508    function doEncrypt(x) {
    509      return crypto.subtle.encrypt(
    510        { name: "AES-CBC", iv: tv.aes_cbc_enc.iv },
    511        x, tv.aes_cbc_enc.data);
    512    }
    513 
    514    crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ["encrypt"])
    515      .then(doEncrypt)
    516      .then(
    517        memcmp_complete(that, tv.aes_cbc_enc.result),
    518        error(that)
    519      );
    520  }
    521 );
    522 
    523 // -----------------------------------------------------------------------------
    524 TestArray.addTest(
    525  "AES-CBC encrypt with wrong IV size",
    526  function() {
    527    var that = this;
    528 
    529    function encrypt(x, iv) {
    530      return crypto.subtle.encrypt(
    531        { name: "AES-CBC", iv },
    532        x, tv.aes_cbc_enc.data);
    533    }
    534 
    535    function checkPromises(promises) {
    536      for (var promise of promises) {
    537        if (promise.status != "rejected") {
    538          return false;
    539        }
    540        if (promise.reason.name != "OperationError") {
    541          return false;
    542        }
    543      }
    544 
    545      return true;
    546    }
    547 
    548    crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ["encrypt"])
    549      .then(function(key) {
    550        var p1 = encrypt(key, new Uint8Array(15));
    551        var p2 = encrypt(key, new Uint8Array(17));
    552 
    553        Promise.allSettled([p1, p2])
    554          .then(complete(that, checkPromises));
    555      });
    556  }
    557 );
    558 
    559 // -----------------------------------------------------------------------------
    560 TestArray.addTest(
    561  "AES-CBC decrypt",
    562  function() {
    563    var that = this;
    564 
    565    function doDecrypt(x) {
    566      return crypto.subtle.decrypt(
    567        { name: "AES-CBC", iv: tv.aes_cbc_dec.iv },
    568        x, tv.aes_cbc_dec.data);
    569    }
    570 
    571    crypto.subtle.importKey("raw", tv.aes_cbc_dec.key, "AES-CBC", false, ["decrypt"])
    572      .then(doDecrypt)
    573      .then(
    574        memcmp_complete(that, tv.aes_cbc_dec.result),
    575        error(that)
    576      );
    577  }
    578 );
    579 
    580 // -----------------------------------------------------------------------------
    581 TestArray.addTest(
    582  "AES-CBC decrypt with wrong IV size",
    583  function() {
    584    var that = this;
    585 
    586    function decrypt(x, iv) {
    587      return crypto.subtle.decrypt(
    588        { name: "AES-CBC", iv },
    589        x, tv.aes_cbc_dec.data);
    590    }
    591 
    592    function checkPromises(promises) {
    593      for (var promise of promises) {
    594        if (promise.status != "rejected") {
    595          return false;
    596        }
    597        if (promise.reason.name != "OperationError") {
    598          return false;
    599        }
    600      }
    601 
    602      return true;
    603    }
    604 
    605    crypto.subtle.importKey("raw", tv.aes_cbc_dec.key, "AES-CBC", false, ["decrypt"])
    606      .then(function(key) {
    607        var p1 = decrypt(key, new Uint8Array(15));
    608        var p2 = decrypt(key, new Uint8Array(17));
    609 
    610        Promise.allSettled([p1, p2])
    611          .then(complete(that, checkPromises));
    612      });
    613  }
    614 );
    615 
    616 // -----------------------------------------------------------------------------
    617 TestArray.addTest(
    618  "AES-CTR encryption",
    619  function() {
    620    var that = this;
    621 
    622    function doEncrypt(x) {
    623      return crypto.subtle.encrypt(
    624        { name: "AES-CTR", counter: tv.aes_ctr_enc.iv, length: 32 },
    625        x, tv.aes_ctr_enc.data);
    626    }
    627 
    628    crypto.subtle.importKey("raw", tv.aes_ctr_enc.key, "AES-CTR", false, ["encrypt"])
    629      .then(doEncrypt)
    630      .then(
    631        memcmp_complete(that, tv.aes_ctr_enc.result),
    632        error(that)
    633      );
    634  }
    635 );
    636 
    637 // -----------------------------------------------------------------------------
    638 TestArray.addTest(
    639  "AES-CTR encryption with wrong IV size",
    640  function() {
    641    var that = this;
    642 
    643    function encrypt(x, iv) {
    644      return crypto.subtle.encrypt(
    645        { name: "AES-CTR", counter: iv, length: 32 },
    646        x, tv.aes_ctr_enc.data);
    647    }
    648 
    649    function checkPromises(promises) {
    650      for (var promise of promises) {
    651        if (promise.status != "rejected") {
    652          return false;
    653        }
    654        if (promise.reason.name != "OperationError") {
    655          return false;
    656        }
    657      }
    658 
    659      return true;
    660    }
    661 
    662    crypto.subtle.importKey("raw", tv.aes_ctr_enc.key, "AES-CTR", false, ["encrypt"])
    663      .then(function(key) {
    664        var p1 = encrypt(key, new Uint8Array(15));
    665        var p2 = encrypt(key, new Uint8Array(17));
    666 
    667        Promise.allSettled([p1, p2])
    668          .then(complete(that, checkPromises));
    669      });
    670  }
    671 );
    672 
    673 // -----------------------------------------------------------------------------
    674 TestArray.addTest(
    675  "AES-CTR decryption",
    676  function() {
    677    var that = this;
    678 
    679    function doDecrypt(x) {
    680      return crypto.subtle.decrypt(
    681        { name: "AES-CTR", counter: tv.aes_ctr_dec.iv, length: 32 },
    682        x, tv.aes_ctr_dec.data);
    683    }
    684 
    685    crypto.subtle.importKey("raw", tv.aes_ctr_dec.key, "AES-CTR", false, ["decrypt"])
    686      .then(doDecrypt)
    687      .then(
    688        memcmp_complete(that, tv.aes_ctr_dec.result),
    689        error(that)
    690      );
    691  }
    692 );
    693 
    694 // -----------------------------------------------------------------------------
    695 TestArray.addTest(
    696  "AES-CTR decryption with wrong IV size",
    697  function() {
    698    var that = this;
    699 
    700    function decrypt(x, iv) {
    701      return crypto.subtle.decrypt(
    702        { name: "AES-CTR", counter: iv, length: 32 },
    703        x, tv.aes_ctr_dec.data);
    704    }
    705 
    706    function checkPromises(promises) {
    707      for (var promise of promises) {
    708        if (promise.status != "rejected") {
    709          return false;
    710        }
    711        if (promise.reason.name != "OperationError") {
    712          return false;
    713        }
    714      }
    715 
    716      return true;
    717    }
    718 
    719    crypto.subtle.importKey("raw", tv.aes_ctr_dec.key, "AES-CTR", false, ["decrypt"])
    720      .then(function(key) {
    721        var p1 = decrypt(key, new Uint8Array(15));
    722        var p2 = decrypt(key, new Uint8Array(17));
    723 
    724        Promise.allSettled([p1, p2])
    725          .then(complete(that, checkPromises));
    726      });
    727  }
    728 );
    729 
    730 // -----------------------------------------------------------------------------
    731 TestArray.addTest(
    732  "AES-GCM encryption",
    733  function() {
    734    var that = this;
    735 
    736    function doEncrypt(x) {
    737      return crypto.subtle.encrypt(
    738        {
    739          name: "AES-GCM",
    740          iv: tv.aes_gcm_enc.iv,
    741          additionalData: tv.aes_gcm_enc.adata,
    742          tagLength: 128,
    743        },
    744        x, tv.aes_gcm_enc.data);
    745    }
    746 
    747    crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"])
    748      .then(doEncrypt)
    749      .then(
    750        memcmp_complete(that, tv.aes_gcm_enc.result),
    751        error(that)
    752      );
    753  }
    754 );
    755 
    756 // -----------------------------------------------------------------------------
    757 TestArray.addTest(
    758  "AES-GCM decryption",
    759  function() {
    760    var that = this;
    761 
    762    function doDecrypt(x) {
    763      return crypto.subtle.decrypt(
    764        {
    765          name: "AES-GCM",
    766          iv: tv.aes_gcm_dec.iv,
    767          additionalData: tv.aes_gcm_dec.adata,
    768          tagLength: 128,
    769        },
    770        x, tv.aes_gcm_dec.data);
    771    }
    772 
    773    crypto.subtle.importKey("raw", tv.aes_gcm_dec.key, "AES-GCM", false, ["decrypt"])
    774      .then(doDecrypt)
    775      .then(
    776        memcmp_complete(that, tv.aes_gcm_dec.result),
    777        error(that)
    778      );
    779  }
    780 );
    781 
    782 // -----------------------------------------------------------------------------
    783 TestArray.addTest(
    784  "AES-GCM decryption, failing authentication check",
    785  function() {
    786    var that = this;
    787 
    788    function doDecrypt(x) {
    789      return crypto.subtle.decrypt(
    790        {
    791          name: "AES-GCM",
    792          iv: tv.aes_gcm_dec_fail.iv,
    793          additionalData: tv.aes_gcm_dec_fail.adata,
    794          tagLength: 128,
    795        },
    796        x, tv.aes_gcm_dec_fail.data);
    797    }
    798 
    799    crypto.subtle.importKey("raw", tv.aes_gcm_dec_fail.key, "AES-GCM", false, ["decrypt"])
    800      .then(doDecrypt)
    801      .then(
    802        error(that),
    803        complete(that)
    804      );
    805  }
    806 );
    807 
    808 // -----------------------------------------------------------------------------
    809 TestArray.addTest(
    810  "AES-GCM encryption, fail with a zero-length IV",
    811  function() {
    812    var that = this;
    813    var alg = {
    814      name: "AES-GCM",
    815      iv: new Uint8Array(),
    816      additionalData: tv.aes_gcm_enc.adata,
    817      tagLength: 128,
    818    };
    819 
    820    function doEncrypt(x) {
    821      return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data);
    822    }
    823 
    824    crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"])
    825      .then(doEncrypt)
    826      .then(error(that), complete(that));
    827  }
    828 );
    829 
    830 // -----------------------------------------------------------------------------
    831 TestArray.addTest(
    832  "AES-GCM encryption, accept an all-zero IV (1 byte)",
    833  function() {
    834    var that = this;
    835    var alg = {
    836      name: "AES-GCM",
    837      iv: new Uint8Array(1),
    838      additionalData: tv.aes_gcm_enc.adata,
    839      tagLength: 128,
    840    };
    841 
    842    function doEncrypt(x) {
    843      return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data);
    844    }
    845 
    846    crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"])
    847      .then(doEncrypt)
    848      .then(complete(that), error(that));
    849  }
    850 );
    851 
    852 // -----------------------------------------------------------------------------
    853 TestArray.addTest(
    854  "AES-GCM encryption, accept an all-zero IV (12 bytes)",
    855  function() {
    856    var that = this;
    857    var alg = {
    858      name: "AES-GCM",
    859      iv: new Uint8Array(12),
    860      additionalData: tv.aes_gcm_enc.adata,
    861      tagLength: 128,
    862    };
    863 
    864    function doEncrypt(x) {
    865      return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data);
    866    }
    867 
    868    crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"])
    869      .then(doEncrypt)
    870      .then(complete(that), error(that));
    871  }
    872 );
    873 
    874 // -----------------------------------------------------------------------------
    875 TestArray.addTest(
    876  "AES-GCM encryption, accept an all-zero IV (16 bytes)",
    877  function() {
    878    var that = this;
    879    var alg = {
    880      name: "AES-GCM",
    881      iv: new Uint8Array(16),
    882      additionalData: tv.aes_gcm_enc.adata,
    883      tagLength: 128,
    884    };
    885 
    886    function doEncrypt(x) {
    887      return crypto.subtle.encrypt(alg, x, tv.aes_gcm_enc.data);
    888    }
    889 
    890    crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ["encrypt"])
    891      .then(doEncrypt)
    892      .then(complete(that), error(that));
    893  }
    894 );
    895 
    896 // -----------------------------------------------------------------------------
    897 TestArray.addTest(
    898  "HMAC SHA-256 sign",
    899  function() {
    900    var that = this;
    901    var alg = {
    902      name: "HMAC",
    903      hash: "SHA-256",
    904    };
    905 
    906    function doSign(x) {
    907      return crypto.subtle.sign("HMAC", x, tv.hmac_sign.data);
    908    }
    909 
    910    crypto.subtle.importKey("raw", tv.hmac_sign.key, alg, false, ["sign"])
    911      .then(doSign)
    912      .then(
    913        memcmp_complete(that, tv.hmac_sign.result),
    914        error(that)
    915      );
    916  }
    917 );
    918 
    919 // -----------------------------------------------------------------------------
    920 TestArray.addTest(
    921  "HMAC SHA-256 verify",
    922  function() {
    923    var that = this;
    924    var alg = {
    925      name: "HMAC",
    926      hash: "SHA-256",
    927    };
    928 
    929    function doVerify(x) {
    930      return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig, tv.hmac_verify.data);
    931    }
    932 
    933    crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["verify"])
    934      .then(doVerify)
    935      .then(
    936        complete(that, function(x) { return !!x; }),
    937        error(that)
    938      );
    939  }
    940 );
    941 
    942 // -----------------------------------------------------------------------------
    943 TestArray.addTest(
    944  "HMAC SHA-256, failing verification due to bad signature",
    945  function() {
    946    var that = this;
    947    var alg = {
    948      name: "HMAC",
    949      hash: "SHA-256",
    950    };
    951 
    952    function doVerify(x) {
    953      return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig_fail,
    954                                             tv.hmac_verify.data);
    955    }
    956 
    957    crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["verify"])
    958      .then(doVerify)
    959      .then(
    960        complete(that, function(x) { return !x; }),
    961        error(that)
    962      );
    963  }
    964 );
    965 
    966 // -----------------------------------------------------------------------------
    967 TestArray.addTest(
    968  "HMAC SHA-256, failing verification due to key usage restriction",
    969  function() {
    970    var that = this;
    971    var alg = {
    972      name: "HMAC",
    973      hash: "SHA-256",
    974    };
    975 
    976    function doVerify(x) {
    977      return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig,
    978                                             tv.hmac_verify.data);
    979    }
    980 
    981    crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ["encrypt"])
    982      .then(doVerify)
    983      .then(
    984        error(that),
    985        complete(that, function() { return true; })
    986      );
    987  }
    988 );
    989 
    990 // -----------------------------------------------------------------------------
    991 TestArray.addTest(
    992  "RSASSA/SHA-1 signature",
    993  function() {
    994    var that = this;
    995    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
    996 
    997    function doSign(x) {
    998      return crypto.subtle.sign(alg.name, x, tv.rsassa.data);
    999    }
   1000 
   1001    crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ["sign"])
   1002      .then( doSign )
   1003      .then( memcmp_complete(that, tv.rsassa.sig1), error(that) );
   1004  }
   1005 );
   1006 
   1007 // -----------------------------------------------------------------------------
   1008 TestArray.addTest(
   1009  "RSASSA verification (SHA-1)",
   1010  function() {
   1011    var that = this;
   1012    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
   1013 
   1014    function doVerify(x) {
   1015      return crypto.subtle.verify(alg.name, x, tv.rsassa.sig1, tv.rsassa.data);
   1016    }
   1017 
   1018    crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"])
   1019      .then( doVerify )
   1020      .then(
   1021        complete(that, function(x) { return x; }),
   1022        error(that)
   1023      );
   1024  }
   1025 );
   1026 
   1027 // -----------------------------------------------------------------------------
   1028 TestArray.addTest(
   1029  "RSASSA verification (SHA-1), failing verification",
   1030  function() {
   1031    var that = this;
   1032    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
   1033 
   1034    function doVerify(x) {
   1035      return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data);
   1036    }
   1037 
   1038    crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"])
   1039      .then( doVerify )
   1040      .then(
   1041        complete(that, function(x) { return !x; }),
   1042        error(that)
   1043      );
   1044  }
   1045 );
   1046 
   1047 // -----------------------------------------------------------------------------
   1048 TestArray.addTest(
   1049  "RSASSA/SHA-256 signature",
   1050  function() {
   1051    var that = this;
   1052    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
   1053 
   1054    function doSign(x) {
   1055      return crypto.subtle.sign(alg.name, x, tv.rsassa.data);
   1056    }
   1057 
   1058    crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ["sign"])
   1059      .then( doSign )
   1060      .then( memcmp_complete(that, tv.rsassa.sig256), error(that) );
   1061  }
   1062 );
   1063 
   1064 // -----------------------------------------------------------------------------
   1065 TestArray.addTest(
   1066  "RSASSA verification (SHA-256)",
   1067  function() {
   1068    var that = this;
   1069    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
   1070 
   1071    function doVerify(x) {
   1072      return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data);
   1073    }
   1074 
   1075    crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"])
   1076      .then( doVerify )
   1077      .then(
   1078        complete(that, function(x) { return x; }),
   1079        error(that)
   1080      );
   1081  }
   1082 );
   1083 
   1084 // -----------------------------------------------------------------------------
   1085 TestArray.addTest(
   1086  "RSASSA verification (SHA-256), failing verification",
   1087  function() {
   1088    var that = this;
   1089    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
   1090 
   1091    function doVerify(x) {
   1092      return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data);
   1093    }
   1094 
   1095    crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ["verify"])
   1096      .then( doVerify )
   1097      .then(
   1098        complete(that, function(x) { return !x; }),
   1099        error(that)
   1100      );
   1101  }
   1102 );
   1103 
   1104 // -----------------------------------------------------------------------------
   1105 TestArray.addTest(
   1106  "Test that we return ArrayBuffers not ArrayBufferViews",
   1107  function() {
   1108    var that = this;
   1109 
   1110    crypto.subtle.digest("SHA-256", tv.sha256.data)
   1111      .then(complete(that, function(x) {
   1112        return x instanceof ArrayBuffer;
   1113      }), error(that));
   1114  }
   1115 );
   1116 
   1117 // -----------------------------------------------------------------------------
   1118 TestArray.addTest(
   1119  "Ensure that importing an invalid key doesn't crash",
   1120  function() {
   1121    var that = this;
   1122    var alg = {name: "RSA-OAEP", hash: "SHA-1"};
   1123 
   1124    crypto.subtle.importKey("pkcs8", tv.broken_pkcs8.rsa, alg, false, ["decrypt"])
   1125      .then(error(that), complete(that));
   1126  }
   1127 );
   1128 
   1129 // -----------------------------------------------------------------------------
   1130 TestArray.addTest(
   1131  "Test that we check keys before using them for encryption/signatures",
   1132  function() {
   1133    var that = this;
   1134 
   1135    function doCheckRSASSA() {
   1136      var alg = {name: "HMAC", hash: {name: "SHA-1"}};
   1137 
   1138      function doSign(x) {
   1139        return crypto.subtle.sign("RSASSA-PKCS1-v1_5", x, new Uint8Array());
   1140      }
   1141 
   1142      return crypto.subtle.generateKey(alg, false, ["sign"]).then(doSign);
   1143    }
   1144 
   1145    doCheckRSASSA().then(error(that), complete(that));
   1146  }
   1147 );
   1148 
   1149 // -----------------------------------------------------------------------------
   1150 TestArray.addTest(
   1151  "Test that we're using the right globals when creating objects",
   1152  function() {
   1153    // This test isn't supported in workers.
   1154    if (window.importScripts) {
   1155      return this.complete(true);
   1156    }
   1157 
   1158    var that = this;
   1159    var data = crypto.getRandomValues(new Uint8Array(10));
   1160    var hmacAlg = {name: "HMAC", length: 256, hash: "SHA-1"};
   1161 
   1162    var rsaAlg = {
   1163      name: "RSA-PSS",
   1164      hash: "SHA-1",
   1165      modulusLength: 1024,
   1166      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
   1167    };
   1168 
   1169    function checkPrototypes(obj, type) {
   1170      return obj.__proto__ != window[type].prototype &&
   1171             obj.__proto__ == frames[0][type].prototype;
   1172    }
   1173 
   1174    var p1 = crypto.subtle.importKey.call(
   1175      frames[0].crypto.subtle, "raw", data, hmacAlg, false, ["sign", "verify"]);
   1176    var p2 = crypto.subtle.generateKey.call(
   1177      frames[0].crypto.subtle, hmacAlg, false, ["sign", "verify"]);
   1178    var p3 = crypto.subtle.generateKey.call(
   1179      frames[0].crypto.subtle, rsaAlg, false, ["sign", "verify"]);
   1180 
   1181    if (!checkPrototypes(p1, "Promise") ||
   1182        !checkPrototypes(p2, "Promise") ||
   1183        !checkPrototypes(p3, "Promise")) {
   1184      error(that)();
   1185    }
   1186 
   1187    return Promise.all([p1, p2, p3]).then(complete(that, keys => {
   1188      return keys.every(key => {
   1189        if (key instanceof frames[0].CryptoKey) {
   1190          return checkPrototypes(key, "CryptoKey");
   1191        }
   1192 
   1193        return checkPrototypes(key.publicKey, "CryptoKey") &&
   1194               checkPrototypes(key.privateKey, "CryptoKey");
   1195      });
   1196    }), error(that));
   1197  }
   1198 );
   1199 /* ]]>*/</script>
   1200 </head>
   1201 
   1202 <body>
   1203 
   1204 <div id="content">
   1205 <div id="head">
   1206 	<b>Web</b>Crypto<br>
   1207 </div>
   1208 
   1209    <iframe style="display: none;"></iframe>
   1210    <div id="start" onclick="start();">RUN ALL</div>
   1211 
   1212    <div id="resultDiv" class="content">
   1213    Summary:
   1214    <span class="pass"><span id="passN">0</span> passed, </span>
   1215    <span class="fail"><span id="failN">0</span> failed, </span>
   1216    <span class="pending"><span id="pendingN">0</span> pending.</span>
   1217    <br/>
   1218    <br/>
   1219 
   1220    <table id="results">
   1221        <tr>
   1222            <th>Test</th>
   1223            <th>Result</th>
   1224            <th>Time</th>
   1225        </tr>
   1226    </table>
   1227 
   1228    </div>
   1229 
   1230    <div id="foot"></div>
   1231 </div>
   1232 
   1233 </body>
   1234 </html>