summaryrefslogtreecommitdiffstats
path: root/dom/webauthn/WinWebAuthnManager.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/webauthn/WinWebAuthnManager.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/webauthn/WinWebAuthnManager.cpp')
-rw-r--r--dom/webauthn/WinWebAuthnManager.cpp706
1 files changed, 706 insertions, 0 deletions
diff --git a/dom/webauthn/WinWebAuthnManager.cpp b/dom/webauthn/WinWebAuthnManager.cpp
new file mode 100644
index 0000000000..aa330212bf
--- /dev/null
+++ b/dom/webauthn/WinWebAuthnManager.cpp
@@ -0,0 +1,706 @@
+/* -*- 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/dom/WebAuthnCBORUtil.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/CryptoBuffer.h"
+#include "mozilla/Unused.h"
+#include "nsTextFormatter.h"
+#include "nsWindowsHelpers.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;
+
+ WEBAUTHN_EXTENSION rgExtension[1] = {};
+ DWORD cExtensions = 0;
+ BOOL HmacCreateSecret = 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 = aInfo.Rp().Icon().get();
+
+ 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 = aInfo.User().Icon().get();
+ 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;
+ }
+
+ 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::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++;
+ }
+ }
+ }
+
+ 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_4,
+ 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
+ };
+
+ 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;
+ }
+
+ WEBAUTHN_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;
+ if (winAttestation == WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE) {
+ // Zero AAGuid
+ const uint8_t zeroGuid[16] = {0};
+ authenticatorData.ReplaceElementsAt(32 + 1 + 4 /*AAGuid offset*/, 16,
+ zeroGuid, 16);
+
+ CryptoBuffer authData;
+ authData.Assign(authenticatorData);
+ CryptoBuffer noneAttObj;
+ CBOREncodeNoneAttestationObj(authData, noneAttObj);
+ attObject.AppendElements(noneAttObj);
+ } else {
+ attObject.AppendElements(
+ pWebAuthNCredentialAttestation->pbAttestationObject,
+ pWebAuthNCredentialAttestation->cbAttestationObject);
+ }
+
+ 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));
+ }
+ }
+ }
+ }
+ }
+
+ WebAuthnMakeCredentialResult result(aInfo.ClientDataJSON(), attObject,
+ credentialId, extensions);
+
+ 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_CURRENT_VERSION,
+ aInfo.TimeoutMS(),
+ {0, NULL},
+ {0, NULL},
+ winAttachment,
+ winUserVerificationReq,
+ 0, // dwFlags
+ winAppIdentifier,
+ pbU2fAppIdUsed,
+ nullptr, // pCancellationId
+ pAllowCredentialList,
+ };
+
+ 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));
+ }
+
+ WebAuthnGetAssertionResult result(aInfo.ClientDataJSON(), keyHandle,
+ signature, authenticatorData, extensions,
+ userHandle);
+
+ 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