Bug 1421723 - Allow localhost as appId for U2F r=jcj

Reviewers: jcj

Reviewed By: jcj

Bug #: 1421723

Differential Revision: https://phabricator.services.mozilla.com/D321
This commit is contained in:
Tim Taubert 2017-12-06 16:28:20 +01:00
parent b12ae1861e
commit 91a23b2116
8 changed files with 121 additions and 20 deletions

Binary file not shown.

Binary file not shown.

View File

@ -292,3 +292,6 @@ https://mochitest.youtube.com:443
# Hosts for stylo blocklist tests
http://stylo-blocklist.com:80 privileged
http://test.stylo-blocklist.com:80 privileged
# Host for U2F localhost tests
https://localhost:443

View File

@ -160,6 +160,23 @@ EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
return ErrorCode::BAD_REQUEST;
}
nsAutoCString appIdHost;
if (NS_FAILED(appIdUri->GetAsciiHost(appIdHost))) {
return ErrorCode::BAD_REQUEST;
}
// Allow localhost.
if (appIdHost.EqualsLiteral("localhost")) {
nsAutoCString facetHost;
if (NS_FAILED(facetUri->GetAsciiHost(facetHost))) {
return ErrorCode::BAD_REQUEST;
}
if (facetHost.EqualsLiteral("localhost")) {
return ErrorCode::OK;
}
}
// Run the HTML5 algorithm to relax the same-origin policy, copied from W3C
// Web Authentication. See Bug 1244959 comment #8 for context on why we are
// doing this instead of implementing the external-fetch FacetID logic.
@ -184,10 +201,6 @@ EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
if (NS_FAILED(tldService->GetBaseDomain(facetUri, 0, lowestFacetHost))) {
return ErrorCode::BAD_REQUEST;
}
nsAutoCString appIdHost;
if (NS_FAILED(appIdUri->GetAsciiHost(appIdHost))) {
return ErrorCode::BAD_REQUEST;
}
MOZ_LOG(gU2FLog, LogLevel::Debug,
("AppId %s Facet %s", appIdHost.get(), lowestFacetHost.get()));

View File

@ -1,6 +1,8 @@
[DEFAULT]
support-files =
head.js
tab_u2f_result.html
skip-if = !e10s
[browser_abort_visibility.js]
[browser_appid_localhost.js]

View File

@ -6,22 +6,6 @@
const TEST_URL = "https://example.com/browser/dom/u2f/tests/browser/tab_u2f_result.html";
function bytesToBase64(u8a){
let CHUNK_SZ = 0x8000;
let c = [];
for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
}
return window.btoa(c.join(""));
}
function bytesToBase64UrlSafe(buf) {
return bytesToBase64(buf)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
async function assertStatus(tab, expected) {
let actual = await ContentTask.spawn(tab.linkedBrowser, null, async function () {
return content.document.getElementById("status").value;

View File

@ -0,0 +1,78 @@
/* 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";
const TEST_URL = "https://localhost/";
function promiseU2FRegister(tab, app_id) {
let challenge = crypto.getRandomValues(new Uint8Array(16));
challenge = bytesToBase64UrlSafe(challenge);
return ContentTask.spawn(tab.linkedBrowser, [app_id, challenge], async function ([app_id, challenge]) {
return new Promise(resolve => {
let version = "U2F_V2";
content.u2f.register(app_id, [{version, challenge}], [], resolve);
});
});
}
add_task(async function () {
// Enable the soft token.
Services.prefs.setBoolPref("security.webauth.u2f", true);
Services.prefs.setBoolPref("security.webauth.webauthn_enable_softtoken", true);
Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", false);
// Open a new tab.
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
// Check that we have the right origin, and U2F is available.
let ready = await ContentTask.spawn(tab.linkedBrowser, null, async () => {
return content.location.origin == "https://localhost" && content.u2f;
});
ok(ready, "Origin is https://localhost. U2F is available.");
// Test: Null AppID
await promiseU2FRegister(tab, null).then(res => {
is(res.errorCode, 0, "Null AppID should work.");
});
// Test: Empty AppID
await promiseU2FRegister(tab, "").then(res => {
is(res.errorCode, 0, "Empty AppID should work.");
});
// Test: Correct TLD, incorrect scheme
await promiseU2FRegister(tab, "http://localhost/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect scheme.");
});
// Test: Incorrect TLD
await promiseU2FRegister(tab, "https://localhost.ssl/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect TLD.");
});
// Test: Incorrect TLD
await promiseU2FRegister(tab, "https://sub.localhost/appId").then(res => {
isnot(res.errorCode, 0, "Incorrect TLD.");
});
// Test: Correct TLD
await promiseU2FRegister(tab, "https://localhost/appId").then(res => {
is(res.errorCode, 0, "https://localhost/appId should work.");
});
// Test: Correct TLD
await promiseU2FRegister(tab, "https://localhost:443/appId").then(res => {
is(res.errorCode, 0, "https://localhost:443/appId should work.");
});
// Close tab.
await BrowserTestUtils.removeTab(tab);
// Cleanup.
Services.prefs.clearUserPref("security.webauth.u2f");
Services.prefs.clearUserPref("security.webauth.webauthn_enable_softtoken");
Services.prefs.clearUserPref("security.webauth.webauthn_enable_usbtoken");
});

View File

@ -0,0 +1,21 @@
/* 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";
function bytesToBase64(u8a){
let CHUNK_SZ = 0x8000;
let c = [];
for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
}
return window.btoa(c.join(""));
}
function bytesToBase64UrlSafe(buf) {
return bytesToBase64(buf)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}