tor-browser

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

test_WebCrypto_ECDH.html (22288B)


      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  "Generate an ECDH key for named curve P-256",
     28  function() {
     29    var that = this;
     30    var alg = { name: "ECDH", namedCurve: "P-256" };
     31    crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]).then(
     32      complete(that, function(x) {
     33        return exists(x.publicKey) &&
     34               (x.publicKey.algorithm.name == alg.name) &&
     35               (x.publicKey.algorithm.namedCurve == alg.namedCurve) &&
     36               (x.publicKey.type == "public") &&
     37               x.publicKey.extractable &&
     38               (!x.publicKey.usages.length) &&
     39               exists(x.privateKey) &&
     40               (x.privateKey.algorithm.name == alg.name) &&
     41               (x.privateKey.algorithm.namedCurve == alg.namedCurve) &&
     42               (x.privateKey.type == "private") &&
     43               !x.privateKey.extractable &&
     44               (x.privateKey.usages.length == 2) &&
     45               (x.privateKey.usages[0] == "deriveKey") &&
     46               (x.privateKey.usages[1] == "deriveBits");
     47      }),
     48      error(that)
     49    );
     50  }
     51 );
     52 
     53 // -----------------------------------------------------------------------------
     54 TestArray.addTest(
     55  "Generate an ECDH key and derive some bits",
     56  function() {
     57    var that = this;
     58    var alg = { name: "ECDH", namedCurve: "P-256" };
     59 
     60    var pair;
     61    function setKeyPair(x) { pair = x; }
     62 
     63    function doDerive(n) {
     64      return function() {
     65        return crypto.subtle.deriveBits({ name: "ECDH", public: pair.publicKey }, pair.privateKey, n * 8);
     66      };
     67    }
     68 
     69    crypto.subtle.generateKey(alg, false, ["deriveBits"])
     70      .then(setKeyPair, error(that))
     71      .then(doDerive(2), error(that))
     72      .then(function(x) {
     73        // Deriving less bytes works.
     74        if (x.byteLength != 2) {
     75          throw new Error("should have derived two bytes");
     76        }
     77      })
     78      // Deriving more than the curve yields doesn't.
     79      .then(doDerive(33), error(that))
     80      .then(error(that), complete(that));
     81  }
     82 );
     83 
     84 // -----------------------------------------------------------------------------
     85 TestArray.addTest(
     86  "Test that ECDH deriveBits() fails when the public key is not an ECDH key",
     87  function() {
     88    var that = this;
     89    var pubKey, privKey;
     90    function setPub(x) { pubKey = x.publicKey; }
     91    function setPriv(x) { privKey = x.privateKey; }
     92 
     93    function doGenerateP256() {
     94      var alg = { name: "ECDH", namedCurve: "P-256" };
     95      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
     96    }
     97 
     98    function doGenerateRSA() {
     99      var alg = {
    100        name: "RSA-OAEP",
    101        hash: "SHA-256",
    102        modulusLength: 2048,
    103        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    104      };
    105      return crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]);
    106    }
    107 
    108    function doDerive() {
    109      var alg = { name: "ECDH", public: pubKey };
    110      return crypto.subtle.deriveBits(alg, privKey, 16);
    111    }
    112 
    113    doGenerateP256()
    114      .then(setPriv, error(that))
    115      .then(doGenerateRSA, error(that))
    116      .then(setPub, error(that))
    117      .then(doDerive, error(that))
    118      .then(error(that), complete(that));
    119  }
    120 );
    121 
    122 // -----------------------------------------------------------------------------
    123 TestArray.addTest(
    124  "Test that ECDH deriveBits() fails when the given keys' curves don't match",
    125  function() {
    126    var that = this;
    127    var pubKey, privKey;
    128    function setPub(x) { pubKey = x.publicKey; }
    129    function setPriv(x) { privKey = x.privateKey; }
    130 
    131    function doGenerateP256() {
    132      var alg = { name: "ECDH", namedCurve: "P-256" };
    133      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
    134    }
    135 
    136    function doGenerateP384() {
    137      var alg = { name: "ECDH", namedCurve: "P-384" };
    138      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
    139    }
    140 
    141    function doDerive() {
    142      var alg = { name: "ECDH", public: pubKey };
    143      return crypto.subtle.deriveBits(alg, privKey, 16);
    144    }
    145 
    146    doGenerateP256()
    147      .then(setPriv, error(that))
    148      .then(doGenerateP384, error(that))
    149      .then(setPub, error(that))
    150      .then(doDerive, error(that))
    151      .then(error(that), complete(that));
    152  }
    153 );
    154 
    155 // -----------------------------------------------------------------------------
    156 TestArray.addTest(
    157  "Verify that ECDH import fails with a key with a mismatched 'crv' field",
    158  function() {
    159    var that = this;
    160    var alg = { name: "ECDH", namedCurve: "P-521"};
    161 
    162    crypto.subtle.importKey("jwk", tv.ecdsa_jwk_crv_mismatch.pub_jwk, alg, true, ["verify"])
    163      .then(error(that), complete(that));
    164  }
    165 );
    166 
    167 // -----------------------------------------------------------------------------
    168 TestArray.addTest(
    169  "JWK import an ECDH public and private key and derive bits (P-256)",
    170  function() {
    171    var that = this;
    172    var alg = { name: "ECDH", namedCurve: "P-256" };
    173 
    174    var pubKey, privKey;
    175    function setPub(x) { pubKey = x; }
    176    function setPriv(x) { privKey = x; }
    177 
    178    function doDerive() {
    179      return crypto.subtle.deriveBits({ name: "ECDH", public: pubKey }, privKey, tv.ecdh_p256.secret.byteLength * 8);
    180    }
    181 
    182    Promise.all([
    183      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, false, ["deriveBits"])
    184        .then(setPriv, error(that)),
    185      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_pub, alg, false, [])
    186        .then(setPub, error(that)),
    187    ]).then(doDerive, error(that))
    188      .then(memcmp_complete(that, tv.ecdh_p256.secret), error(that));
    189  }
    190 );
    191 
    192 // -----------------------------------------------------------------------------
    193 TestArray.addTest(
    194  "JWK import an ECDH public and private key and derive bits (P-384)",
    195  function() {
    196    var that = this;
    197    var alg = { name: "ECDH", namedCurve: "P-384"};
    198 
    199    var pubKey, privKey;
    200    function setPub(x) { pubKey = x; }
    201    function setPriv(x) { privKey = x; }
    202 
    203    function doDerive() {
    204      return crypto.subtle.deriveBits({ name: "ECDH", public: pubKey }, privKey, tv.ecdh_p384.secret.byteLength * 8);
    205    }
    206 
    207    Promise.all([
    208      crypto.subtle.importKey("jwk", tv.ecdh_p384.jwk_priv, alg, false, ["deriveBits"])
    209        .then(setPriv, error(that)),
    210      crypto.subtle.importKey("jwk", tv.ecdh_p384.jwk_pub, alg, false, [])
    211        .then(setPub, error(that)),
    212    ]).then(doDerive, error(that))
    213      .then(memcmp_complete(that, tv.ecdh_p384.secret), error(that));
    214  }
    215 );
    216 
    217 // -----------------------------------------------------------------------------
    218 TestArray.addTest(
    219  "JWK import an ECDH public and private key and derive bits (P-521)",
    220  function() {
    221    var that = this;
    222    var alg = { name: "ECDH", namedCurve : "P-521" };
    223 
    224    var pubKey, privKey;
    225    function setPub(x) { pubKey = x; }
    226    function setPriv(x) { privKey = x; }
    227 
    228    function doDerive() {
    229      return crypto.subtle.deriveBits({ name: "ECDH", public: pubKey }, privKey, tv.ecdh_p521.secret.byteLength * 8);
    230    }
    231 
    232    Promise.all([
    233      crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveBits"])
    234        .then(setPriv, error(that)),
    235      crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, [])
    236        .then(setPub, error(that)),
    237    ]).then(doDerive, error(that))
    238      .then(memcmp_complete(that, tv.ecdh_p521.secret), error(that));
    239  }
    240 );
    241 
    242 // -----------------------------------------------------------------------------
    243 TestArray.addTest(
    244  "JWK import/export roundtrip with ECDH (P-256)",
    245  function() {
    246    var that = this;
    247    var alg = { name: "ECDH", namedCurve : "P-256" };
    248 
    249    var pubKey, privKey;
    250    function setPub(x) { pubKey = x; }
    251    function setPriv(x) { privKey = x; }
    252 
    253    function doExportPub() {
    254      return crypto.subtle.exportKey("jwk", pubKey);
    255    }
    256    function doExportPriv() {
    257      return crypto.subtle.exportKey("jwk", privKey);
    258    }
    259 
    260    Promise.all([
    261      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, true, ["deriveBits"])
    262        .then(setPriv, error(that)),
    263      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_pub, alg, true, [])
    264        .then(setPub, error(that)),
    265    ]).then(doExportPub, error(that))
    266      .then(function(x) {
    267        var tp = tv.ecdh_p256.jwk_pub;
    268        if ((tp.kty != x.kty) &&
    269            (tp.crv != x.crv) &&
    270            (tp.x != x.x) &&
    271            (tp.y != x.y)) {
    272          throw new Error("exported public key doesn't match");
    273        }
    274      }, error(that))
    275      .then(doExportPriv, error(that))
    276      .then(complete(that, function(x) {
    277        var tp = tv.ecdh_p256.jwk_priv;
    278        return (tp.kty == x.kty) &&
    279               (tp.crv == x.crv) &&
    280               (tp.d == x.d) &&
    281               (tp.x == x.x) &&
    282               (tp.y == x.y);
    283      }), error(that));
    284  }
    285 );
    286 
    287 // -----------------------------------------------------------------------------
    288 TestArray.addTest(
    289  "PKCS8 import/export roundtrip with ECDH (P-256)",
    290  function() {
    291    var that = this;
    292    var alg = { name: "ECDH", namedCurve: "P-256" };
    293 
    294    function doExportPriv(x) {
    295      return crypto.subtle.exportKey("pkcs8", x);
    296    }
    297 
    298    crypto.subtle.importKey("pkcs8", tv.ecdh_p256.pkcs8, alg, true, ["deriveBits"])
    299   .then(doExportPriv, error(that))
    300      .then(complete(that, function(x) {
    301        return util.memcmp(x, tv.ecdh_p256.pkcs8);
    302      }), error(that));
    303  }
    304 );
    305 
    306 // -----------------------------------------------------------------------------
    307 TestArray.addTest(
    308  "Test that importing bad JWKs fails",
    309  function() {
    310    var that = this;
    311    var alg = { name: "ECDH", namedCurve: "P-256" };
    312    var tvs = tv.ecdh_p256_negative;
    313 
    314    function doTryImport(jwk) {
    315      return function() {
    316        return crypto.subtle.importKey("jwk", jwk, alg, false, ["deriveBits"]);
    317      };
    318    }
    319 
    320    doTryImport(tvs.jwk_bad_crv)()
    321      .then(error(that), doTryImport(tvs.jwk_different_crv))
    322      .then(error(that), doTryImport(tvs.jwk_missing_crv))
    323      .then(error(that), doTryImport(tvs.jwk_missing_x))
    324      .then(error(that), doTryImport(tvs.jwk_missing_y))
    325      .then(error(that), complete(that));
    326  }
    327 );
    328 
    329 // -----------------------------------------------------------------------------
    330 TestArray.addTest(
    331  "JWK export of a newly generated ECDH private key",
    332  function() {
    333    var that = this;
    334    var alg = { name: "ECDH", namedCurve: "P-256" };
    335    var reBase64URL = /^[a-zA-Z0-9_-]+$/;
    336 
    337    function doExportToJWK(x) {
    338      return crypto.subtle.exportKey("jwk", x.privateKey);
    339    }
    340 
    341    crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"])
    342      .then(doExportToJWK)
    343      .then(
    344        complete(that, function(x) {
    345          return x.ext &&
    346                 x.kty == "EC" &&
    347                 x.crv == "P-256" &&
    348                 reBase64URL.test(x.x) &&
    349                 reBase64URL.test(x.y) &&
    350                 reBase64URL.test(x.d) &&
    351                 x.x.length == 43 && // 32 octets, base64-encoded
    352                 x.y.length == 43 && // 32 octets, base64-encoded
    353                 shallowArrayEquals(x.key_ops, ["deriveKey", "deriveBits"]);
    354          }),
    355        error(that)
    356      );
    357  }
    358 );
    359 
    360 // -----------------------------------------------------------------------------
    361 TestArray.addTest(
    362  "Derive an HMAC key from two ECDH keys and test sign/verify",
    363  function() {
    364    var that = this;
    365    var alg = { name: "ECDH", namedCurve: "P-521" };
    366    var algDerived = { name: "HMAC", hash: {name: "SHA-1"} };
    367 
    368    var pubKey, privKey;
    369    function setPub(x) { pubKey = x; }
    370    function setPriv(x) { privKey = x; }
    371 
    372    function doDerive() {
    373      return crypto.subtle.deriveKey({ name: "ECDH", public: pubKey }, privKey, algDerived, false, ["sign", "verify"])
    374        .then(function(x) {
    375          if (!hasKeyFields(x)) {
    376            throw new Error("Invalid key; missing field(s)");
    377          }
    378 
    379          // 512 bit is the default for HMAC-SHA1.
    380          if (x.algorithm.length != 512) {
    381            throw new Error("Invalid key; incorrect length");
    382          }
    383 
    384          return x;
    385        });
    386    }
    387 
    388    function doSignAndVerify(x) {
    389      var data = crypto.getRandomValues(new Uint8Array(1024));
    390      return crypto.subtle.sign("HMAC", x, data)
    391        .then(function(sig) {
    392          return crypto.subtle.verify("HMAC", x, sig, data);
    393        });
    394    }
    395 
    396    Promise.all([
    397      crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveKey"])
    398        .then(setPriv),
    399      crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, [])
    400        .then(setPub),
    401    ]).then(doDerive)
    402      .then(doSignAndVerify)
    403      .then(complete(that, x => x), error(that));
    404  }
    405 );
    406 
    407 // -----------------------------------------------------------------------------
    408 TestArray.addTest(
    409  "Derive an HKDF key from two ECDH keys and derive an HMAC key from that",
    410  function() {
    411    var that = this;
    412    var alg = { name: "ECDH", namedCurve: "P-256" };
    413 
    414    async function doTest() {
    415      let privKey = await crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, false, ["deriveKey"]);
    416      let pubKey = await crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_pub, alg, false, []);
    417      let ecdhAlg = { name: "ECDH", public: pubKey };
    418      let hkdfAlg = { name: "HKDF", hash: "SHA-256", salt: new Uint8Array(), info: new Uint8Array() };
    419      let hkdfKey = await crypto.subtle.deriveKey(ecdhAlg, privKey, hkdfAlg, false, ["deriveKey"]);
    420      let hmacAlg = { name: "HMAC", hash: "SHA-256" };
    421      let hmacKey = await crypto.subtle.deriveKey(hkdfAlg, hkdfKey, hmacAlg, false, ["sign"]);
    422      return crypto.subtle.sign("HMAC", hmacKey, new Uint8Array());
    423    }
    424    const expected = util.hex2abv("acf62832fa93469824cd997593bc963b28a68e6f73f4516bbe51b35942fe9811");
    425    doTest().then(memcmp_complete(that, expected), error(that));
    426  }
    427 );
    428 
    429 // -----------------------------------------------------------------------------
    430 // See bug 1994770
    431 TestArray.addTest(
    432  "Derive an AES Key from two X25519 keys",
    433  function() {
    434    var that = this;
    435    const alg = { name: 'X25519' };
    436    const lengths = [128, 192, 256];
    437 
    438    async function deriveKey(algorithm, privateKey, publicKey, length) {
    439      return window.crypto.subtle.deriveKey(
    440        { name: algorithm.name, public: publicKey },
    441        privateKey,
    442        { name: 'AES-GCM', length },
    443        true,
    444        ['encrypt', 'decrypt'],
    445      );
    446    }
    447 
    448    async function doTest(length) {
    449      let keyPair1 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]);
    450      let keyPair2 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]);
    451      let derivedKey = await deriveKey(alg, keyPair1.privateKey, keyPair2.publicKey, length);
    452      const raw = await window.crypto.subtle.exportKey('raw', derivedKey);
    453      const bitLength = raw.byteLength * 8;
    454      return bitLength === length;
    455    }
    456 
    457    Promise.all(lengths.map(doTest))
    458      .then(complete(that, function(results) {
    459        return results.every(result => result === true);
    460      }))
    461      .catch(error(that));
    462  }
    463 );
    464 
    465 // See bug 1994770
    466 TestArray.addTest(
    467  "Derive an AES Key from two X25519 keys (invalid length)",
    468  function() {
    469    var that = this;
    470    const alg = { name: "X25519" };
    471    // AES-GCM only accepts 128, 192, 256.
    472    const invalidLengths = [0, 64, 129, 200];
    473 
    474    async function deriveKey(algorithm, privateKey, publicKey, length) {
    475      return window.crypto.subtle.deriveKey(
    476        { name: algorithm.name, public: publicKey },
    477        privateKey,
    478        { name: "AES-GCM", length },
    479        true,
    480        ["encrypt", "decrypt"],
    481      );
    482    }
    483 
    484    async function doTest(length) {
    485      let keyPair1 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]);
    486      let keyPair2 = await crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"]);
    487      try {
    488        await deriveKey(alg, keyPair1.privateKey, keyPair2.publicKey, length);
    489        return false;
    490      } catch (e) {
    491        return true;
    492      }
    493    }
    494 
    495    Promise.all(invalidLengths.map(doTest))
    496      .then(complete(that, function(results) {
    497          return results.every(result => result === true);
    498        }),
    499      )
    500      .catch(error(that));
    501  }
    502 );
    503 
    504 // -----------------------------------------------------------------------------
    505 TestArray.addTest(
    506  "SPKI import/export of public ECDH keys (P-256)",
    507  function() {
    508    var that = this;
    509    var alg = { name: "ECDH" };
    510    var keys = ["spki", "spki_id_ecpk"];
    511 
    512    function doImport(key) {
    513      return crypto.subtle.importKey("spki", tv.ecdh_p256[key], alg, true, []);
    514    }
    515 
    516    function doExport(x) {
    517      return crypto.subtle.exportKey("spki", x);
    518    }
    519 
    520    function nextKey() {
    521      var key = keys.shift();
    522      var imported = doImport(key);
    523      var derived = imported.then(doExport);
    524 
    525      return derived.then(function(x) {
    526        if (!util.memcmp(x, tv.ecdh_p256.spki_id_ecpk)) {
    527          throw new Error("exported key is invalid");
    528        }
    529 
    530        if (keys.length) {
    531          return nextKey();
    532        }
    533        return Promise.resolve();
    534      });
    535    }
    536 
    537    nextKey().then(complete(that), error(that));
    538  }
    539 );
    540 
    541 // -----------------------------------------------------------------------------
    542 TestArray.addTest(
    543  "SPKI/JWK import ECDH keys (P-256) and derive a known secret",
    544  function() {
    545    var that = this;
    546    var alg = { name: "ECDH", namedCurve: "P-256" };
    547 
    548    var pubKey, privKey;
    549    function setPub(x) { pubKey = x; }
    550    function setPriv(x) { privKey = x; }
    551 
    552    function doDerive() {
    553      return crypto.subtle.deriveBits({ name: "ECDH", public: pubKey }, privKey, tv.ecdh_p256.secret.byteLength * 8);
    554    }
    555 
    556    Promise.all([
    557      crypto.subtle.importKey("spki", tv.ecdh_p256.spki, alg, false, [])
    558        .then(setPub),
    559      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, false, ["deriveBits"])
    560        .then(setPriv),
    561    ]).then(doDerive)
    562      .then(memcmp_complete(that, tv.ecdh_p256.secret), error(that));
    563  }
    564 );
    565 
    566 // -----------------------------------------------------------------------------
    567 TestArray.addTest(
    568  "Raw import/export of a public ECDH key (P-256)",
    569  function() {
    570    var that = this;
    571    var alg = { name: "ECDH", namedCurve: "P-256" };
    572 
    573    function doExport(x) {
    574      return crypto.subtle.exportKey("raw", x);
    575    }
    576 
    577    crypto.subtle.importKey("raw", tv.ecdh_p256.raw, alg, true, [])
    578      .then(doExport)
    579      .then(memcmp_complete(that, tv.ecdh_p256.raw), error(that));
    580  }
    581 );
    582 
    583 // -----------------------------------------------------------------------------
    584 TestArray.addTest(
    585  "Test that importing bad raw ECDH keys fails",
    586  function() {
    587    var that = this;
    588    var alg = { name: "ECDH", namedCurve: "P-256" };
    589 
    590    crypto.subtle.importKey("raw", tv.ecdh_p256_negative.raw_bad, alg, false, [])
    591      .then(error(that), complete(that));
    592  }
    593 );
    594 
    595 // -----------------------------------------------------------------------------
    596 TestArray.addTest(
    597  "Test that importing ECDH keys with an unknown format fails",
    598  function() {
    599    var that = this;
    600    var alg = { name: "ECDH", namedCurve: "P-256" };
    601 
    602    crypto.subtle.importKey("unknown", tv.ecdh_p256.raw, alg, false, [])
    603      .then(error(that), complete(that));
    604  }
    605 );
    606 
    607 // -----------------------------------------------------------------------------
    608 TestArray.addTest(
    609  "Test that importing too short raw ECDH keys fails",
    610  function() {
    611    var that = this;
    612    var alg = { name: "ECDH", namedCurve: "P-256" };
    613 
    614    crypto.subtle.importKey("raw", tv.ecdh_p256_negative.raw_short, alg, false, [])
    615      .then(error(that), complete(that));
    616  }
    617 );
    618 
    619 // -----------------------------------------------------------------------------
    620 TestArray.addTest(
    621  "Test that importing too long raw ECDH keys fails",
    622  function() {
    623    var that = this;
    624    var alg = { name: "ECDH", namedCurve: "P-256" };
    625 
    626    crypto.subtle.importKey("raw", tv.ecdh_p256_negative.raw_long, alg, false, [])
    627      .then(error(that), complete(that));
    628  }
    629 );
    630 
    631 // -----------------------------------------------------------------------------
    632 TestArray.addTest(
    633  "Test that importing compressed raw ECDH keys fails",
    634  function() {
    635    var that = this;
    636    var alg = { name: "ECDH", namedCurve: "P-256" };
    637 
    638    crypto.subtle.importKey("raw", tv.ecdh_p256_negative.raw_compressed, alg, false, [])
    639      .then(error(that), complete(that));
    640  }
    641 );
    642 
    643 // -----------------------------------------------------------------------------
    644 TestArray.addTest(
    645  "RAW/JWK import ECDH keys (P-256) and derive a known secret",
    646  function() {
    647    var that = this;
    648    var alg = { name: "ECDH", namedCurve: "P-256" };
    649 
    650    var pubKey, privKey;
    651    function setPub(x) { pubKey = x; }
    652    function setPriv(x) { privKey = x; }
    653 
    654    function doDerive() {
    655      return crypto.subtle.deriveBits({ name: "ECDH", public: pubKey }, privKey, tv.ecdh_p256.secret.byteLength * 8);
    656    }
    657 
    658    Promise.all([
    659      crypto.subtle.importKey("raw", tv.ecdh_p256.raw, alg, false, [])
    660        .then(setPub),
    661      crypto.subtle.importKey("jwk", tv.ecdh_p256.jwk_priv, alg, false, ["deriveBits"])
    662        .then(setPriv),
    663    ]).then(doDerive)
    664      .then(memcmp_complete(that, tv.ecdh_p256.secret), error(that));
    665  }
    666 );
    667 /* ]]>*/</script>
    668 </head>
    669 
    670 <body>
    671 
    672 <div id="content">
    673 <div id="head">
    674 	<b>Web</b>Crypto<br>
    675 </div>
    676 
    677    <div id="start" onclick="start();">RUN ALL</div>
    678 
    679    <div id="resultDiv" class="content">
    680    Summary:
    681    <span class="pass"><span id="passN">0</span> passed, </span>
    682    <span class="fail"><span id="failN">0</span> failed, </span>
    683    <span class="pending"><span id="pendingN">0</span> pending.</span>
    684    <br/>
    685    <br/>
    686 
    687    <table id="results">
    688        <tr>
    689            <th>Test</th>
    690            <th>Result</th>
    691            <th>Time</th>
    692        </tr>
    693    </table>
    694 
    695    </div>
    696 
    697    <div id="foot"></div>
    698 </div>
    699 
    700 </body>
    701 </html>