tor-browser

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

test_webauthn_make_credential.html (18013B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <head>
      4  <title>Test for MakeCredential for W3C Web Authentication</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <script type="text/javascript" src="u2futil.js"></script>
      7  <script type="text/javascript" src="pkijs/common.js"></script>
      8  <script type="text/javascript" src="pkijs/asn1.js"></script>
      9  <script type="text/javascript" src="pkijs/x509_schema.js"></script>
     10  <script type="text/javascript" src="pkijs/x509_simpl.js"></script>
     11  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     12 </head>
     13 <body>
     14 
     15  <h1>Test for MakeCredential for W3C Web Authentication</h1>
     16  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
     17 
     18  <script class="testbody" type="text/javascript">
     19    "use strict";
     20 
     21    add_task(async () => {
     22      await addVirtualAuthenticator();
     23    });
     24 
     25    is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
     26    isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
     27    isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
     28    isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
     29 
     30    let credm;
     31    let gCredentialChallenge;
     32    let rp;
     33    let user;
     34    let param;
     35    let unsupportedParam;
     36    let unknownParam;
     37 
     38    // Setup test env
     39    add_task(() => {
     40      gCredentialChallenge = new Uint8Array(16);
     41      window.crypto.getRandomValues(gCredentialChallenge);
     42 
     43      rp = {id: document.domain, name: "none"};
     44      user = {id: new Uint8Array(64), name: "none", displayName: "none"};
     45      param = {type: "public-key", alg: cose_alg_ECDSA_w_SHA256};
     46      unsupportedParam = {type: "public-key", alg: cose_alg_ECDSA_w_SHA512};
     47      unknownParam = {type: "SimplePassword", alg: "MaxLength=2"};
     48      credm = navigator.credentials;
     49    });
     50    // Add tests
     51    add_task(test_good_call);
     52    add_task(test_empty_account);
     53    add_task(test_without_rp_name);
     54    add_task(test_without_user_id);
     55    add_task(test_without_user_name);
     56    add_task(test_without_user_displayname);
     57    add_task(test_user_too_large);
     58    add_task(test_empty_parameters);
     59    add_task(test_without_parameters);
     60    add_task(test_unsupported_parameter);
     61    add_task(test_unsupported_but_one_param);
     62    add_task(test_one_unknown_parameter);
     63    add_task(test_one_unknown_one_unsupported_param);
     64    add_task(test_one_of_each_parameters);
     65    add_task(test_without_challenge);
     66    add_task(test_invalid_challenge);
     67    add_task(test_duplicate_pub_key);
     68    add_task(test_invalid_rp_id);
     69    add_task(test_invalid_rp_id_2);
     70    add_task(test_missing_rp);
     71    add_task(test_incorrect_user_id_type);
     72    add_task(test_missing_user);
     73    add_task(test_complete_account);
     74    add_task(test_too_large_user_id);
     75    add_task(test_excluding_unknown_transports);
     76    add_task(test_unknown_attestation_type);
     77    add_task(test_unknown_selection_criteria);
     78    add_task(test_no_unexpected_extensions);
     79    add_task(test_cred_props_with_rk_required);
     80    add_task(test_cred_props_with_rk_discouraged);
     81 
     82    function arrivingHereIsGood(aResult) {
     83      ok(true, "Good result! Received a: " + aResult);
     84      return Promise.resolve();
     85    }
     86 
     87    function arrivingHereIsBad(aResult) {
     88      ok(false, "Bad result! Received a: " + aResult);
     89      return Promise.resolve();
     90    }
     91 
     92    function expectNotAllowedError(aResult) {
     93      ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
     94      return Promise.resolve();
     95    }
     96 
     97    function expectTypeError(aResult) {
     98      ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
     99      return Promise.resolve();
    100    }
    101 
    102    function expectNotSupportedError(aResult) {
    103      ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
    104      return Promise.resolve();
    105    }
    106 
    107    // Test basic good call
    108    async function test_good_call() {
    109      let makeCredentialOptions = {
    110        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    111      };
    112      return credm.create({publicKey: makeCredentialOptions})
    113                  .then(arrivingHereIsGood)
    114                  .catch(arrivingHereIsBad);
    115    }
    116 
    117    // Test empty account
    118    async function test_empty_account() {
    119      let makeCredentialOptions = {
    120        challenge: gCredentialChallenge, pubKeyCredParams: [param]
    121      };
    122      return credm.create({publicKey: makeCredentialOptions})
    123                  .then(arrivingHereIsBad)
    124                  .catch(expectTypeError);
    125    }
    126 
    127    // Test without rp.name
    128    async function test_without_rp_name() {
    129      let rp1 = {id: document.domain};
    130      let makeCredentialOptions = {
    131        rp: rp1, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    132      };
    133      return credm.create({publicKey: makeCredentialOptions})
    134                  .then(arrivingHereIsBad)
    135                  .catch(expectTypeError);
    136    }
    137 
    138    // Test without user.id
    139    async function test_without_user_id() {
    140      let user1 = {name: "none", displayName: "none"};
    141      let makeCredentialOptions = {
    142        rp, user: user1, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    143      };
    144      return credm.create({publicKey: makeCredentialOptions})
    145                  .then(arrivingHereIsBad)
    146                  .catch(expectTypeError);
    147    }
    148 
    149    // Test without user.name
    150    async function test_without_user_name() {
    151      let user1 = {id: new Uint8Array(64), displayName: "none"};
    152      let makeCredentialOptions = {
    153        rp, user: user1, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    154      };
    155      return credm.create({publicKey: makeCredentialOptions})
    156                  .then(arrivingHereIsBad)
    157                  .catch(expectTypeError);
    158    }
    159 
    160    // Test without user.displayName
    161    async function test_without_user_displayname() {
    162      let user1 = {id: new Uint8Array(64), name: "none"};
    163      let makeCredentialOptions = {
    164        rp, user: user1, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    165      };
    166      return credm.create({publicKey: makeCredentialOptions})
    167                  .then(arrivingHereIsBad)
    168                  .catch(expectTypeError);
    169    }
    170 
    171    // Test with a user handle that exceeds the max length
    172    async function test_user_too_large() {
    173      let user1 = {id: new Uint8Array(65), name: "none", displayName: "none"};
    174      let makeCredentialOptions = {
    175        rp, user: user1, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    176      };
    177      return credm.create({publicKey: makeCredentialOptions})
    178                  .then(arrivingHereIsBad)
    179                  .catch(expectTypeError);
    180    }
    181 
    182    // Test without any parameters; this is acceptable meaning the RP ID is
    183    // happy to accept either ECDSA-SHA256 or RSA-SHA256
    184    async function test_empty_parameters() {
    185      let makeCredentialOptions = {
    186        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: []
    187      };
    188      return credm.create({publicKey: makeCredentialOptions})
    189                  .then(arrivingHereIsGood)
    190                  .catch(arrivingHereIsBad);
    191    }
    192 
    193    // Test without a parameter array at all
    194    async function test_without_parameters() {
    195      let makeCredentialOptions = {
    196        rp, user, challenge: gCredentialChallenge
    197      };
    198      return credm.create({publicKey: makeCredentialOptions})
    199           .then(arrivingHereIsBad)
    200           .catch(expectTypeError);
    201    }
    202 
    203    // Test with an unsupported parameter
    204    // The result depends on the tokens that are available, so we
    205    // expect a NotAllowedError so as not to leak this.
    206    async function test_unsupported_parameter() {
    207      let makeCredentialOptions = {
    208        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [unsupportedParam]
    209      };
    210      return credm.create({publicKey: makeCredentialOptions})
    211                  .then(arrivingHereIsBad)
    212                  .catch(expectNotAllowedError);
    213    }
    214 
    215    // Test with an unsupported parameter and a good one
    216    async function test_unsupported_but_one_param() {
    217      let makeCredentialOptions = {
    218        rp, user, challenge: gCredentialChallenge,
    219        pubKeyCredParams: [param, unsupportedParam]
    220      };
    221      return credm.create({publicKey: makeCredentialOptions})
    222                  .then(arrivingHereIsGood)
    223                  .catch(arrivingHereIsBad);
    224    }
    225 
    226    // Test with one unknown (not "public-key") parameter.
    227    async function test_one_unknown_parameter() {
    228      let makeCredentialOptions = {
    229        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [unknownParam]
    230      };
    231      return credm.create({publicKey: makeCredentialOptions})
    232           .then(arrivingHereIsBad)
    233           .catch(expectNotSupportedError);
    234    }
    235 
    236    // Test with an unsupported parameter, and an unknown one
    237    // The result depends on the tokens that are available, so we
    238    // expect a NotAllowedError so as not to leak this.
    239    async function test_one_unknown_one_unsupported_param() {
    240      let makeCredentialOptions = {
    241        rp, user, challenge: gCredentialChallenge,
    242        pubKeyCredParams: [unsupportedParam, unknownParam]
    243      };
    244      return credm.create({publicKey: makeCredentialOptions})
    245                  .then(arrivingHereIsBad)
    246                  .catch(expectNotAllowedError);
    247    }
    248 
    249    // Test with an unsupported parameter, an unknown one, and a good one. This
    250    // should succeed, as the unsupported and unknown should be ignored.
    251    async function test_one_of_each_parameters() {
    252      let makeCredentialOptions = {
    253        rp, user, challenge: gCredentialChallenge,
    254        pubKeyCredParams: [param, unsupportedParam, unknownParam]
    255      };
    256      return credm.create({publicKey: makeCredentialOptions})
    257                  .then(arrivingHereIsGood)
    258                  .catch(arrivingHereIsBad);
    259    }
    260 
    261    // Test without a challenge
    262    async function test_without_challenge() {
    263      let makeCredentialOptions = {
    264        rp, user, pubKeyCredParams: [param]
    265      };
    266      return credm.create({publicKey: makeCredentialOptions})
    267                  .then(arrivingHereIsBad)
    268                  .catch(expectTypeError);
    269    }
    270 
    271    // Test with an invalid challenge
    272    async function test_invalid_challenge() {
    273      let makeCredentialOptions = {
    274        rp, user, challenge: "begone, thou ill-fitting moist glove!",
    275        pubKeyCredParams: [unsupportedParam]
    276      };
    277      return credm.create({publicKey: makeCredentialOptions})
    278           .then(arrivingHereIsBad)
    279           .catch(expectTypeError);
    280    }
    281 
    282    // Test with duplicate pubKeyCredParams
    283    async function test_duplicate_pub_key() {
    284      let makeCredentialOptions = {
    285        rp, user, challenge: gCredentialChallenge,
    286        pubKeyCredParams: [param, param, param]
    287      };
    288      return credm.create({publicKey: makeCredentialOptions})
    289                  .then(arrivingHereIsGood)
    290                  .catch(arrivingHereIsBad);
    291    }
    292 
    293    // Test with an RP ID that is not a valid domain string
    294    async function test_invalid_rp_id() {
    295      let rp1 = { id: document.domain + ":somejunk", name: "none"};
    296      let makeCredentialOptions = {
    297        rp: rp1, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    298      };
    299      return credm.create({publicKey: makeCredentialOptions})
    300                  .then(arrivingHereIsBad)
    301                  .catch(arrivingHereIsGood);
    302    }
    303 
    304    // Test with another RP ID that is not a valid domain string
    305    async function test_invalid_rp_id_2() {
    306      let rp1 = { id: document.domain + ":8888", name: "none"};
    307      let makeCredentialOptions = {
    308        rp: rp1, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    309      };
    310      return credm.create({publicKey: makeCredentialOptions})
    311                  .then(arrivingHereIsBad)
    312                  .catch(arrivingHereIsGood);
    313    }
    314 
    315    // Test with missing rp
    316    async function test_missing_rp() {
    317      let makeCredentialOptions = {
    318        user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    319      };
    320      return credm.create({publicKey: makeCredentialOptions})
    321                  .then(arrivingHereIsBad)
    322                  .catch(expectTypeError);
    323    }
    324 
    325    // Test with incorrect user ID type
    326    async function test_incorrect_user_id_type() {
    327      let invalidType = {id: "a string, which is not a buffer", name: "none", displayName: "none"};
    328      let makeCredentialOptions = {
    329        user: invalidType, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    330      };
    331      return credm.create({publicKey: makeCredentialOptions})
    332                  .then(arrivingHereIsBad)
    333                  .catch(expectTypeError);
    334    }
    335 
    336    // Test with missing user
    337    async function test_missing_user() {
    338      let makeCredentialOptions = {
    339        rp, challenge: gCredentialChallenge, pubKeyCredParams: [param]
    340      };
    341      return credm.create({publicKey: makeCredentialOptions})
    342                  .then(arrivingHereIsBad)
    343                  .catch(expectTypeError);
    344    }
    345 
    346    // Test a complete account
    347    async function test_complete_account() {
    348      // the icon fields are deprecated, but including them should not cause an error
    349      let completeRP = {id: document.domain, name: "Foxxy Name",
    350                        icon: "https://example.com/fox.svg"};
    351      let completeUser = {id: string2buffer("foxes_are_the_best@example.com"),
    352                          name: "Fox F. Foxington",
    353                          icon: "https://example.com/fox.svg",
    354                          displayName: "Foxxy V"};
    355      let makeCredentialOptions = {
    356        rp: completeRP, user: completeUser, challenge: gCredentialChallenge,
    357        pubKeyCredParams: [param]
    358      };
    359      return credm.create({publicKey: makeCredentialOptions})
    360                  .then(arrivingHereIsGood)
    361                  .catch(arrivingHereIsBad);
    362    }
    363 
    364    // Test with too-large user ID buffer
    365    async function test_too_large_user_id() {
    366      let hugeUser = {id: new Uint8Array(65),
    367                          name: "Fox F. Foxington",
    368                          displayName: "Foxxy V"};
    369      let makeCredentialOptions = {
    370        rp, user: hugeUser, challenge: gCredentialChallenge,
    371        pubKeyCredParams: [param]
    372      };
    373      return credm.create({publicKey: makeCredentialOptions})
    374                  .then(arrivingHereIsBad)
    375                  .catch(expectTypeError);
    376    }
    377 
    378    // Test with excluding unknown transports
    379    async function test_excluding_unknown_transports() {
    380      let completeRP = {id: document.domain, name: "Foxxy Name"};
    381      let completeUser = {id: string2buffer("foxes_are_the_best@example.com"),
    382                          name: "Fox F. Foxington",
    383                          displayName: "Foxxy V"};
    384      let excludedUnknownTransport = {type: "public-key",
    385                                      id: string2buffer("123"),
    386                                      transports: ["unknown", "usb"]};
    387      let makeCredentialOptions = {
    388        rp: completeRP, user: completeUser, challenge: gCredentialChallenge,
    389        pubKeyCredParams: [param], excludeCredentials: [excludedUnknownTransport]
    390      };
    391      return credm.create({publicKey: makeCredentialOptions})
    392                  .then(arrivingHereIsGood)
    393                  .catch(arrivingHereIsBad);
    394    }
    395 
    396    async function test_unknown_attestation_type() {
    397      let makeCredentialOptions = {
    398        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
    399        attestation: "unknown"
    400      };
    401      return credm.create({publicKey: makeCredentialOptions })
    402                  .then(arrivingHereIsGood)
    403                  .catch(arrivingHereIsBad);
    404    }
    405 
    406    async function test_unknown_selection_criteria() {
    407      let makeCredentialOptions = {
    408        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
    409            authenticatorSelection: {
    410                  userVerificationRequirement: "unknown UV requirement",
    411                  authenticatorAttachment: "unknown authenticator attachment type"
    412            },
    413      };
    414      return credm.create({publicKey: makeCredentialOptions })
    415                  .then(arrivingHereIsGood)
    416                  .catch(arrivingHereIsBad);
    417    }
    418 
    419    async function test_no_unexpected_extensions() {
    420      let makeCredentialOptions = {
    421        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
    422      };
    423      let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
    424      let extensionResults = cred.getClientExtensionResults();
    425      is(extensionResults.credProps, undefined, "no credProps output");
    426    }
    427 
    428    async function test_cred_props_with_rk_required() {
    429      let makeCredentialOptions = {
    430        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
    431            authenticatorSelection: {
    432                  authenticatorAttachment: "cross-platform",
    433                  residentKey: "required",
    434            },
    435            extensions: { credProps: true }
    436      };
    437      let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
    438      let extensionResults = cred.getClientExtensionResults();
    439      is(extensionResults.credProps?.rk, true, "rk is true");
    440    }
    441 
    442    async function test_cred_props_with_rk_discouraged() {
    443      let makeCredentialOptions = {
    444        rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
    445            authenticatorSelection: {
    446                  authenticatorAttachment: "cross-platform",
    447                  residentKey: "discouraged",
    448            },
    449            extensions: { credProps: true }
    450      };
    451      let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
    452      let extensionResults = cred.getClientExtensionResults();
    453      is(extensionResults.credProps?.rk, false, "rk is false");
    454    }
    455 
    456  </script>
    457 
    458 </body>
    459 </html>