forked from mirrors/gecko-dev
Bug 1857336 - expose an nsIWebAuthnService on Android. r=keeler
Differential Revision: https://phabricator.services.mozilla.com/D190232
This commit is contained in:
parent
93adfae975
commit
d5e1715d6b
32 changed files with 940 additions and 1196 deletions
|
|
@ -72,8 +72,7 @@ async function addVirtualAuthenticator() {
|
||||||
add_task(async () => {
|
add_task(async () => {
|
||||||
await SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
await SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
||||||
["security.webauth.webauthn_enable_softtoken", true],
|
["security.webauth.webauthn_enable_softtoken", true],
|
||||||
["security.webauth.webauthn_enable_usbtoken", false],
|
["security.webauth.webauthn_enable_usbtoken", false]]});
|
||||||
["security.webauth.webauthn_enable_android_fido2", false]]});
|
|
||||||
await addVirtualAuthenticator();
|
await addVirtualAuthenticator();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
384
dom/webauthn/AndroidWebAuthnService.cpp
Normal file
384
dom/webauthn/AndroidWebAuthnService.cpp
Normal file
|
|
@ -0,0 +1,384 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "mozilla/StaticPtr.h"
|
||||||
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
|
#include "mozilla/jni/GeckoBundleUtils.h"
|
||||||
|
|
||||||
|
#include "AndroidWebAuthnService.h"
|
||||||
|
#include "JavaBuiltins.h"
|
||||||
|
#include "JavaExceptions.h"
|
||||||
|
#include "WebAuthnPromiseHolder.h"
|
||||||
|
#include "WebAuthnEnumStrings.h"
|
||||||
|
#include "WebAuthnResult.h"
|
||||||
|
#include "mozilla/StaticPrefs_security.h"
|
||||||
|
#include "mozilla/java/WebAuthnTokenManagerWrappers.h"
|
||||||
|
#include "mozilla/jni/Conversions.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace jni {
|
||||||
|
template <>
|
||||||
|
dom::AndroidWebAuthnError Java2Native(mozilla::jni::Object::Param aData,
|
||||||
|
JNIEnv* aEnv) {
|
||||||
|
MOZ_ASSERT(aData.IsInstanceOf<jni::Throwable>());
|
||||||
|
java::sdk::Throwable::LocalRef throwable(aData);
|
||||||
|
return dom::AndroidWebAuthnError(throwable->GetMessage()->ToString());
|
||||||
|
}
|
||||||
|
} // namespace jni
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(AndroidWebAuthnService, nsIWebAuthnService)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::MakeCredential(uint64_t aTransactionId,
|
||||||
|
uint64_t browsingContextId,
|
||||||
|
nsIWebAuthnRegisterArgs* aArgs,
|
||||||
|
nsIWebAuthnRegisterPromise* aPromise) {
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
|
||||||
|
"java::WebAuthnTokenManager::WebAuthnMakeCredential",
|
||||||
|
[aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise}]() {
|
||||||
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
|
GECKOBUNDLE_START(credentialBundle);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "isWebAuthn",
|
||||||
|
java::sdk::Integer::ValueOf(1));
|
||||||
|
|
||||||
|
nsString rpId;
|
||||||
|
Unused << aArgs->GetRpId(rpId);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "rpId", jni::StringParam(rpId));
|
||||||
|
|
||||||
|
nsString rpName;
|
||||||
|
Unused << aArgs->GetRpName(rpName);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "rpName", jni::StringParam(rpName));
|
||||||
|
|
||||||
|
nsString userName;
|
||||||
|
Unused << aArgs->GetUserName(userName);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "userName",
|
||||||
|
jni::StringParam(userName));
|
||||||
|
|
||||||
|
nsString userDisplayName;
|
||||||
|
Unused << aArgs->GetUserDisplayName(userDisplayName);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "userDisplayName",
|
||||||
|
jni::StringParam(userDisplayName));
|
||||||
|
|
||||||
|
nsString origin;
|
||||||
|
Unused << aArgs->GetOrigin(origin);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "origin", jni::StringParam(origin));
|
||||||
|
|
||||||
|
uint32_t timeout;
|
||||||
|
Unused << aArgs->GetTimeoutMS(&timeout);
|
||||||
|
GECKOBUNDLE_PUT(credentialBundle, "timeoutMS",
|
||||||
|
java::sdk::Double::New(timeout));
|
||||||
|
GECKOBUNDLE_FINISH(credentialBundle);
|
||||||
|
|
||||||
|
nsTArray<uint8_t> userId;
|
||||||
|
Unused << aArgs->GetUserId(userId);
|
||||||
|
jni::ByteBuffer::LocalRef uid = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(static_cast<const void*>(userId.Elements())),
|
||||||
|
userId.Length());
|
||||||
|
|
||||||
|
nsTArray<uint8_t> challBuf;
|
||||||
|
nsresult rv = aArgs->GetClientDataHash(challBuf);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
aPromise->Reject(rv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(static_cast<const void*>(challBuf.Elements())),
|
||||||
|
challBuf.Length());
|
||||||
|
|
||||||
|
nsTArray<nsTArray<uint8_t>> excludeList;
|
||||||
|
Unused << aArgs->GetExcludeList(excludeList);
|
||||||
|
jni::ObjectArray::LocalRef idList =
|
||||||
|
jni::ObjectArray::New(excludeList.Length());
|
||||||
|
int ix = 0;
|
||||||
|
for (const nsTArray<uint8_t>& credId : excludeList) {
|
||||||
|
jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(static_cast<const void*>(credId.Elements())),
|
||||||
|
credId.Length());
|
||||||
|
|
||||||
|
idList->SetElement(ix, id);
|
||||||
|
|
||||||
|
ix += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<uint8_t> transportBuf;
|
||||||
|
/* Bug 1857335 - nsIWebAuthnRegisterArgs doesn't expose the transports
|
||||||
|
* associated with the allowList entries. They're optional, so it's
|
||||||
|
* not critical that we include them. */
|
||||||
|
jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(
|
||||||
|
static_cast<const void*>(transportBuf.Elements())),
|
||||||
|
transportBuf.Length());
|
||||||
|
|
||||||
|
GECKOBUNDLE_START(authSelBundle);
|
||||||
|
// Add UI support to consent to attestation, bug 1550164
|
||||||
|
GECKOBUNDLE_PUT(authSelBundle, "attestationPreference",
|
||||||
|
jni::StringParam(u"none"_ns));
|
||||||
|
|
||||||
|
nsString residentKey;
|
||||||
|
Unused << aArgs->GetResidentKey(residentKey);
|
||||||
|
|
||||||
|
// Get extensions
|
||||||
|
bool requestedCredProps;
|
||||||
|
Unused << aArgs->GetCredProps(&requestedCredProps);
|
||||||
|
|
||||||
|
// Unfortunately, GMS's FIDO2 API has no option for Passkey. If using
|
||||||
|
// residentKey, credential will be synced with Passkey via Google
|
||||||
|
// account or credential provider service. So this is experimental.
|
||||||
|
Maybe<bool> credPropsResponse;
|
||||||
|
if (requestedCredProps &&
|
||||||
|
StaticPrefs::
|
||||||
|
security_webauthn_webauthn_enable_android_fido2_residentkey()) {
|
||||||
|
GECKOBUNDLE_PUT(authSelBundle, "residentKey",
|
||||||
|
jni::StringParam(residentKey));
|
||||||
|
bool residentKeyRequired = residentKey.EqualsLiteral(
|
||||||
|
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED);
|
||||||
|
credPropsResponse = Some(residentKeyRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsString userVerification;
|
||||||
|
Unused << aArgs->GetUserVerification(userVerification);
|
||||||
|
if (userVerification.EqualsLiteral(
|
||||||
|
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
|
||||||
|
GECKOBUNDLE_PUT(authSelBundle, "requireUserVerification",
|
||||||
|
java::sdk::Integer::ValueOf(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
nsString authenticatorAttachment;
|
||||||
|
rv = aArgs->GetAuthenticatorAttachment(authenticatorAttachment);
|
||||||
|
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
aPromise->Reject(rv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (authenticatorAttachment.EqualsLiteral(
|
||||||
|
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
|
||||||
|
GECKOBUNDLE_PUT(authSelBundle, "requirePlatformAttachment",
|
||||||
|
java::sdk::Integer::ValueOf(1));
|
||||||
|
} else if (
|
||||||
|
authenticatorAttachment.EqualsLiteral(
|
||||||
|
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
|
||||||
|
GECKOBUNDLE_PUT(authSelBundle, "requireCrossPlatformAttachment",
|
||||||
|
java::sdk::Integer::ValueOf(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GECKOBUNDLE_FINISH(authSelBundle);
|
||||||
|
|
||||||
|
GECKOBUNDLE_START(extensionsBundle);
|
||||||
|
GECKOBUNDLE_FINISH(extensionsBundle);
|
||||||
|
|
||||||
|
auto result = java::WebAuthnTokenManager::WebAuthnMakeCredential(
|
||||||
|
credentialBundle, uid, challenge, idList, transportList,
|
||||||
|
authSelBundle, extensionsBundle);
|
||||||
|
|
||||||
|
auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
|
||||||
|
|
||||||
|
MozPromise<RefPtr<WebAuthnRegisterResult>, AndroidWebAuthnError,
|
||||||
|
true>::FromGeckoResult(geckoResult)
|
||||||
|
->Then(
|
||||||
|
GetCurrentSerialEventTarget(), __func__,
|
||||||
|
[aPromise, credPropsResponse = std::move(credPropsResponse)](
|
||||||
|
RefPtr<WebAuthnRegisterResult>&& aValue) {
|
||||||
|
if (credPropsResponse.isSome()) {
|
||||||
|
Unused << aValue->SetCredPropsRk(credPropsResponse.ref());
|
||||||
|
}
|
||||||
|
aPromise->Resolve(aValue);
|
||||||
|
},
|
||||||
|
[aPromise](AndroidWebAuthnError&& aValue) {
|
||||||
|
aPromise->Reject(aValue.GetError());
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::GetAssertion(uint64_t aTransactionId,
|
||||||
|
uint64_t browsingContextId,
|
||||||
|
nsIWebAuthnSignArgs* aArgs,
|
||||||
|
nsIWebAuthnSignPromise* aPromise) {
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
|
||||||
|
"java::WebAuthnTokenManager::WebAuthnGetAssertion",
|
||||||
|
[self = RefPtr{this}, aArgs = RefPtr{aArgs},
|
||||||
|
aPromise = RefPtr{aPromise}]() {
|
||||||
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
|
nsTArray<uint8_t> challBuf;
|
||||||
|
nsresult rv = aArgs->GetClientDataHash(challBuf);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
aPromise->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(static_cast<const void*>(challBuf.Elements())),
|
||||||
|
challBuf.Length());
|
||||||
|
|
||||||
|
nsTArray<nsTArray<uint8_t>> allowList;
|
||||||
|
Unused << aArgs->GetAllowList(allowList);
|
||||||
|
jni::ObjectArray::LocalRef idList =
|
||||||
|
jni::ObjectArray::New(allowList.Length());
|
||||||
|
int ix = 0;
|
||||||
|
for (const nsTArray<uint8_t>& credId : allowList) {
|
||||||
|
jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(static_cast<const void*>(credId.Elements())),
|
||||||
|
credId.Length());
|
||||||
|
|
||||||
|
idList->SetElement(ix, id);
|
||||||
|
|
||||||
|
ix += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<uint8_t> transportBuf;
|
||||||
|
/* Bug 1857335 - nsIWebAuthnSignArgs doesn't expose the transports
|
||||||
|
* associated with the allowList entries. They're optional, so it's
|
||||||
|
* not critical that we include them. */
|
||||||
|
jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New(
|
||||||
|
const_cast<void*>(
|
||||||
|
static_cast<const void*>(transportBuf.Elements())),
|
||||||
|
transportBuf.Length());
|
||||||
|
|
||||||
|
GECKOBUNDLE_START(assertionBundle);
|
||||||
|
|
||||||
|
GECKOBUNDLE_PUT(assertionBundle, "isWebAuthn",
|
||||||
|
java::sdk::Integer::ValueOf(1));
|
||||||
|
|
||||||
|
nsString rpId;
|
||||||
|
Unused << aArgs->GetRpId(rpId);
|
||||||
|
GECKOBUNDLE_PUT(assertionBundle, "rpId", jni::StringParam(rpId));
|
||||||
|
|
||||||
|
nsString origin;
|
||||||
|
Unused << aArgs->GetOrigin(origin);
|
||||||
|
GECKOBUNDLE_PUT(assertionBundle, "origin", jni::StringParam(origin));
|
||||||
|
|
||||||
|
uint32_t timeout;
|
||||||
|
Unused << aArgs->GetTimeoutMS(&timeout);
|
||||||
|
GECKOBUNDLE_PUT(assertionBundle, "timeoutMS",
|
||||||
|
java::sdk::Double::New(timeout));
|
||||||
|
|
||||||
|
// User Verification Requirement is not currently used in the
|
||||||
|
// Android FIDO API.
|
||||||
|
|
||||||
|
GECKOBUNDLE_FINISH(assertionBundle);
|
||||||
|
|
||||||
|
GECKOBUNDLE_START(extensionsBundle);
|
||||||
|
|
||||||
|
nsString appId;
|
||||||
|
rv = aArgs->GetAppId(appId);
|
||||||
|
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
aPromise->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GECKOBUNDLE_PUT(extensionsBundle, "fidoAppId",
|
||||||
|
jni::StringParam(appId));
|
||||||
|
}
|
||||||
|
|
||||||
|
GECKOBUNDLE_FINISH(extensionsBundle);
|
||||||
|
|
||||||
|
auto result = java::WebAuthnTokenManager::WebAuthnGetAssertion(
|
||||||
|
challenge, idList, transportList, assertionBundle,
|
||||||
|
extensionsBundle);
|
||||||
|
auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
|
||||||
|
MozPromise<RefPtr<WebAuthnSignResult>, AndroidWebAuthnError,
|
||||||
|
true>::FromGeckoResult(geckoResult)
|
||||||
|
->Then(
|
||||||
|
GetCurrentSerialEventTarget(), __func__,
|
||||||
|
[aPromise](RefPtr<WebAuthnSignResult>&& aValue) {
|
||||||
|
aPromise->Resolve(aValue);
|
||||||
|
},
|
||||||
|
[aPromise](AndroidWebAuthnError&& aValue) {
|
||||||
|
aPromise->Reject(aValue.GetError());
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::Reset() {
|
||||||
|
mRegisterCredPropsRk = Nothing();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::Cancel(uint64_t aTransactionId) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::PinCallback(uint64_t aTransactionId,
|
||||||
|
const nsACString& aPin) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::ResumeMakeCredential(uint64_t aTransactionId,
|
||||||
|
bool aForceNoneAttestation) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::SelectionCallback(uint64_t aTransactionId,
|
||||||
|
uint64_t aIndex) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::AddVirtualAuthenticator(
|
||||||
|
const nsACString& protocol, const nsACString& transport,
|
||||||
|
bool hasResidentKey, bool hasUserVerification, bool isUserConsenting,
|
||||||
|
bool isUserVerified, uint64_t* _retval) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::AddCredential(uint64_t authenticatorId,
|
||||||
|
const nsACString& credentialId,
|
||||||
|
bool isResidentCredential,
|
||||||
|
const nsACString& rpId,
|
||||||
|
const nsACString& privateKey,
|
||||||
|
const nsACString& userHandle,
|
||||||
|
uint32_t signCount) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::GetCredentials(
|
||||||
|
uint64_t authenticatorId,
|
||||||
|
nsTArray<RefPtr<nsICredentialParameters>>& _retval) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::RemoveCredential(uint64_t authenticatorId,
|
||||||
|
const nsACString& credentialId) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AndroidWebAuthnService::SetUserVerified(uint64_t authenticatorId,
|
||||||
|
bool isUserVerified) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef mozilla_dom_AndroidWebAuthnTokenManager_h
|
#ifndef mozilla_dom_AndroidWebAuthnService_h_
|
||||||
#define mozilla_dom_AndroidWebAuthnTokenManager_h
|
#define mozilla_dom_AndroidWebAuthnService_h_
|
||||||
|
|
||||||
#include "mozilla/dom/U2FTokenTransport.h"
|
|
||||||
#include "mozilla/java/WebAuthnTokenManagerNatives.h"
|
#include "mozilla/java/WebAuthnTokenManagerNatives.h"
|
||||||
|
#include "nsIWebAuthnService.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
// Collected from
|
// Collected from
|
||||||
|
|
@ -27,27 +28,13 @@ constexpr auto kTimeoutError = u"TIMEOUT_ERR"_ns;
|
||||||
constexpr auto kNetworkError = u"NETWORK_ERR"_ns;
|
constexpr auto kNetworkError = u"NETWORK_ERR"_ns;
|
||||||
constexpr auto kUnknownError = u"UNKNOWN_ERR"_ns;
|
constexpr auto kUnknownError = u"UNKNOWN_ERR"_ns;
|
||||||
|
|
||||||
class AndroidWebAuthnResult {
|
class AndroidWebAuthnError {
|
||||||
public:
|
public:
|
||||||
explicit AndroidWebAuthnResult(const nsAString& aErrorCode)
|
explicit AndroidWebAuthnError(const nsAString& aErrorCode)
|
||||||
: mErrorCode(aErrorCode) {}
|
: mErrorCode(aErrorCode) {}
|
||||||
|
|
||||||
explicit AndroidWebAuthnResult(
|
|
||||||
const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef&
|
|
||||||
aResponse);
|
|
||||||
|
|
||||||
explicit AndroidWebAuthnResult(
|
|
||||||
const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef&
|
|
||||||
aResponse);
|
|
||||||
|
|
||||||
AndroidWebAuthnResult() = delete;
|
|
||||||
|
|
||||||
bool IsError() const { return NS_FAILED(GetError()); }
|
|
||||||
|
|
||||||
nsresult GetError() const {
|
nsresult GetError() const {
|
||||||
if (mErrorCode.IsEmpty()) {
|
if (mErrorCode.Equals(kSecurityError)) {
|
||||||
return NS_OK;
|
|
||||||
} else if (mErrorCode.Equals(kSecurityError)) {
|
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
} else if (mErrorCode.Equals(kConstraintError)) {
|
} else if (mErrorCode.Equals(kConstraintError)) {
|
||||||
// TODO: The message is right, but it's not about indexeddb.
|
// TODO: The message is right, but it's not about indexeddb.
|
||||||
|
|
@ -79,63 +66,19 @@ class AndroidWebAuthnResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidWebAuthnResult(const AndroidWebAuthnResult&) = delete;
|
|
||||||
AndroidWebAuthnResult(AndroidWebAuthnResult&&) = default;
|
|
||||||
|
|
||||||
// Attestation-only
|
|
||||||
nsTArray<uint8_t> mAttObj;
|
|
||||||
nsTArray<nsString> mTransports;
|
|
||||||
|
|
||||||
// Attestations and assertions
|
|
||||||
nsTArray<uint8_t> mKeyHandle;
|
|
||||||
nsCString mClientDataJSON;
|
|
||||||
|
|
||||||
// Assertions-only
|
|
||||||
nsTArray<uint8_t> mAuthData;
|
|
||||||
nsTArray<uint8_t> mSignature;
|
|
||||||
nsTArray<uint8_t> mUserHandle;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const nsString mErrorCode;
|
const nsString mErrorCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
class AndroidWebAuthnService final : public nsIWebAuthnService {
|
||||||
* WebAuthnAndroidTokenManager is a token implementation communicating with
|
|
||||||
* Android Fido2 APIs.
|
|
||||||
*/
|
|
||||||
class AndroidWebAuthnTokenManager final : public U2FTokenTransport {
|
|
||||||
public:
|
public:
|
||||||
explicit AndroidWebAuthnTokenManager();
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
~AndroidWebAuthnTokenManager() {}
|
NS_DECL_NSIWEBAUTHNSERVICE
|
||||||
|
|
||||||
virtual RefPtr<U2FRegisterPromise> Register(
|
AndroidWebAuthnService() = default;
|
||||||
const WebAuthnMakeCredentialInfo& aInfo,
|
|
||||||
bool aForceNoneAttestation) override;
|
|
||||||
|
|
||||||
virtual RefPtr<U2FSignPromise> Sign(
|
|
||||||
const WebAuthnGetAssertionInfo& aInfo) override;
|
|
||||||
|
|
||||||
void Cancel() override;
|
|
||||||
|
|
||||||
void Drop() override;
|
|
||||||
|
|
||||||
static AndroidWebAuthnTokenManager* GetInstance();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleRegisterResult(AndroidWebAuthnResult&& aResult);
|
~AndroidWebAuthnService() = default;
|
||||||
|
|
||||||
void HandleSignResult(AndroidWebAuthnResult&& aResult);
|
|
||||||
|
|
||||||
void ClearPromises() {
|
|
||||||
mRegisterPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
|
||||||
mSignPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
|
||||||
mRegisterCredPropsRk = Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssertIsOnOwningThread() const;
|
|
||||||
|
|
||||||
MozPromiseHolder<U2FRegisterPromise> mRegisterPromise;
|
|
||||||
MozPromiseHolder<U2FSignPromise> mSignPromise;
|
|
||||||
|
|
||||||
// The Android FIDO2 API doesn't accept the credProps extension. However, the
|
// The Android FIDO2 API doesn't accept the credProps extension. However, the
|
||||||
// appropriate value for CredentialPropertiesOutput.rk can be determined
|
// appropriate value for CredentialPropertiesOutput.rk can be determined
|
||||||
|
|
@ -147,4 +90,4 @@ class AndroidWebAuthnTokenManager final : public U2FTokenTransport {
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_dom_AndroidWebAuthnTokenManager_h
|
#endif // mozilla_dom_AndroidWebAuthnService_h_
|
||||||
|
|
@ -1,467 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "mozilla/ipc/BackgroundParent.h"
|
|
||||||
#include "mozilla/jni/GeckoBundleUtils.h"
|
|
||||||
#include "mozilla/StaticPtr.h"
|
|
||||||
|
|
||||||
#include "AndroidWebAuthnTokenManager.h"
|
|
||||||
#include "JavaBuiltins.h"
|
|
||||||
#include "JavaExceptions.h"
|
|
||||||
#include "mozilla/java/WebAuthnTokenManagerWrappers.h"
|
|
||||||
#include "mozilla/jni/Conversions.h"
|
|
||||||
#include "mozilla/StaticPrefs_security.h"
|
|
||||||
#include "WebAuthnEnumStrings.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace jni {
|
|
||||||
|
|
||||||
template <>
|
|
||||||
dom::AndroidWebAuthnResult Java2Native(mozilla::jni::Object::Param aData,
|
|
||||||
JNIEnv* aEnv) {
|
|
||||||
// TODO:
|
|
||||||
// AndroidWebAuthnResult stores successful both result and failure result.
|
|
||||||
// We should split it into success and failure (Bug 1754157)
|
|
||||||
if (aData.IsInstanceOf<jni::Throwable>()) {
|
|
||||||
java::sdk::Throwable::LocalRef throwable(aData);
|
|
||||||
return dom::AndroidWebAuthnResult(throwable->GetMessage()->ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aData
|
|
||||||
.IsInstanceOf<java::WebAuthnTokenManager::MakeCredentialResponse>()) {
|
|
||||||
java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef response(
|
|
||||||
aData);
|
|
||||||
return dom::AndroidWebAuthnResult(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(
|
|
||||||
aData.IsInstanceOf<java::WebAuthnTokenManager::GetAssertionResponse>());
|
|
||||||
java::WebAuthnTokenManager::GetAssertionResponse::LocalRef response(aData);
|
|
||||||
return dom::AndroidWebAuthnResult(response);
|
|
||||||
}
|
|
||||||
} // namespace jni
|
|
||||||
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
static nsIThread* gAndroidPBackgroundThread;
|
|
||||||
|
|
||||||
StaticRefPtr<AndroidWebAuthnTokenManager> gAndroidWebAuthnManager;
|
|
||||||
|
|
||||||
/* static */ AndroidWebAuthnTokenManager*
|
|
||||||
AndroidWebAuthnTokenManager::GetInstance() {
|
|
||||||
if (!gAndroidWebAuthnManager) {
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
gAndroidWebAuthnManager = new AndroidWebAuthnTokenManager();
|
|
||||||
}
|
|
||||||
return gAndroidWebAuthnManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidWebAuthnTokenManager::AndroidWebAuthnTokenManager() {
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
MOZ_ASSERT(!gAndroidWebAuthnManager);
|
|
||||||
|
|
||||||
gAndroidPBackgroundThread = NS_GetCurrentThread();
|
|
||||||
MOZ_ASSERT(gAndroidPBackgroundThread, "This should never be null!");
|
|
||||||
gAndroidWebAuthnManager = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidWebAuthnTokenManager::AssertIsOnOwningThread() const {
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
MOZ_ASSERT(gAndroidPBackgroundThread);
|
|
||||||
#ifdef DEBUG
|
|
||||||
bool current;
|
|
||||||
MOZ_ASSERT(
|
|
||||||
NS_SUCCEEDED(gAndroidPBackgroundThread->IsOnCurrentThread(¤t)));
|
|
||||||
MOZ_ASSERT(current);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidWebAuthnTokenManager::Drop() {
|
|
||||||
AssertIsOnOwningThread();
|
|
||||||
|
|
||||||
ClearPromises();
|
|
||||||
gAndroidWebAuthnManager = nullptr;
|
|
||||||
gAndroidPBackgroundThread = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<U2FRegisterPromise> AndroidWebAuthnTokenManager::Register(
|
|
||||||
const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) {
|
|
||||||
AssertIsOnOwningThread();
|
|
||||||
|
|
||||||
ClearPromises();
|
|
||||||
|
|
||||||
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"java::WebAuthnTokenManager::WebAuthnMakeCredential",
|
|
||||||
[self = RefPtr{this}, aInfo, aForceNoneAttestation]() {
|
|
||||||
AssertIsOnMainThread();
|
|
||||||
|
|
||||||
// Produce the credential exclusion list
|
|
||||||
jni::ObjectArray::LocalRef idList =
|
|
||||||
jni::ObjectArray::New(aInfo.ExcludeList().Length());
|
|
||||||
|
|
||||||
nsTArray<uint8_t> transportBuf;
|
|
||||||
int ix = 0;
|
|
||||||
|
|
||||||
for (const WebAuthnScopedCredential& cred : aInfo.ExcludeList()) {
|
|
||||||
jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(static_cast<const void*>(cred.id().Elements())),
|
|
||||||
cred.id().Length());
|
|
||||||
|
|
||||||
idList->SetElement(ix, id);
|
|
||||||
transportBuf.AppendElement(cred.transports());
|
|
||||||
|
|
||||||
ix += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(
|
|
||||||
static_cast<const void*>(transportBuf.Elements())),
|
|
||||||
transportBuf.Length());
|
|
||||||
|
|
||||||
const nsTArray<uint8_t>& challBuf = aInfo.Challenge();
|
|
||||||
jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(static_cast<const void*>(challBuf.Elements())),
|
|
||||||
challBuf.Length());
|
|
||||||
|
|
||||||
nsTArray<uint8_t> uidBuf;
|
|
||||||
|
|
||||||
// Get authenticator selection criteria
|
|
||||||
GECKOBUNDLE_START(authSelBundle);
|
|
||||||
GECKOBUNDLE_START(extensionsBundle);
|
|
||||||
GECKOBUNDLE_START(credentialBundle);
|
|
||||||
|
|
||||||
const auto& rp = aInfo.Rp();
|
|
||||||
const auto& user = aInfo.User();
|
|
||||||
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "isWebAuthn",
|
|
||||||
java::sdk::Integer::ValueOf(1));
|
|
||||||
|
|
||||||
// Get the attestation preference and override if the user asked
|
|
||||||
if (aForceNoneAttestation) {
|
|
||||||
// Add UI support to trigger this, bug 1550164
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "attestationPreference",
|
|
||||||
jni::StringParam(u"none"_ns));
|
|
||||||
} else {
|
|
||||||
const nsString& attestation = aInfo.attestationConveyancePreference();
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "attestationPreference",
|
|
||||||
jni::StringParam(attestation));
|
|
||||||
}
|
|
||||||
|
|
||||||
const WebAuthnAuthenticatorSelection& sel =
|
|
||||||
aInfo.AuthenticatorSelection();
|
|
||||||
|
|
||||||
// Get extensions
|
|
||||||
bool requestedCredProps = false;
|
|
||||||
for (const WebAuthnExtension& ext : aInfo.Extensions()) {
|
|
||||||
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionCredProps) {
|
|
||||||
requestedCredProps =
|
|
||||||
ext.get_WebAuthnExtensionCredProps().credProps();
|
|
||||||
}
|
|
||||||
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
|
|
||||||
GECKOBUNDLE_PUT(
|
|
||||||
extensionsBundle, "fidoAppId",
|
|
||||||
jni::StringParam(
|
|
||||||
ext.get_WebAuthnExtensionAppId().appIdentifier()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unfortunately, GMS's FIDO2 API has no option for Passkey. If using
|
|
||||||
// residentKey, credential will be synced with Passkey via Google
|
|
||||||
// account or credential provider service. So this is experimental.
|
|
||||||
if (StaticPrefs::
|
|
||||||
security_webauthn_webauthn_enable_android_fido2_residentkey()) {
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "residentKey",
|
|
||||||
jni::StringParam(sel.residentKey()));
|
|
||||||
if (requestedCredProps) {
|
|
||||||
// In WebAuthnTokenManager.java we set the "requireResidentKey"
|
|
||||||
// parameter to true if and only if "residentKey" here is
|
|
||||||
// "required". This determines the credProps extension output.
|
|
||||||
self->mRegisterCredPropsRk.emplace(sel.residentKey().EqualsLiteral(
|
|
||||||
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.userVerificationRequirement().EqualsLiteral(
|
|
||||||
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "requireUserVerification",
|
|
||||||
java::sdk::Integer::ValueOf(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.authenticatorAttachment().isSome()) {
|
|
||||||
const nsString& authenticatorAttachment =
|
|
||||||
sel.authenticatorAttachment().value();
|
|
||||||
if (authenticatorAttachment.EqualsLiteral(
|
|
||||||
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "requirePlatformAttachment",
|
|
||||||
java::sdk::Integer::ValueOf(1));
|
|
||||||
} else if (
|
|
||||||
authenticatorAttachment.EqualsLiteral(
|
|
||||||
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
|
|
||||||
GECKOBUNDLE_PUT(authSelBundle, "requireCrossPlatformAttachment",
|
|
||||||
java::sdk::Integer::ValueOf(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uidBuf.Assign(user.Id());
|
|
||||||
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "rpName",
|
|
||||||
jni::StringParam(rp.Name()));
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "userName",
|
|
||||||
jni::StringParam(user.Name()));
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "userDisplayName",
|
|
||||||
jni::StringParam(user.DisplayName()));
|
|
||||||
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "rpId",
|
|
||||||
jni::StringParam(aInfo.RpId()));
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "origin",
|
|
||||||
jni::StringParam(aInfo.Origin()));
|
|
||||||
GECKOBUNDLE_PUT(credentialBundle, "timeoutMS",
|
|
||||||
java::sdk::Double::New(aInfo.TimeoutMS()));
|
|
||||||
|
|
||||||
GECKOBUNDLE_FINISH(authSelBundle);
|
|
||||||
GECKOBUNDLE_FINISH(extensionsBundle);
|
|
||||||
GECKOBUNDLE_FINISH(credentialBundle);
|
|
||||||
|
|
||||||
// For non-WebAuthn cases, uidBuf is empty (and unused)
|
|
||||||
jni::ByteBuffer::LocalRef uid = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(static_cast<const void*>(uidBuf.Elements())),
|
|
||||||
uidBuf.Length());
|
|
||||||
|
|
||||||
auto result = java::WebAuthnTokenManager::WebAuthnMakeCredential(
|
|
||||||
credentialBundle, uid, challenge, idList, transportList,
|
|
||||||
authSelBundle, extensionsBundle);
|
|
||||||
auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
|
|
||||||
// This is likely running on the main thread, so we'll always dispatch
|
|
||||||
// to the background for state updates.
|
|
||||||
MozPromise<AndroidWebAuthnResult, AndroidWebAuthnResult,
|
|
||||||
true>::FromGeckoResult(geckoResult)
|
|
||||||
->Then(
|
|
||||||
GetMainThreadSerialEventTarget(), __func__,
|
|
||||||
[self = std::move(self)](AndroidWebAuthnResult&& aValue) {
|
|
||||||
self->HandleRegisterResult(std::move(aValue));
|
|
||||||
},
|
|
||||||
[self = std::move(self)](AndroidWebAuthnResult&& aValue) {
|
|
||||||
self->HandleRegisterResult(std::move(aValue));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
return mRegisterPromise.Ensure(__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidWebAuthnTokenManager::HandleRegisterResult(
|
|
||||||
AndroidWebAuthnResult&& aResult) {
|
|
||||||
if (!gAndroidPBackgroundThread) {
|
|
||||||
// Promise is already rejected when shutting down background thread
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// This is likely running on the main thread, so we'll always dispatch to the
|
|
||||||
// background for state updates.
|
|
||||||
if (aResult.IsError()) {
|
|
||||||
nsresult aError = aResult.GetError();
|
|
||||||
|
|
||||||
gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"AndroidWebAuthnTokenManager::RegisterAbort",
|
|
||||||
[self = RefPtr<AndroidWebAuthnTokenManager>(this), aError]() {
|
|
||||||
self->mRegisterPromise.RejectIfExists(aError, __func__);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"AndroidWebAuthnTokenManager::RegisterComplete",
|
|
||||||
[self = RefPtr<AndroidWebAuthnTokenManager>(this),
|
|
||||||
aResult = std::move(aResult)]() {
|
|
||||||
nsTArray<WebAuthnExtensionResult> extensions;
|
|
||||||
if (self->mRegisterCredPropsRk.isSome()) {
|
|
||||||
extensions.AppendElement(WebAuthnExtensionResultCredProps(
|
|
||||||
self->mRegisterCredPropsRk.value()));
|
|
||||||
}
|
|
||||||
WebAuthnMakeCredentialResult result(
|
|
||||||
aResult.mClientDataJSON, aResult.mAttObj, aResult.mKeyHandle,
|
|
||||||
aResult.mTransports, extensions);
|
|
||||||
self->mRegisterPromise.Resolve(std::move(result), __func__);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<U2FSignPromise> AndroidWebAuthnTokenManager::Sign(
|
|
||||||
const WebAuthnGetAssertionInfo& aInfo) {
|
|
||||||
AssertIsOnOwningThread();
|
|
||||||
|
|
||||||
ClearPromises();
|
|
||||||
|
|
||||||
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"java::WebAuthnTokenManager::WebAuthnGetAssertion",
|
|
||||||
[self = RefPtr{this}, aInfo]() {
|
|
||||||
AssertIsOnMainThread();
|
|
||||||
|
|
||||||
jni::ObjectArray::LocalRef idList =
|
|
||||||
jni::ObjectArray::New(aInfo.AllowList().Length());
|
|
||||||
|
|
||||||
nsTArray<uint8_t> transportBuf;
|
|
||||||
|
|
||||||
int ix = 0;
|
|
||||||
for (const WebAuthnScopedCredential& cred : aInfo.AllowList()) {
|
|
||||||
jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(static_cast<const void*>(cred.id().Elements())),
|
|
||||||
cred.id().Length());
|
|
||||||
|
|
||||||
idList->SetElement(ix, id);
|
|
||||||
transportBuf.AppendElement(cred.transports());
|
|
||||||
|
|
||||||
ix += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(
|
|
||||||
static_cast<const void*>(transportBuf.Elements())),
|
|
||||||
transportBuf.Length());
|
|
||||||
|
|
||||||
const nsTArray<uint8_t>& challBuf = aInfo.Challenge();
|
|
||||||
jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New(
|
|
||||||
const_cast<void*>(static_cast<const void*>(challBuf.Elements())),
|
|
||||||
challBuf.Length());
|
|
||||||
|
|
||||||
// Get extensions
|
|
||||||
GECKOBUNDLE_START(assertionBundle);
|
|
||||||
GECKOBUNDLE_START(extensionsBundle);
|
|
||||||
|
|
||||||
GECKOBUNDLE_PUT(assertionBundle, "isWebAuthn",
|
|
||||||
java::sdk::Integer::ValueOf(1));
|
|
||||||
|
|
||||||
// User Verification Requirement is not currently used in the
|
|
||||||
// Android FIDO API. Adding it should look like
|
|
||||||
// AttestationConveyancePreference
|
|
||||||
|
|
||||||
for (const WebAuthnExtension& ext : aInfo.Extensions()) {
|
|
||||||
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
|
|
||||||
GECKOBUNDLE_PUT(
|
|
||||||
extensionsBundle, "fidoAppId",
|
|
||||||
jni::StringParam(
|
|
||||||
ext.get_WebAuthnExtensionAppId().appIdentifier()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GECKOBUNDLE_PUT(assertionBundle, "rpId",
|
|
||||||
jni::StringParam(aInfo.RpId()));
|
|
||||||
GECKOBUNDLE_PUT(assertionBundle, "origin",
|
|
||||||
jni::StringParam(aInfo.Origin()));
|
|
||||||
GECKOBUNDLE_PUT(assertionBundle, "timeoutMS",
|
|
||||||
java::sdk::Double::New(aInfo.TimeoutMS()));
|
|
||||||
|
|
||||||
GECKOBUNDLE_FINISH(assertionBundle);
|
|
||||||
GECKOBUNDLE_FINISH(extensionsBundle);
|
|
||||||
|
|
||||||
auto result = java::WebAuthnTokenManager::WebAuthnGetAssertion(
|
|
||||||
challenge, idList, transportList, assertionBundle,
|
|
||||||
extensionsBundle);
|
|
||||||
auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
|
|
||||||
MozPromise<AndroidWebAuthnResult, AndroidWebAuthnResult,
|
|
||||||
true>::FromGeckoResult(geckoResult)
|
|
||||||
->Then(
|
|
||||||
GetMainThreadSerialEventTarget(), __func__,
|
|
||||||
[self = std::move(self)](AndroidWebAuthnResult&& aValue) {
|
|
||||||
self->HandleSignResult(std::move(aValue));
|
|
||||||
},
|
|
||||||
[self = std::move(self)](AndroidWebAuthnResult&& aValue) {
|
|
||||||
self->HandleSignResult(std::move(aValue));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
return mSignPromise.Ensure(__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidWebAuthnTokenManager::HandleSignResult(
|
|
||||||
AndroidWebAuthnResult&& aResult) {
|
|
||||||
if (!gAndroidPBackgroundThread) {
|
|
||||||
// Promise is already rejected when shutting down background thread
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// This is likely running on the main thread, so we'll always dispatch to the
|
|
||||||
// background for state updates.
|
|
||||||
if (aResult.IsError()) {
|
|
||||||
nsresult aError = aResult.GetError();
|
|
||||||
|
|
||||||
gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"AndroidWebAuthnTokenManager::SignAbort",
|
|
||||||
[self = RefPtr<AndroidWebAuthnTokenManager>(this), aError]() {
|
|
||||||
self->mSignPromise.RejectIfExists(aError, __func__);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"AndroidWebAuthnTokenManager::SignComplete",
|
|
||||||
[self = RefPtr<AndroidWebAuthnTokenManager>(this),
|
|
||||||
aResult = std::move(aResult)]() {
|
|
||||||
nsTArray<WebAuthnExtensionResult> emptyExtensions;
|
|
||||||
WebAuthnGetAssertionResult result(
|
|
||||||
aResult.mClientDataJSON, aResult.mKeyHandle, aResult.mSignature,
|
|
||||||
aResult.mAuthData, emptyExtensions, aResult.mUserHandle);
|
|
||||||
nsTArray<WebAuthnGetAssertionResultWrapper> results = {
|
|
||||||
{result, mozilla::Nothing()}};
|
|
||||||
self->mSignPromise.Resolve(std::move(results), __func__);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidWebAuthnTokenManager::Cancel() {
|
|
||||||
AssertIsOnOwningThread();
|
|
||||||
|
|
||||||
ClearPromises();
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidWebAuthnResult::AndroidWebAuthnResult(
|
|
||||||
const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef&
|
|
||||||
aResponse) {
|
|
||||||
mClientDataJSON.Assign(
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
aResponse->ClientDataJson()->GetElements().Elements()),
|
|
||||||
aResponse->ClientDataJson()->Length());
|
|
||||||
mKeyHandle.Clear();
|
|
||||||
mKeyHandle.AppendElements(
|
|
||||||
reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->KeyHandle()->GetElements().Elements()),
|
|
||||||
aResponse->KeyHandle()->Length());
|
|
||||||
mAttObj.Clear();
|
|
||||||
mAttObj.AppendElements(
|
|
||||||
reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->AttestationObject()->GetElements().Elements()),
|
|
||||||
aResponse->AttestationObject()->Length());
|
|
||||||
auto transports = aResponse->Transports();
|
|
||||||
for (size_t i = 0; i < transports->Length(); i++) {
|
|
||||||
mTransports.AppendElement(
|
|
||||||
jni::String::LocalRef(transports->GetElement(i))->ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidWebAuthnResult::AndroidWebAuthnResult(
|
|
||||||
const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef&
|
|
||||||
aResponse) {
|
|
||||||
mClientDataJSON.Assign(
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
aResponse->ClientDataJson()->GetElements().Elements()),
|
|
||||||
aResponse->ClientDataJson()->Length());
|
|
||||||
mKeyHandle.Clear();
|
|
||||||
mKeyHandle.AppendElements(
|
|
||||||
reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->KeyHandle()->GetElements().Elements()),
|
|
||||||
aResponse->KeyHandle()->Length());
|
|
||||||
mAuthData.Clear();
|
|
||||||
mAuthData.AppendElements(reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->AuthData()->GetElements().Elements()),
|
|
||||||
aResponse->AuthData()->Length());
|
|
||||||
mSignature.Clear();
|
|
||||||
mSignature.AppendElements(
|
|
||||||
reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->Signature()->GetElements().Elements()),
|
|
||||||
aResponse->Signature()->Length());
|
|
||||||
mUserHandle.Clear();
|
|
||||||
mUserHandle.AppendElements(
|
|
||||||
reinterpret_cast<uint8_t*>(
|
|
||||||
aResponse->UserHandle()->GetElements().Elements()),
|
|
||||||
aResponse->UserHandle()->Length());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "AuthrsService.h"
|
|
||||||
#include "AuthrsBridge_ffi.h"
|
|
||||||
#include "nsIWebAuthnService.h"
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom {
|
|
||||||
|
|
||||||
already_AddRefed<nsIWebAuthnService> NewAuthrsService() {
|
|
||||||
nsCOMPtr<nsIWebAuthnService> webauthnService;
|
|
||||||
nsresult rv = authrs_service_constructor(getter_AddRefs(webauthnService));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return webauthnService.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef DOM_WEBAUTHN_AUTHRS_BRIDGE_H_
|
|
||||||
#define DOM_WEBAUTHN_AUTHRS_BRIDGE_H_
|
|
||||||
|
|
||||||
#include "mozilla/AlreadyAddRefed.h"
|
|
||||||
#include "nsIWebAuthnService.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom {
|
|
||||||
|
|
||||||
already_AddRefed<nsIWebAuthnService> NewAuthrsService();
|
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
|
||||||
|
|
||||||
#endif // DOM_WEBAUTHN_AUTHRS_BRIDGE_H_
|
|
||||||
|
|
@ -1,254 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
#include "json/json.h"
|
|
||||||
#include "mozilla/dom/U2FTokenManager.h"
|
|
||||||
#include "mozilla/dom/U2FTokenTransport.h"
|
|
||||||
#include "mozilla/dom/PWebAuthnTransactionParent.h"
|
|
||||||
#include "mozilla/MozPromise.h"
|
|
||||||
#include "mozilla/ipc/BackgroundParent.h"
|
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
|
||||||
#include "mozilla/Services.h"
|
|
||||||
#include "mozilla/Unused.h"
|
|
||||||
#include "nsEscape.h"
|
|
||||||
#include "nsIObserver.h"
|
|
||||||
#include "nsIObserverService.h"
|
|
||||||
#include "nsIThread.h"
|
|
||||||
#include "nsTextFormatter.h"
|
|
||||||
#include "mozilla/Telemetry.h"
|
|
||||||
#include "WebAuthnEnumStrings.h"
|
|
||||||
|
|
||||||
#include "mozilla/dom/AndroidWebAuthnTokenManager.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom {
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* Statics
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
static mozilla::LazyLogModule gU2FTokenManagerLog("u2fkeymanager");
|
|
||||||
StaticAutoPtr<U2FTokenManager> gU2FTokenManager;
|
|
||||||
static nsIThread* gBackgroundThread;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* U2FManager Implementation
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
U2FTokenManager::U2FTokenManager()
|
|
||||||
: mTransactionParent(nullptr), mLastTransactionId(0) {
|
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
// Create on the main thread to make sure ClearOnShutdown() works.
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void U2FTokenManager::Initialize() {
|
|
||||||
if (!XRE_IsParentProcess()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
MOZ_ASSERT(!gU2FTokenManager);
|
|
||||||
gU2FTokenManager = new U2FTokenManager();
|
|
||||||
ClearOnShutdown(&gU2FTokenManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
U2FTokenManager* U2FTokenManager::Get() {
|
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
|
||||||
// We should only be accessing this on the background thread
|
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
|
||||||
return gU2FTokenManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::AbortTransaction(const uint64_t& aTransactionId,
|
|
||||||
const nsresult& aError) {
|
|
||||||
Unused << mTransactionParent->SendAbort(aTransactionId, aError);
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::AbortOngoingTransaction() {
|
|
||||||
if (mLastTransactionId > 0 && mTransactionParent) {
|
|
||||||
// Send an abort to any other ongoing transaction
|
|
||||||
Unused << mTransactionParent->SendAbort(mLastTransactionId,
|
|
||||||
NS_ERROR_DOM_ABORT_ERR);
|
|
||||||
}
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::MaybeClearTransaction(
|
|
||||||
PWebAuthnTransactionParent* aParent) {
|
|
||||||
// Only clear if we've been requested to do so by our current transaction
|
|
||||||
// parent.
|
|
||||||
if (mTransactionParent == aParent) {
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::ClearTransaction() {
|
|
||||||
mTransactionParent = nullptr;
|
|
||||||
|
|
||||||
// Drop managers at the end of all transactions
|
|
||||||
if (mTokenManagerImpl) {
|
|
||||||
mTokenManagerImpl->Drop();
|
|
||||||
mTokenManagerImpl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forget promises, if necessary.
|
|
||||||
mRegisterPromise.DisconnectIfExists();
|
|
||||||
mSignPromise.DisconnectIfExists();
|
|
||||||
|
|
||||||
// Clear transaction id.
|
|
||||||
mLastTransactionId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<U2FTokenTransport> U2FTokenManager::GetTokenManagerImpl() {
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
if (mTokenManagerImpl) {
|
|
||||||
return mTokenManagerImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gBackgroundThread) {
|
|
||||||
gBackgroundThread = NS_GetCurrentThread();
|
|
||||||
MOZ_ASSERT(gBackgroundThread, "This should never be null!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return AndroidWebAuthnTokenManager::GetInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::Register(
|
|
||||||
PWebAuthnTransactionParent* aTransactionParent,
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnMakeCredentialInfo& aTransactionInfo) {
|
|
||||||
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
|
|
||||||
|
|
||||||
AbortOngoingTransaction();
|
|
||||||
mTransactionParent = aTransactionParent;
|
|
||||||
mTokenManagerImpl = GetTokenManagerImpl();
|
|
||||||
|
|
||||||
if (!mTokenManagerImpl) {
|
|
||||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mLastTransactionId = aTransactionId;
|
|
||||||
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
MOZ_ASSERT(mLastTransactionId > 0);
|
|
||||||
|
|
||||||
uint64_t tid = mLastTransactionId;
|
|
||||||
|
|
||||||
mTokenManagerImpl
|
|
||||||
->Register(aTransactionInfo, /* aForceNoneAttestation */ true)
|
|
||||||
->Then(
|
|
||||||
GetCurrentSerialEventTarget(), __func__,
|
|
||||||
[tid](WebAuthnMakeCredentialResult&& aResult) {
|
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
|
|
||||||
u"U2FRegisterFinish"_ns, 1);
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
mgr->MaybeConfirmRegister(tid, aResult);
|
|
||||||
},
|
|
||||||
[tid](nsresult rv) {
|
|
||||||
MOZ_ASSERT(NS_FAILED(rv));
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
|
|
||||||
u"U2FRegisterAbort"_ns, 1);
|
|
||||||
mgr->MaybeAbortRegister(tid, rv);
|
|
||||||
})
|
|
||||||
->Track(mRegisterPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::MaybeConfirmRegister(
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnMakeCredentialResult& aResult) {
|
|
||||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
|
||||||
mRegisterPromise.Complete();
|
|
||||||
|
|
||||||
Unused << mTransactionParent->SendConfirmRegister(aTransactionId, aResult);
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::MaybeAbortRegister(const uint64_t& aTransactionId,
|
|
||||||
const nsresult& aError) {
|
|
||||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
|
||||||
mRegisterPromise.Complete();
|
|
||||||
AbortTransaction(aTransactionId, aError);
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnGetAssertionInfo& aTransactionInfo) {
|
|
||||||
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
|
|
||||||
|
|
||||||
AbortOngoingTransaction();
|
|
||||||
mTransactionParent = aTransactionParent;
|
|
||||||
mTokenManagerImpl = GetTokenManagerImpl();
|
|
||||||
|
|
||||||
if (!mTokenManagerImpl) {
|
|
||||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mLastTransactionId = aTransactionId;
|
|
||||||
|
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
MOZ_ASSERT(mLastTransactionId > 0);
|
|
||||||
uint64_t tid = mLastTransactionId;
|
|
||||||
|
|
||||||
mTokenManagerImpl->Sign(aTransactionInfo)
|
|
||||||
->Then(
|
|
||||||
GetCurrentSerialEventTarget(), __func__,
|
|
||||||
[tid](nsTArray<WebAuthnGetAssertionResultWrapper>&& aResult) {
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
|
|
||||||
u"U2FSignFinish"_ns, 1);
|
|
||||||
if (aResult.Length() == 1) {
|
|
||||||
WebAuthnGetAssertionResult result = aResult[0].assertion;
|
|
||||||
mgr->MaybeConfirmSign(tid, result);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[tid](nsresult rv) {
|
|
||||||
MOZ_ASSERT(NS_FAILED(rv));
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED,
|
|
||||||
u"U2FSignAbort"_ns, 1);
|
|
||||||
mgr->MaybeAbortSign(tid, rv);
|
|
||||||
})
|
|
||||||
->Track(mSignPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::MaybeConfirmSign(
|
|
||||||
const uint64_t& aTransactionId, const WebAuthnGetAssertionResult& aResult) {
|
|
||||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
|
||||||
mSignPromise.Complete();
|
|
||||||
|
|
||||||
Unused << mTransactionParent->SendConfirmSign(aTransactionId, aResult);
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::MaybeAbortSign(const uint64_t& aTransactionId,
|
|
||||||
const nsresult& aError) {
|
|
||||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
|
||||||
mSignPromise.Complete();
|
|
||||||
AbortTransaction(aTransactionId, aError);
|
|
||||||
}
|
|
||||||
|
|
||||||
void U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent,
|
|
||||||
const Tainted<uint64_t>& aTransactionId) {
|
|
||||||
// The last transaction ID also suffers from the issue described in Bug
|
|
||||||
// 1696159. A content process could cancel another content processes
|
|
||||||
// transaction by guessing the last transaction ID.
|
|
||||||
if (mTransactionParent != aParent ||
|
|
||||||
!MOZ_IS_VALID(aTransactionId, mLastTransactionId == aTransactionId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mTokenManagerImpl->Cancel();
|
|
||||||
ClearTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_dom_U2FTokenManager_h
|
|
||||||
#define mozilla_dom_U2FTokenManager_h
|
|
||||||
|
|
||||||
#include "mozilla/dom/U2FTokenTransport.h"
|
|
||||||
#include "mozilla/dom/PWebAuthnTransaction.h"
|
|
||||||
#include "mozilla/Tainting.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parent process manager for U2F and WebAuthn API transactions. Handles process
|
|
||||||
* transactions from all content processes, make sure only one transaction is
|
|
||||||
* live at any time. Manages access to hardware and software based key systems.
|
|
||||||
*
|
|
||||||
* U2FTokenManager is created on the first access to functions of either the U2F
|
|
||||||
* or WebAuthn APIs that require key registration or signing. It lives until the
|
|
||||||
* end of the browser process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace mozilla::dom {
|
|
||||||
|
|
||||||
class U2FSoftTokenManager;
|
|
||||||
class WebAuthnTransactionParent;
|
|
||||||
|
|
||||||
class U2FTokenManager final {
|
|
||||||
public:
|
|
||||||
static U2FTokenManager* Get();
|
|
||||||
void Register(PWebAuthnTransactionParent* aTransactionParent,
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnMakeCredentialInfo& aTransactionInfo);
|
|
||||||
void Sign(PWebAuthnTransactionParent* aTransactionParent,
|
|
||||||
const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnGetAssertionInfo& aTransactionInfo);
|
|
||||||
void Cancel(PWebAuthnTransactionParent* aTransactionParent,
|
|
||||||
const Tainted<uint64_t>& aTransactionId);
|
|
||||||
void MaybeClearTransaction(PWebAuthnTransactionParent* aParent);
|
|
||||||
static void Initialize();
|
|
||||||
|
|
||||||
U2FTokenManager();
|
|
||||||
~U2FTokenManager() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<U2FTokenTransport> GetTokenManagerImpl();
|
|
||||||
void AbortTransaction(const uint64_t& aTransactionId, const nsresult& aError);
|
|
||||||
void AbortOngoingTransaction();
|
|
||||||
void ClearTransaction();
|
|
||||||
void MaybeConfirmRegister(const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnMakeCredentialResult& aResult);
|
|
||||||
void MaybeAbortRegister(const uint64_t& aTransactionId,
|
|
||||||
const nsresult& aError);
|
|
||||||
void MaybeConfirmSign(const uint64_t& aTransactionId,
|
|
||||||
const WebAuthnGetAssertionResult& aResult);
|
|
||||||
void MaybeAbortSign(const uint64_t& aTransactionId, const nsresult& aError);
|
|
||||||
// Using a raw pointer here, as the lifetime of the IPC object is managed by
|
|
||||||
// the PBackground protocol code. This means we cannot be left holding an
|
|
||||||
// invalid IPC protocol object after the transaction is finished.
|
|
||||||
PWebAuthnTransactionParent* mTransactionParent;
|
|
||||||
RefPtr<U2FTokenTransport> mTokenManagerImpl;
|
|
||||||
MozPromiseRequestHolder<U2FRegisterPromise> mRegisterPromise;
|
|
||||||
MozPromiseRequestHolder<U2FSignPromise> mSignPromise;
|
|
||||||
// The last transaction id, non-zero if there's an active transaction. This
|
|
||||||
// guards any cancel messages to ensure we don't cancel newer transactions
|
|
||||||
// due to a stale message.
|
|
||||||
uint64_t mLastTransactionId;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
|
||||||
|
|
||||||
#endif // mozilla_dom_U2FTokenManager_h
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_dom_U2FTokenTransport_h
|
|
||||||
#define mozilla_dom_U2FTokenTransport_h
|
|
||||||
|
|
||||||
#include "mozilla/dom/PWebAuthnTransaction.h"
|
|
||||||
#include "mozilla/MozPromise.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abstract class representing a transport manager for U2F Keys (software,
|
|
||||||
* bluetooth, usb, etc.). Hides the implementation details for specific key
|
|
||||||
* transport types.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace mozilla::dom {
|
|
||||||
|
|
||||||
class WebAuthnGetAssertionResultWrapper {
|
|
||||||
public:
|
|
||||||
WebAuthnGetAssertionResult assertion;
|
|
||||||
mozilla::Maybe<nsCString> username;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef MozPromise<WebAuthnMakeCredentialResult, nsresult, true>
|
|
||||||
U2FRegisterPromise;
|
|
||||||
typedef MozPromise<nsTArray<WebAuthnGetAssertionResultWrapper>, nsresult, true>
|
|
||||||
U2FSignPromise;
|
|
||||||
|
|
||||||
class U2FTokenTransport {
|
|
||||||
public:
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FTokenTransport);
|
|
||||||
U2FTokenTransport() = default;
|
|
||||||
|
|
||||||
virtual RefPtr<U2FRegisterPromise> Register(
|
|
||||||
const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) = 0;
|
|
||||||
|
|
||||||
virtual RefPtr<U2FSignPromise> Sign(
|
|
||||||
const WebAuthnGetAssertionInfo& aInfo) = 0;
|
|
||||||
|
|
||||||
virtual void Cancel() = 0;
|
|
||||||
|
|
||||||
virtual void Drop() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~U2FTokenTransport() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
|
||||||
|
|
||||||
#endif // mozilla_dom_U2FTokenTransport_h
|
|
||||||
|
|
@ -4,26 +4,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "CtapArgs.h"
|
#include "WebAuthnArgs.h"
|
||||||
#include "WebAuthnEnumStrings.h"
|
#include "WebAuthnEnumStrings.h"
|
||||||
#include "WebAuthnUtil.h"
|
#include "WebAuthnUtil.h"
|
||||||
#include "mozilla/dom/PWebAuthnTransactionParent.h"
|
#include "mozilla/dom/PWebAuthnTransactionParent.h"
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CtapRegisterArgs, nsICtapRegisterArgs)
|
NS_IMPL_ISUPPORTS(WebAuthnRegisterArgs, nsIWebAuthnRegisterArgs)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetOrigin(nsAString& aOrigin) {
|
WebAuthnRegisterArgs::GetOrigin(nsAString& aOrigin) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aOrigin = mInfo.Origin();
|
aOrigin = mInfo.Origin();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
WebAuthnRegisterArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
|
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
@ -33,44 +30,37 @@ CtapRegisterArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetRpId(nsAString& aRpId) {
|
WebAuthnRegisterArgs::GetRpId(nsAString& aRpId) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aRpId = mInfo.RpId();
|
aRpId = mInfo.RpId();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetRpName(nsAString& aRpName) {
|
WebAuthnRegisterArgs::GetRpName(nsAString& aRpName) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aRpName = mInfo.Rp().Name();
|
aRpName = mInfo.Rp().Name();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetUserId(nsTArray<uint8_t>& aUserId) {
|
WebAuthnRegisterArgs::GetUserId(nsTArray<uint8_t>& aUserId) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
aUserId.Assign(mInfo.User().Id());
|
||||||
aUserId.Clear();
|
|
||||||
aUserId.AppendElements(mInfo.User().Id());
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetUserName(nsAString& aUserName) {
|
WebAuthnRegisterArgs::GetUserName(nsAString& aUserName) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aUserName = mInfo.User().Name();
|
aUserName = mInfo.User().Name();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetUserDisplayName(nsAString& aUserDisplayName) {
|
WebAuthnRegisterArgs::GetUserDisplayName(nsAString& aUserDisplayName) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aUserDisplayName = mInfo.User().DisplayName();
|
aUserDisplayName = mInfo.User().DisplayName();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetCoseAlgs(nsTArray<int32_t>& aCoseAlgs) {
|
WebAuthnRegisterArgs::GetCoseAlgs(nsTArray<int32_t>& aCoseAlgs) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aCoseAlgs.Clear();
|
aCoseAlgs.Clear();
|
||||||
for (const CoseAlg& coseAlg : mInfo.coseAlgs()) {
|
for (const CoseAlg& coseAlg : mInfo.coseAlgs()) {
|
||||||
aCoseAlgs.AppendElement(coseAlg.alg());
|
aCoseAlgs.AppendElement(coseAlg.alg());
|
||||||
|
|
@ -79,8 +69,8 @@ CtapRegisterArgs::GetCoseAlgs(nsTArray<int32_t>& aCoseAlgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetExcludeList(nsTArray<nsTArray<uint8_t> >& aExcludeList) {
|
WebAuthnRegisterArgs::GetExcludeList(
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
nsTArray<nsTArray<uint8_t> >& aExcludeList) {
|
||||||
aExcludeList.Clear();
|
aExcludeList.Clear();
|
||||||
for (const WebAuthnScopedCredential& cred : mInfo.ExcludeList()) {
|
for (const WebAuthnScopedCredential& cred : mInfo.ExcludeList()) {
|
||||||
aExcludeList.AppendElement(cred.id().Clone());
|
aExcludeList.AppendElement(cred.id().Clone());
|
||||||
|
|
@ -89,51 +79,43 @@ CtapRegisterArgs::GetExcludeList(nsTArray<nsTArray<uint8_t> >& aExcludeList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetCredProps(bool* aCredProps) {
|
WebAuthnRegisterArgs::GetCredProps(bool* aCredProps) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
*aCredProps = mCredProps;
|
*aCredProps = mCredProps;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
|
WebAuthnRegisterArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
*aHmacCreateSecret = mHmacCreateSecret;
|
*aHmacCreateSecret = mHmacCreateSecret;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetMinPinLength(bool* aMinPinLength) {
|
WebAuthnRegisterArgs::GetMinPinLength(bool* aMinPinLength) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
*aMinPinLength = mMinPinLength;
|
*aMinPinLength = mMinPinLength;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetResidentKey(nsAString& aResidentKey) {
|
WebAuthnRegisterArgs::GetResidentKey(nsAString& aResidentKey) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aResidentKey = mInfo.AuthenticatorSelection().residentKey();
|
aResidentKey = mInfo.AuthenticatorSelection().residentKey();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetUserVerification(nsAString& aUserVerificationRequirement) {
|
WebAuthnRegisterArgs::GetUserVerification(
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
nsAString& aUserVerificationRequirement) {
|
||||||
aUserVerificationRequirement =
|
aUserVerificationRequirement =
|
||||||
mInfo.AuthenticatorSelection().userVerificationRequirement();
|
mInfo.AuthenticatorSelection().userVerificationRequirement();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetAuthenticatorAttachment(
|
WebAuthnRegisterArgs::GetAuthenticatorAttachment(
|
||||||
nsAString& aAuthenticatorAttachment) {
|
nsAString& aAuthenticatorAttachment) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
if (mInfo.AuthenticatorSelection().authenticatorAttachment().isNothing()) {
|
if (mInfo.AuthenticatorSelection().authenticatorAttachment().isNothing()) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
@ -143,40 +125,34 @@ CtapRegisterArgs::GetAuthenticatorAttachment(
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetTimeoutMS(uint32_t* aTimeoutMS) {
|
WebAuthnRegisterArgs::GetTimeoutMS(uint32_t* aTimeoutMS) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
*aTimeoutMS = mInfo.TimeoutMS();
|
*aTimeoutMS = mInfo.TimeoutMS();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapRegisterArgs::GetAttestationConveyancePreference(
|
WebAuthnRegisterArgs::GetAttestationConveyancePreference(
|
||||||
nsAString& aAttestationConveyancePreference) {
|
nsAString& aAttestationConveyancePreference) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aAttestationConveyancePreference = mInfo.attestationConveyancePreference();
|
aAttestationConveyancePreference = mInfo.attestationConveyancePreference();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CtapSignArgs, nsICtapSignArgs)
|
NS_IMPL_ISUPPORTS(WebAuthnSignArgs, nsIWebAuthnSignArgs)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetOrigin(nsAString& aOrigin) {
|
WebAuthnSignArgs::GetOrigin(nsAString& aOrigin) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aOrigin = mInfo.Origin();
|
aOrigin = mInfo.Origin();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetRpId(nsAString& aRpId) {
|
WebAuthnSignArgs::GetRpId(nsAString& aRpId) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aRpId = mInfo.RpId();
|
aRpId = mInfo.RpId();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
WebAuthnSignArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
|
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
@ -186,8 +162,7 @@ CtapSignArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetAllowList(nsTArray<nsTArray<uint8_t> >& aAllowList) {
|
WebAuthnSignArgs::GetAllowList(nsTArray<nsTArray<uint8_t> >& aAllowList) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aAllowList.Clear();
|
aAllowList.Clear();
|
||||||
for (const WebAuthnScopedCredential& cred : mInfo.AllowList()) {
|
for (const WebAuthnScopedCredential& cred : mInfo.AllowList()) {
|
||||||
aAllowList.AppendElement(cred.id().Clone());
|
aAllowList.AppendElement(cred.id().Clone());
|
||||||
|
|
@ -196,9 +171,7 @@ CtapSignArgs::GetAllowList(nsTArray<nsTArray<uint8_t> >& aAllowList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
|
WebAuthnSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
||||||
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionHmacSecret) {
|
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionHmacSecret) {
|
||||||
*aHmacCreateSecret =
|
*aHmacCreateSecret =
|
||||||
|
|
@ -211,9 +184,7 @@ CtapSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetAppId(nsAString& aAppId) {
|
WebAuthnSignArgs::GetAppId(nsAString& aAppId) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
|
|
||||||
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
||||||
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
|
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
|
||||||
aAppId = ext.get_WebAuthnExtensionAppId().appIdentifier();
|
aAppId = ext.get_WebAuthnExtensionAppId().appIdentifier();
|
||||||
|
|
@ -225,15 +196,13 @@ CtapSignArgs::GetAppId(nsAString& aAppId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetUserVerification(nsAString& aUserVerificationRequirement) {
|
WebAuthnSignArgs::GetUserVerification(nsAString& aUserVerificationRequirement) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
aUserVerificationRequirement = mInfo.userVerificationRequirement();
|
aUserVerificationRequirement = mInfo.userVerificationRequirement();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CtapSignArgs::GetTimeoutMS(uint32_t* aTimeoutMS) {
|
WebAuthnSignArgs::GetTimeoutMS(uint32_t* aTimeoutMS) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
*aTimeoutMS = mInfo.TimeoutMS();
|
*aTimeoutMS = mInfo.TimeoutMS();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef CtapArgs_h
|
#ifndef mozilla_dom_WebAuthnArgs_H_
|
||||||
#define CtapArgs_h
|
#define mozilla_dom_WebAuthnArgs_H_
|
||||||
|
|
||||||
#include "mozilla/dom/WebAuthnTransactionChild.h"
|
#include "mozilla/dom/WebAuthnTransactionChild.h"
|
||||||
#include "mozilla/ipc/BackgroundParent.h"
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
|
|
@ -13,24 +13,16 @@
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
// These classes provide an FFI between C++ and Rust for the getters of IPC
|
class WebAuthnRegisterArgs final : public nsIWebAuthnRegisterArgs {
|
||||||
// objects (WebAuthnMakeCredentialInfo and WebAuthnGetAssertionInfo). They hold
|
|
||||||
// non-owning references to IPC objects, and must only be used within the
|
|
||||||
// lifetime of the IPC transaction that created them. There are runtime
|
|
||||||
// assertions to ensure that these types are created and used on the IPC
|
|
||||||
// background thread, but that alone does not guarantee safety.
|
|
||||||
|
|
||||||
class CtapRegisterArgs final : public nsICtapRegisterArgs {
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
NS_DECL_NSICTAPREGISTERARGS
|
NS_DECL_NSIWEBAUTHNREGISTERARGS
|
||||||
|
|
||||||
explicit CtapRegisterArgs(const WebAuthnMakeCredentialInfo& aInfo)
|
explicit WebAuthnRegisterArgs(const WebAuthnMakeCredentialInfo& aInfo)
|
||||||
: mInfo(aInfo),
|
: mInfo(aInfo),
|
||||||
mCredProps(false),
|
mCredProps(false),
|
||||||
mHmacCreateSecret(false),
|
mHmacCreateSecret(false),
|
||||||
mMinPinLength(false) {
|
mMinPinLength(false) {
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
|
||||||
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
|
||||||
switch (ext.type()) {
|
switch (ext.type()) {
|
||||||
case WebAuthnExtension::TWebAuthnExtensionCredProps:
|
case WebAuthnExtension::TWebAuthnExtensionCredProps:
|
||||||
|
|
@ -53,9 +45,9 @@ class CtapRegisterArgs final : public nsICtapRegisterArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~CtapRegisterArgs() = default;
|
~WebAuthnRegisterArgs() = default;
|
||||||
|
|
||||||
const WebAuthnMakeCredentialInfo& mInfo;
|
const WebAuthnMakeCredentialInfo mInfo;
|
||||||
|
|
||||||
// Flags to indicate whether an extension is being requested.
|
// Flags to indicate whether an extension is being requested.
|
||||||
bool mCredProps;
|
bool mCredProps;
|
||||||
|
|
@ -63,21 +55,20 @@ class CtapRegisterArgs final : public nsICtapRegisterArgs {
|
||||||
bool mMinPinLength;
|
bool mMinPinLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CtapSignArgs final : public nsICtapSignArgs {
|
class WebAuthnSignArgs final : public nsIWebAuthnSignArgs {
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
NS_DECL_NSICTAPSIGNARGS
|
NS_DECL_NSIWEBAUTHNSIGNARGS
|
||||||
|
|
||||||
explicit CtapSignArgs(const WebAuthnGetAssertionInfo& aInfo) : mInfo(aInfo) {
|
explicit WebAuthnSignArgs(const WebAuthnGetAssertionInfo& aInfo)
|
||||||
mozilla::ipc::AssertIsOnBackgroundThread();
|
: mInfo(aInfo) {}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~CtapSignArgs() = default;
|
~WebAuthnSignArgs() = default;
|
||||||
|
|
||||||
const WebAuthnGetAssertionInfo& mInfo;
|
const WebAuthnGetAssertionInfo mInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|
||||||
#endif // CtapArgs_h
|
#endif // mozilla_dom_WebAuthnArgs_H_
|
||||||
|
|
@ -15,14 +15,14 @@ WebAuthnRegisterPromiseHolder::Ensure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
WebAuthnRegisterPromiseHolder::Resolve(nsICtapRegisterResult* aResult) {
|
WebAuthnRegisterPromiseHolder::Resolve(nsIWebAuthnRegisterResult* aResult) {
|
||||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
|
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
|
||||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the promise on its owning thread if Disconnect() has not been
|
// Resolve the promise on its owning thread if Disconnect() has not been
|
||||||
// called.
|
// called.
|
||||||
RefPtr<nsICtapRegisterResult> result(aResult);
|
RefPtr<nsIWebAuthnRegisterResult> result(aResult);
|
||||||
mEventTarget->Dispatch(NS_NewRunnableFunction(
|
mEventTarget->Dispatch(NS_NewRunnableFunction(
|
||||||
"WebAuthnRegisterPromiseHolder::Resolve",
|
"WebAuthnRegisterPromiseHolder::Resolve",
|
||||||
[self = RefPtr{this}, result]() {
|
[self = RefPtr{this}, result]() {
|
||||||
|
|
@ -54,14 +54,14 @@ already_AddRefed<WebAuthnSignPromise> WebAuthnSignPromiseHolder::Ensure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
WebAuthnSignPromiseHolder::Resolve(nsICtapSignResult* aResult) {
|
WebAuthnSignPromiseHolder::Resolve(nsIWebAuthnSignResult* aResult) {
|
||||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
|
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
|
||||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the promise on its owning thread if Disconnect() has not been
|
// Resolve the promise on its owning thread if Disconnect() has not been
|
||||||
// called.
|
// called.
|
||||||
RefPtr<nsICtapSignResult> result(aResult);
|
RefPtr<nsIWebAuthnSignResult> result(aResult);
|
||||||
mEventTarget->Dispatch(NS_NewRunnableFunction(
|
mEventTarget->Dispatch(NS_NewRunnableFunction(
|
||||||
"WebAuthnSignPromiseHolder::Resolve", [self = RefPtr{this}, result]() {
|
"WebAuthnSignPromiseHolder::Resolve", [self = RefPtr{this}, result]() {
|
||||||
self->mSignPromise.ResolveIfExists(result, __func__);
|
self->mSignPromise.ResolveIfExists(result, __func__);
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ namespace mozilla::dom {
|
||||||
* at least one of Resolve(), Reject(), or Disconnect().
|
* at least one of Resolve(), Reject(), or Disconnect().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef MozPromise<RefPtr<nsICtapRegisterResult>, nsresult, true>
|
using WebAuthnRegisterPromise =
|
||||||
WebAuthnRegisterPromise;
|
MozPromise<RefPtr<nsIWebAuthnRegisterResult>, nsresult, true>;
|
||||||
|
|
||||||
typedef MozPromise<RefPtr<nsICtapSignResult>, nsresult, true>
|
using WebAuthnSignPromise =
|
||||||
WebAuthnSignPromise;
|
MozPromise<RefPtr<nsIWebAuthnSignResult>, nsresult, true>;
|
||||||
|
|
||||||
class WebAuthnRegisterPromiseHolder final : public nsIWebAuthnRegisterPromise {
|
class WebAuthnRegisterPromiseHolder final : public nsIWebAuthnRegisterPromise {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
111
dom/webauthn/WebAuthnResult.cpp
Normal file
111
dom/webauthn/WebAuthnResult.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "nsString.h"
|
||||||
|
#include "WebAuthnResult.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
namespace mozilla::jni {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
RefPtr<dom::WebAuthnRegisterResult> Java2Native(
|
||||||
|
mozilla::jni::Object::Param aData, JNIEnv* aEnv) {
|
||||||
|
MOZ_ASSERT(
|
||||||
|
aData.IsInstanceOf<java::WebAuthnTokenManager::MakeCredentialResponse>());
|
||||||
|
java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef response(aData);
|
||||||
|
RefPtr<dom::WebAuthnRegisterResult> result =
|
||||||
|
new dom::WebAuthnRegisterResult(response);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
RefPtr<dom::WebAuthnSignResult> Java2Native(mozilla::jni::Object::Param aData,
|
||||||
|
JNIEnv* aEnv) {
|
||||||
|
MOZ_ASSERT(
|
||||||
|
aData.IsInstanceOf<java::WebAuthnTokenManager::GetAssertionResponse>());
|
||||||
|
java::WebAuthnTokenManager::GetAssertionResponse::LocalRef response(aData);
|
||||||
|
RefPtr<dom::WebAuthnSignResult> result =
|
||||||
|
new dom::WebAuthnSignResult(response);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla::jni
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(WebAuthnRegisterResult, nsIWebAuthnRegisterResult)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnRegisterResult::GetAttestationObject(
|
||||||
|
nsTArray<uint8_t>& aAttestationObject) {
|
||||||
|
aAttestationObject.Assign(mAttestationObject);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnRegisterResult::GetCredentialId(nsTArray<uint8_t>& aCredentialId) {
|
||||||
|
aCredentialId.Assign(mCredentialId);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnRegisterResult::GetTransports(nsTArray<nsString>& aTransports) {
|
||||||
|
aTransports.Assign(mTransports);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnRegisterResult::GetCredPropsRk(bool* aCredPropsRk) {
|
||||||
|
if (mCredPropsRk.isSome()) {
|
||||||
|
*aCredPropsRk = mCredPropsRk.ref();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnRegisterResult::SetCredPropsRk(bool aCredPropsRk) {
|
||||||
|
mCredPropsRk = Some(aCredPropsRk);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(WebAuthnSignResult, nsIWebAuthnSignResult)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetAuthenticatorData(
|
||||||
|
nsTArray<uint8_t>& aAuthenticatorData) {
|
||||||
|
aAuthenticatorData.Assign(mAuthenticatorData);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetCredentialId(nsTArray<uint8_t>& aCredentialId) {
|
||||||
|
aCredentialId.Assign(mCredentialId);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetSignature(nsTArray<uint8_t>& aSignature) {
|
||||||
|
aSignature.Assign(mSignature);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetUserHandle(nsTArray<uint8_t>& aUserHandle) {
|
||||||
|
aUserHandle.Assign(mUserHandle);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetUserName(nsACString& aUserName) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnSignResult::GetUsedAppId(bool* aUsedAppId) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
||||||
120
dom/webauthn/WebAuthnResult.h
Normal file
120
dom/webauthn/WebAuthnResult.h
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_WebAuthnResult_h_
|
||||||
|
#define mozilla_dom_WebAuthnResult_h_
|
||||||
|
|
||||||
|
#include "nsIWebAuthnResult.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
# include "mozilla/java/WebAuthnTokenManagerNatives.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult {
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIWEBAUTHNREGISTERRESULT
|
||||||
|
|
||||||
|
WebAuthnRegisterResult(const nsTArray<uint8_t>& aAttestationObject,
|
||||||
|
const nsCString& aClientDataJSON,
|
||||||
|
const nsTArray<uint8_t>& aCredentialId,
|
||||||
|
const nsTArray<nsString>& aTransports)
|
||||||
|
: mClientDataJSON(aClientDataJSON), mCredPropsRk(Nothing()) {
|
||||||
|
mAttestationObject.AppendElements(aAttestationObject);
|
||||||
|
mCredentialId.AppendElements(aCredentialId);
|
||||||
|
mTransports.AppendElements(aTransports);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
explicit WebAuthnRegisterResult(
|
||||||
|
const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef&
|
||||||
|
aResponse) {
|
||||||
|
mAttestationObject.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->AttestationObject()->GetElements().Elements()),
|
||||||
|
aResponse->AttestationObject()->Length());
|
||||||
|
mClientDataJSON.Assign(
|
||||||
|
reinterpret_cast<const char*>(
|
||||||
|
aResponse->ClientDataJson()->GetElements().Elements()),
|
||||||
|
aResponse->ClientDataJson()->Length());
|
||||||
|
mCredentialId.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->KeyHandle()->GetElements().Elements()),
|
||||||
|
aResponse->KeyHandle()->Length());
|
||||||
|
auto transports = aResponse->Transports();
|
||||||
|
for (size_t i = 0; i < transports->Length(); i++) {
|
||||||
|
mTransports.AppendElement(
|
||||||
|
jni::String::LocalRef(transports->GetElement(i))->ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
~WebAuthnRegisterResult() = default;
|
||||||
|
|
||||||
|
nsTArray<uint8_t> mAttestationObject;
|
||||||
|
nsTArray<uint8_t> mCredentialId;
|
||||||
|
nsTArray<nsString> mTransports;
|
||||||
|
nsCString mClientDataJSON;
|
||||||
|
Maybe<bool> mCredPropsRk;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WebAuthnSignResult final : public nsIWebAuthnSignResult {
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIWEBAUTHNSIGNRESULT
|
||||||
|
|
||||||
|
WebAuthnSignResult(const nsTArray<uint8_t>& aAuthenticatorData,
|
||||||
|
const nsCString& aClientDataJSON,
|
||||||
|
const nsTArray<uint8_t>& aCredentialId,
|
||||||
|
const nsTArray<uint8_t>& aSignature,
|
||||||
|
const nsTArray<uint8_t>& aUserHandle)
|
||||||
|
: mClientDataJSON(aClientDataJSON) {
|
||||||
|
mAuthenticatorData.AppendElements(aAuthenticatorData);
|
||||||
|
mCredentialId.AppendElements(aCredentialId);
|
||||||
|
mSignature.AppendElements(aSignature);
|
||||||
|
mUserHandle.AppendElements(aUserHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
explicit WebAuthnSignResult(
|
||||||
|
const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef&
|
||||||
|
aResponse) {
|
||||||
|
mAuthenticatorData.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->AuthData()->GetElements().Elements()),
|
||||||
|
aResponse->AuthData()->Length());
|
||||||
|
mClientDataJSON.Assign(
|
||||||
|
reinterpret_cast<const char*>(
|
||||||
|
aResponse->ClientDataJson()->GetElements().Elements()),
|
||||||
|
aResponse->ClientDataJson()->Length());
|
||||||
|
mCredentialId.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->KeyHandle()->GetElements().Elements()),
|
||||||
|
aResponse->KeyHandle()->Length());
|
||||||
|
mSignature.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->Signature()->GetElements().Elements()),
|
||||||
|
aResponse->Signature()->Length());
|
||||||
|
mUserHandle.AppendElements(
|
||||||
|
reinterpret_cast<uint8_t*>(
|
||||||
|
aResponse->UserHandle()->GetElements().Elements()),
|
||||||
|
aResponse->UserHandle()->Length());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
~WebAuthnSignResult() = default;
|
||||||
|
|
||||||
|
nsTArray<uint8_t> mAuthenticatorData;
|
||||||
|
nsCString mClientDataJSON;
|
||||||
|
nsTArray<uint8_t> mCredentialId;
|
||||||
|
nsTArray<uint8_t> mSignature;
|
||||||
|
nsTArray<uint8_t> mUserHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
||||||
|
#endif // mozilla_dom_WebAuthnResult_h
|
||||||
163
dom/webauthn/WebAuthnService.cpp
Normal file
163
dom/webauthn/WebAuthnService.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "mozilla/StaticPrefs_security.h"
|
||||||
|
#include "WebAuthnService.h"
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
already_AddRefed<nsIWebAuthnService> NewWebAuthnService() {
|
||||||
|
nsCOMPtr<nsIWebAuthnService> webauthnService(new WebAuthnService());
|
||||||
|
return webauthnService.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(WebAuthnService, nsIWebAuthnService)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::MakeCredential(uint64_t aTransactionId,
|
||||||
|
uint64_t browsingContextId,
|
||||||
|
nsIWebAuthnRegisterArgs* aArgs,
|
||||||
|
nsIWebAuthnRegisterPromise* aPromise) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->MakeCredential(aTransactionId, browsingContextId,
|
||||||
|
aArgs, aPromise);
|
||||||
|
}
|
||||||
|
return mPlatformService->MakeCredential(aTransactionId, browsingContextId,
|
||||||
|
aArgs, aPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::GetAssertion(uint64_t aTransactionId,
|
||||||
|
uint64_t browsingContextId,
|
||||||
|
nsIWebAuthnSignArgs* aArgs,
|
||||||
|
nsIWebAuthnSignPromise* aPromise) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->GetAssertion(aTransactionId, browsingContextId, aArgs,
|
||||||
|
aPromise);
|
||||||
|
}
|
||||||
|
return mPlatformService->GetAssertion(aTransactionId, browsingContextId,
|
||||||
|
aArgs, aPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::Reset() {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->Reset();
|
||||||
|
}
|
||||||
|
return mPlatformService->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::Cancel(uint64_t aTransactionId) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->Cancel(aTransactionId);
|
||||||
|
}
|
||||||
|
return mPlatformService->Cancel(aTransactionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::PinCallback(uint64_t aTransactionId, const nsACString& aPin) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->PinCallback(aTransactionId, aPin);
|
||||||
|
}
|
||||||
|
return mPlatformService->PinCallback(aTransactionId, aPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::ResumeMakeCredential(uint64_t aTransactionId,
|
||||||
|
bool aForceNoneAttestation) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->ResumeMakeCredential(aTransactionId,
|
||||||
|
aForceNoneAttestation);
|
||||||
|
}
|
||||||
|
return mPlatformService->ResumeMakeCredential(aTransactionId,
|
||||||
|
aForceNoneAttestation);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::SelectionCallback(uint64_t aTransactionId, uint64_t aIndex) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->SelectionCallback(aTransactionId, aIndex);
|
||||||
|
}
|
||||||
|
return mPlatformService->SelectionCallback(aTransactionId, aIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::AddVirtualAuthenticator(
|
||||||
|
const nsACString& protocol, const nsACString& transport,
|
||||||
|
bool hasResidentKey, bool hasUserVerification, bool isUserConsenting,
|
||||||
|
bool isUserVerified, uint64_t* retval) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->AddVirtualAuthenticator(
|
||||||
|
protocol, transport, hasResidentKey, hasUserVerification,
|
||||||
|
isUserConsenting, isUserVerified, retval);
|
||||||
|
}
|
||||||
|
return mPlatformService->AddVirtualAuthenticator(
|
||||||
|
protocol, transport, hasResidentKey, hasUserVerification,
|
||||||
|
isUserConsenting, isUserVerified, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->RemoveVirtualAuthenticator(authenticatorId);
|
||||||
|
}
|
||||||
|
return mPlatformService->RemoveVirtualAuthenticator(authenticatorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::AddCredential(uint64_t authenticatorId,
|
||||||
|
const nsACString& credentialId,
|
||||||
|
bool isResidentCredential,
|
||||||
|
const nsACString& rpId,
|
||||||
|
const nsACString& privateKey,
|
||||||
|
const nsACString& userHandle,
|
||||||
|
uint32_t signCount) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->AddCredential(authenticatorId, credentialId,
|
||||||
|
isResidentCredential, rpId, privateKey,
|
||||||
|
userHandle, signCount);
|
||||||
|
}
|
||||||
|
return mPlatformService->AddCredential(authenticatorId, credentialId,
|
||||||
|
isResidentCredential, rpId, privateKey,
|
||||||
|
userHandle, signCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::GetCredentials(
|
||||||
|
uint64_t authenticatorId,
|
||||||
|
nsTArray<RefPtr<nsICredentialParameters>>& retval) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->GetCredentials(authenticatorId, retval);
|
||||||
|
}
|
||||||
|
return mPlatformService->GetCredentials(authenticatorId, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::RemoveCredential(uint64_t authenticatorId,
|
||||||
|
const nsACString& credentialId) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->RemoveCredential(authenticatorId, credentialId);
|
||||||
|
}
|
||||||
|
return mPlatformService->RemoveCredential(authenticatorId, credentialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->RemoveAllCredentials(authenticatorId);
|
||||||
|
}
|
||||||
|
return mPlatformService->RemoveAllCredentials(authenticatorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
WebAuthnService::SetUserVerified(uint64_t authenticatorId,
|
||||||
|
bool isUserVerified) {
|
||||||
|
if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) {
|
||||||
|
return mTestService->SetUserVerified(authenticatorId, isUserVerified);
|
||||||
|
}
|
||||||
|
return mPlatformService->SetUserVerified(authenticatorId, isUserVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
||||||
42
dom/webauthn/WebAuthnService.h
Normal file
42
dom/webauthn/WebAuthnService.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_WebAuthnService_h_
|
||||||
|
#define mozilla_dom_WebAuthnService_h_
|
||||||
|
|
||||||
|
#include "nsIWebAuthnService.h"
|
||||||
|
#include "AuthrsBridge_ffi.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
# include "AndroidWebAuthnService.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
already_AddRefed<nsIWebAuthnService> NewWebAuthnService();
|
||||||
|
|
||||||
|
class WebAuthnService final : public nsIWebAuthnService {
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIWEBAUTHNSERVICE
|
||||||
|
|
||||||
|
WebAuthnService() {
|
||||||
|
Unused << authrs_service_constructor(getter_AddRefs(mTestService));
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
mPlatformService = new AndroidWebAuthnService();
|
||||||
|
#else
|
||||||
|
mPlatformService = mTestService;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~WebAuthnService() = default;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIWebAuthnService> mPlatformService;
|
||||||
|
nsCOMPtr<nsIWebAuthnService> mTestService;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::dom
|
||||||
|
|
||||||
|
#endif // mozilla_dom_WebAuthnService_h_
|
||||||
|
|
@ -9,13 +9,9 @@
|
||||||
#include "mozilla/ipc/BackgroundParent.h"
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
#include "mozilla/StaticPrefs_security.h"
|
#include "mozilla/StaticPrefs_security.h"
|
||||||
|
|
||||||
#include "CtapArgs.h"
|
|
||||||
#include "nsIWebAuthnService.h"
|
#include "nsIWebAuthnService.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
#include "WebAuthnArgs.h"
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
# include "mozilla/dom/U2FTokenManager.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
# include "WinWebAuthnManager.h"
|
# include "WinWebAuthnManager.h"
|
||||||
|
|
@ -40,23 +36,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bug 1819414 will reroute requests on Android through WebAuthnController and
|
|
||||||
// allow us to remove this.
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
bool usingTestToken =
|
|
||||||
StaticPrefs::security_webauth_webauthn_enable_softtoken();
|
|
||||||
bool androidFido2 =
|
|
||||||
StaticPrefs::security_webauth_webauthn_enable_android_fido2();
|
|
||||||
|
|
||||||
if (!usingTestToken && androidFido2) {
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
if (mgr) {
|
|
||||||
mgr->Register(this, aTransactionId, aTransactionInfo);
|
|
||||||
}
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If there's an ongoing transaction, abort it.
|
// If there's an ongoing transaction, abort it.
|
||||||
if (mTransactionId.isSome()) {
|
if (mTransactionId.isSome()) {
|
||||||
mRegisterPromiseRequest.DisconnectIfExists();
|
mRegisterPromiseRequest.DisconnectIfExists();
|
||||||
|
|
@ -142,11 +121,11 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
|
||||||
nsCOMPtr<nsIWebAuthnService> webauthnService(
|
nsCOMPtr<nsIWebAuthnService> webauthnService(
|
||||||
do_GetService("@mozilla.org/webauthn/service;1"));
|
do_GetService("@mozilla.org/webauthn/service;1"));
|
||||||
|
|
||||||
RefPtr<CtapRegisterArgs> args(new CtapRegisterArgs(aTransactionInfo));
|
uint64_t browsingContextId = aTransactionInfo.BrowsingContextId();
|
||||||
|
RefPtr<WebAuthnRegisterArgs> args(new WebAuthnRegisterArgs(aTransactionInfo));
|
||||||
|
|
||||||
nsresult rv = webauthnService->MakeCredential(
|
nsresult rv = webauthnService->MakeCredential(
|
||||||
aTransactionId, aTransactionInfo.BrowsingContextId(), args,
|
aTransactionId, browsingContextId, args, promiseHolder);
|
||||||
promiseHolder);
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||||
}
|
}
|
||||||
|
|
@ -171,23 +150,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bug 1819414 will reroute requests on Android through WebAuthnController and
|
|
||||||
// allow us to remove this.
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
bool usingTestToken =
|
|
||||||
StaticPrefs::security_webauth_webauthn_enable_softtoken();
|
|
||||||
bool androidFido2 =
|
|
||||||
StaticPrefs::security_webauth_webauthn_enable_android_fido2();
|
|
||||||
|
|
||||||
if (!usingTestToken && androidFido2) {
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
if (mgr) {
|
|
||||||
mgr->Sign(this, aTransactionId, aTransactionInfo);
|
|
||||||
}
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mTransactionId.isSome()) {
|
if (mTransactionId.isSome()) {
|
||||||
mRegisterPromiseRequest.DisconnectIfExists();
|
mRegisterPromiseRequest.DisconnectIfExists();
|
||||||
mSignPromiseRequest.DisconnectIfExists();
|
mSignPromiseRequest.DisconnectIfExists();
|
||||||
|
|
@ -272,7 +234,7 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign(
|
||||||
})
|
})
|
||||||
->Track(mSignPromiseRequest);
|
->Track(mSignPromiseRequest);
|
||||||
|
|
||||||
RefPtr<CtapSignArgs> args(new CtapSignArgs(aTransactionInfo));
|
RefPtr<WebAuthnSignArgs> args(new WebAuthnSignArgs(aTransactionInfo));
|
||||||
|
|
||||||
nsCOMPtr<nsIWebAuthnService> webauthnService(
|
nsCOMPtr<nsIWebAuthnService> webauthnService(
|
||||||
do_GetService("@mozilla.org/webauthn/service;1"));
|
do_GetService("@mozilla.org/webauthn/service;1"));
|
||||||
|
|
@ -300,16 +262,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestCancel(
|
||||||
// fall through in case the virtual token was used.
|
// fall through in case the virtual token was used.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bug 1819414 will reroute requests on Android through WebAuthnController and
|
|
||||||
// allow us to remove this.
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
if (mgr) {
|
|
||||||
mgr->Cancel(this, aTransactionId);
|
|
||||||
}
|
|
||||||
// fall through in case the virtual token was used.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mTransactionId.isNothing() ||
|
if (mTransactionId.isNothing() ||
|
||||||
!MOZ_IS_VALID(aTransactionId, mTransactionId.ref() == aTransactionId)) {
|
!MOZ_IS_VALID(aTransactionId, mTransactionId.ref() == aTransactionId)) {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
|
|
@ -362,16 +314,6 @@ void WebAuthnTransactionParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||||
// fall through in case the virtual token was used.
|
// fall through in case the virtual token was used.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bug 1819414 will reroute requests on Android through WebAuthnController and
|
|
||||||
// allow us to remove this.
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
|
||||||
if (mgr) {
|
|
||||||
mgr->MaybeClearTransaction(this);
|
|
||||||
}
|
|
||||||
// fall through in case the virtual token was used.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mRegisterPromiseRequest.DisconnectIfExists();
|
mRegisterPromiseRequest.DisconnectIfExists();
|
||||||
mSignPromiseRequest.DisconnectIfExists();
|
mSignPromiseRequest.DisconnectIfExists();
|
||||||
mTransactionId.reset();
|
mTransactionId.reset();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#ifndef mozilla_dom_WinWebAuthnManager_h
|
#ifndef mozilla_dom_WinWebAuthnManager_h
|
||||||
#define mozilla_dom_WinWebAuthnManager_h
|
#define mozilla_dom_WinWebAuthnManager_h
|
||||||
|
|
||||||
#include "mozilla/dom/U2FTokenTransport.h"
|
|
||||||
#include "mozilla/dom/PWebAuthnTransaction.h"
|
#include "mozilla/dom/PWebAuthnTransaction.h"
|
||||||
#include "mozilla/Tainting.h"
|
#include "mozilla/Tainting.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ use cstr::cstr;
|
||||||
use moz_task::{get_main_thread, RunnableBuilder};
|
use moz_task::{get_main_thread, RunnableBuilder};
|
||||||
use nserror::{
|
use nserror::{
|
||||||
nsresult, NS_ERROR_DOM_ABORT_ERR, NS_ERROR_DOM_INVALID_STATE_ERR, NS_ERROR_DOM_NOT_ALLOWED_ERR,
|
nsresult, NS_ERROR_DOM_ABORT_ERR, NS_ERROR_DOM_INVALID_STATE_ERR, NS_ERROR_DOM_NOT_ALLOWED_ERR,
|
||||||
NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NULL_POINTER, NS_OK,
|
NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NOT_IMPLEMENTED,
|
||||||
|
NS_ERROR_NULL_POINTER, NS_OK,
|
||||||
};
|
};
|
||||||
use nsstring::{nsACString, nsCString, nsString};
|
use nsstring::{nsACString, nsCString, nsString};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
@ -38,9 +39,9 @@ use std::sync::mpsc::{channel, Receiver, RecvError, Sender};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
use xpcom::interfaces::{
|
use xpcom::interfaces::{
|
||||||
nsICredentialParameters, nsICtapRegisterArgs, nsICtapRegisterResult, nsICtapSignArgs,
|
nsICredentialParameters, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnRegisterArgs,
|
||||||
nsICtapSignResult, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnRegisterPromise,
|
nsIWebAuthnRegisterPromise, nsIWebAuthnRegisterResult, nsIWebAuthnService, nsIWebAuthnSignArgs,
|
||||||
nsIWebAuthnService, nsIWebAuthnSignPromise,
|
nsIWebAuthnSignPromise, nsIWebAuthnSignResult,
|
||||||
};
|
};
|
||||||
use xpcom::{xpcom_method, RefPtr};
|
use xpcom::{xpcom_method, RefPtr};
|
||||||
|
|
||||||
|
|
@ -135,12 +136,12 @@ fn cancel_prompts(tid: u64) -> Result<(), nsresult> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[xpcom(implement(nsICtapRegisterResult), atomic)]
|
#[xpcom(implement(nsIWebAuthnRegisterResult), atomic)]
|
||||||
pub struct CtapRegisterResult {
|
pub struct WebAuthnRegisterResult {
|
||||||
result: RegisterResult,
|
result: RegisterResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtapRegisterResult {
|
impl WebAuthnRegisterResult {
|
||||||
xpcom_method!(get_attestation_object => GetAttestationObject() -> ThinVec<u8>);
|
xpcom_method!(get_attestation_object => GetAttestationObject() -> ThinVec<u8>);
|
||||||
fn get_attestation_object(&self) -> Result<ThinVec<u8>, nsresult> {
|
fn get_attestation_object(&self) -> Result<ThinVec<u8>, nsresult> {
|
||||||
let mut out = ThinVec::new();
|
let mut out = ThinVec::new();
|
||||||
|
|
@ -172,6 +173,11 @@ impl CtapRegisterResult {
|
||||||
};
|
};
|
||||||
Ok(cred_props.rk)
|
Ok(cred_props.rk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xpcom_method!(set_cred_props_rk => SetCredPropsRk(aCredPropsRk: bool));
|
||||||
|
fn set_cred_props_rk(&self, _cred_props_rk: bool) -> Result<(), nsresult> {
|
||||||
|
Err(NS_ERROR_NOT_IMPLEMENTED)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[xpcom(implement(nsIWebAuthnAttObj), atomic)]
|
#[xpcom(implement(nsIWebAuthnAttObj), atomic)]
|
||||||
|
|
@ -215,12 +221,12 @@ impl WebAuthnAttObj {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[xpcom(implement(nsICtapSignResult), atomic)]
|
#[xpcom(implement(nsIWebAuthnSignResult), atomic)]
|
||||||
pub struct CtapSignResult {
|
pub struct WebAuthnSignResult {
|
||||||
result: SignResult,
|
result: SignResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtapSignResult {
|
impl WebAuthnSignResult {
|
||||||
xpcom_method!(get_credential_id => GetCredentialId() -> ThinVec<u8>);
|
xpcom_method!(get_credential_id => GetCredentialId() -> ThinVec<u8>);
|
||||||
fn get_credential_id(&self) -> Result<ThinVec<u8>, nsresult> {
|
fn get_credential_id(&self) -> Result<ThinVec<u8>, nsresult> {
|
||||||
let Some(cred) = &self.result.assertion.credentials else {
|
let Some(cred) = &self.result.assertion.credentials else {
|
||||||
|
|
@ -396,8 +402,8 @@ impl RegisterPromise {
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let wrapped_result =
|
let wrapped_result =
|
||||||
CtapRegisterResult::allocate(InitCtapRegisterResult { result })
|
WebAuthnRegisterResult::allocate(InitWebAuthnRegisterResult { result })
|
||||||
.query_interface::<nsICtapRegisterResult>()
|
.query_interface::<nsIWebAuthnRegisterResult>()
|
||||||
.ok_or(NS_ERROR_FAILURE)?;
|
.ok_or(NS_ERROR_FAILURE)?;
|
||||||
unsafe { self.0.Resolve(wrapped_result.coerce()) };
|
unsafe { self.0.Resolve(wrapped_result.coerce()) };
|
||||||
}
|
}
|
||||||
|
|
@ -416,9 +422,10 @@ impl SignPromise {
|
||||||
fn resolve_or_reject(&self, result: Result<SignResult, nsresult>) -> Result<(), nsresult> {
|
fn resolve_or_reject(&self, result: Result<SignResult, nsresult>) -> Result<(), nsresult> {
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let wrapped_result = CtapSignResult::allocate(InitCtapSignResult { result })
|
let wrapped_result =
|
||||||
.query_interface::<nsICtapSignResult>()
|
WebAuthnSignResult::allocate(InitWebAuthnSignResult { result })
|
||||||
.ok_or(NS_ERROR_FAILURE)?;
|
.query_interface::<nsIWebAuthnSignResult>()
|
||||||
|
.ok_or(NS_ERROR_FAILURE)?;
|
||||||
unsafe { self.0.Resolve(wrapped_result.coerce()) };
|
unsafe { self.0.Resolve(wrapped_result.coerce()) };
|
||||||
}
|
}
|
||||||
Err(result) => {
|
Err(result) => {
|
||||||
|
|
@ -504,12 +511,12 @@ impl AuthrsService {
|
||||||
//
|
//
|
||||||
// This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at
|
// This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at
|
||||||
// most one WebAuthn transaction is active at any given time.
|
// most one WebAuthn transaction is active at any given time.
|
||||||
xpcom_method!(make_credential => MakeCredential(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsICtapRegisterArgs, aPromise: *const nsIWebAuthnRegisterPromise));
|
xpcom_method!(make_credential => MakeCredential(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsIWebAuthnRegisterArgs, aPromise: *const nsIWebAuthnRegisterPromise));
|
||||||
fn make_credential(
|
fn make_credential(
|
||||||
&self,
|
&self,
|
||||||
tid: u64,
|
tid: u64,
|
||||||
browsing_context_id: u64,
|
browsing_context_id: u64,
|
||||||
args: &nsICtapRegisterArgs,
|
args: &nsIWebAuthnRegisterArgs,
|
||||||
promise: &nsIWebAuthnRegisterPromise,
|
promise: &nsIWebAuthnRegisterPromise,
|
||||||
) -> Result<(), nsresult> {
|
) -> Result<(), nsresult> {
|
||||||
self.reset()?;
|
self.reset()?;
|
||||||
|
|
@ -762,12 +769,12 @@ impl AuthrsService {
|
||||||
//
|
//
|
||||||
// This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at
|
// This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at
|
||||||
// most one WebAuthn transaction is active at any given time.
|
// most one WebAuthn transaction is active at any given time.
|
||||||
xpcom_method!(get_assertion => GetAssertion(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsICtapSignArgs, aPromise: *const nsIWebAuthnSignPromise));
|
xpcom_method!(get_assertion => GetAssertion(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsIWebAuthnSignArgs, aPromise: *const nsIWebAuthnSignPromise));
|
||||||
fn get_assertion(
|
fn get_assertion(
|
||||||
&self,
|
&self,
|
||||||
tid: u64,
|
tid: u64,
|
||||||
browsing_context_id: u64,
|
browsing_context_id: u64,
|
||||||
args: &nsICtapSignArgs,
|
args: &nsIWebAuthnSignArgs,
|
||||||
promise: &nsIWebAuthnSignPromise,
|
promise: &nsIWebAuthnSignPromise,
|
||||||
) -> Result<(), nsresult> {
|
) -> Result<(), nsresult> {
|
||||||
self.reset()?;
|
self.reset()?;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ Classes = [
|
||||||
{
|
{
|
||||||
'cid': '{ebe8a51d-bd54-4838-b031-cd2289990e14}',
|
'cid': '{ebe8a51d-bd54-4838-b031-cd2289990e14}',
|
||||||
'contract_ids': ['@mozilla.org/webauthn/service;1'],
|
'contract_ids': ['@mozilla.org/webauthn/service;1'],
|
||||||
'headers': ['/dom/webauthn/AuthrsService.h'],
|
'headers': ['/dom/webauthn/WebAuthnService.h'],
|
||||||
'constructor': 'mozilla::dom::NewAuthrsService',
|
'constructor': 'mozilla::dom::NewWebAuthnService',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ EXPORTS.mozilla.dom += [
|
||||||
"AuthenticatorAttestationResponse.h",
|
"AuthenticatorAttestationResponse.h",
|
||||||
"AuthenticatorResponse.h",
|
"AuthenticatorResponse.h",
|
||||||
"PublicKeyCredential.h",
|
"PublicKeyCredential.h",
|
||||||
"U2FTokenTransport.h",
|
|
||||||
"WebAuthnManager.h",
|
"WebAuthnManager.h",
|
||||||
"WebAuthnManagerBase.h",
|
"WebAuthnManagerBase.h",
|
||||||
"WebAuthnPromiseHolder.h",
|
"WebAuthnPromiseHolder.h",
|
||||||
|
|
@ -42,12 +41,13 @@ UNIFIED_SOURCES += [
|
||||||
"AuthenticatorAssertionResponse.cpp",
|
"AuthenticatorAssertionResponse.cpp",
|
||||||
"AuthenticatorAttestationResponse.cpp",
|
"AuthenticatorAttestationResponse.cpp",
|
||||||
"AuthenticatorResponse.cpp",
|
"AuthenticatorResponse.cpp",
|
||||||
"AuthrsService.cpp",
|
|
||||||
"CtapArgs.cpp",
|
|
||||||
"PublicKeyCredential.cpp",
|
"PublicKeyCredential.cpp",
|
||||||
|
"WebAuthnArgs.cpp",
|
||||||
"WebAuthnManager.cpp",
|
"WebAuthnManager.cpp",
|
||||||
"WebAuthnManagerBase.cpp",
|
"WebAuthnManagerBase.cpp",
|
||||||
"WebAuthnPromiseHolder.cpp",
|
"WebAuthnPromiseHolder.cpp",
|
||||||
|
"WebAuthnResult.cpp",
|
||||||
|
"WebAuthnService.cpp",
|
||||||
"WebAuthnTransactionChild.cpp",
|
"WebAuthnTransactionChild.cpp",
|
||||||
"WebAuthnTransactionParent.cpp",
|
"WebAuthnTransactionParent.cpp",
|
||||||
"WebAuthnUtil.cpp",
|
"WebAuthnUtil.cpp",
|
||||||
|
|
@ -62,21 +62,11 @@ LOCAL_INCLUDES += [
|
||||||
"/dom/crypto",
|
"/dom/crypto",
|
||||||
"/security/manager/ssl",
|
"/security/manager/ssl",
|
||||||
"/third_party/rust",
|
"/third_party/rust",
|
||||||
"/toolkit/components/jsoncpp/include",
|
|
||||||
]
|
|
||||||
|
|
||||||
USE_LIBS += [
|
|
||||||
"jsoncpp",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
||||||
EXPORTS.mozilla.dom += [
|
|
||||||
"AndroidWebAuthnTokenManager.h",
|
|
||||||
"U2FTokenManager.h",
|
|
||||||
]
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
"AndroidWebAuthnTokenManager.cpp",
|
"AndroidWebAuthnService.cpp",
|
||||||
"U2FTokenManager.cpp",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG["OS_ARCH"] == "WINNT":
|
if CONFIG["OS_ARCH"] == "WINNT":
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,8 @@
|
||||||
|
|
||||||
typedef long COSEAlgorithmIdentifier;
|
typedef long COSEAlgorithmIdentifier;
|
||||||
|
|
||||||
// The nsICtapRegisterArgs interface encapsulates the arguments to the CTAP
|
|
||||||
// authenticatorMakeCredential command as defined in
|
|
||||||
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorMakeCredential
|
|
||||||
// It is essentially a shim that allows data to be copied from an IPDL-defined
|
|
||||||
// WebAuthnMakeCredentialInfo C++ struct to an authenticator-rs defined
|
|
||||||
// RegisterArgsCtap2 Rust struct.
|
|
||||||
//
|
|
||||||
[uuid(2fc8febe-a277-11ed-bda2-8f6495a5e75c)]
|
[uuid(2fc8febe-a277-11ed-bda2-8f6495a5e75c)]
|
||||||
interface nsICtapRegisterArgs : nsISupports {
|
interface nsIWebAuthnRegisterArgs : nsISupports {
|
||||||
// TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove.
|
// TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove.
|
||||||
readonly attribute AString origin;
|
readonly attribute AString origin;
|
||||||
|
|
||||||
|
|
@ -48,8 +41,8 @@ interface nsICtapRegisterArgs : nsISupports {
|
||||||
[must_use] readonly attribute bool minPinLength;
|
[must_use] readonly attribute bool minPinLength;
|
||||||
|
|
||||||
// Options.
|
// Options.
|
||||||
[must_use] readonly attribute AString residentKey;
|
readonly attribute AString residentKey;
|
||||||
[must_use] readonly attribute AString userVerification;
|
readonly attribute AString userVerification;
|
||||||
[must_use] readonly attribute AString authenticatorAttachment;
|
[must_use] readonly attribute AString authenticatorAttachment;
|
||||||
|
|
||||||
// This is the WebAuthn PublicKeyCredentialCreationOptions timeout.
|
// This is the WebAuthn PublicKeyCredentialCreationOptions timeout.
|
||||||
|
|
@ -63,15 +56,8 @@ interface nsICtapRegisterArgs : nsISupports {
|
||||||
[must_use] readonly attribute AString attestationConveyancePreference;
|
[must_use] readonly attribute AString attestationConveyancePreference;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The nsICtapSignArgs interface encapsulates the arguments to the CTAP
|
|
||||||
// authenticatorGetAssertion command as defined in
|
|
||||||
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetAssertion
|
|
||||||
// It is essentially a shim that allows data to be copied from an IPDL-defined
|
|
||||||
// WebAuthnGetAssertionInfo C++ struct to an authenticator-rs defined
|
|
||||||
// SignArgsCtap2 Rust struct.
|
|
||||||
//
|
|
||||||
[uuid(2e621cf4-a277-11ed-ae00-bf41a54ef553)]
|
[uuid(2e621cf4-a277-11ed-ae00-bf41a54ef553)]
|
||||||
interface nsICtapSignArgs : nsISupports {
|
interface nsIWebAuthnSignArgs : nsISupports {
|
||||||
// TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove.
|
// TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove.
|
||||||
readonly attribute AString origin;
|
readonly attribute AString origin;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
[rust_sync, uuid(3c969aec-e0e0-4aa4-9422-394b321e6918)]
|
[rust_sync, uuid(3c969aec-e0e0-4aa4-9422-394b321e6918)]
|
||||||
interface nsIWebAuthnRegisterPromise : nsISupports
|
interface nsIWebAuthnRegisterPromise : nsISupports
|
||||||
{
|
{
|
||||||
[noscript] void resolve(in nsICtapRegisterResult aResult);
|
[noscript] void resolve(in nsIWebAuthnRegisterResult aResult);
|
||||||
[noscript] void reject(in nsresult error);
|
[noscript] void reject(in nsresult error);
|
||||||
};
|
};
|
||||||
|
|
||||||
[rust_sync, uuid(35e35bdc-5369-4bfe-8d5c-bdf7b782b735)]
|
[rust_sync, uuid(35e35bdc-5369-4bfe-8d5c-bdf7b782b735)]
|
||||||
interface nsIWebAuthnSignPromise : nsISupports
|
interface nsIWebAuthnSignPromise : nsISupports
|
||||||
{
|
{
|
||||||
[noscript] void resolve(in nsICtapSignResult aResult);
|
[noscript] void resolve(in nsIWebAuthnSignResult aResult);
|
||||||
[noscript] void reject(in nsresult error);
|
[noscript] void reject(in nsresult error);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
[uuid(0567c384-a728-11ed-85f7-030324a370f0)]
|
[uuid(0567c384-a728-11ed-85f7-030324a370f0)]
|
||||||
interface nsICtapRegisterResult : nsISupports {
|
interface nsIWebAuthnRegisterResult : nsISupports {
|
||||||
// The serialied attestation object as defined in
|
// The serialied attestation object as defined in
|
||||||
// https://www.w3.org/TR/webauthn-2/#sctn-attestation
|
// https://www.w3.org/TR/webauthn-2/#sctn-attestation
|
||||||
// Includes the format, the attestation statement, and
|
// Includes the format, the attestation statement, and
|
||||||
|
|
@ -24,14 +24,14 @@ interface nsICtapRegisterResult : nsISupports {
|
||||||
// bug 1593571
|
// bug 1593571
|
||||||
// readonly attribute bool hmacCreateSecret;
|
// readonly attribute bool hmacCreateSecret;
|
||||||
|
|
||||||
readonly attribute bool credPropsRk;
|
[must_use] attribute bool credPropsRk;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The nsICtapSignResult interface is used to construct IPDL-defined
|
// The nsIWebAuthnSignResult interface is used to construct IPDL-defined
|
||||||
// WebAuthnGetAssertionResult from either Rust or C++.
|
// WebAuthnGetAssertionResult from either Rust or C++.
|
||||||
//
|
//
|
||||||
[uuid(05fff816-a728-11ed-b9ac-ff38cc2c8c28)]
|
[uuid(05fff816-a728-11ed-b9ac-ff38cc2c8c28)]
|
||||||
interface nsICtapSignResult : nsISupports {
|
interface nsIWebAuthnSignResult : nsISupports {
|
||||||
// The ID field of the PublicKeyCredentialDescriptor returned
|
// The ID field of the PublicKeyCredentialDescriptor returned
|
||||||
// from authenticatorGetAssertion.
|
// from authenticatorGetAssertion.
|
||||||
readonly attribute Array<octet> credentialId;
|
readonly attribute Array<octet> credentialId;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ interface nsIWebAuthnService : nsISupports
|
||||||
void makeCredential(
|
void makeCredential(
|
||||||
in uint64_t aTransactionId,
|
in uint64_t aTransactionId,
|
||||||
in uint64_t browsingContextId,
|
in uint64_t browsingContextId,
|
||||||
in nsICtapRegisterArgs args,
|
in nsIWebAuthnRegisterArgs args,
|
||||||
in nsIWebAuthnRegisterPromise promise);
|
in nsIWebAuthnRegisterPromise promise);
|
||||||
|
|
||||||
void getAssertion(
|
void getAssertion(
|
||||||
in uint64_t aTransactionId,
|
in uint64_t aTransactionId,
|
||||||
in uint64_t browsingContextId,
|
in uint64_t browsingContextId,
|
||||||
in nsICtapSignArgs args,
|
in nsIWebAuthnSignArgs args,
|
||||||
in nsIWebAuthnSignPromise promise);
|
in nsIWebAuthnSignPromise promise);
|
||||||
|
|
||||||
// Cancel the ongoing transaction and any prompts that are shown, but do not reject
|
// Cancel the ongoing transaction and any prompts that are shown, but do not reject
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ support-files = [
|
||||||
prefs = [
|
prefs = [
|
||||||
"security.webauth.webauthn=true",
|
"security.webauth.webauthn=true",
|
||||||
"security.webauth.webauthn_enable_softtoken=true",
|
"security.webauth.webauthn_enable_softtoken=true",
|
||||||
"security.webauth.webauthn_enable_android_fido2=false",
|
|
||||||
"security.webauth.webauthn_enable_usbtoken=false",
|
"security.webauth.webauthn_enable_usbtoken=false",
|
||||||
"security.webauthn.ctap2=true",
|
"security.webauthn.ctap2=true",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ add_task(async function test_setup() {
|
||||||
["security.webauth.webauthn", true],
|
["security.webauth.webauthn", true],
|
||||||
["security.webauth.webauthn_enable_softtoken", true],
|
["security.webauth.webauthn_enable_softtoken", true],
|
||||||
["security.webauth.webauthn_enable_usbtoken", false],
|
["security.webauth.webauthn_enable_usbtoken", false],
|
||||||
["security.webauth.webauthn_enable_android_fido2", false],
|
|
||||||
["security.webauth.webauthn_testing_allow_direct_attestation", true],
|
["security.webauth.webauthn_testing_allow_direct_attestation", true],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ prefs =
|
||||||
dom.security.featurePolicy.webidl.enabled=true
|
dom.security.featurePolicy.webidl.enabled=true
|
||||||
security.webauth.webauthn=true
|
security.webauth.webauthn=true
|
||||||
security.webauth.webauthn_enable_softtoken=true
|
security.webauth.webauthn_enable_softtoken=true
|
||||||
security.webauth.webauthn_enable_android_fido2=false
|
|
||||||
security.webauth.webauthn_enable_usbtoken=false
|
security.webauth.webauthn_enable_usbtoken=false
|
||||||
security.webauthn.ctap2=true
|
security.webauthn.ctap2=true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,6 @@
|
||||||
#include "mozilla/dom/AbstractRange.h"
|
#include "mozilla/dom/AbstractRange.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
# include "mozilla/dom/U2FTokenManager.h"
|
|
||||||
#endif
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
# include "mozilla/dom/WinWebAuthnManager.h"
|
# include "mozilla/dom/WinWebAuthnManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -260,10 +257,6 @@ nsresult nsLayoutStatics::Initialize() {
|
||||||
// This must be initialized on the main-thread.
|
// This must be initialized on the main-thread.
|
||||||
mozilla::RemoteLazyInputStreamStorage::Initialize();
|
mozilla::RemoteLazyInputStreamStorage::Initialize();
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
mozilla::dom::U2FTokenManager::Initialize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
mozilla::dom::WinWebAuthnManager::Initialize();
|
mozilla::dom::WinWebAuthnManager::Initialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13709,20 +13709,14 @@
|
||||||
mirror: always
|
mirror: always
|
||||||
rust: true
|
rust: true
|
||||||
|
|
||||||
# Dispatch WebAuthn requests to virtual authenticators. (mutually exclusive
|
# Dispatch WebAuthn requests to virtual authenticators (mutually exclusive
|
||||||
# with webauthn_enable_android_fido2, and webauthn_enable_usbtoken)
|
# with and webauthn_enable_usbtoken)
|
||||||
- name: security.webauth.webauthn_enable_softtoken
|
- name: security.webauth.webauthn_enable_softtoken
|
||||||
type: RelaxedAtomicBool
|
type: RelaxedAtomicBool
|
||||||
value: false
|
value: false
|
||||||
mirror: always
|
mirror: always
|
||||||
rust: true
|
rust: true
|
||||||
|
|
||||||
# Dispatch WebAuthn requests to the Android platform API
|
|
||||||
- name: security.webauth.webauthn_enable_android_fido2
|
|
||||||
type: RelaxedAtomicBool
|
|
||||||
value: @IS_ANDROID@
|
|
||||||
mirror: always
|
|
||||||
|
|
||||||
# residentKey support when using Android platform API
|
# residentKey support when using Android platform API
|
||||||
- name: security.webauthn.webauthn_enable_android_fido2.residentkey
|
- name: security.webauthn.webauthn_enable_android_fido2.residentkey
|
||||||
type: RelaxedAtomicBool
|
type: RelaxedAtomicBool
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ user_pref("gecko.handlerService.defaultHandlersVersion", 100);
|
||||||
user_pref("security.webauth.webauthn_enable_softtoken", true);
|
user_pref("security.webauth.webauthn_enable_softtoken", true);
|
||||||
// Disable hardware WebAuthn authenticators.
|
// Disable hardware WebAuthn authenticators.
|
||||||
user_pref("security.webauth.webauthn_enable_usbtoken", false);
|
user_pref("security.webauth.webauthn_enable_usbtoken", false);
|
||||||
user_pref("security.webauth.webauthn_enable_android_fido2", false);
|
|
||||||
// Disable the WebAuthn direct attestation consent prompt.
|
// Disable the WebAuthn direct attestation consent prompt.
|
||||||
user_pref("security.webauth.webauthn_testing_allow_direct_attestation", true);
|
user_pref("security.webauth.webauthn_testing_allow_direct_attestation", true);
|
||||||
// Disable captive portal service
|
// Disable captive portal service
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue