Bug 1330138 - Divide U2F and WebAuthn into separate directories; r=jcj

MozReview-Commit-ID: FCCSL6XWhTf


--HG--
rename : dom/u2f/NSSU2FTokenRemote.cpp => dom/webauthn/NSSU2FTokenRemote.cpp
rename : dom/u2f/NSSU2FTokenRemote.h => dom/webauthn/NSSU2FTokenRemote.h
rename : dom/u2f/ScopedCredential.cpp => dom/webauthn/ScopedCredential.cpp
rename : dom/u2f/ScopedCredential.h => dom/webauthn/ScopedCredential.h
rename : dom/u2f/ScopedCredentialInfo.cpp => dom/webauthn/ScopedCredentialInfo.cpp
rename : dom/u2f/ScopedCredentialInfo.h => dom/webauthn/ScopedCredentialInfo.h
rename : dom/u2f/WebAuthnAssertion.cpp => dom/webauthn/WebAuthnAssertion.cpp
rename : dom/u2f/WebAuthnAssertion.h => dom/webauthn/WebAuthnAssertion.h
rename : dom/u2f/WebAuthnAttestation.cpp => dom/webauthn/WebAuthnAttestation.cpp
rename : dom/u2f/WebAuthnAttestation.h => dom/webauthn/WebAuthnAttestation.h
rename : dom/u2f/tests/test_webauthn_get_assertion.html => dom/webauthn/tests/test_webauthn_get_assertion.html
rename : dom/u2f/tests/test_webauthn_loopback.html => dom/webauthn/tests/test_webauthn_loopback.html
rename : dom/u2f/tests/test_webauthn_make_credential.html => dom/webauthn/tests/test_webauthn_make_credential.html
rename : dom/u2f/tests/test_webauthn_no_token.html => dom/webauthn/tests/test_webauthn_no_token.html
rename : dom/u2f/tests/test_webauthn_sameorigin.html => dom/webauthn/tests/test_webauthn_sameorigin.html
This commit is contained in:
Kyle Machulis 2017-01-11 12:38:08 -08:00
Родитель 4fca25988e
Коммит 14bcecc66f
31 изменённых файлов: 16475 добавлений и 42 удалений

Просмотреть файл

@ -85,6 +85,7 @@ DIRS += [
'promise',
'smil',
'url',
'webauthn',
'webidl',
'xbl',
'xml',

Просмотреть файл

@ -42,7 +42,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(U2F)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(U2F, mParent)
static mozilla::LazyLogModule gWebauthLog("webauth_u2f");
static mozilla::LazyLogModule gU2FLog("u2f");
static nsresult
AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp,
@ -81,7 +81,7 @@ U2FStatus::WaitGroupAdd()
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mCount += 1;
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("U2FStatus::WaitGroupAdd, now %d", mCount));
}
@ -92,7 +92,7 @@ U2FStatus::WaitGroupDone()
MOZ_ASSERT(mCount > 0);
mCount -= 1;
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("U2FStatus::WaitGroupDone, now %d", mCount));
if (mCount == 0) {
mReentrantMonitor.NotifyAll();
@ -103,7 +103,7 @@ void
U2FStatus::WaitGroupWait()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("U2FStatus::WaitGroupWait, now %d", mCount));
while (mCount > 0) {
@ -111,7 +111,7 @@ U2FStatus::WaitGroupWait()
}
MOZ_ASSERT(mCount == 0);
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("U2FStatus::Wait completed, now count=%d stopped=%d", mCount,
mIsStopped));
}
@ -627,7 +627,7 @@ U2FRegisterRunnable::Run()
U2FPrepPromise::All(AbstractThread::MainThread(), prepPromiseList)
->Then(AbstractThread::MainThread(), __func__,
[status] (const nsTArray<Authenticator>& aTokens) {
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("ALL: None of the RegisteredKeys were recognized. n=%d",
aTokens.Length()));
@ -784,7 +784,7 @@ U2FSignRunnable::U2FSignRunnable(const nsAString& aOrigin,
nsresult rv = AssembleClientData(aOrigin, kGetAssertion, aChallenge,
mClientData);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(gWebauthLog, LogLevel::Warning,
MOZ_LOG(gU2FLog, LogLevel::Warning,
("Failed to AssembleClientData for the U2FSignRunnable."));
return;
}
@ -976,7 +976,7 @@ U2F::Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv)
}
if (!EnsureNSSInitializedChromeOrContent()) {
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("Failed to get NSS context for U2F"));
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -984,7 +984,7 @@ U2F::Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv)
// This only functions in e10s mode
if (XRE_IsParentProcess()) {
MOZ_LOG(gWebauthLog, LogLevel::Debug,
MOZ_LOG(gU2FLog, LogLevel::Debug,
("Is non-e10s Process, U2F not available"));
aRv.Throw(NS_ERROR_FAILURE);
return;

Просмотреть файл

@ -5,27 +5,14 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'NSSU2FTokenRemote.h',
'ScopedCredential.h',
'ScopedCredentialInfo.h',
'U2F.h',
'U2FAuthenticator.h',
'USBToken.h',
'WebAuthentication.h',
'WebAuthnAssertion.h',
'WebAuthnAttestation.h',
'WebAuthnRequest.h',
]
UNIFIED_SOURCES += [
'NSSU2FTokenRemote.cpp',
'ScopedCredential.cpp',
'ScopedCredentialInfo.cpp',
'U2F.cpp',
'USBToken.cpp',
'WebAuthentication.cpp',
'WebAuthnAssertion.cpp',
'WebAuthnAttestation.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -27,18 +27,3 @@ skip-if = !e10s
skip-if = !e10s
[test_appid_facet_subdomain.html]
skip-if = !e10s
[test_webauthn_loopback.html]
skip-if = !e10s
scheme = https
[test_webauthn_no_token.html]
skip-if = !e10s
scheme = https
[test_webauthn_make_credential.html]
skip-if = !e10s
scheme = https
[test_webauthn_get_assertion.html]
skip-if = !e10s
scheme = https
[test_webauthn_sameorigin.html]
skip-if = !e10s
scheme = https

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -13,10 +13,13 @@
#include "pkix/Input.h"
#include "pkixutil.h"
#define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f_enable_softtoken"
#define PREF_U2F_USBTOKEN_ENABLED "security.webauth.u2f_enable_usbtoken"
namespace mozilla {
namespace dom {
extern mozilla::LazyLogModule gWebauthLog; // defined in U2F.cpp
static mozilla::LazyLogModule gWebauthLog("webauthn");
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebAuthentication, mParent)

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_dom_WebAuthentication_h
#define mozilla_dom_WebAuthentication_h
#include "hasht.h"
#include "js/TypeDecls.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/BindingDeclarations.h"
@ -18,6 +19,7 @@
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/SharedThreadPool.h"
#include "nsCycleCollectionParticipant.h"
#include "nsNetCID.h"
#include "nsWrapperCache.h"
#include "U2FAuthenticator.h"

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -15,7 +15,7 @@
namespace mozilla {
namespace dom {
extern mozilla::LazyLogModule gWebauthLog; // defined in U2F.cpp
//extern mozilla::LazyLogModule gWebauthLog; // defined in U2F.cpp
// WebAuthnRequest tracks the completion of a single WebAuthn request that
// may run on multiple kinds of authenticators, and be subject to a deadline.
@ -32,9 +32,9 @@ public:
void AddActiveToken(const char* aCallSite)
{
MOZ_LOG(gWebauthLog, LogLevel::Debug,
("WebAuthnRequest is tracking a new token, called from [%s]",
aCallSite));
// MOZ_LOG(gWebauthLog, LogLevel::Debug,
// ("WebAuthnRequest is tracking a new token, called from [%s]",
// aCallSite));
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(!IsComplete());
mCountTokens += 1;

38
dom/webauthn/moz.build Normal file
Просмотреть файл

@ -0,0 +1,38 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.dom += [
'NSSU2FTokenRemote.h',
'ScopedCredential.h',
'ScopedCredentialInfo.h',
'WebAuthentication.h',
'WebAuthnAssertion.h',
'WebAuthnAttestation.h',
'WebAuthnRequest.h',
]
UNIFIED_SOURCES += [
'NSSU2FTokenRemote.cpp',
'ScopedCredential.cpp',
'ScopedCredentialInfo.cpp',
'WebAuthentication.cpp',
'WebAuthnAssertion.cpp',
'WebAuthnAttestation.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base',
'/dom/crypto',
'/security/manager/ssl',
'/security/pkix/include',
'/security/pkix/lib',
]
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']

Просмотреть файл

@ -0,0 +1,23 @@
[DEFAULT]
support-files =
pkijs/asn1.js
pkijs/common.js
pkijs/x509_schema.js
pkijs/x509_simpl.js
u2futil.js
[test_webauthn_loopback.html]
skip-if = !e10s
scheme = https
[test_webauthn_no_token.html]
skip-if = !e10s
scheme = https
[test_webauthn_make_credential.html]
skip-if = !e10s
scheme = https
[test_webauthn_get_assertion.html]
skip-if = !e10s
scheme = https
[test_webauthn_sameorigin.html]
skip-if = !e10s
scheme = https

Просмотреть файл

@ -0,0 +1,30 @@
Copyright (c) 2014, GMO GlobalSign
Copyright (c) 2015, Peculiar Ventures
All rights reserved.
Author 2014-2015, Yury Strozhevsky
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Просмотреть файл

@ -0,0 +1 @@
PKIjs and ASN1js are from https://pkijs.org/ and https://asn1js.org/.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,227 @@
// Used by local_addTest() / local_completeTest()
var _countCompletions = 0;
var _expectedCompletions = 0;
function handleEventMessage(event) {
if ("test" in event.data) {
let summary = event.data.test + ": " + event.data.msg;
log(event.data.status + ": " + summary);
ok(event.data.status, summary);
} else if ("done" in event.data) {
SimpleTest.finish();
} else {
ok(false, "Unexpected message in the test harness: " + event.data)
}
}
function log(msg) {
console.log(msg)
let logBox = document.getElementById("log");
if (logBox) {
logBox.textContent += "\n" + msg;
}
}
function local_is(value, expected, message) {
if (value === expected) {
local_ok(true, message);
} else {
local_ok(false, message + " unexpectedly: " + value + " !== " + expected);
}
}
function local_isnot(value, expected, message) {
if (value !== expected) {
local_ok(true, message);
} else {
local_ok(false, message + " unexpectedly: " + value + " === " + expected);
}
}
function local_ok(expression, message) {
let body = {"test": this.location.pathname, "status":expression, "msg": message}
parent.postMessage(body, "http://mochi.test:8888");
}
function local_doesThrow(fn, name) {
let gotException = false;
try {
fn();
} catch (ex) { gotException = true; }
local_ok(gotException, name);
};
function local_expectThisManyTests(count) {
if (_expectedCompletions > 0) {
local_ok(false, "Error: local_expectThisManyTests should only be called once.");
}
_expectedCompletions = count;
}
function local_completeTest() {
_countCompletions += 1
if (_countCompletions == _expectedCompletions) {
log("All tests completed.")
local_finished();
}
if (_countCompletions > _expectedCompletions) {
local_ok(false, "Error: local_completeTest called more than local_addTest.");
}
}
function local_finished() {
parent.postMessage({"done":true}, "http://mochi.test:8888");
}
function string2buffer(str) {
return (new Uint8Array(str.length)).map((x, i) => str.charCodeAt(i));
}
function buffer2string(buf) {
let str = "";
buf.map(x => str += String.fromCharCode(x));
return str;
}
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 base64ToBytes(b64encoded) {
return new Uint8Array(window.atob(b64encoded).split("").map(function(c) {
return c.charCodeAt(0);
}));
}
function bytesToBase64UrlSafe(buf) {
return bytesToBase64(buf)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
function base64ToBytesUrlSafe(str) {
if (str.length % 4 == 1) {
throw "Improper b64 string";
}
var b64 = str.replace(/\-/g, "+").replace(/\_/g, "/");
while (b64.length % 4 != 0) {
b64 += "=";
}
return base64ToBytes(b64);
}
function hexEncode(buf) {
return Array.from(buf)
.map(x => ("0"+x.toString(16)).substr(-2))
.join("");
}
function hexDecode(str) {
return new Uint8Array(str.match(/../g).map(x => parseInt(x, 16)));
}
function decodeU2FRegistration(aRegData) {
if (aRegData[0] != 0x05) {
return Promise.reject("Sentinal byte != 0x05");
}
let keyHandleLength = aRegData[66];
let u2fRegObj = {
publicKeyBytes: aRegData.slice(1, 66),
keyHandleBytes: aRegData.slice(67, 67 + keyHandleLength),
attestationBytes: aRegData.slice(67 + keyHandleLength)
}
u2fRegObj.keyHandle = bytesToBase64UrlSafe(u2fRegObj.keyHandleBytes);
return importPublicKey(u2fRegObj.publicKeyBytes)
.then(function(keyObj) {
u2fRegObj.publicKey = keyObj;
return u2fRegObj;
});
}
function importPublicKey(keyBytes) {
if (keyBytes[0] != 0x04 || keyBytes.byteLength != 65) {
throw "Bad public key octet string";
}
var jwk = {
kty: "EC",
crv: "P-256",
x: bytesToBase64UrlSafe(keyBytes.slice(1, 33)),
y: bytesToBase64UrlSafe(keyBytes.slice(33))
};
return crypto.subtle.importKey("jwk", jwk, {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"])
}
function deriveAppAndChallengeParam(appId, clientData) {
var appIdBuf = string2buffer(appId);
return Promise.all([
crypto.subtle.digest("SHA-256", appIdBuf),
crypto.subtle.digest("SHA-256", clientData)
])
.then(function(digests) {
return {
appParam: new Uint8Array(digests[0]),
challengeParam: new Uint8Array(digests[1]),
};
});
}
function assembleSignedData(appParam, presenceAndCounter, challengeParam) {
let signedData = new Uint8Array(32 + 1 + 4 + 32);
appParam.map((x, i) => signedData[0 + i] = x);
presenceAndCounter.map((x, i) => signedData[32 + i] = x);
challengeParam.map((x, i) => signedData[37 + i] = x);
return signedData;
}
function assembleRegistrationSignedData(appParam, challengeParam, keyHandle, pubKey) {
let signedData = new Uint8Array(1 + 32 + 32 + keyHandle.length + 65);
signedData[0] = 0x00;
appParam.map((x, i) => signedData[1 + i] = x);
challengeParam.map((x, i) => signedData[33 + i] = x);
keyHandle.map((x, i) => signedData[65 + i] = x);
pubKey.map((x, i) => signedData[65 + keyHandle.length + i] = x);
return signedData;
}
function sanitizeSigArray(arr) {
// ECDSA signature fields into WebCrypto must be exactly 32 bytes long, so
// this method strips leading padding bytes, if added, and also appends
// padding zeros, if needed.
if (arr.length > 32) {
arr = arr.slice(arr.length - 32)
}
let ret = new Uint8Array(32);
ret.set(arr, ret.length - arr.length);
return ret;
}
function verifySignature(key, data, derSig) {
let sigAsn1 = org.pkijs.fromBER(derSig.buffer);
let sigR = new Uint8Array(sigAsn1.result.value_block.value[0].value_block.value_hex);
let sigS = new Uint8Array(sigAsn1.result.value_block.value[1].value_block.value_hex);
// The resulting R and S values from the ASN.1 Sequence must be fit into 32
// bytes. Sometimes they have leading zeros, sometimes they're too short, it
// all depends on what lib generated the signature.
let R = sanitizeSigArray(sigR);
let S = sanitizeSigArray(sigS);
console.log("Verifying these bytes: " + bytesToBase64UrlSafe(data));
let sigData = new Uint8Array(R.length + S.length);
sigData.set(R);
sigData.set(S, R.length);
let alg = {name: "ECDSA", hash: "SHA-256"};
return crypto.subtle.verify(alg, key, sigData, data);
}