tor-browser

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

test_WebCrypto_JWK.html (10693B)


      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  "JWK import and use of an AES-GCM key",
     28  function() {
     29    var that = this;
     30 
     31    function doEncrypt(x) {
     32      return crypto.subtle.encrypt(
     33        {
     34          name: "AES-GCM",
     35          iv: tv.aes_gcm_enc.iv,
     36          additionalData: tv.aes_gcm_enc.adata,
     37          tagLength: 128,
     38        },
     39        x, tv.aes_gcm_enc.data);
     40    }
     41 
     42    crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, "AES-GCM", false, ["encrypt"])
     43      .then(doEncrypt)
     44      .then(
     45        memcmp_complete(that, tv.aes_gcm_enc.result),
     46        error(that)
     47      );
     48  }
     49 );
     50 
     51 // -----------------------------------------------------------------------------
     52 TestArray.addTest(
     53  "JWK import and use of an RSASSA-PKCS1-v1_5 private key",
     54  function() {
     55    var that = this;
     56    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
     57 
     58    function doSign(x) {
     59      return crypto.subtle.sign(alg.name, x, tv.rsassa.data);
     60    }
     61    function fail(x) { console.log(x); error(that); }
     62 
     63    crypto.subtle.importKey("jwk", tv.rsassa.jwk_priv, alg, false, ["sign"])
     64      .then( doSign, fail )
     65      .then( memcmp_complete(that, tv.rsassa.sig256), fail );
     66  }
     67 );
     68 
     69 // -----------------------------------------------------------------------------
     70 TestArray.addTest(
     71  "JWK import and use of an RSASSA-PKCS1-v1_5 public key",
     72  function() {
     73    var that = this;
     74    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
     75 
     76    function doVerify(x) {
     77      return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data);
     78    }
     79    function fail() { error(that); }
     80 
     81    crypto.subtle.importKey("jwk", tv.rsassa.jwk_pub, alg, false, ["verify"])
     82      .then( doVerify, fail )
     83      .then(
     84        complete(that, function(x) { return x; }),
     85        fail
     86      );
     87  });
     88 
     89 // -----------------------------------------------------------------------------
     90 TestArray.addTest(
     91  "JWK import failure on incomplete RSA private key (missing 'qi')",
     92  function() {
     93    var that = this;
     94    var alg = { name: "RSA-OAEP", hash: "SHA-256" };
     95    var jwk = {
     96      kty: "RSA",
     97      n: tv.rsassa.jwk_priv.n,
     98      e: tv.rsassa.jwk_priv.e,
     99      d: tv.rsassa.jwk_priv.d,
    100      p: tv.rsassa.jwk_priv.p,
    101      q: tv.rsassa.jwk_priv.q,
    102      dp: tv.rsassa.jwk_priv.dp,
    103      dq: tv.rsassa.jwk_priv.dq,
    104    };
    105 
    106    crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"])
    107      .then( error(that), complete(that) );
    108  }
    109 );
    110 
    111 // -----------------------------------------------------------------------------
    112 TestArray.addTest(
    113  "JWK import failure on algorithm mismatch",
    114  function() {
    115    var that = this;
    116    var alg = "AES-GCM";
    117    var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", alg: "A256GCM" };
    118 
    119    crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"])
    120      .then( error(that), complete(that) );
    121  }
    122 );
    123 
    124 // -----------------------------------------------------------------------------
    125 TestArray.addTest(
    126  "JWK import failure on usages mismatch",
    127  function() {
    128    var that = this;
    129    var alg = "AES-GCM";
    130    var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", key_ops: ["encrypt"] };
    131 
    132    crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"])
    133      .then( error(that), complete(that) );
    134  }
    135 );
    136 
    137 // -----------------------------------------------------------------------------
    138 TestArray.addTest(
    139  "JWK import failure on extractable mismatch",
    140  function() {
    141    var that = this;
    142    var alg = "AES-GCM";
    143    var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", ext: false };
    144 
    145    crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt"])
    146      .then( error(that), complete(that) );
    147  }
    148 );
    149 
    150 // -----------------------------------------------------------------------------
    151 TestArray.addTest(
    152  "JWK export of a symmetric key",
    153  function() {
    154    var that = this;
    155    var alg = "AES-GCM";
    156    var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", kty: "oct" };
    157 
    158    function doExport(k) {
    159      return crypto.subtle.exportKey("jwk", k);
    160    }
    161 
    162    crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"])
    163      .then(doExport)
    164      .then(
    165        complete(that, function(x) {
    166          return hasBaseJwkFields(x) &&
    167                 hasFields(x, ["k"]) &&
    168                 x.kty == "oct" &&
    169                 x.alg == "A128GCM" &&
    170                 x.ext &&
    171                 shallowArrayEquals(x.key_ops, ["encrypt", "decrypt"]) &&
    172                 x.k == jwk.k;
    173        }),
    174        error(that)
    175      );
    176  }
    177 );
    178 
    179 // -----------------------------------------------------------------------------
    180 TestArray.addTest(
    181  "JWK import/export of an RSA private key",
    182  function() {
    183    var jwk = tv.rsassa.jwk_priv;
    184 
    185    var that = this;
    186    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
    187 
    188    function doExport(k) {
    189      return crypto.subtle.exportKey("jwk", k);
    190    }
    191 
    192    crypto.subtle.importKey("jwk", jwk, alg, true, ["sign"])
    193      .then(doExport)
    194      .then(
    195        complete(that, function(x) {
    196          return hasBaseJwkFields(x) &&
    197                 hasFields(x, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]) &&
    198                 x.kty == "RSA" &&
    199                 x.alg == "RS256" &&
    200                 x.ext &&
    201                 shallowArrayEquals(x.key_ops, ["sign"]) &&
    202                 x.n == jwk.n &&
    203                 x.e == jwk.e &&
    204                 x.d == jwk.d &&
    205                 x.p == jwk.p &&
    206                 x.q == jwk.q &&
    207                 x.dp == jwk.dp &&
    208                 x.dq == jwk.dq &&
    209                 x.qi == jwk.qi;
    210          }),
    211        error(that)
    212      );
    213  }
    214 );
    215 
    216 // -----------------------------------------------------------------------------
    217 TestArray.addTest(
    218  "JWK import/export of an RSA private key where p < q",
    219  function() {
    220    var jwk = tv.rsassa.jwk_priv_pLTq;
    221 
    222    var that = this;
    223    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
    224 
    225    function doExport(k) {
    226      return crypto.subtle.exportKey("jwk", k);
    227    }
    228 
    229    crypto.subtle.importKey("jwk", jwk, alg, true, ["sign"])
    230      .then(doExport)
    231      .then(
    232        complete(that, function(x) {
    233          return hasBaseJwkFields(x) &&
    234                 hasFields(x, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]) &&
    235                 x.kty == "RSA" &&
    236                 x.alg == "RS256" &&
    237                 x.ext &&
    238                 shallowArrayEquals(x.key_ops, ["sign"]) &&
    239                 x.n == jwk.n &&
    240                 x.e == jwk.e &&
    241                 x.d == jwk.d &&
    242                 x.p == jwk.p &&
    243                 x.q == jwk.q &&
    244                 x.dp == jwk.dp &&
    245                 x.dq == jwk.dq &&
    246                 x.qi == jwk.qi;
    247          }),
    248        error(that)
    249      );
    250  }
    251 );
    252 
    253 // -----------------------------------------------------------------------------
    254 TestArray.addTest(
    255  "JWK export of an RSA public key",
    256  function() {
    257    var that = this;
    258    var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
    259    var jwk = tv.rsassa.jwk_pub;
    260 
    261    function doExport(k) {
    262      return crypto.subtle.exportKey("jwk", k);
    263    }
    264 
    265    crypto.subtle.importKey("jwk", jwk, alg, true, ["verify"])
    266      .then(doExport)
    267      .then(
    268        complete(that, function(x) {
    269          window.jwk_pub = x;
    270          return hasBaseJwkFields(x) &&
    271                 hasFields(x, ["n", "e"]) &&
    272                 x.kty == "RSA" &&
    273                 x.alg == "RS256" &&
    274                 x.ext &&
    275                 shallowArrayEquals(x.key_ops, ["verify"]) &&
    276                 x.n == jwk.n &&
    277                 x.e == jwk.e;
    278          }),
    279        error(that)
    280      );
    281  }
    282 );
    283 
    284 // --------
    285 TestArray.addTest(
    286  "Check JWK parameters on generated ECDSA key pair",
    287  function() {
    288    crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"])
    289      .then(pair => Promise.all([
    290         crypto.subtle.exportKey("jwk", pair.privateKey),
    291         crypto.subtle.exportKey("jwk", pair.publicKey),
    292      ]))
    293      .then(
    294        complete(this, function(x) {
    295          var priv = x[0];
    296          var pub = x[1];
    297          var pubIsSubsetOfPriv = Object.keys(pub)
    298            .filter(k => k !== "key_ops") // key_ops is the only complex attr
    299            .reduce((all, k) => all && pub[k] === priv[k], true);
    300          // Can't use hasBaseJwkFields() because EC keys don't get "alg":
    301          // "alg" matches curve to hash, but WebCrypto keys are more flexible.
    302          return hasFields(pub, ["kty", "crv", "key_ops", "ext"]) &&
    303            pub.kty === "EC" &&
    304            pub.crv === "P-256" &&
    305            pub.ext &&
    306            typeof(pub.x) === "string" &&
    307            typeof(pub.y) === "string" &&
    308            shallowArrayEquals(pub.key_ops, ["verify"]) &&
    309            pubIsSubsetOfPriv &&
    310            shallowArrayEquals(priv.key_ops, ["sign"]) &&
    311            typeof(priv.d) === "string";
    312        }),
    313        error(this));
    314  }
    315 );
    316 
    317 // --------
    318 TestArray.addTest(
    319  "Check key_ops parameter on an unusable RSA public key",
    320  function() {
    321    var parameters = {
    322      name: "RSASSA-PKCS1-v1_5",
    323      modulusLength: 1024,
    324      publicExponent: new Uint8Array([1, 0, 1]),
    325      hash: "SHA-256",
    326    };
    327    // The public key generated here will have no usages and will therefore
    328    // have an empty key_ops list.
    329    crypto.subtle.generateKey(parameters, true, ["sign"])
    330      .then(pair => crypto.subtle.exportKey("jwk", pair.publicKey))
    331      .then(complete(this, x => x.key_ops.length === 0),
    332            error(this));
    333  }
    334 );
    335 /* ]]>*/</script>
    336 </head>
    337 
    338 <body>
    339 
    340 <div id="content">
    341 <div id="head">
    342 	<b>Web</b>Crypto<br>
    343 </div>
    344 
    345    <div id="start" onclick="start();">RUN ALL</div>
    346 
    347    <div id="resultDiv" class="content">
    348    Summary:
    349    <span class="pass"><span id="passN">0</span> passed, </span>
    350    <span class="fail"><span id="failN">0</span> failed, </span>
    351    <span class="pending"><span id="pendingN">0</span> pending.</span>
    352    <br/>
    353    <br/>
    354 
    355    <table id="results">
    356        <tr>
    357            <th>Test</th>
    358            <th>Result</th>
    359            <th>Time</th>
    360        </tr>
    361    </table>
    362 
    363    </div>
    364 
    365    <div id="foot"></div>
    366 </div>
    367 
    368 </body>
    369 </html>