mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 03:05:34 +00:00
2afc1ad18b
- This patch reworks the U2F module to asynchronously call U2FManager, which in turn handles constructing and managing the U2FTokenManager via IPC. - Add U2FTransaction{Parent,Child} implementations to mirror similar ones for WebAuthn - Rewrite all tests to compensate for U2F executing asynchronously now. - Used async tasks, used the manifest parameters for scheme, and generally made these cleaner. - The mochitest "pref =" functionality from Bug 1328830 doesn't support Android yet, causing breakage on Android. Rework the tests to go back to the old way of using iframes to test U2F. NOTE TO REVIEWERS: Since this is huge, I recommend the following: keeler - please review U2F.cpp/h, the tests, and the security-prefs.js. Most of the U2F logic is still in U2F.cpp like before, but there's been some reworking of how it is called. ttaubert - please review U2FManager, the Transaction classes, build changes, and the changes to nsGlobalWindow. All of these should be very similar to the WebAuthn code it's patterned off. MozReview-Commit-ID: C1ZN2ch66Rm --HG-- extra : rebase_source : 5a2c52b0340c13f471af5040b998eb7e661b1981
112 lines
4.2 KiB
HTML
112 lines
4.2 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset=utf-8>
|
|
<head>
|
|
<script type="text/javascript" src="frame_utils.js"></script>
|
|
<script type="text/javascript" src="u2futil.js"></script>
|
|
</head>
|
|
<body>
|
|
<p>Test for multiple simultaneous key</p>
|
|
<script class="testbody" type="text/javascript">
|
|
"use strict";
|
|
|
|
function keyHandleFromRegResponse(aRegResponse) {
|
|
// Parse the response data from the U2F token
|
|
let registrationData = base64ToBytesUrlSafe(aRegResponse.registrationData);
|
|
local_is(registrationData[0], 0x05, "Reserved byte is correct")
|
|
|
|
let keyHandleLength = registrationData[66];
|
|
let keyHandleBytes = registrationData.slice(67, 67 + keyHandleLength);
|
|
|
|
return {
|
|
version: "U2F_V2",
|
|
keyHandle: bytesToBase64UrlSafe(keyHandleBytes),
|
|
};
|
|
}
|
|
|
|
let challenge = new Uint8Array(16);
|
|
window.crypto.getRandomValues(challenge);
|
|
|
|
let regRequest = {
|
|
version: "U2F_V2",
|
|
challenge: bytesToBase64UrlSafe(challenge),
|
|
};
|
|
|
|
let testState = {
|
|
key1: null,
|
|
key2: null,
|
|
}
|
|
|
|
// Just a key that came from a random profile; syntactically valid but not
|
|
// unwrappable.
|
|
let invalidKey = {
|
|
"version": "U2F_V2",
|
|
"keyHandle": "rQdreHgHrmKfsnGPAElEP9yfTx6eq2eU3_Y8n0RRsGKML0DY2d1_a8_-sOtxDr3"
|
|
};
|
|
|
|
async function doTests() {
|
|
// Ensure the SpecialPowers push worked properly
|
|
local_isnot(window.u2f, undefined, "U2F API endpoint must exist");
|
|
|
|
// Get two valid keys and present them
|
|
await promiseU2FRegister(window.location.origin, [regRequest], [], function(aRegResponse) {
|
|
testState.key1 = keyHandleFromRegResponse(aRegResponse);
|
|
});
|
|
|
|
// Get the second key...
|
|
// It's OK to repeat the regRequest; not material for this test
|
|
await promiseU2FRegister(window.location.origin, [regRequest], [], function(aRegResponse) {
|
|
testState.key2 = keyHandleFromRegResponse(aRegResponse);
|
|
});
|
|
|
|
await promiseU2FRegister(window.location.origin, [regRequest],
|
|
[invalidKey], function(aRegResponse) {
|
|
// The invalid key shouldn't match anything, so we should register OK here, too
|
|
local_is(aRegResponse.errorCode, 0, "The register should have gone through with the invalid key");
|
|
});
|
|
|
|
|
|
await promiseU2FRegister(window.location.origin, [regRequest],
|
|
[invalidKey, testState.key1], function(aRegResponse) {
|
|
// Expect a failure response since key1 is already registered
|
|
local_is(aRegResponse.errorCode, 4, "The register should have skipped since there was a valid key");
|
|
});
|
|
|
|
await promiseU2FSign(window.location.origin, bytesToBase64UrlSafe(challenge),
|
|
[testState.key1], function(aSignResponse) {
|
|
local_is(aSignResponse.errorCode, 0, "The signing did not error with one key");
|
|
local_isnot(aSignResponse.clientData, undefined, "The signing provided clientData with one key");
|
|
});
|
|
|
|
// It's OK to sign with either one
|
|
await promiseU2FSign(window.location.origin, bytesToBase64UrlSafe(challenge),
|
|
[testState.key1, testState.key2], function(aSignResponse) {
|
|
local_is(aSignResponse.errorCode, 0, "The signing did not error with two keys");
|
|
local_isnot(aSignResponse.clientData, undefined, "The signing provided clientData with two keys");
|
|
});
|
|
|
|
await promiseU2FSign(window.location.origin, bytesToBase64UrlSafe(challenge),
|
|
[invalidKey, testState.key2], function(aSignResponse) {
|
|
local_is(aSignResponse.errorCode, 0, "The signing did not error when given an invalid key");
|
|
local_isnot(aSignResponse.clientData, undefined, "The signing provided clientData even when given an invalid key");
|
|
});
|
|
|
|
await promiseU2FSign(window.location.origin, bytesToBase64UrlSafe(challenge),
|
|
[testState.key2, invalidKey], function(aSignResponse) {
|
|
local_is(aSignResponse.errorCode, 0, "The signing did not error when given an invalid key");
|
|
local_isnot(aSignResponse.clientData, undefined, "The signing provided clientData even when given an invalid key");
|
|
});
|
|
|
|
await promiseU2FSign(window.location.origin, bytesToBase64UrlSafe(challenge),
|
|
[invalidKey], function(aSignResponse) {
|
|
local_is(aSignResponse.errorCode, 4, "The signing couldn't complete with this invalid key");
|
|
local_is(aSignResponse.clientData, undefined, "The signing shouldn't provide clientData when there's no valid key");
|
|
});
|
|
|
|
local_finished();
|
|
};
|
|
|
|
doTests();
|
|
</script>
|
|
</body>
|
|
</html>
|