mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
c95cff3481
Differential Revision: https://phabricator.services.mozilla.com/D206860
1039 lines
39 KiB
C++
1039 lines
39 KiB
C++
/* -*- 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);
|
|
// 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;
|
|
} 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);
|
|
|
|
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::SetHasAttestationConsent(uint64_t aTransactionId,
|
|
bool aHasConsent) {
|
|
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
|