diff options
Diffstat (limited to 'dom/webauthn/tests/browser/head.js')
-rw-r--r-- | dom/webauthn/tests/browser/head.js | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/dom/webauthn/tests/browser/head.js b/dom/webauthn/tests/browser/head.js new file mode 100644 index 0000000000..d6cbd56133 --- /dev/null +++ b/dom/webauthn/tests/browser/head.js @@ -0,0 +1,259 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let exports = this; + +const scripts = [ + "pkijs/common.js", + "pkijs/asn1.js", + "pkijs/x509_schema.js", + "pkijs/x509_simpl.js", + "browser/cbor.js", + "browser/u2futil.js", +]; + +for (let script of scripts) { + Services.scriptloader.loadSubScript( + `chrome://mochitests/content/browser/dom/webauthn/tests/${script}`, + this + ); +} + +function add_virtual_authenticator(autoremove = true) { + let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService( + Ci.nsIWebAuthnService + ); + let id = webauthnService.addVirtualAuthenticator( + "ctap2_1", + "internal", + true, + true, + true, + true + ); + if (autoremove) { + registerCleanupFunction(() => { + webauthnService.removeVirtualAuthenticator(id); + }); + } + return id; +} + +async function addCredential(authenticatorId, rpId) { + let keyPair = await crypto.subtle.generateKey( + { + name: "ECDSA", + namedCurve: "P-256", + }, + true, + ["sign"] + ); + + let credId = new Uint8Array(32); + crypto.getRandomValues(credId); + credId = bytesToBase64UrlSafe(credId); + + let privateKey = await crypto.subtle + .exportKey("pkcs8", keyPair.privateKey) + .then(privateKey => bytesToBase64UrlSafe(privateKey)); + + let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService( + Ci.nsIWebAuthnService + ); + + webauthnService.addCredential( + authenticatorId, + credId, + true, // resident key + rpId, + privateKey, + "VGVzdCBVc2Vy", // "Test User" + 0 // sign count + ); + + return credId; +} + +async function removeCredential(authenticatorId, credId) { + let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService( + Ci.nsIWebAuthnService + ); + + webauthnService.removeCredential(authenticatorId, credId); +} + +function memcmp(x, y) { + let xb = new Uint8Array(x); + let yb = new Uint8Array(y); + + if (x.byteLength != y.byteLength) { + return false; + } + + for (let i = 0; i < xb.byteLength; ++i) { + if (xb[i] != yb[i]) { + return false; + } + } + + return true; +} + +function arrivingHereIsBad(aResult) { + ok(false, "Bad result! Received a: " + aResult); +} + +function expectError(aType) { + let expected = `${aType}Error`; + return function (aResult) { + is( + aResult.slice(0, expected.length), + expected, + `Expecting a ${aType}Error` + ); + }; +} + +/* eslint-disable no-shadow */ +function promiseWebAuthnMakeCredential( + tab, + attestation = "none", + residentKey = "discouraged", + extensions = {} +) { + return ContentTask.spawn( + tab.linkedBrowser, + [attestation, residentKey, extensions], + ([attestation, residentKey, extensions]) => { + const cose_alg_ECDSA_w_SHA256 = -7; + + let challenge = content.crypto.getRandomValues(new Uint8Array(16)); + + let pubKeyCredParams = [ + { + type: "public-key", + alg: cose_alg_ECDSA_w_SHA256, + }, + ]; + + let publicKey = { + rp: { id: content.document.domain, name: "none" }, + user: { + id: new Uint8Array(), + name: "none", + displayName: "none", + }, + pubKeyCredParams, + authenticatorSelection: { + authenticatorAttachment: "cross-platform", + residentKey, + }, + extensions, + attestation, + challenge, + }; + + return content.navigator.credentials + .create({ publicKey }) + .then(credential => { + return { + clientDataJSON: credential.response.clientDataJSON, + attObj: credential.response.attestationObject, + rawId: credential.rawId, + }; + }); + } + ); +} + +function promiseWebAuthnGetAssertion(tab, key_handle = null, extensions = {}) { + return ContentTask.spawn( + tab.linkedBrowser, + [key_handle, extensions], + ([key_handle, extensions]) => { + let challenge = content.crypto.getRandomValues(new Uint8Array(16)); + if (key_handle == null) { + key_handle = content.crypto.getRandomValues(new Uint8Array(16)); + } + + let credential = { + id: key_handle, + type: "public-key", + transports: ["usb"], + }; + + let publicKey = { + challenge, + extensions, + rpId: content.document.domain, + allowCredentials: [credential], + }; + + return content.navigator.credentials + .get({ publicKey }) + .then(assertion => { + return { + authenticatorData: assertion.response.authenticatorData, + clientDataJSON: assertion.response.clientDataJSON, + extensions: assertion.getClientExtensionResults(), + signature: assertion.response.signature, + }; + }); + } + ); +} + +function promiseWebAuthnGetAssertionDiscoverable( + tab, + mediation = "optional", + extensions = {} +) { + return ContentTask.spawn( + tab.linkedBrowser, + [extensions, mediation], + ([extensions, mediation]) => { + let challenge = content.crypto.getRandomValues(new Uint8Array(16)); + + let publicKey = { + challenge, + extensions, + rpId: content.document.domain, + allowCredentials: [], + }; + + return content.navigator.credentials.get({ publicKey, mediation }); + } + ); +} + +function checkRpIdHash(rpIdHash, hostname) { + return crypto.subtle + .digest("SHA-256", string2buffer(hostname)) + .then(calculatedRpIdHash => { + let calcHashStr = bytesToBase64UrlSafe( + new Uint8Array(calculatedRpIdHash) + ); + let providedHashStr = bytesToBase64UrlSafe(new Uint8Array(rpIdHash)); + + if (calcHashStr != providedHashStr) { + throw new Error("Calculated RP ID hash doesn't match."); + } + }); +} + +function promiseNotification(id) { + return new Promise(resolve => { + PopupNotifications.panel.addEventListener("popupshown", function shown() { + let notification = PopupNotifications.getNotification(id); + if (notification) { + ok(true, `${id} prompt visible`); + PopupNotifications.panel.removeEventListener("popupshown", shown); + resolve(); + } + }); + }); +} +/* eslint-enable no-shadow */ |