Backed out changeset 58b6164020f0 (bug 1858799) for causing build bustage on dom/webauthn/winwebauthn/webauthn.h

This commit is contained in:
Sandor Molnar 2023-10-24 00:32:00 +03:00
Родитель 5bad8fb623
Коммит 10a73a45ac
17 изменённых файлов: 932 добавлений и 1076 удалений

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

@ -16,7 +16,7 @@
#include "nsCycleCollectionParticipant.h"
#ifdef XP_WIN
# include "WinWebAuthnService.h"
# include "WinWebAuthnManager.h"
#endif
#ifdef MOZ_WIDGET_ANDROID
@ -129,7 +129,7 @@ PublicKeyCredential::IsUserVerifyingPlatformAuthenticatorAvailable(
// have other UVPAAs available at this time.
#ifdef XP_WIN
if (WinWebAuthnService::IsUserVerifyingPlatformAuthenticatorAvailable()) {
if (WinWebAuthnManager::IsUserVerifyingPlatformAuthenticatorAvailable()) {
promise->MaybeResolve(true);
return promise.forget();
}
@ -183,7 +183,7 @@ PublicKeyCredential::IsExternalCTAP2SecurityKeySupported(GlobalObject& aGlobal,
}
#ifdef XP_WIN
if (WinWebAuthnService::AreWebAuthNApisAvailable()) {
if (WinWebAuthnManager::AreWebAuthNApisAvailable()) {
promise->MaybeResolve(true);
} else {
promise->MaybeResolve(StaticPrefs::security_webauthn_ctap2());

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

@ -25,12 +25,6 @@ WebAuthnRegisterArgs::GetChallenge(nsTArray<uint8_t>& aChallenge) {
return NS_OK;
}
NS_IMETHODIMP
WebAuthnRegisterArgs::GetClientDataJSON(nsACString& aClientDataJSON) {
aClientDataJSON = mInfo.ClientDataJSON();
return NS_OK;
}
NS_IMETHODIMP
WebAuthnRegisterArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
@ -179,12 +173,6 @@ WebAuthnSignArgs::GetChallenge(nsTArray<uint8_t>& aChallenge) {
return NS_OK;
}
NS_IMETHODIMP
WebAuthnSignArgs::GetClientDataJSON(nsACString& aClientDataJSON) {
aClientDataJSON = mInfo.ClientDataJSON();
return NS_OK;
}
NS_IMETHODIMP
WebAuthnSignArgs::GetClientDataHash(nsTArray<uint8_t>& aClientDataHash) {
nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash);
@ -229,11 +217,14 @@ WebAuthnSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) {
NS_IMETHODIMP
WebAuthnSignArgs::GetAppId(nsAString& aAppId) {
if (mAppId.isNothing()) {
return NS_ERROR_NOT_AVAILABLE;
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
aAppId = ext.get_WebAuthnExtensionAppId().appIdentifier();
return NS_OK;
}
}
aAppId = mAppId.ref();
return NS_OK;
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP

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

@ -61,29 +61,12 @@ class WebAuthnSignArgs final : public nsIWebAuthnSignArgs {
NS_DECL_NSIWEBAUTHNSIGNARGS
explicit WebAuthnSignArgs(const WebAuthnGetAssertionInfo& aInfo)
: mInfo(aInfo) {
for (const WebAuthnExtension& ext : mInfo.Extensions()) {
switch (ext.type()) {
case WebAuthnExtension::TWebAuthnExtensionAppId:
mAppId = Some(ext.get_WebAuthnExtensionAppId().appIdentifier());
break;
case WebAuthnExtension::TWebAuthnExtensionCredProps:
break;
case WebAuthnExtension::TWebAuthnExtensionHmacSecret:
break;
case WebAuthnExtension::TWebAuthnExtensionMinPinLength:
break;
case WebAuthnExtension::T__None:
break;
}
}
}
: mInfo(aInfo) {}
private:
~WebAuthnSignArgs() = default;
const WebAuthnGetAssertionInfo mInfo;
Maybe<nsString> mAppId;
};
} // namespace mozilla::dom

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

@ -25,7 +25,7 @@
#include "mozilla/ipc/PBackgroundChild.h"
#ifdef XP_WIN
# include "WinWebAuthnService.h"
# include "WinWebAuthnManager.h"
#endif
using namespace mozilla::ipc;
@ -461,7 +461,7 @@ already_AddRefed<Promise> WebAuthnManager::MakeCredential(
// initialized the only valid ways to end the transaction are
// CancelTransaction, RejectTransaction, and FinishMakeCredential.
#ifdef XP_WIN
if (!WinWebAuthnService::AreWebAuthNApisAvailable()) {
if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
ListenForVisibilityEvents();
}
#else
@ -678,7 +678,7 @@ already_AddRefed<Promise> WebAuthnManager::GetAssertion(
// initialized the only valid ways to end the transaction are
// CancelTransaction, RejectTransaction, and FinishGetAssertion.
#ifdef XP_WIN
if (!WinWebAuthnService::AreWebAuthNApisAvailable()) {
if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
ListenForVisibilityEvents();
}
#else

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

@ -2,11 +2,8 @@
* 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 "AuthrsBridge_ffi.h"
#include "WebAuthnResult.h"
#include "nsIWebAuthnAttObj.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "WebAuthnResult.h"
#ifdef MOZ_WIDGET_ANDROID
namespace mozilla::jni {
@ -65,15 +62,6 @@ WebAuthnRegisterResult::GetTransports(nsTArray<nsString>& aTransports) {
return NS_OK;
}
NS_IMETHODIMP
WebAuthnRegisterResult::GetHmacCreateSecret(bool* aHmacCreateSecret) {
if (mHmacCreateSecret.isSome()) {
*aHmacCreateSecret = mHmacCreateSecret.ref();
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
WebAuthnRegisterResult::GetCredPropsRk(bool* aCredPropsRk) {
if (mCredPropsRk.isSome()) {
@ -99,27 +87,6 @@ WebAuthnRegisterResult::GetAuthenticatorAttachment(
return NS_ERROR_NOT_AVAILABLE;
}
nsresult WebAuthnRegisterResult::Anonymize() {
// The anonymize flag in the nsIWebAuthnAttObj constructor causes the
// attestation statement to be removed during deserialization. It also
// causes the AAGUID to be zeroed out. If we can't deserialize the
// existing attestation, then we can't ensure that it is anonymized, so we
// act as though the user denied consent and we return NotAllowed.
nsCOMPtr<nsIWebAuthnAttObj> anonymizedAttObj;
nsresult rv = authrs_webauthn_att_obj_constructor(
mAttestationObject,
/* anonymize */ true, getter_AddRefs(anonymizedAttObj));
if (NS_FAILED(rv)) {
return rv;
}
mAttestationObject.Clear();
rv = anonymizedAttObj->GetAttestationObject(mAttestationObject);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(WebAuthnSignResult, nsIWebAuthnSignResult)
NS_IMETHODIMP
@ -160,17 +127,7 @@ WebAuthnSignResult::GetUserName(nsACString& aUserName) {
NS_IMETHODIMP
WebAuthnSignResult::GetUsedAppId(bool* aUsedAppId) {
if (mUsedAppId.isNothing()) {
return NS_ERROR_NOT_AVAILABLE;
}
*aUsedAppId = mUsedAppId.ref();
return NS_OK;
}
NS_IMETHODIMP
WebAuthnSignResult::SetUsedAppId(bool aUsedAppId) {
mUsedAppId = Some(aUsedAppId);
return NS_OK;
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP

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

@ -7,17 +7,10 @@
#include "nsIWebAuthnResult.h"
#include "mozilla/Maybe.h"
#include "nsString.h"
#ifdef MOZ_WIDGET_ANDROID
# include "mozilla/java/WebAuthnTokenManagerNatives.h"
#endif
#ifdef XP_WIN
# include "winwebauthn/webauthn.h"
#endif
namespace mozilla::dom {
class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult {
@ -64,74 +57,6 @@ class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult {
}
#endif
#ifdef XP_WIN
WebAuthnRegisterResult(nsACString& aClientDataJSON,
PCWEBAUTHN_CREDENTIAL_ATTESTATION aResponse)
: mClientDataJSON(aClientDataJSON) {
mCredentialId.AppendElements(aResponse->pbCredentialId,
aResponse->cbCredentialId);
mAttestationObject.AppendElements(aResponse->pbAttestationObject,
aResponse->cbAttestationObject);
nsTArray<WebAuthnExtensionResult> extensions;
if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2) {
PCWEBAUTHN_EXTENSIONS pExtensionList = &aResponse->Extensions;
if (pExtensionList->cExtensions != 0 &&
pExtensionList->pExtensions != NULL) {
for (DWORD dwIndex = 0; dwIndex < pExtensionList->cExtensions;
dwIndex++) {
PWEBAUTHN_EXTENSION pExtension =
&pExtensionList->pExtensions[dwIndex];
if (pExtension->pwszExtensionIdentifier &&
(0 == _wcsicmp(pExtension->pwszExtensionIdentifier,
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET)) &&
pExtension->cbExtension == sizeof(BOOL)) {
BOOL* pCredentialCreatedWithHmacSecret =
(BOOL*)pExtension->pvExtension;
if (*pCredentialCreatedWithHmacSecret) {
mHmacCreateSecret = Some(true);
}
}
}
}
}
if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) {
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_USB) {
mTransports.AppendElement(u"usb"_ns);
}
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_NFC) {
mTransports.AppendElement(u"nfc"_ns);
}
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_BLE) {
mTransports.AppendElement(u"ble"_ns);
}
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_INTERNAL) {
mTransports.AppendElement(u"internal"_ns);
}
}
// WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5 corresponds to
// WEBAUTHN_API_VERSION_6 which is where WEBAUTHN_CTAP_TRANSPORT_HYBRID was
// defined.
if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5) {
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_HYBRID) {
mTransports.AppendElement(u"hybrid"_ns);
}
}
if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) {
if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_INTERNAL) {
mAuthenticatorAttachment = Some(u"platform"_ns);
} else {
mAuthenticatorAttachment = Some(u"cross-platform"_ns);
}
}
}
#endif
nsresult Anonymize();
private:
~WebAuthnRegisterResult() = default;
@ -140,7 +65,6 @@ class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult {
nsTArray<nsString> mTransports;
nsCString mClientDataJSON;
Maybe<bool> mCredPropsRk;
Maybe<bool> mHmacCreateSecret;
Maybe<nsString> mAuthenticatorAttachment;
};
@ -192,24 +116,6 @@ class WebAuthnSignResult final : public nsIWebAuthnSignResult {
}
#endif
#ifdef XP_WIN
WebAuthnSignResult(nsACString& aClientDataJSON,
PCWEBAUTHN_ASSERTION aResponse)
: mClientDataJSON(aClientDataJSON) {
mSignature.AppendElements(aResponse->pbSignature, aResponse->cbSignature);
mCredentialId.AppendElements(aResponse->Credential.pbId,
aResponse->Credential.cbId);
mUserHandle.AppendElements(aResponse->pbUserId, aResponse->cbUserId);
mAuthenticatorData.AppendElements(aResponse->pbAuthenticatorData,
aResponse->cbAuthenticatorData);
mAuthenticatorAttachment = Nothing(); // not available
}
#endif
private:
~WebAuthnSignResult() = default;
@ -219,7 +125,6 @@ class WebAuthnSignResult final : public nsIWebAuthnSignResult {
nsTArray<uint8_t> mSignature;
nsTArray<uint8_t> mUserHandle;
Maybe<nsString> mAuthenticatorAttachment;
Maybe<bool> mUsedAppId;
};
} // namespace mozilla::dom

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

@ -12,10 +12,6 @@
# include "AndroidWebAuthnService.h"
#endif
#ifdef XP_WIN
# include "WinWebAuthnService.h"
#endif
namespace mozilla::dom {
already_AddRefed<nsIWebAuthnService> NewWebAuthnService();
@ -27,13 +23,7 @@ class WebAuthnService final : public nsIWebAuthnService {
WebAuthnService() {
Unused << authrs_service_constructor(getter_AddRefs(mTestService));
#if defined(XP_WIN)
if (WinWebAuthnService::AreWebAuthNApisAvailable()) {
mPlatformService = new WinWebAuthnService();
} else {
mPlatformService = mTestService;
}
#elif defined(MOZ_WIDGET_ANDROID)
#ifdef MOZ_WIDGET_ANDROID
mPlatformService = new AndroidWebAuthnService();
#else
mPlatformService = mTestService;

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

@ -13,6 +13,10 @@
#include "nsThreadUtils.h"
#include "WebAuthnArgs.h"
#ifdef XP_WIN
# include "WinWebAuthnManager.h"
#endif
namespace mozilla::dom {
mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
@ -20,6 +24,18 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
const WebAuthnMakeCredentialInfo& aTransactionInfo) {
::mozilla::ipc::AssertIsOnBackgroundThread();
#ifdef XP_WIN
bool usingTestToken =
StaticPrefs::security_webauth_webauthn_enable_softtoken();
if (!usingTestToken && WinWebAuthnManager::AreWebAuthNApisAvailable()) {
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
if (mgr) {
mgr->Register(this, aTransactionId, aTransactionInfo);
}
return IPC_OK();
}
#endif
// If there's an ongoing transaction, abort it.
if (mTransactionId.isSome()) {
mRegisterPromiseRequest.DisconnectIfExists();
@ -101,18 +117,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
WebAuthnExtensionResultCredProps(credPropsRk));
}
bool hmacCreateSecret;
rv = aValue->GetHmacCreateSecret(&hmacCreateSecret);
if (rv != NS_ERROR_NOT_AVAILABLE) {
if (NS_WARN_IF(NS_FAILED(rv))) {
Unused << parent->SendAbort(aTransactionId,
NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
extensions.AppendElement(
WebAuthnExtensionResultHmacSecret(hmacCreateSecret));
}
WebAuthnMakeCredentialResult result(
clientData, attObj, credentialId, transports, extensions,
authenticatorAttachment);
@ -147,6 +151,18 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign(
const WebAuthnGetAssertionInfo& aTransactionInfo) {
::mozilla::ipc::AssertIsOnBackgroundThread();
#ifdef XP_WIN
bool usingTestToken =
StaticPrefs::security_webauth_webauthn_enable_softtoken();
if (!usingTestToken && WinWebAuthnManager::AreWebAuthNApisAvailable()) {
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
if (mgr) {
mgr->Sign(this, aTransactionId, aTransactionInfo);
}
return IPC_OK();
}
#endif
if (mTransactionId.isSome()) {
mRegisterPromiseRequest.DisconnectIfExists();
mSignPromiseRequest.DisconnectIfExists();
@ -262,6 +278,16 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestCancel(
const Tainted<uint64_t>& aTransactionId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
#ifdef XP_WIN
if (WinWebAuthnManager::AreWebAuthNApisAvailable()) {
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
if (mgr) {
mgr->Cancel(this, aTransactionId);
}
}
// fall through in case the virtual token was used.
#endif
if (mTransactionId.isNothing() ||
!MOZ_IS_VALID(aTransactionId, mTransactionId.ref() == aTransactionId)) {
return IPC_OK();
@ -304,6 +330,16 @@ void WebAuthnTransactionParent::ActorDestroy(ActorDestroyReason aWhy) {
// Called either by Send__delete__() in RecvDestroyMe() above, or when
// the channel disconnects. Ensure the token manager forgets about us.
#ifdef XP_WIN
if (WinWebAuthnManager::AreWebAuthNApisAvailable()) {
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
if (mgr) {
mgr->MaybeClearTransaction(this);
}
}
// fall through in case the virtual token was used.
#endif
if (mTransactionId.isSome()) {
mRegisterPromiseRequest.DisconnectIfExists();
mSignPromiseRequest.DisconnectIfExists();

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

@ -0,0 +1,803 @@
/* -*- 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/Assertions.h"
#include "mozilla/dom/PWebAuthnTransactionParent.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Unused.h"
#include "nsIWebAuthnAttObj.h"
#include "nsTextFormatter.h"
#include "nsWindowsHelpers.h"
#include "AuthrsBridge_ffi.h"
#include "WebAuthnEnumStrings.h"
#include "WebAuthnTransportIdentifiers.h"
#include "winwebauthn/webauthn.h"
#include "WinWebAuthnManager.h"
namespace mozilla::dom {
namespace {
static mozilla::LazyLogModule gWinWebAuthnManagerLog("winwebauthnkeymanager");
StaticAutoPtr<WinWebAuthnManager> gWinWebAuthnManager;
static HMODULE gWinWebAuthnModule = 0;
static decltype(WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*
gWinWebauthnIsUVPAA = nullptr;
static decltype(WebAuthNAuthenticatorMakeCredential)*
gWinWebauthnMakeCredential = nullptr;
static decltype(WebAuthNFreeCredentialAttestation)*
gWinWebauthnFreeCredentialAttestation = nullptr;
static decltype(WebAuthNAuthenticatorGetAssertion)* gWinWebauthnGetAssertion =
nullptr;
static decltype(WebAuthNFreeAssertion)* gWinWebauthnFreeAssertion = nullptr;
static decltype(WebAuthNGetCancellationId)* gWinWebauthnGetCancellationId =
nullptr;
static decltype(WebAuthNCancelCurrentOperation)*
gWinWebauthnCancelCurrentOperation = nullptr;
static decltype(WebAuthNGetErrorName)* gWinWebauthnGetErrorName = nullptr;
static decltype(WebAuthNGetApiVersionNumber)* gWinWebauthnGetApiVersionNumber =
nullptr;
} // namespace
/***********************************************************************
* WinWebAuthnManager Implementation
**********************************************************************/
constexpr uint32_t kMinWinWebAuthNApiVersion = WEBAUTHN_API_VERSION_1;
WinWebAuthnManager::WinWebAuthnManager() {
// Create on the main thread to make sure ClearOnShutdown() works.
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!gWinWebAuthnModule);
gWinWebAuthnModule = LoadLibrarySystem32(L"webauthn.dll");
if (gWinWebAuthnModule) {
gWinWebauthnIsUVPAA = reinterpret_cast<
decltype(WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*>(
GetProcAddress(
gWinWebAuthnModule,
"WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable"));
gWinWebauthnMakeCredential =
reinterpret_cast<decltype(WebAuthNAuthenticatorMakeCredential)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNAuthenticatorMakeCredential"));
gWinWebauthnFreeCredentialAttestation =
reinterpret_cast<decltype(WebAuthNFreeCredentialAttestation)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNFreeCredentialAttestation"));
gWinWebauthnGetAssertion =
reinterpret_cast<decltype(WebAuthNAuthenticatorGetAssertion)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNAuthenticatorGetAssertion"));
gWinWebauthnFreeAssertion =
reinterpret_cast<decltype(WebAuthNFreeAssertion)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNFreeAssertion"));
gWinWebauthnGetCancellationId =
reinterpret_cast<decltype(WebAuthNGetCancellationId)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetCancellationId"));
gWinWebauthnCancelCurrentOperation =
reinterpret_cast<decltype(WebAuthNCancelCurrentOperation)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNCancelCurrentOperation"));
gWinWebauthnGetErrorName =
reinterpret_cast<decltype(WebAuthNGetErrorName)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetErrorName"));
gWinWebauthnGetApiVersionNumber =
reinterpret_cast<decltype(WebAuthNGetApiVersionNumber)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetApiVersionNumber"));
if (gWinWebauthnIsUVPAA && gWinWebauthnMakeCredential &&
gWinWebauthnFreeCredentialAttestation && gWinWebauthnGetAssertion &&
gWinWebauthnFreeAssertion && gWinWebauthnGetCancellationId &&
gWinWebauthnCancelCurrentOperation && gWinWebauthnGetErrorName &&
gWinWebauthnGetApiVersionNumber) {
mWinWebAuthNApiVersion = gWinWebauthnGetApiVersionNumber();
}
}
}
WinWebAuthnManager::~WinWebAuthnManager() {
if (gWinWebAuthnModule) {
FreeLibrary(gWinWebAuthnModule);
}
gWinWebAuthnModule = 0;
}
// static
void WinWebAuthnManager::Initialize() {
if (!gWinWebAuthnManager) {
gWinWebAuthnManager = new WinWebAuthnManager();
ClearOnShutdown(&gWinWebAuthnManager);
}
}
// static
WinWebAuthnManager* WinWebAuthnManager::Get() {
MOZ_ASSERT(gWinWebAuthnManager);
return gWinWebAuthnManager;
}
uint32_t WinWebAuthnManager::GetWebAuthNApiVersion() {
return mWinWebAuthNApiVersion;
}
// static
bool WinWebAuthnManager::AreWebAuthNApisAvailable() {
WinWebAuthnManager* mgr = WinWebAuthnManager::Get();
return mgr->GetWebAuthNApiVersion() >= kMinWinWebAuthNApiVersion;
}
bool WinWebAuthnManager::
IsUserVerifyingPlatformAuthenticatorAvailableInternal() {
BOOL isUVPAA = FALSE;
return (gWinWebauthnIsUVPAA(&isUVPAA) == S_OK && isUVPAA == TRUE);
}
// static
bool WinWebAuthnManager::IsUserVerifyingPlatformAuthenticatorAvailable() {
if (WinWebAuthnManager::AreWebAuthNApisAvailable()) {
return WinWebAuthnManager::Get()
->IsUserVerifyingPlatformAuthenticatorAvailableInternal();
}
return false;
}
void WinWebAuthnManager::AbortTransaction(const uint64_t& aTransactionId,
const nsresult& aError) {
Unused << mTransactionParent->SendAbort(aTransactionId, aError);
ClearTransaction();
}
void WinWebAuthnManager::MaybeClearTransaction(
PWebAuthnTransactionParent* aParent) {
// Only clear if we've been requested to do so by our current transaction
// parent.
if (mTransactionParent == aParent) {
ClearTransaction();
}
}
void WinWebAuthnManager::ClearTransaction() { mTransactionParent = nullptr; }
void WinWebAuthnManager::Register(
PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aInfo) {
MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNRegister"));
ClearTransaction();
mTransactionParent = aTransactionParent;
BOOL HmacCreateSecret = FALSE;
BOOL MinPinLength = FALSE;
// RP Information
WEBAUTHN_RP_ENTITY_INFORMATION rpInfo = {
WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION, aInfo.RpId().get(),
nullptr, nullptr};
// User Information
WEBAUTHN_USER_ENTITY_INFORMATION userInfo = {
WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION,
0,
nullptr,
nullptr,
nullptr,
nullptr};
// Client Data
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
(DWORD)aInfo.ClientDataJSON().Length(),
(BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};
// Algorithms
nsTArray<WEBAUTHN_COSE_CREDENTIAL_PARAMETER> coseParams;
// User Verification Requirement
DWORD winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
// Attachment
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
// Resident Key
BOOL winRequireResidentKey = FALSE;
BOOL winPreferResidentKey = FALSE;
// AttestationConveyance
DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
rpInfo.pwszName = aInfo.Rp().Name().get();
rpInfo.pwszIcon = nullptr;
userInfo.cbId = static_cast<DWORD>(aInfo.User().Id().Length());
userInfo.pbId = const_cast<unsigned char*>(aInfo.User().Id().Elements());
userInfo.pwszName = aInfo.User().Name().get();
userInfo.pwszIcon = nullptr;
userInfo.pwszDisplayName = aInfo.User().DisplayName().get();
for (const auto& coseAlg : aInfo.coseAlgs()) {
WEBAUTHN_COSE_CREDENTIAL_PARAMETER coseAlgorithm = {
WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, coseAlg.alg()};
coseParams.AppendElement(coseAlgorithm);
}
const auto& sel = aInfo.AuthenticatorSelection();
const nsString& userVerificationRequirement =
sel.userVerificationRequirement();
// This mapping needs to be reviewed if values are added to the
// UserVerificationRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (userVerificationRequirement.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
} else if (userVerificationRequirement.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
} else if (userVerificationRequirement.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
} else {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
}
if (sel.authenticatorAttachment().isSome()) {
const nsString& authenticatorAttachment =
sel.authenticatorAttachment().value();
// This mapping needs to be reviewed if values are added to the
// AuthenticatorAttachement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (authenticatorAttachment.EqualsLiteral(
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM;
} else if (authenticatorAttachment.EqualsLiteral(
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
} else {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
}
}
const nsString& residentKey = sel.residentKey();
// This mapping needs to be reviewed if values are added to the
// ResidentKeyRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED)) {
winRequireResidentKey = TRUE;
winPreferResidentKey = TRUE;
} else if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_PREFERRED)) {
winRequireResidentKey = FALSE;
winPreferResidentKey = TRUE;
} else if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winRequireResidentKey = FALSE;
winPreferResidentKey = FALSE;
} else {
// WebAuthnManager::MakeCredential is supposed to assign one of the above
// values, so this shouldn't happen.
MOZ_ASSERT_UNREACHABLE();
MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
// AttestationConveyance
const nsString& attestation = aInfo.attestationConveyancePreference();
// This mapping needs to be reviewed if values are added to the
// AttestationConveyancePreference enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE;
} else if (attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT;
} else if (attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
} else {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
}
bool requestedCredProps = FALSE;
// The number of entries in rgExtension should match the number of supported
// extensions.
// Supported extensions: credProps, hmac-secret, minPinLength.
WEBAUTHN_EXTENSION rgExtension[3] = {};
DWORD cExtensions = 0;
if (aInfo.Extensions().Length() >
(int)(sizeof(rgExtension) / sizeof(rgExtension[0]))) {
nsresult aError = NS_ERROR_DOM_INVALID_STATE_ERR;
MaybeAbortRegister(aTransactionId, aError);
return;
}
for (const WebAuthnExtension& ext : aInfo.Extensions()) {
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionCredProps) {
requestedCredProps = ext.get_WebAuthnExtensionCredProps().credProps();
}
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionHmacSecret) {
HmacCreateSecret =
ext.get_WebAuthnExtensionHmacSecret().hmacCreateSecret() == true;
if (HmacCreateSecret) {
rgExtension[cExtensions].pwszExtensionIdentifier =
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET;
rgExtension[cExtensions].cbExtension = sizeof(BOOL);
rgExtension[cExtensions].pvExtension = &HmacCreateSecret;
cExtensions++;
}
}
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionMinPinLength) {
MinPinLength =
ext.get_WebAuthnExtensionMinPinLength().minPinLength() == true;
if (MinPinLength) {
rgExtension[cExtensions].pwszExtensionIdentifier =
WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH;
rgExtension[cExtensions].cbExtension = sizeof(BOOL);
rgExtension[cExtensions].pvExtension = &MinPinLength;
cExtensions++;
}
}
}
WEBAUTHN_COSE_CREDENTIAL_PARAMETERS WebAuthNCredentialParameters = {
static_cast<DWORD>(coseParams.Length()), coseParams.Elements()};
// Exclude Credentials
nsTArray<WEBAUTHN_CREDENTIAL_EX> excludeCredentials;
WEBAUTHN_CREDENTIAL_EX* pExcludeCredentials = nullptr;
nsTArray<WEBAUTHN_CREDENTIAL_EX*> excludeCredentialsPtrs;
WEBAUTHN_CREDENTIAL_LIST excludeCredentialList = {0};
WEBAUTHN_CREDENTIAL_LIST* pExcludeCredentialList = nullptr;
for (auto& cred : aInfo.ExcludeList()) {
uint8_t transports = cred.transports();
DWORD winTransports = 0;
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
}
WEBAUTHN_CREDENTIAL_EX credential = {
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(cred.id().Length()), (PBYTE)(cred.id().Elements()),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
excludeCredentials.AppendElement(credential);
}
if (!excludeCredentials.IsEmpty()) {
pExcludeCredentials = excludeCredentials.Elements();
for (DWORD i = 0; i < excludeCredentials.Length(); i++) {
excludeCredentialsPtrs.AppendElement(&pExcludeCredentials[i]);
}
excludeCredentialList.cCredentials = excludeCredentials.Length();
excludeCredentialList.ppCredentials = excludeCredentialsPtrs.Elements();
pExcludeCredentialList = &excludeCredentialList;
}
// MakeCredentialOptions
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS WebAuthNCredentialOptions = {
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_7,
aInfo.TimeoutMS(),
{0, NULL},
{0, NULL},
winAttachment,
winRequireResidentKey,
winUserVerificationReq,
winAttestation,
0, // Flags
NULL, // CancellationId
pExcludeCredentialList,
WEBAUTHN_ENTERPRISE_ATTESTATION_NONE,
WEBAUTHN_LARGE_BLOB_SUPPORT_NONE,
winPreferResidentKey, // PreferResidentKey
FALSE, // BrowserInPrivateMode
FALSE, // EnablePrf
NULL, // LinkedDevice
0, // size of JsonExt
NULL, // JsonExt
};
GUID cancellationId = {0};
if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) {
WebAuthNCredentialOptions.pCancellationId = &cancellationId;
mCancellationIds.emplace(aTransactionId, &cancellationId);
}
if (cExtensions != 0) {
WebAuthNCredentialOptions.Extensions.cExtensions = cExtensions;
WebAuthNCredentialOptions.Extensions.pExtensions = rgExtension;
}
PWEBAUTHN_CREDENTIAL_ATTESTATION pWebAuthNCredentialAttestation = nullptr;
// Bug 1518876: Get Window Handle from Content process for Windows WebAuthN
// APIs
HWND hWnd = GetForegroundWindow();
HRESULT hr = gWinWebauthnMakeCredential(
hWnd, &rpInfo, &userInfo, &WebAuthNCredentialParameters,
&WebAuthNClientData, &WebAuthNCredentialOptions,
&pWebAuthNCredentialAttestation);
mCancellationIds.erase(aTransactionId);
if (hr == S_OK) {
nsTArray<uint8_t> credentialId;
credentialId.AppendElements(pWebAuthNCredentialAttestation->pbCredentialId,
pWebAuthNCredentialAttestation->cbCredentialId);
nsTArray<uint8_t> authenticatorData;
authenticatorData.AppendElements(
pWebAuthNCredentialAttestation->pbAuthenticatorData,
pWebAuthNCredentialAttestation->cbAuthenticatorData);
nsTArray<uint8_t> attObject;
attObject.AppendElements(
pWebAuthNCredentialAttestation->pbAttestationObject,
pWebAuthNCredentialAttestation->cbAttestationObject);
if (winAttestation == WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE) {
// The anonymize flag in the nsIWebAuthnAttObj constructor causes the
// attestation statement to be removed during deserialization. It also
// causes the AAGUID to be zeroed out. If we can't deserialize the
// existing attestation, then we can't ensure that it is anonymized, so we
// act as though the user denied consent and we return NotAllowed.
nsCOMPtr<nsIWebAuthnAttObj> anonymizedAttObj;
nsresult rv = authrs_webauthn_att_obj_constructor(
attObject,
/* anonymize */ true, getter_AddRefs(anonymizedAttObj));
if (NS_FAILED(rv)) {
MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
attObject.Clear();
rv = anonymizedAttObj->GetAttestationObject(attObject);
if (NS_FAILED(rv)) {
MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
}
nsTArray<WebAuthnExtensionResult> extensions;
if (pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2) {
PCWEBAUTHN_EXTENSIONS pExtensionList =
&pWebAuthNCredentialAttestation->Extensions;
if (pExtensionList->cExtensions != 0 &&
pExtensionList->pExtensions != NULL) {
for (DWORD dwIndex = 0; dwIndex < pExtensionList->cExtensions;
dwIndex++) {
PWEBAUTHN_EXTENSION pExtension =
&pExtensionList->pExtensions[dwIndex];
if (pExtension->pwszExtensionIdentifier &&
(0 == _wcsicmp(pExtension->pwszExtensionIdentifier,
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET)) &&
pExtension->cbExtension == sizeof(BOOL)) {
BOOL* pCredentialCreatedWithHmacSecret =
(BOOL*)pExtension->pvExtension;
if (*pCredentialCreatedWithHmacSecret) {
extensions.AppendElement(WebAuthnExtensionResultHmacSecret(true));
}
}
}
}
}
// WEBAUTHN_CREDENTIAL_ATTESTATION structs of version >= 4 always include a
// flag to indicate whether a resident key was created. We copy that flag to
// the credProps extension output only if the RP requested the credProps
// extension.
if (requestedCredProps && pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4) {
BOOL rk = pWebAuthNCredentialAttestation->bResidentKey;
extensions.AppendElement(WebAuthnExtensionResultCredProps(rk == TRUE));
}
nsTArray<nsString> transports;
if (pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) {
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_USB) {
transports.AppendElement(u"usb"_ns);
}
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_NFC) {
transports.AppendElement(u"nfc"_ns);
}
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_BLE) {
transports.AppendElement(u"ble"_ns);
}
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_INTERNAL) {
transports.AppendElement(u"internal"_ns);
}
}
// WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5 corresponds to
// WEBAUTHN_API_VERSION_6 which is where WEBAUTHN_CTAP_TRANSPORT_HYBRID was
// defined.
if (pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_5) {
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_HYBRID) {
transports.AppendElement(u"hybrid"_ns);
}
}
Maybe<nsString> authenticatorAttachment;
if (pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) {
if (pWebAuthNCredentialAttestation->dwUsedTransport &
WEBAUTHN_CTAP_TRANSPORT_INTERNAL) {
authenticatorAttachment = Some(u"platform"_ns);
} else {
authenticatorAttachment = Some(u"cross-platform"_ns);
}
}
WebAuthnMakeCredentialResult result(aInfo.ClientDataJSON(), attObject,
credentialId, transports, extensions,
authenticatorAttachment);
Unused << mTransactionParent->SendConfirmRegister(aTransactionId, result);
ClearTransaction();
gWinWebauthnFreeCredentialAttestation(pWebAuthNCredentialAttestation);
} else {
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
_wcsicmp(errorName, L"UnknownError") == 0) {
aError = NS_ERROR_DOM_UNKNOWN_ERR;
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
}
MaybeAbortRegister(aTransactionId, aError);
}
}
void WinWebAuthnManager::MaybeAbortRegister(const uint64_t& aTransactionId,
const nsresult& aError) {
AbortTransaction(aTransactionId, aError);
}
void WinWebAuthnManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId,
const WebAuthnGetAssertionInfo& aInfo) {
MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNSign"));
ClearTransaction();
mTransactionParent = aTransactionParent;
// User Verification Requirement
DWORD winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
// RPID
PCWSTR rpID = nullptr;
// Attachment
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
// AppId
BOOL bU2fAppIdUsed = FALSE;
BOOL* pbU2fAppIdUsed = nullptr;
PCWSTR winAppIdentifier = nullptr;
// Client Data
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
(DWORD)aInfo.ClientDataJSON().Length(),
(BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};
for (const WebAuthnExtension& ext : aInfo.Extensions()) {
if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
winAppIdentifier = ext.get_WebAuthnExtensionAppId().appIdentifier().get();
pbU2fAppIdUsed = &bU2fAppIdUsed;
break;
}
}
// RPID
rpID = aInfo.RpId().get();
// User Verification Requirement
const nsString& userVerificationReq = aInfo.userVerificationRequirement();
// This mapping needs to be reviewed if values are added to the
// UserVerificationRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
} else {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
}
// allow Credentials
nsTArray<WEBAUTHN_CREDENTIAL_EX> allowCredentials;
WEBAUTHN_CREDENTIAL_EX* pAllowCredentials = nullptr;
nsTArray<WEBAUTHN_CREDENTIAL_EX*> allowCredentialsPtrs;
WEBAUTHN_CREDENTIAL_LIST allowCredentialList = {0};
WEBAUTHN_CREDENTIAL_LIST* pAllowCredentialList = nullptr;
for (auto& cred : aInfo.AllowList()) {
uint8_t transports = cred.transports();
DWORD winTransports = 0;
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
}
WEBAUTHN_CREDENTIAL_EX credential = {
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(cred.id().Length()), (PBYTE)(cred.id().Elements()),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
allowCredentials.AppendElement(credential);
}
if (allowCredentials.Length()) {
pAllowCredentials = allowCredentials.Elements();
for (DWORD i = 0; i < allowCredentials.Length(); i++) {
allowCredentialsPtrs.AppendElement(&pAllowCredentials[i]);
}
allowCredentialList.cCredentials = allowCredentials.Length();
allowCredentialList.ppCredentials = allowCredentialsPtrs.Elements();
pAllowCredentialList = &allowCredentialList;
}
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS WebAuthNAssertionOptions = {
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_7,
aInfo.TimeoutMS(),
{0, NULL},
{0, NULL},
winAttachment,
winUserVerificationReq,
0, // dwFlags
winAppIdentifier,
pbU2fAppIdUsed,
nullptr, // pCancellationId
pAllowCredentialList,
WEBAUTHN_CRED_LARGE_BLOB_OPERATION_NONE,
0, // Size of CredLargeBlob
NULL, // CredLargeBlob
NULL, // HmacSecretSaltValues
FALSE, // BrowserInPrivateMode
NULL, // LinkedDevice
FALSE, // AutoFill
0, // Size of JsonExt
NULL, // JsonExt
};
GUID cancellationId = {0};
if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) {
WebAuthNAssertionOptions.pCancellationId = &cancellationId;
mCancellationIds.emplace(aTransactionId, &cancellationId);
}
PWEBAUTHN_ASSERTION pWebAuthNAssertion = nullptr;
// Bug 1518876: Get Window Handle from Content process for Windows WebAuthN
// APIs
HWND hWnd = GetForegroundWindow();
HRESULT hr =
gWinWebauthnGetAssertion(hWnd, rpID, &WebAuthNClientData,
&WebAuthNAssertionOptions, &pWebAuthNAssertion);
mCancellationIds.erase(aTransactionId);
if (hr == S_OK) {
nsTArray<uint8_t> signature;
signature.AppendElements(pWebAuthNAssertion->pbSignature,
pWebAuthNAssertion->cbSignature);
nsTArray<uint8_t> keyHandle;
keyHandle.AppendElements(pWebAuthNAssertion->Credential.pbId,
pWebAuthNAssertion->Credential.cbId);
nsTArray<uint8_t> userHandle;
userHandle.AppendElements(pWebAuthNAssertion->pbUserId,
pWebAuthNAssertion->cbUserId);
nsTArray<uint8_t> authenticatorData;
authenticatorData.AppendElements(pWebAuthNAssertion->pbAuthenticatorData,
pWebAuthNAssertion->cbAuthenticatorData);
nsTArray<WebAuthnExtensionResult> extensions;
if (pbU2fAppIdUsed && *pbU2fAppIdUsed) {
extensions.AppendElement(WebAuthnExtensionResultAppId(true));
}
Maybe<nsString> authenticatorAttachment = Nothing(); // not available
WebAuthnGetAssertionResult result(aInfo.ClientDataJSON(), keyHandle,
signature, authenticatorData, extensions,
userHandle, authenticatorAttachment);
Unused << mTransactionParent->SendConfirmSign(aTransactionId, result);
ClearTransaction();
gWinWebauthnFreeAssertion(pWebAuthNAssertion);
} else {
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
_wcsicmp(errorName, L"UnknownError") == 0) {
aError = NS_ERROR_DOM_UNKNOWN_ERR;
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
}
MaybeAbortSign(aTransactionId, aError);
}
}
void WinWebAuthnManager::MaybeAbortSign(const uint64_t& aTransactionId,
const nsresult& aError) {
AbortTransaction(aTransactionId, aError);
}
void WinWebAuthnManager::Cancel(PWebAuthnTransactionParent* aParent,
const Tainted<uint64_t>& aTransactionId) {
if (mTransactionParent != aParent) {
return;
}
ClearTransaction();
auto iter = mCancellationIds.find(
MOZ_NO_VALIDATE(aTransactionId,
"Transaction ID is checked against a global container, "
"so an invalid entry can affect another origin's "
"request. This issue is filed as Bug 1696159."));
if (iter != mCancellationIds.end()) {
gWinWebauthnCancelCurrentOperation(iter->second);
}
}
} // namespace mozilla::dom

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

@ -0,0 +1,52 @@
/* -*- 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_WinWebAuthnManager_h
#define mozilla_dom_WinWebAuthnManager_h
#include "mozilla/dom/PWebAuthnTransaction.h"
#include "mozilla/Tainting.h"
namespace mozilla::dom {
class WebAuthnTransactionParent;
class WinWebAuthnManager final {
public:
static WinWebAuthnManager* 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();
static bool IsUserVerifyingPlatformAuthenticatorAvailable();
static bool AreWebAuthNApisAvailable();
WinWebAuthnManager();
~WinWebAuthnManager();
private:
void AbortTransaction(const uint64_t& aTransactionId, const nsresult& aError);
void ClearTransaction();
void MaybeAbortRegister(const uint64_t& aTransactionId,
const nsresult& aError);
void MaybeAbortSign(const uint64_t& aTransactionId, const nsresult& aError);
bool IsUserVerifyingPlatformAuthenticatorAvailableInternal();
uint32_t GetWebAuthNApiVersion();
PWebAuthnTransactionParent* mTransactionParent;
uint32_t mWinWebAuthNApiVersion = 0;
std::map<uint64_t, GUID*> mCancellationIds;
};
} // namespace mozilla::dom
#endif // mozilla_dom_WinWebAuthnManager_h

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

@ -1,814 +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/dom/PWebAuthnTransactionParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/Assertions.h"
#include "mozilla/MozPromise.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/Unused.h"
#include "nsTextFormatter.h"
#include "nsWindowsHelpers.h"
#include "WebAuthnEnumStrings.h"
#include "WebAuthnTransportIdentifiers.h"
#include "winwebauthn/webauthn.h"
#include "WinWebAuthnService.h"
namespace mozilla::dom {
namespace {
StaticRWLock gWinWebAuthnModuleLock;
static HMODULE gWinWebAuthnModule = 0;
static decltype(WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*
gWinWebauthnIsUVPAA = nullptr;
static decltype(WebAuthNAuthenticatorMakeCredential)*
gWinWebauthnMakeCredential = nullptr;
static decltype(WebAuthNFreeCredentialAttestation)*
gWinWebauthnFreeCredentialAttestation = nullptr;
static decltype(WebAuthNAuthenticatorGetAssertion)* gWinWebauthnGetAssertion =
nullptr;
static decltype(WebAuthNFreeAssertion)* gWinWebauthnFreeAssertion = nullptr;
static decltype(WebAuthNGetCancellationId)* gWinWebauthnGetCancellationId =
nullptr;
static decltype(WebAuthNCancelCurrentOperation)*
gWinWebauthnCancelCurrentOperation = nullptr;
static decltype(WebAuthNGetErrorName)* gWinWebauthnGetErrorName = nullptr;
static decltype(WebAuthNGetApiVersionNumber)* gWinWebauthnGetApiVersionNumber =
nullptr;
} // namespace
/***********************************************************************
* WinWebAuthnService Implementation
**********************************************************************/
constexpr uint32_t kMinWinWebAuthNApiVersion = WEBAUTHN_API_VERSION_1;
NS_IMPL_ISUPPORTS(WinWebAuthnService, nsIWebAuthnService)
/* static */
nsresult WinWebAuthnService::EnsureWinWebAuthnModuleLoaded() {
{
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (gWinWebAuthnModule) {
return NS_OK;
}
}
StaticAutoWriteLock lock(gWinWebAuthnModuleLock);
if (gWinWebAuthnModule) {
return NS_OK;
}
gWinWebAuthnModule = LoadLibrarySystem32(L"webauthn.dll");
if (!gWinWebAuthnModule) {
return NS_ERROR_NOT_AVAILABLE;
}
gWinWebauthnIsUVPAA = reinterpret_cast<
decltype(WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable"));
gWinWebauthnMakeCredential =
reinterpret_cast<decltype(WebAuthNAuthenticatorMakeCredential)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNAuthenticatorMakeCredential"));
gWinWebauthnFreeCredentialAttestation =
reinterpret_cast<decltype(WebAuthNFreeCredentialAttestation)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNFreeCredentialAttestation"));
gWinWebauthnGetAssertion =
reinterpret_cast<decltype(WebAuthNAuthenticatorGetAssertion)*>(
GetProcAddress(gWinWebAuthnModule,
"WebAuthNAuthenticatorGetAssertion"));
gWinWebauthnFreeAssertion =
reinterpret_cast<decltype(WebAuthNFreeAssertion)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNFreeAssertion"));
gWinWebauthnGetCancellationId =
reinterpret_cast<decltype(WebAuthNGetCancellationId)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetCancellationId"));
gWinWebauthnCancelCurrentOperation =
reinterpret_cast<decltype(WebAuthNCancelCurrentOperation)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNCancelCurrentOperation"));
gWinWebauthnGetErrorName = reinterpret_cast<decltype(WebAuthNGetErrorName)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetErrorName"));
gWinWebauthnGetApiVersionNumber =
reinterpret_cast<decltype(WebAuthNGetApiVersionNumber)*>(
GetProcAddress(gWinWebAuthnModule, "WebAuthNGetApiVersionNumber"));
if (!(gWinWebauthnIsUVPAA && gWinWebauthnMakeCredential &&
gWinWebauthnFreeCredentialAttestation && gWinWebauthnGetAssertion &&
gWinWebauthnFreeAssertion && gWinWebauthnGetCancellationId &&
gWinWebauthnCancelCurrentOperation && gWinWebauthnGetErrorName &&
gWinWebauthnGetApiVersionNumber)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
WinWebAuthnService::~WinWebAuthnService() {
StaticAutoWriteLock lock(gWinWebAuthnModuleLock);
if (gWinWebAuthnModule) {
FreeLibrary(gWinWebAuthnModule);
}
gWinWebAuthnModule = 0;
}
// static
bool WinWebAuthnService::AreWebAuthNApisAvailable() {
nsresult rv = EnsureWinWebAuthnModuleLoaded();
NS_ENSURE_SUCCESS(rv, false);
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
return gWinWebAuthnModule &&
gWinWebauthnGetApiVersionNumber() >= kMinWinWebAuthNApiVersion;
}
// static
bool WinWebAuthnService::IsUserVerifyingPlatformAuthenticatorAvailable() {
nsresult rv = EnsureWinWebAuthnModuleLoaded();
NS_ENSURE_SUCCESS(rv, false);
if (WinWebAuthnService::AreWebAuthNApisAvailable()) {
BOOL isUVPAA = FALSE;
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
return gWinWebAuthnModule && gWinWebauthnIsUVPAA(&isUVPAA) == S_OK &&
isUVPAA == TRUE;
}
return false;
}
NS_IMETHODIMP
WinWebAuthnService::Cancel(uint64_t aTransactionId) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::Reset() {
// Reset will never be the first function to use gWinWebAuthnModule, so
// we shouldn't try to initialize it here.
if (mTransactionId.isSome()) {
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (gWinWebAuthnModule) {
gWinWebauthnCancelCurrentOperation(&mCancellationId);
}
mTransactionId.reset();
}
return NS_OK;
}
NS_IMETHODIMP
WinWebAuthnService::MakeCredential(uint64_t aTransactionId,
uint64_t browsingContextId,
nsIWebAuthnRegisterArgs* aArgs,
nsIWebAuthnRegisterPromise* aPromise) {
nsresult rv = EnsureWinWebAuthnModuleLoaded();
NS_ENSURE_SUCCESS(rv, rv);
Reset();
mTransactionId = Some(aTransactionId);
{
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (gWinWebauthnGetCancellationId(&mCancellationId) != S_OK) {
// caller will reject promise
return NS_ERROR_DOM_UNKNOWN_ERR;
}
}
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
"WinWebAuthnService::MakeCredential",
[self = RefPtr{this}, aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise},
aCancellationId = mCancellationId]() mutable {
// Take a read lock on gWinWebAuthnModuleLock to prevent the module from
// being unloaded while the operation is in progress. This does not
// prevent the operation from being cancelled, so it does not block a
// clean shutdown.
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (!gWinWebAuthnModule) {
aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
BOOL HmacCreateSecret = FALSE;
BOOL MinPinLength = FALSE;
// RP Information
nsString rpId;
Unused << aArgs->GetRpId(rpId);
WEBAUTHN_RP_ENTITY_INFORMATION rpInfo = {
WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION, rpId.get(), nullptr,
nullptr};
// User Information
WEBAUTHN_USER_ENTITY_INFORMATION userInfo = {
WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION,
0,
nullptr,
nullptr,
nullptr,
nullptr};
// Client Data
nsCString clientDataJSON;
Unused << aArgs->GetClientDataJSON(clientDataJSON);
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
(DWORD)clientDataJSON.Length(), (BYTE*)(clientDataJSON.get()),
WEBAUTHN_HASH_ALGORITHM_SHA_256};
// User Verification Requirement
DWORD winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
// Resident Key
BOOL winRequireResidentKey = FALSE;
BOOL winPreferResidentKey = FALSE;
// AttestationConveyance
DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
nsString rpName;
Unused << aArgs->GetRpName(rpName);
rpInfo.pwszName = rpName.get();
rpInfo.pwszIcon = nullptr;
nsTArray<uint8_t> userId;
Unused << aArgs->GetUserId(userId);
userInfo.cbId = static_cast<DWORD>(userId.Length());
userInfo.pbId = const_cast<unsigned char*>(userId.Elements());
nsString userName;
Unused << aArgs->GetUserName(userName);
userInfo.pwszName = userName.get();
userInfo.pwszIcon = nullptr;
nsString userDisplayName;
Unused << aArgs->GetUserDisplayName(userDisplayName);
userInfo.pwszDisplayName = userDisplayName.get();
// Algorithms
nsTArray<WEBAUTHN_COSE_CREDENTIAL_PARAMETER> coseParams;
nsTArray<int32_t> coseAlgs;
Unused << aArgs->GetCoseAlgs(coseAlgs);
for (const int32_t& coseAlg : coseAlgs) {
WEBAUTHN_COSE_CREDENTIAL_PARAMETER coseAlgorithm = {
WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, coseAlg};
coseParams.AppendElement(coseAlgorithm);
}
nsString userVerificationReq;
Unused << aArgs->GetUserVerification(userVerificationReq);
// This mapping needs to be reviewed if values are added to the
// UserVerificationRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
} else {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
}
// Attachment
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
nsString authenticatorAttachment;
nsresult rv =
aArgs->GetAuthenticatorAttachment(authenticatorAttachment);
if (rv != NS_ERROR_NOT_AVAILABLE) {
if (NS_FAILED(rv)) {
aPromise->Reject(rv);
return;
}
// This mapping needs to be reviewed if values are added to the
// AuthenticatorAttachement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (authenticatorAttachment.EqualsLiteral(
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM;
} else if (
authenticatorAttachment.EqualsLiteral(
MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
} else {
winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
}
}
nsString residentKey;
Unused << aArgs->GetResidentKey(residentKey);
// This mapping needs to be reviewed if values are added to the
// ResidentKeyRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED)) {
winRequireResidentKey = TRUE;
winPreferResidentKey = TRUE;
} else if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_PREFERRED)) {
winRequireResidentKey = FALSE;
winPreferResidentKey = TRUE;
} else if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winRequireResidentKey = FALSE;
winPreferResidentKey = FALSE;
} else {
// WebAuthnManager::MakeCredential is supposed to assign one of the
// above values, so this shouldn't happen.
MOZ_ASSERT_UNREACHABLE();
aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
// AttestationConveyance
nsString attestation;
Unused << aArgs->GetAttestationConveyancePreference(attestation);
bool anonymize = false;
// This mapping needs to be reviewed if values are added to the
// AttestationConveyancePreference enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE;
anonymize = true;
} else if (
attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT;
} else if (attestation.EqualsLiteral(
MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT)) {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
} else {
winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
}
bool requestedCredProps;
Unused << aArgs->GetCredProps(&requestedCredProps);
bool requestedMinPinLength;
Unused << aArgs->GetMinPinLength(&requestedMinPinLength);
bool requestedHmacCreateSecret;
Unused << aArgs->GetHmacCreateSecret(&requestedHmacCreateSecret);
// Extensions that might require an entry: hmac-secret, minPinLength.
WEBAUTHN_EXTENSION rgExtension[2] = {};
DWORD cExtensions = 0;
if (requestedHmacCreateSecret) {
HmacCreateSecret = TRUE;
rgExtension[cExtensions].pwszExtensionIdentifier =
WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET;
rgExtension[cExtensions].cbExtension = sizeof(BOOL);
rgExtension[cExtensions].pvExtension = &HmacCreateSecret;
cExtensions++;
}
if (requestedMinPinLength) {
MinPinLength = TRUE;
rgExtension[cExtensions].pwszExtensionIdentifier =
WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH;
rgExtension[cExtensions].cbExtension = sizeof(BOOL);
rgExtension[cExtensions].pvExtension = &MinPinLength;
cExtensions++;
}
WEBAUTHN_COSE_CREDENTIAL_PARAMETERS WebAuthNCredentialParameters = {
static_cast<DWORD>(coseParams.Length()), coseParams.Elements()};
// Exclude Credentials
nsTArray<nsTArray<uint8_t>> excludeList;
Unused << aArgs->GetExcludeList(excludeList);
nsTArray<uint8_t> excludeListTransports;
Unused << aArgs->GetExcludeListTransports(excludeListTransports);
if (excludeList.Length() != excludeListTransports.Length()) {
aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
nsTArray<WEBAUTHN_CREDENTIAL_EX> excludeCredentials;
WEBAUTHN_CREDENTIAL_EX* pExcludeCredentials = nullptr;
nsTArray<WEBAUTHN_CREDENTIAL_EX*> excludeCredentialsPtrs;
WEBAUTHN_CREDENTIAL_LIST excludeCredentialList = {0};
WEBAUTHN_CREDENTIAL_LIST* pExcludeCredentialList = nullptr;
for (size_t i = 0; i < excludeList.Length(); i++) {
nsTArray<uint8_t>& cred = excludeList[i];
uint8_t& transports = excludeListTransports[i];
DWORD winTransports = 0;
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
}
WEBAUTHN_CREDENTIAL_EX credential = {
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(cred.Length()), (PBYTE)(cred.Elements()),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
excludeCredentials.AppendElement(credential);
}
if (!excludeCredentials.IsEmpty()) {
pExcludeCredentials = excludeCredentials.Elements();
for (DWORD i = 0; i < excludeCredentials.Length(); i++) {
excludeCredentialsPtrs.AppendElement(&pExcludeCredentials[i]);
}
excludeCredentialList.cCredentials = excludeCredentials.Length();
excludeCredentialList.ppCredentials =
excludeCredentialsPtrs.Elements();
pExcludeCredentialList = &excludeCredentialList;
}
uint32_t timeout_u32;
Unused << aArgs->GetTimeoutMS(&timeout_u32);
DWORD timeout = timeout_u32;
// MakeCredentialOptions
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS
WebAuthNCredentialOptions = {
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_7,
timeout,
{0, NULL},
{0, NULL},
winAttachment,
winRequireResidentKey,
winUserVerificationReq,
winAttestation,
0, // Flags
&aCancellationId, // CancellationId
pExcludeCredentialList,
WEBAUTHN_ENTERPRISE_ATTESTATION_NONE,
WEBAUTHN_LARGE_BLOB_SUPPORT_NONE,
winPreferResidentKey, // PreferResidentKey
FALSE, // BrowserInPrivateMode
FALSE, // EnablePrf
NULL, // LinkedDevice
0, // size of JsonExt
NULL, // JsonExt
};
if (cExtensions != 0) {
WebAuthNCredentialOptions.Extensions.cExtensions = cExtensions;
WebAuthNCredentialOptions.Extensions.pExtensions = rgExtension;
}
PWEBAUTHN_CREDENTIAL_ATTESTATION pWebAuthNCredentialAttestation =
nullptr;
// Bug 1518876: Get Window Handle from Content process for Windows
// WebAuthN APIs
HWND hWnd = GetForegroundWindow();
HRESULT hr = gWinWebauthnMakeCredential(
hWnd, &rpInfo, &userInfo, &WebAuthNCredentialParameters,
&WebAuthNClientData, &WebAuthNCredentialOptions,
&pWebAuthNCredentialAttestation);
if (hr == S_OK) {
RefPtr<WebAuthnRegisterResult> result = new WebAuthnRegisterResult(
clientDataJSON, pWebAuthNCredentialAttestation);
// WEBAUTHN_CREDENTIAL_ATTESTATION structs of version >= 4 always
// include a flag to indicate whether a resident key was created. We
// copy that flag to the credProps extension output only if the RP
// requested the credProps extension.
if (requestedCredProps &&
pWebAuthNCredentialAttestation->dwVersion >=
WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4) {
BOOL rk = pWebAuthNCredentialAttestation->bResidentKey;
Unused << result->SetCredPropsRk(rk == TRUE);
}
gWinWebauthnFreeCredentialAttestation(pWebAuthNCredentialAttestation);
if (anonymize) {
nsresult rv = result->Anonymize();
if (NS_FAILED(rv)) {
aPromise->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
}
aPromise->Resolve(result);
} else {
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
_wcsicmp(errorName, L"UnknownError") == 0) {
aError = NS_ERROR_DOM_UNKNOWN_ERR;
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
}
aPromise->Reject(aError);
}
}));
NS_DispatchBackgroundTask(runnable, NS_DISPATCH_EVENT_MAY_BLOCK);
return NS_OK;
}
NS_IMETHODIMP
WinWebAuthnService::GetAssertion(uint64_t aTransactionId,
uint64_t browsingContextId,
nsIWebAuthnSignArgs* aArgs,
nsIWebAuthnSignPromise* aPromise) {
nsresult rv = EnsureWinWebAuthnModuleLoaded();
NS_ENSURE_SUCCESS(rv, rv);
Reset();
mTransactionId = Some(aTransactionId);
{
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (gWinWebauthnGetCancellationId(&mCancellationId) != S_OK) {
// caller will reject promise
return NS_ERROR_DOM_UNKNOWN_ERR;
}
}
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
"WinWebAuthnService::MakeCredential",
[self = RefPtr{this}, aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise},
aCancellationId = mCancellationId]() mutable {
// Take a read lock on gWinWebAuthnModuleLock to prevent the module from
// being unloaded while the operation is in progress. This does not
// prevent the operation from being cancelled, so it does not block a
// clean shutdown.
StaticAutoReadLock lock(gWinWebAuthnModuleLock);
if (!gWinWebAuthnModule) {
aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
// Attachment
DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
// AppId
BOOL bAppIdUsed = FALSE;
BOOL* pbAppIdUsed = nullptr;
PCWSTR winAppIdentifier = nullptr;
// Client Data
nsCString clientDataJSON;
Unused << aArgs->GetClientDataJSON(clientDataJSON);
WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
WEBAUTHN_CLIENT_DATA_CURRENT_VERSION,
(DWORD)clientDataJSON.Length(), (BYTE*)(clientDataJSON.get()),
WEBAUTHN_HASH_ALGORITHM_SHA_256};
nsString appId;
nsresult rv = aArgs->GetAppId(appId);
if (rv != NS_ERROR_NOT_AVAILABLE) {
if (NS_FAILED(rv)) {
aPromise->Reject(rv);
return;
}
winAppIdentifier = appId.get();
pbAppIdUsed = &bAppIdUsed;
}
// RPID
nsString rpId;
Unused << aArgs->GetRpId(rpId);
// User Verification Requirement
nsString userVerificationReq;
Unused << aArgs->GetUserVerification(userVerificationReq);
DWORD winUserVerificationReq;
// This mapping needs to be reviewed if values are added to the
// UserVerificationRequirement enum.
static_assert(MOZ_WEBAUTHN_ENUM_STRINGS_VERSION == 2);
if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
} else if (userVerificationReq.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED)) {
winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
} else {
winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
}
// allow Credentials
nsTArray<nsTArray<uint8_t>> allowList;
Unused << aArgs->GetAllowList(allowList);
nsTArray<uint8_t> allowListTransports;
Unused << aArgs->GetAllowListTransports(allowListTransports);
if (allowList.Length() != allowListTransports.Length()) {
aPromise->Reject(NS_ERROR_DOM_UNKNOWN_ERR);
return;
}
nsTArray<WEBAUTHN_CREDENTIAL_EX> allowCredentials;
WEBAUTHN_CREDENTIAL_EX* pAllowCredentials = nullptr;
nsTArray<WEBAUTHN_CREDENTIAL_EX*> allowCredentialsPtrs;
WEBAUTHN_CREDENTIAL_LIST allowCredentialList = {0};
WEBAUTHN_CREDENTIAL_LIST* pAllowCredentialList = nullptr;
for (size_t i = 0; i < allowList.Length(); i++) {
nsTArray<uint8_t>& cred = allowList[i];
uint8_t& transports = allowListTransports[i];
DWORD winTransports = 0;
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_USB) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_NFC) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_BLE) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE;
}
if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL) {
winTransports |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
}
WEBAUTHN_CREDENTIAL_EX credential = {
WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION,
static_cast<DWORD>(cred.Length()), (PBYTE)(cred.Elements()),
WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, winTransports};
allowCredentials.AppendElement(credential);
}
if (allowCredentials.Length()) {
pAllowCredentials = allowCredentials.Elements();
for (DWORD i = 0; i < allowCredentials.Length(); i++) {
allowCredentialsPtrs.AppendElement(&pAllowCredentials[i]);
}
allowCredentialList.cCredentials = allowCredentials.Length();
allowCredentialList.ppCredentials = allowCredentialsPtrs.Elements();
pAllowCredentialList = &allowCredentialList;
}
uint32_t timeout_u32;
Unused << aArgs->GetTimeoutMS(&timeout_u32);
DWORD timeout = timeout_u32;
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS WebAuthNAssertionOptions =
{
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_7,
timeout,
{0, NULL},
{0, NULL},
winAttachment,
winUserVerificationReq,
0, // dwFlags
winAppIdentifier,
pbAppIdUsed,
&aCancellationId, // CancellationId
pAllowCredentialList,
WEBAUTHN_CRED_LARGE_BLOB_OPERATION_NONE,
0, // Size of CredLargeBlob
NULL, // CredLargeBlob
NULL, // HmacSecretSaltValues
FALSE, // BrowserInPrivateMode
NULL, // LinkedDevice
FALSE, // AutoFill
0, // Size of JsonExt
NULL, // JsonExt
};
PWEBAUTHN_ASSERTION pWebAuthNAssertion = nullptr;
// Bug 1518876: Get Window Handle from Content process for Windows
// WebAuthN APIs
HWND hWnd = GetForegroundWindow();
HRESULT hr = gWinWebauthnGetAssertion(
hWnd, rpId.get(), &WebAuthNClientData, &WebAuthNAssertionOptions,
&pWebAuthNAssertion);
if (hr == S_OK) {
RefPtr<WebAuthnSignResult> result =
new WebAuthnSignResult(clientDataJSON, pWebAuthNAssertion);
gWinWebauthnFreeAssertion(pWebAuthNAssertion);
if (winAppIdentifier != nullptr) {
// The gWinWebauthnGetAssertion call modified bAppIdUsed through
// a pointer provided in WebAuthNAssertionOptions.
Unused << result->SetUsedAppId(bAppIdUsed == TRUE);
}
aPromise->Resolve(result);
} else {
PCWSTR errorName = gWinWebauthnGetErrorName(hr);
nsresult aError = NS_ERROR_DOM_ABORT_ERR;
if (_wcsicmp(errorName, L"InvalidStateError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"ConstraintError") == 0 ||
_wcsicmp(errorName, L"UnknownError") == 0) {
aError = NS_ERROR_DOM_UNKNOWN_ERR;
} else if (_wcsicmp(errorName, L"NotSupportedError") == 0) {
aError = NS_ERROR_DOM_INVALID_STATE_ERR;
} else if (_wcsicmp(errorName, L"NotAllowedError") == 0) {
aError = NS_ERROR_DOM_NOT_ALLOWED_ERR;
}
aPromise->Reject(aError);
}
}));
NS_DispatchBackgroundTask(runnable, NS_DISPATCH_EVENT_MAY_BLOCK);
return NS_OK;
}
NS_IMETHODIMP
WinWebAuthnService::PinCallback(uint64_t aTransactionId,
const nsACString& aPin) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::ResumeMakeCredential(uint64_t aTransactionId,
bool aForceNoneAttestation) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::SelectionCallback(uint64_t aTransactionId,
uint64_t aIndex) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::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
WinWebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::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
WinWebAuthnService::GetCredentials(
uint64_t authenticatorId,
nsTArray<RefPtr<nsICredentialParameters>>& _retval) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::RemoveCredential(uint64_t authenticatorId,
const nsACString& credentialId) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WinWebAuthnService::SetUserVerified(uint64_t authenticatorId,
bool isUserVerified) {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace mozilla::dom

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

@ -1,38 +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_WinWebAuthnService_h
#define mozilla_dom_WinWebAuthnService_h
#include "mozilla/dom/PWebAuthnTransaction.h"
#include "mozilla/Tainting.h"
#include "nsIWebAuthnService.h"
namespace mozilla::dom {
class WinWebAuthnService final : public nsIWebAuthnService {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWEBAUTHNSERVICE
static bool IsUserVerifyingPlatformAuthenticatorAvailable();
static bool AreWebAuthNApisAvailable();
static nsresult EnsureWinWebAuthnModuleLoaded();
WinWebAuthnService() = default;
private:
~WinWebAuthnService();
uint32_t GetWebAuthNApiVersion();
Maybe<uint64_t> mTransactionId;
GUID mCancellationId;
};
} // namespace mozilla::dom
#endif // mozilla_dom_WinWebAuthnService_h

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

@ -177,14 +177,6 @@ impl WebAuthnRegisterResult {
}
}
xpcom_method!(get_hmac_create_secret => GetHmacCreateSecret() -> bool);
fn get_hmac_create_secret(&self) -> Result<bool, nsresult> {
let Some(hmac_create_secret) = self.result.extensions.hmac_create_secret else {
return Err(NS_ERROR_NOT_AVAILABLE);
};
Ok(hmac_create_secret)
}
xpcom_method!(get_cred_props_rk => GetCredPropsRk() -> bool);
fn get_cred_props_rk(&self) -> Result<bool, nsresult> {
let Some(cred_props) = &self.result.extensions.cred_props else {
@ -310,11 +302,6 @@ impl WebAuthnSignResult {
fn get_used_app_id(&self) -> Result<bool, nsresult> {
self.result.extensions.app_id.ok_or(NS_ERROR_NOT_AVAILABLE)
}
xpcom_method!(set_used_app_id => SetUsedAppId(aUsedAppId: bool));
fn set_used_app_id(&self, _used_app_id: bool) -> Result<(), nsresult> {
Err(NS_ERROR_NOT_IMPLEMENTED)
}
}
// A transaction may create a channel to ask a user for additional input, e.g. a PIN. The Sender

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

@ -76,10 +76,10 @@ if CONFIG["OS_ARCH"] == "WINNT":
if CONFIG["OS_TARGET"] == "WINNT":
EXPORTS.mozilla.dom += [
"WinWebAuthnService.h",
"WinWebAuthnManager.h",
]
UNIFIED_SOURCES += [
"WinWebAuthnService.cpp",
"WinWebAuthnManager.cpp",
]
MOCHITEST_MANIFESTS += ["tests/mochitest.ini"]

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

@ -14,8 +14,6 @@ interface nsIWebAuthnRegisterArgs : nsISupports {
readonly attribute Array<octet> challenge;
readonly attribute ACString clientDataJSON;
readonly attribute Array<octet> clientDataHash;
// A PublicKeyCredentialRpEntity
@ -70,8 +68,6 @@ interface nsIWebAuthnSignArgs : nsISupports {
readonly attribute Array<octet> challenge;
readonly attribute ACString clientDataJSON;
readonly attribute Array<octet> clientDataHash;
// The spec defines this as a sequence<PublicKeyCredentialDescriptor>,

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

@ -23,7 +23,8 @@ interface nsIWebAuthnRegisterResult : nsISupports {
readonly attribute Array<AString> transports;
readonly attribute bool hmacCreateSecret;
// bug 1593571
// readonly attribute bool hmacCreateSecret;
[must_use] attribute bool credPropsRk;
@ -56,7 +57,7 @@ interface nsIWebAuthnSignResult : nsISupports {
[must_use] readonly attribute ACString userName;
// appId field of AuthenticationExtensionsClientOutputs (Optional)
[must_use] attribute bool usedAppId;
[must_use] readonly attribute bool usedAppId;
[must_use] readonly attribute AString authenticatorAttachment;
};

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

@ -103,6 +103,9 @@
#include "mozilla/dom/AbstractRange.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#ifdef XP_WIN
# include "mozilla/dom/WinWebAuthnManager.h"
#endif
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/RemoteWorkerService.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
@ -253,6 +256,10 @@ nsresult nsLayoutStatics::Initialize() {
// This must be initialized on the main-thread.
mozilla::RemoteLazyInputStreamStorage::Initialize();
#ifdef XP_WIN
mozilla::dom::WinWebAuthnManager::Initialize();
#endif
if (XRE_IsParentProcess()) {
// On content process we initialize these components when PContentChild is
// fully initialized.