summaryrefslogtreecommitdiffstats
path: root/dom/webauthn/WinWebAuthnService.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /dom/webauthn/WinWebAuthnService.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/webauthn/WinWebAuthnService.cpp')
-rw-r--r--dom/webauthn/WinWebAuthnService.cpp1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/dom/webauthn/WinWebAuthnService.cpp b/dom/webauthn/WinWebAuthnService.cpp
new file mode 100644
index 0000000000..8667cf5615
--- /dev/null
+++ b/dom/webauthn/WinWebAuthnService.cpp
@@ -0,0 +1,1047 @@
+/* -*- 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/Preferences.h"
+#include "mozilla/ScopeExit.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/Unused.h"
+
+#include "nsTextFormatter.h"
+#include "nsWindowsHelpers.h"
+#include "WebAuthnAutoFillEntry.h"
+#include "WebAuthnEnumStrings.h"
+#include "WebAuthnResult.h"
+#include "WebAuthnTransportIdentifiers.h"
+#include "winwebauthn/webauthn.h"
+#include "WinWebAuthnService.h"
+
+namespace mozilla::dom {
+
+namespace {
+StaticRWLock gWinWebAuthnModuleLock;
+
+static bool gWinWebAuthnModuleUnusable = false;
+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;
+static decltype(WebAuthNGetPlatformCredentialList)*
+ gWinWebauthnGetPlatformCredentialList = nullptr;
+static decltype(WebAuthNFreePlatformCredentialList)*
+ gWinWebauthnFreePlatformCredentialList = nullptr;
+
+} // namespace
+
+/***********************************************************************
+ * WinWebAuthnService Implementation
+ **********************************************************************/
+
+constexpr uint32_t kMinWinWebAuthNApiVersion = WEBAUTHN_API_VERSION_1;
+
+NS_IMPL_ISUPPORTS(WinWebAuthnService, nsIWebAuthnService)
+
+/* static */
+nsresult WinWebAuthnService::EnsureWinWebAuthnModuleLoaded() {
+ {
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ if (gWinWebAuthnModule) {
+ // The module is already loaded.
+ return NS_OK;
+ }
+ if (gWinWebAuthnModuleUnusable) {
+ // A previous attempt to load the module failed.
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ }
+
+ StaticAutoWriteLock lock(gWinWebAuthnModuleLock);
+ if (gWinWebAuthnModule) {
+ // Another thread successfully loaded the module while we were waiting.
+ return NS_OK;
+ }
+ if (gWinWebAuthnModuleUnusable) {
+ // Another thread failed to load the module while we were waiting.
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ gWinWebAuthnModule = LoadLibrarySystem32(L"webauthn.dll");
+ auto markModuleUnusable = MakeScopeExit([]() {
+ if (gWinWebAuthnModule) {
+ FreeLibrary(gWinWebAuthnModule);
+ gWinWebAuthnModule = 0;
+ }
+ gWinWebAuthnModuleUnusable = true;
+ });
+
+ 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_NOT_AVAILABLE;
+ }
+
+ DWORD version = gWinWebauthnGetApiVersionNumber();
+
+ if (version >= WEBAUTHN_API_VERSION_4) {
+ gWinWebauthnGetPlatformCredentialList =
+ reinterpret_cast<decltype(WebAuthNGetPlatformCredentialList)*>(
+ GetProcAddress(gWinWebAuthnModule,
+ "WebAuthNGetPlatformCredentialList"));
+ gWinWebauthnFreePlatformCredentialList =
+ reinterpret_cast<decltype(WebAuthNFreePlatformCredentialList)*>(
+ GetProcAddress(gWinWebAuthnModule,
+ "WebAuthNFreePlatformCredentialList"));
+ if (!(gWinWebauthnGetPlatformCredentialList &&
+ gWinWebauthnFreePlatformCredentialList)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ }
+
+ // Bug 1869584: In some of our tests, a content process can end up here due to
+ // a call to WinWebAuthnService::AreWebAuthNApisAvailable. This causes us to
+ // fail an assertion in Preferences::SetBool, which is parent-process only.
+ if (XRE_IsParentProcess()) {
+ NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, [version]() {
+ Preferences::SetBool("security.webauthn.show_ms_settings_link",
+ version >= WEBAUTHN_API_VERSION_7);
+ }));
+ }
+
+ markModuleUnusable.release();
+ 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 moduleLock(gWinWebAuthnModuleLock);
+ return gWinWebAuthnModule &&
+ gWinWebauthnGetApiVersionNumber() >= kMinWinWebAuthNApiVersion;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::GetIsUVPAA(bool* aAvailable) {
+ nsresult rv = EnsureWinWebAuthnModuleLoaded();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (WinWebAuthnService::AreWebAuthNApisAvailable()) {
+ BOOL isUVPAA = FALSE;
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ *aAvailable = gWinWebAuthnModule && gWinWebauthnIsUVPAA(&isUVPAA) == S_OK &&
+ isUVPAA == TRUE;
+ } else {
+ *aAvailable = false;
+ }
+ return NS_OK;
+}
+
+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.
+ auto guard = mTransactionState.Lock();
+ if (guard->isSome()) {
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ if (gWinWebAuthnModule) {
+ const GUID cancellationId = guard->ref().cancellationId;
+ gWinWebauthnCancelCurrentOperation(&cancellationId);
+ }
+ if (guard->ref().pendingSignPromise.isSome()) {
+ // This request was never dispatched to the platform API, so
+ // we need to reject the promise ourselves.
+ guard->ref().pendingSignPromise.ref()->Reject(
+ NS_ERROR_DOM_NOT_ALLOWED_ERR);
+ }
+ guard->reset();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::MakeCredential(uint64_t aTransactionId,
+ uint64_t aBrowsingContextId,
+ nsIWebAuthnRegisterArgs* aArgs,
+ nsIWebAuthnRegisterPromise* aPromise) {
+ nsresult rv = EnsureWinWebAuthnModuleLoaded();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ Reset();
+ auto guard = mTransactionState.Lock();
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ GUID cancellationId;
+ if (gWinWebauthnGetCancellationId(&cancellationId) != S_OK) {
+ // caller will reject promise
+ return NS_ERROR_DOM_UNKNOWN_ERR;
+ }
+ *guard = Some(TransactionState{
+ aTransactionId,
+ aBrowsingContextId,
+ Nothing(),
+ Nothing(),
+ cancellationId,
+ });
+
+ nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
+ "WinWebAuthnService::MakeCredential",
+ [self = RefPtr{this}, aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise},
+ cancellationId]() 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 moduleLock(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 == 3);
+ 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 == 3);
+ 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 == 3);
+ 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 == 3);
+ 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;
+ }
+ if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_HYBRID) {
+ winTransports |= WEBAUTHN_CTAP_TRANSPORT_HYBRID;
+ }
+
+ 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
+ &cancellationId, // 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 aBrowsingContextId,
+ nsIWebAuthnSignArgs* aArgs,
+ nsIWebAuthnSignPromise* aPromise) {
+ nsresult rv = EnsureWinWebAuthnModuleLoaded();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ Reset();
+
+ auto guard = mTransactionState.Lock();
+
+ GUID cancellationId;
+ {
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ if (gWinWebauthnGetCancellationId(&cancellationId) != S_OK) {
+ // caller will reject promise
+ return NS_ERROR_DOM_UNKNOWN_ERR;
+ }
+ }
+
+ *guard = Some(TransactionState{
+ aTransactionId,
+ aBrowsingContextId,
+ Some(RefPtr{aArgs}),
+ Some(RefPtr{aPromise}),
+ cancellationId,
+ });
+
+ bool conditionallyMediated;
+ Unused << aArgs->GetConditionallyMediated(&conditionallyMediated);
+ if (!conditionallyMediated) {
+ DoGetAssertion(Nothing(), guard);
+ }
+ return NS_OK;
+}
+
+void WinWebAuthnService::DoGetAssertion(
+ Maybe<nsTArray<uint8_t>>&& aSelectedCredentialId,
+ const TransactionStateMutex::AutoLock& aGuard) {
+ if (aGuard->isNothing() || aGuard->ref().pendingSignArgs.isNothing() ||
+ aGuard->ref().pendingSignPromise.isNothing()) {
+ return;
+ }
+
+ // Take the pending Args and Promise to prevent repeated calls to
+ // DoGetAssertion for this transaction.
+ RefPtr<nsIWebAuthnSignArgs> aArgs = aGuard->ref().pendingSignArgs.extract();
+ RefPtr<nsIWebAuthnSignPromise> aPromise =
+ aGuard->ref().pendingSignPromise.extract();
+
+ nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
+ "WinWebAuthnService::MakeCredential",
+ [self = RefPtr{this}, aArgs, aPromise,
+ aSelectedCredentialId = std::move(aSelectedCredentialId),
+ aCancellationId = aGuard->ref().cancellationId]() 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 moduleLock(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 == 3);
+ 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;
+ nsTArray<uint8_t> allowListTransports;
+ if (aSelectedCredentialId.isSome()) {
+ allowList.AppendElement(aSelectedCredentialId.extract());
+ allowListTransports.AppendElement(
+ MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL);
+ } else {
+ Unused << aArgs->GetAllowList(allowList);
+ 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;
+ }
+ if (transports & MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_HYBRID) {
+ winTransports |= WEBAUTHN_CTAP_TRANSPORT_HYBRID;
+ }
+
+ 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);
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId,
+ const nsAString& aOrigin,
+ uint64_t* aRv) {
+ auto guard = mTransactionState.Lock();
+ if (guard->isNothing() ||
+ guard->ref().browsingContextId != aBrowsingContextId ||
+ guard->ref().pendingSignArgs.isNothing()) {
+ *aRv = 0;
+ return NS_OK;
+ }
+
+ nsString origin;
+ Unused << guard->ref().pendingSignArgs.ref()->GetOrigin(origin);
+ if (origin != aOrigin) {
+ *aRv = 0;
+ return NS_OK;
+ }
+
+ *aRv = guard->ref().transactionId;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::GetAutoFillEntries(
+ uint64_t aTransactionId, nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>& aRv) {
+ auto guard = mTransactionState.Lock();
+ if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
+ guard->ref().pendingSignArgs.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ StaticAutoReadLock moduleLock(gWinWebAuthnModuleLock);
+ if (!gWinWebAuthnModule) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ aRv.Clear();
+
+ if (gWinWebauthnGetApiVersionNumber() < WEBAUTHN_API_VERSION_4) {
+ // GetPlatformCredentialList was added in version 4. Earlier versions
+ // can still present a generic "Use a Passkey" autofill entry, so
+ // this isn't an error.
+ return NS_OK;
+ }
+
+ nsString rpId;
+ Unused << guard->ref().pendingSignArgs.ref()->GetRpId(rpId);
+
+ WEBAUTHN_GET_CREDENTIALS_OPTIONS getCredentialsOptions{
+ WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1,
+ rpId.get(), // pwszRpId
+ FALSE, // bBrowserInPrivateMode
+ };
+ PWEBAUTHN_CREDENTIAL_DETAILS_LIST pCredentialList = nullptr;
+ HRESULT hr = gWinWebauthnGetPlatformCredentialList(&getCredentialsOptions,
+ &pCredentialList);
+ // WebAuthNGetPlatformCredentialList has an _Outptr_result_maybenull_
+ // annotation and a comment "Returns NTE_NOT_FOUND when credentials are
+ // not found."
+ if (pCredentialList == nullptr) {
+ if (hr != NTE_NOT_FOUND) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+ }
+ MOZ_ASSERT(hr == S_OK);
+ for (size_t i = 0; i < pCredentialList->cCredentialDetails; i++) {
+ RefPtr<nsIWebAuthnAutoFillEntry> entry(
+ new WebAuthnAutoFillEntry(pCredentialList->ppCredentialDetails[i]));
+ aRv.AppendElement(entry);
+ }
+ gWinWebauthnFreePlatformCredentialList(pCredentialList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::SelectAutoFillEntry(
+ uint64_t aTransactionId, const nsTArray<uint8_t>& aCredentialId) {
+ auto guard = mTransactionState.Lock();
+ if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
+ guard->ref().pendingSignArgs.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsTArray<nsTArray<uint8_t>> allowList;
+ Unused << guard->ref().pendingSignArgs.ref()->GetAllowList(allowList);
+ if (!allowList.IsEmpty() && !allowList.Contains(aCredentialId)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Maybe<nsTArray<uint8_t>> id;
+ id.emplace();
+ id.ref().Assign(aCredentialId);
+ DoGetAssertion(std::move(id), guard);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) {
+ auto guard = mTransactionState.Lock();
+ if (guard->isNothing() || guard->ref().transactionId != aTransactionId ||
+ guard->ref().pendingSignArgs.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ DoGetAssertion(Nothing(), guard);
+ 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;
+}
+
+NS_IMETHODIMP
+WinWebAuthnService::Listen() { return NS_ERROR_NOT_IMPLEMENTED; }
+
+NS_IMETHODIMP
+WinWebAuthnService::RunCommand(const nsACString& cmd) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace mozilla::dom