Bug 1945965 – remove new tab April Fools logo. r=home-newtab-reviewers,reemhamz
[gecko.git] / dom / webauthn / tests / test_webauthn_make_credential.html
blob4812d0da0df1bba63d74e10ac03bfb960dc83fc9
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>
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>
18 <script class="testbody" type="text/javascript">
19 "use strict";
21 add_task(async () => {
22 await addVirtualAuthenticator();
23 });
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");
30 let credm;
31 let gCredentialChallenge;
32 let rp;
33 let user;
34 let param;
35 let unsupportedParam;
36 let unknownParam;
38 // Setup test env
39 add_task(() => {
40 gCredentialChallenge = new Uint8Array(16);
41 window.crypto.getRandomValues(gCredentialChallenge);
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);
82 function arrivingHereIsGood(aResult) {
83 ok(true, "Good result! Received a: " + aResult);
84 return Promise.resolve();
87 function arrivingHereIsBad(aResult) {
88 ok(false, "Bad result! Received a: " + aResult);
89 return Promise.resolve();
92 function expectNotAllowedError(aResult) {
93 ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
94 return Promise.resolve();
97 function expectTypeError(aResult) {
98 ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
99 return Promise.resolve();
102 function expectNotSupportedError(aResult) {
103 ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
104 return Promise.resolve();
107 // Test basic good call
108 async function test_good_call() {
109 let makeCredentialOptions = {
110 rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
112 return credm.create({publicKey: makeCredentialOptions})
113 .then(arrivingHereIsGood)
114 .catch(arrivingHereIsBad);
117 // Test empty account
118 async function test_empty_account() {
119 let makeCredentialOptions = {
120 challenge: gCredentialChallenge, pubKeyCredParams: [param]
122 return credm.create({publicKey: makeCredentialOptions})
123 .then(arrivingHereIsBad)
124 .catch(expectTypeError);
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]
133 return credm.create({publicKey: makeCredentialOptions})
134 .then(arrivingHereIsBad)
135 .catch(expectTypeError);
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]
144 return credm.create({publicKey: makeCredentialOptions})
145 .then(arrivingHereIsBad)
146 .catch(expectTypeError);
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]
155 return credm.create({publicKey: makeCredentialOptions})
156 .then(arrivingHereIsBad)
157 .catch(expectTypeError);
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]
166 return credm.create({publicKey: makeCredentialOptions})
167 .then(arrivingHereIsBad)
168 .catch(expectTypeError);
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]
177 return credm.create({publicKey: makeCredentialOptions})
178 .then(arrivingHereIsBad)
179 .catch(expectTypeError);
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: []
188 return credm.create({publicKey: makeCredentialOptions})
189 .then(arrivingHereIsGood)
190 .catch(arrivingHereIsBad);
193 // Test without a parameter array at all
194 async function test_without_parameters() {
195 let makeCredentialOptions = {
196 rp, user, challenge: gCredentialChallenge
198 return credm.create({publicKey: makeCredentialOptions})
199 .then(arrivingHereIsBad)
200 .catch(expectTypeError);
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]
210 return credm.create({publicKey: makeCredentialOptions})
211 .then(arrivingHereIsBad)
212 .catch(expectNotAllowedError);
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]
221 return credm.create({publicKey: makeCredentialOptions})
222 .then(arrivingHereIsGood)
223 .catch(arrivingHereIsBad);
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]
231 return credm.create({publicKey: makeCredentialOptions})
232 .then(arrivingHereIsBad)
233 .catch(expectNotSupportedError);
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]
244 return credm.create({publicKey: makeCredentialOptions})
245 .then(arrivingHereIsBad)
246 .catch(expectNotAllowedError);
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]
256 return credm.create({publicKey: makeCredentialOptions})
257 .then(arrivingHereIsGood)
258 .catch(arrivingHereIsBad);
261 // Test without a challenge
262 async function test_without_challenge() {
263 let makeCredentialOptions = {
264 rp, user, pubKeyCredParams: [param]
266 return credm.create({publicKey: makeCredentialOptions})
267 .then(arrivingHereIsBad)
268 .catch(expectTypeError);
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]
277 return credm.create({publicKey: makeCredentialOptions})
278 .then(arrivingHereIsBad)
279 .catch(expectTypeError);
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]
288 return credm.create({publicKey: makeCredentialOptions})
289 .then(arrivingHereIsGood)
290 .catch(arrivingHereIsBad);
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]
299 return credm.create({publicKey: makeCredentialOptions})
300 .then(arrivingHereIsBad)
301 .catch(arrivingHereIsGood);
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]
310 return credm.create({publicKey: makeCredentialOptions})
311 .then(arrivingHereIsBad)
312 .catch(arrivingHereIsGood);
315 // Test with missing rp
316 async function test_missing_rp() {
317 let makeCredentialOptions = {
318 user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
320 return credm.create({publicKey: makeCredentialOptions})
321 .then(arrivingHereIsBad)
322 .catch(expectTypeError);
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]
331 return credm.create({publicKey: makeCredentialOptions})
332 .then(arrivingHereIsBad)
333 .catch(expectTypeError);
336 // Test with missing user
337 async function test_missing_user() {
338 let makeCredentialOptions = {
339 rp, challenge: gCredentialChallenge, pubKeyCredParams: [param]
341 return credm.create({publicKey: makeCredentialOptions})
342 .then(arrivingHereIsBad)
343 .catch(expectTypeError);
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]
359 return credm.create({publicKey: makeCredentialOptions})
360 .then(arrivingHereIsGood)
361 .catch(arrivingHereIsBad);
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]
373 return credm.create({publicKey: makeCredentialOptions})
374 .then(arrivingHereIsBad)
375 .catch(expectTypeError);
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]
391 return credm.create({publicKey: makeCredentialOptions})
392 .then(arrivingHereIsGood)
393 .catch(arrivingHereIsBad);
396 async function test_unknown_attestation_type() {
397 let makeCredentialOptions = {
398 rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
399 attestation: "unknown"
401 return credm.create({publicKey: makeCredentialOptions })
402 .then(arrivingHereIsGood)
403 .catch(arrivingHereIsBad);
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"
414 return credm.create({publicKey: makeCredentialOptions })
415 .then(arrivingHereIsGood)
416 .catch(arrivingHereIsBad);
419 async function test_no_unexpected_extensions() {
420 let makeCredentialOptions = {
421 rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param],
423 let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
424 let extensionResults = cred.getClientExtensionResults();
425 is(extensionResults.credProps, undefined, "no credProps output");
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",
435 extensions: { credProps: true }
437 let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
438 let extensionResults = cred.getClientExtensionResults();
439 is(extensionResults.credProps?.rk, true, "rk is true");
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",
449 extensions: { credProps: true }
451 let cred = await credm.create({publicKey: makeCredentialOptions}).catch(arrivingHereIsBad);
452 let extensionResults = cred.getClientExtensionResults();
453 is(extensionResults.credProps?.rk, false, "rk is false");
456 </script>
458 </body>
459 </html>