зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1264472 - Use nsRunnables in FIDO U2F. r=keeler
- Move the AppID/FacetID algorithm into its own (potentially reentrant) method to facilitate Bug 1244959 - Change the Register and Sign operations to be Runnables so that in the future they can be executed after (future) remote fetches - Clean up error handling - Remove unnecessary remote-load Facet test files; we'll re-add some form of them when the remote load algorithm is completed MozReview-Commit-ID: 4K1q6ovzhgf --HG-- extra : transplant_source : /%7F/%96o1%3E%5E%17%20%A2%D0%AA%10%21%88%19%D9%B3%C9 extra : histedit_source : 4d3c61294951920a22e1f1eb7846a2a03f7cd2f0
This commit is contained in:
Родитель
d8d938eb8b
Коммит
f55c5966d7
1204
dom/u2f/U2F.cpp
1204
dom/u2f/U2F.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
112
dom/u2f/U2F.h
112
dom/u2f/U2F.h
|
@ -34,6 +34,88 @@ class U2FSignCallback;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// These enumerations are defined in the FIDO U2F Javascript API under the
|
||||
// interface "ErrorCode" as constant integers, and thus in the U2F.webidl file.
|
||||
// Any changes to these must occur in both locations.
|
||||
enum class ErrorCode {
|
||||
OK = 0,
|
||||
OTHER_ERROR = 1,
|
||||
BAD_REQUEST = 2,
|
||||
CONFIGURATION_UNSUPPORTED = 3,
|
||||
DEVICE_INELIGIBLE = 4,
|
||||
TIMEOUT = 5
|
||||
};
|
||||
|
||||
class U2FTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
U2FTask(const nsAString& aOrigin,
|
||||
const nsAString& aAppId);
|
||||
|
||||
nsString mOrigin;
|
||||
nsString mAppId;
|
||||
|
||||
virtual
|
||||
void ReturnError(ErrorCode code) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~U2FTask();
|
||||
};
|
||||
|
||||
class U2FRegisterTask final : public nsNSSShutDownObject,
|
||||
public U2FTask
|
||||
{
|
||||
public:
|
||||
U2FRegisterTask(const nsAString& aOrigin,
|
||||
const nsAString& aAppId,
|
||||
const Sequence<RegisterRequest>& aRegisterRequests,
|
||||
const Sequence<RegisteredKey>& aRegisteredKeys,
|
||||
U2FRegisterCallback* aCallback,
|
||||
const nsCOMPtr<nsINSSU2FToken>& aNSSToken);
|
||||
|
||||
// No NSS resources to release.
|
||||
virtual
|
||||
void virtualDestroyNSSReference() override {};
|
||||
|
||||
void ReturnError(ErrorCode code) override;
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
private:
|
||||
~U2FRegisterTask();
|
||||
|
||||
Sequence<RegisterRequest> mRegisterRequests;
|
||||
Sequence<RegisteredKey> mRegisteredKeys;
|
||||
RefPtr<U2FRegisterCallback> mCallback;
|
||||
nsCOMPtr<nsINSSU2FToken> mNSSToken;
|
||||
};
|
||||
|
||||
class U2FSignTask final : public nsNSSShutDownObject,
|
||||
public U2FTask
|
||||
{
|
||||
public:
|
||||
U2FSignTask(const nsAString& aOrigin,
|
||||
const nsAString& aAppId,
|
||||
const nsAString& aChallenge,
|
||||
const Sequence<RegisteredKey>& aRegisteredKeys,
|
||||
U2FSignCallback* aCallback,
|
||||
const nsCOMPtr<nsINSSU2FToken>& aNSSToken);
|
||||
|
||||
// No NSS resources to release.
|
||||
virtual
|
||||
void virtualDestroyNSSReference() override {};
|
||||
|
||||
void ReturnError(ErrorCode code) override;
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
private:
|
||||
~U2FSignTask();
|
||||
|
||||
nsString mChallenge;
|
||||
Sequence<RegisteredKey> mRegisteredKeys;
|
||||
RefPtr<U2FSignCallback> mCallback;
|
||||
nsCOMPtr<nsINSSU2FToken> mNSSToken;
|
||||
};
|
||||
|
||||
class U2F final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public nsNSSShutDownObject
|
||||
|
@ -82,37 +164,7 @@ private:
|
|||
USBToken mUSBToken;
|
||||
nsCOMPtr<nsINSSU2FToken> mNSSToken;
|
||||
|
||||
static const nsString FinishEnrollment;
|
||||
static const nsString GetAssertion;
|
||||
|
||||
~U2F();
|
||||
|
||||
nsresult
|
||||
AssembleClientData(const nsAString& aTyp,
|
||||
const nsAString& aChallenge,
|
||||
CryptoBuffer& aClientData) const;
|
||||
|
||||
// ValidAppID determines whether the supplied FIDO AppID is valid for
|
||||
// the current FacetID, e.g., the current origin. If the supplied
|
||||
// aAppId param is null or empty, it will be filled in per the algorithm.
|
||||
// See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html
|
||||
// for a description of the algorithm.
|
||||
bool
|
||||
ValidAppID(/* in/out */ nsString& aAppId) const;
|
||||
|
||||
nsresult
|
||||
NSSTokenIsCompatible(const nsString& versionString, bool* isCompatible);
|
||||
|
||||
nsresult
|
||||
NSSTokenIsRegistered(CryptoBuffer& keyHandle, bool* isRegistered);
|
||||
|
||||
nsresult
|
||||
NSSTokenRegister(CryptoBuffer& application, CryptoBuffer& challenge,
|
||||
CryptoBuffer& registrationData);
|
||||
|
||||
nsresult
|
||||
NSSTokenSign(CryptoBuffer& keyHandle, CryptoBuffer& application,
|
||||
CryptoBuffer& challenge, CryptoBuffer& signatureData);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"trustedFacets" : [{
|
||||
"version": { "major": 1, "minor" : 0 },
|
||||
"ids": [
|
||||
"https://fido.example.com"
|
||||
]
|
||||
}]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Content-Type: application/fido.trusted-apps+json
|
|
@ -1,6 +0,0 @@
|
|||
# This file isn't actually JSON, so it shouldn't successfully parse.
|
||||
{
|
||||
"trustedFacets" : [{
|
||||
"version": { "major": 1, "minor" : 0 },
|
||||
},{}]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Content-Type: application/fido.trusted-apps+json
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"trustedFacets" : [{
|
||||
"version": { "major": 1, "minor" : 0 },
|
||||
"ids": [
|
||||
"https://example.net",
|
||||
"http://www.example.com"
|
||||
]
|
||||
}]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Content-Type: application/fido.trusted-apps+json
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"trustedFacets" : [{
|
||||
"version": { "major": 1, "minor" : 0 },
|
||||
"ids": [
|
||||
"https://fido.example.com"
|
||||
]
|
||||
}]
|
||||
}
|
|
@ -5,16 +5,8 @@ support-files =
|
|||
test_frame_appid_facet.html
|
||||
test_frame_register.html
|
||||
test_frame_register_sign.html
|
||||
test_frame_appid_facet_remoteload.html
|
||||
test_frame_appid_facet_insecure.html
|
||||
test_frame_appid_facet_subdomain.html
|
||||
facet/facetList.txt
|
||||
facet/facetList-good
|
||||
facet/facetList-good^headers^
|
||||
facet/facetList-no_overlap
|
||||
facet/facetList-no_overlap^headers^
|
||||
facet/facetList-invalid_format
|
||||
facet/facetList-invalid_format^headers^
|
||||
pkijs/common.js
|
||||
pkijs/asn1.js
|
||||
pkijs/x509_schema.js
|
||||
|
|
|
@ -26,7 +26,6 @@ function() {
|
|||
"https://example.com/tests/dom/u2f/tests/test_frame_register_sign.html",
|
||||
"http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html",
|
||||
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html",
|
||||
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html",
|
||||
"https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html"
|
||||
];
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<script src="u2futil.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test for Remote AppId Load behavior for FIDO Universal Second Factor</p>
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
var version = "U2F_V2";
|
||||
var challenge = new Uint8Array(16);
|
||||
|
||||
local_is(window.location.origin, "https://example.com", "Is loaded correctly");
|
||||
|
||||
// TODO: Must support remote loads of AppID manifests first.
|
||||
//
|
||||
// u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetList.txt", [{
|
||||
// version: version,
|
||||
// challenge: bytesToBase64UrlSafe(challenge),
|
||||
// }], [], function(res){
|
||||
// local_is(res.errorCode, 2, "Should not permit this AppId contentType");
|
||||
// });
|
||||
|
||||
// u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetListMissing", [{
|
||||
// version: version,
|
||||
// challenge: bytesToBase64UrlSafe(challenge),
|
||||
// }], [], function(res){
|
||||
// local_is(res.errorCode, 2, "Should not permit with a missing AppID list");
|
||||
// });
|
||||
|
||||
// u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetList-good", [{
|
||||
// version: version,
|
||||
// challenge: bytesToBase64UrlSafe(challenge),
|
||||
// }], [], function(res){
|
||||
// local_is(res.errorCode, 0, "The AppId should permit example.com");
|
||||
// });
|
||||
|
||||
// u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetList-no_overlap", [{
|
||||
// version: version,
|
||||
// challenge: bytesToBase64UrlSafe(challenge),
|
||||
// }], [], function(res){
|
||||
// local_is(res.errorCode, 2, "Should not permit with a missing AppID list");
|
||||
// });
|
||||
|
||||
// u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetList-invalid_format", [{
|
||||
// version: version,
|
||||
// challenge: bytesToBase64UrlSafe(challenge),
|
||||
// }], [], function(res){
|
||||
// local_is(res.errorCode, 2, "Should not fail gracefully on invalid formatted facet lists");
|
||||
// });
|
||||
|
||||
local_finished();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -82,9 +82,9 @@ function() {
|
|||
var clientDataJSON = "";
|
||||
base64ToBytesUrlSafe(regResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x));
|
||||
var clientData = JSON.parse(clientDataJSON);
|
||||
local_is(clientData.typ, "navigator.id.finishEnrollment", "Data type matches");
|
||||
local_is(clientData.challenge, state.regRequest.challenge, "Register challenge matches");
|
||||
local_is(clientData.origin, window.location.origin, "Origins are the same");
|
||||
local_is(clientData.typ, "navigator.id.finishEnrollment", "Register - Data type matches");
|
||||
local_is(clientData.challenge, state.regRequest.challenge, "Register - Challenge matches");
|
||||
local_is(clientData.origin, window.location.origin, "Register - Origins are the same");
|
||||
|
||||
// Verify the signature from the attestation certificate
|
||||
deriveAppAndChallengeParam(state.appId, string2buffer(clientDataJSON))
|
||||
|
@ -161,9 +161,9 @@ function() {
|
|||
var clientDataJSON = "";
|
||||
base64ToBytesUrlSafe(signResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x));
|
||||
var clientData = JSON.parse(clientDataJSON);
|
||||
local_is(clientData.typ, "navigator.id.getAssertion", "Data type matches");
|
||||
local_is(clientData.challenge, state.signChallenge, "Sign challenge matches");
|
||||
local_is(clientData.origin, window.location.origin, "Origins are the same");
|
||||
local_is(clientData.typ, "navigator.id.getAssertion", "Sign - Data type matches");
|
||||
local_is(clientData.challenge, state.signChallenge, "Sign - Challenge matches");
|
||||
local_is(clientData.origin, window.location.origin, "Sign - Origins are the same");
|
||||
|
||||
// Parse the signature data
|
||||
var signatureData = base64ToBytesUrlSafe(signResponse.signatureData);
|
||||
|
|
Загрузка…
Ссылка в новой задаче