void U2FTokenManager::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 U2FTokenManager::MaybeConfirmSign(const uint64_t& aTransactionId, const WebAuthnGetAssertionResult& aResult) { MOZ_ASSERT(mLastTransactionId == aTransactionId); mSignPromise.Complete(); Unused << mTransactionParent->SendConfirmSign(aTransactionId, aResult); ClearTransaction(); }
void U2FTokenManager::MaybeConfirmRegister(const uint64_t& aTransactionId, const WebAuthnMakeCredentialResult& aResult) { MOZ_ASSERT(mLastTransactionId == aTransactionId); mRegisterPromise.Complete(); Unused << mTransactionParent->SendConfirmRegister(aTransactionId, aResult); ClearTransaction(); }
void U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent, const uint64_t& aTransactionId) { if (mTransactionParent != aParent || mLastTransactionId != aTransactionId) { return; } mTokenManagerImpl->Cancel(); ClearTransaction(); }
void U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent, const uint64_t& aTransactionId, const WebAuthnGetAssertionInfo& aTransactionInfo) { MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign")); ClearTransaction(); mTransactionParent = aTransactionParent; mTokenManagerImpl = GetTokenManagerImpl(); if (!mTokenManagerImpl) { AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); return; } if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) || (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) { AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR); return; } // Show a prompt that lets the user cancel the ongoing transaction. NS_ConvertUTF16toUTF8 origin(aTransactionInfo.Origin()); SendPromptNotification(kSignPromptNotifcation, aTransactionId, origin.get()); uint64_t tid = mLastTransactionId = aTransactionId; mozilla::TimeStamp startTime = mozilla::TimeStamp::Now(); mTokenManagerImpl ->Sign(aTransactionInfo) ->Then(GetCurrentThreadSerialEventTarget(), __func__, [tid, startTime](WebAuthnGetAssertionResult&& aResult) { U2FTokenManager* mgr = U2FTokenManager::Get(); mgr->MaybeConfirmSign(tid, aResult); Telemetry::ScalarAdd( Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, NS_LITERAL_STRING("U2FSignFinish"), 1); Telemetry::AccumulateTimeDelta( Telemetry::WEBAUTHN_GET_ASSERTION_MS, startTime); }, [tid](nsresult rv) { MOZ_ASSERT(NS_FAILED(rv)); U2FTokenManager* mgr = U2FTokenManager::Get(); mgr->MaybeAbortSign(tid, rv); Telemetry::ScalarAdd( Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, NS_LITERAL_STRING("U2FSignAbort"), 1); }) ->Track(mSignPromise); }
void U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent, const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aTransactionInfo) { MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister")); ClearTransaction(); mTransactionParent = aTransactionParent; mTokenManagerImpl = GetTokenManagerImpl(); if (!mTokenManagerImpl) { AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); return; } // Check if all the supplied parameters are syntactically well-formed and // of the correct length. If not, return an error code equivalent to // UnknownError and terminate the operation. if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) || (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) { AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR); return; } uint64_t tid = mLastTransactionId = aTransactionId; mozilla::TimeStamp startTime = mozilla::TimeStamp::Now(); mTokenManagerImpl->Register(aTransactionInfo.ExcludeList(), aTransactionInfo.AuthenticatorSelection(), aTransactionInfo.RpIdHash(), aTransactionInfo.ClientDataHash(), aTransactionInfo.TimeoutMS()) ->Then(GetCurrentThreadSerialEventTarget(), __func__, [tid, startTime](U2FRegisterResult&& aResult) { U2FTokenManager* mgr = U2FTokenManager::Get(); mgr->MaybeConfirmRegister(tid, aResult); Telemetry::ScalarAdd( Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, NS_LITERAL_STRING("U2FRegisterFinish"), 1); Telemetry::AccumulateTimeDelta( Telemetry::WEBAUTHN_CREATE_CREDENTIAL_MS, startTime); }, [tid](nsresult rv) { MOZ_ASSERT(NS_FAILED(rv)); U2FTokenManager* mgr = U2FTokenManager::Get(); mgr->MaybeAbortRegister(tid, rv); Telemetry::ScalarAdd( Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, NS_LITERAL_STRING("U2FRegisterAbort"), 1); }) ->Track(mRegisterPromise); }
void WinWebAuthnManager::Cancel(PWebAuthnTransactionParent* aParent, const uint64_t& aTransactionId) { if (mTransactionParent != aParent) { return; } ClearTransaction(); auto iter = mCancellationIds.find(aTransactionId); if (iter != mCancellationIds.end()) { gWinWebauthnCancelCurrentOperation(iter->second); } }
void U2FTokenManager::MaybeConfirmRegister(const uint64_t& aTransactionId, U2FRegisterResult& aResult) { MOZ_ASSERT(mLastTransactionId == aTransactionId); mRegisterPromise.Complete(); nsTArray<uint8_t> registration; aResult.ConsumeRegistration(registration); Unused << mTransactionParent->SendConfirmRegister(aTransactionId, registration); ClearTransaction(); }
void U2FTokenManager::MaybeConfirmSign(const uint64_t& aTransactionId, U2FSignResult& aResult) { MOZ_ASSERT(mLastTransactionId == aTransactionId); mSignPromise.Complete(); nsTArray<uint8_t> keyHandle; aResult.ConsumeKeyHandle(keyHandle); nsTArray<uint8_t> signature; aResult.ConsumeSignature(signature); Unused << mTransactionParent->SendConfirmSign(aTransactionId, keyHandle, signature); ClearTransaction(); }
void U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent, const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aTransactionInfo) { MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister")); ClearTransaction(); mTransactionParent = aTransactionParent; mTokenManagerImpl = GetTokenManagerImpl(); if (!mTokenManagerImpl) { AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); return; } mLastTransactionId = aTransactionId; // Determine whether direct attestation was requested. bool directAttestationRequested = false; if (aTransactionInfo.Extra().type() == WebAuthnMaybeMakeCredentialExtraInfo::TWebAuthnMakeCredentialExtraInfo) { const auto& extra = aTransactionInfo.Extra().get_WebAuthnMakeCredentialExtraInfo(); directAttestationRequested = extra.RequestDirectAttestation(); } // Start a register request immediately if direct attestation // wasn't requested or the test pref is set. if (!directAttestationRequested || U2FPrefManager::Get()->GetAllowDirectAttestationForTesting()) { // Force "none" attestation when "direct" attestation wasn't requested. DoRegister(aTransactionInfo, !directAttestationRequested); return; } // If the RP request direct attestation, ask the user for permission and // store the transaction info until the user proceeds or cancels. NS_ConvertUTF16toUTF8 origin(aTransactionInfo.Origin()); SendPromptNotification(kRegisterDirectPromptNotifcation, aTransactionId, origin.get()); MOZ_ASSERT(mPendingRegisterInfo.isNothing()); mPendingRegisterInfo = Some(aTransactionInfo); }
void U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent, const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aTransactionInfo) { MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister")); ClearTransaction(); mTransactionParent = aTransactionParent; mTokenManagerImpl = GetTokenManagerImpl(); if (!mTokenManagerImpl) { AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); return; } // Check if all the supplied parameters are syntactically well-formed and // of the correct length. If not, return an error code equivalent to // UnknownError and terminate the operation. if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) || (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) { AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR); return; } mLastTransactionId = aTransactionId; // If the RP request direct attestation, ask the user for permission and // store the transaction info until the user proceeds or cancels. // Might be overriden by a pref for testing purposes. if (aTransactionInfo.RequestDirectAttestation() && !U2FPrefManager::Get()->GetAllowDirectAttestationForTesting()) { NS_ConvertUTF16toUTF8 origin(aTransactionInfo.Origin()); SendPromptNotification(kRegisterDirectPromptNotifcation, aTransactionId, origin.get()); MOZ_ASSERT(mPendingRegisterInfo.isNothing()); mPendingRegisterInfo = Some(aTransactionInfo); } else { DoRegister(aTransactionInfo); } }
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, aInfo.ClientDataJSON().Length(), (BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256}; if (aInfo.Extra().type() == WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) { const auto& extra = aInfo.Extra().get_WebAuthnGetAssertionExtraInfo(); for (const WebAuthnExtension& ext : extra.Extensions()) { if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) { winAppIdentifier = ext.get_WebAuthnExtensionAppId().appIdentifier().get(); pbU2fAppIdUsed = &bU2fAppIdUsed; break; } } // RPID rpID = aInfo.RpId().get(); // User Verification Requirement UserVerificationRequirement userVerificationReq = static_cast<UserVerificationRequirement>( extra.userVerificationRequirement()); switch (userVerificationReq) { case UserVerificationRequirement::Required: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED; break; case UserVerificationRequirement::Preferred: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED; break; case UserVerificationRequirement::Discouraged: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED; break; default: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY; break; } } else { rpID = aInfo.Origin().get(); winAppIdentifier = aInfo.RpId().get(); pbU2fAppIdUsed = &bU2fAppIdUsed; winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2; winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED; } // 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 & U2F_AUTHENTICATOR_TRANSPORT_USB) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB; } if (transports & U2F_AUTHENTICATOR_TRANSPORT_NFC) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC; } if (transports & U2F_AUTHENTICATOR_TRANSPORT_BLE) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE; } if (transports & CTAP_AUTHENTICATOR_TRANSPORT_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}, WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY, 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; if (aInfo.Extra().type() == WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) { signature.AppendElements(pWebAuthNAssertion->pbSignature, pWebAuthNAssertion->cbSignature); } else { // AuthenticatorData Length check. // First 32 bytes: RPID Hash // Next 1 byte: Flags // Next 4 bytes: Counter if (pWebAuthNAssertion->cbAuthenticatorData < 32 + 1 + 4) { MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_INVALID_STATE_ERR); } signature.AppendElement(0x01); // User Presence bit signature.AppendElements(pWebAuthNAssertion->pbAuthenticatorData + 32 + // RPID Hash length 1, // Flags 4); // Counter length signature.AppendElements(pWebAuthNAssertion->pbSignature, pWebAuthNAssertion->cbSignature); } nsTArray<uint8_t> keyHandle; keyHandle.AppendElements(pWebAuthNAssertion->Credential.pbId, pWebAuthNAssertion->Credential.cbId); 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, signature); 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::Register( PWebAuthnTransactionParent* aTransactionParent, const uint64_t& aTransactionId, const WebAuthnMakeCredentialInfo& aInfo) { MOZ_LOG(gWinWebAuthnManagerLog, LogLevel::Debug, ("WinWebAuthNRegister")); ClearTransaction(); mTransactionParent = aTransactionParent; BYTE U2FUserId = 0x01; // 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, 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; // AttestationConveyance DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY; if (aInfo.Extra().type() == WebAuthnMaybeMakeCredentialExtraInfo::TWebAuthnMakeCredentialExtraInfo) { const auto& extra = aInfo.Extra().get_WebAuthnMakeCredentialExtraInfo(); rpInfo.pwszName = extra.Rp().Name().get(); rpInfo.pwszIcon = extra.Rp().Icon().get(); userInfo.cbId = static_cast<DWORD>(extra.User().Id().Length()); userInfo.pbId = const_cast<unsigned char*>(extra.User().Id().Elements()); userInfo.pwszName = extra.User().Name().get(); userInfo.pwszIcon = extra.User().Icon().get(); userInfo.pwszDisplayName = extra.User().DisplayName().get(); for (const auto& coseAlg : extra.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 = extra.AuthenticatorSelection(); UserVerificationRequirement userVerificationReq = static_cast<UserVerificationRequirement>( sel.userVerificationRequirement()); switch (userVerificationReq) { case UserVerificationRequirement::Required: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED; break; case UserVerificationRequirement::Preferred: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED; break; case UserVerificationRequirement::Discouraged: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED; break; default: winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY; break; } if (sel.authenticatorAttachment().type() == WebAuthnMaybeAuthenticatorAttachment::Tuint8_t) { const AuthenticatorAttachment authenticatorAttachment = static_cast<AuthenticatorAttachment>( sel.authenticatorAttachment().get_uint8_t()); switch (authenticatorAttachment) { case AuthenticatorAttachment::Platform: winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM; break; case AuthenticatorAttachment::Cross_platform: winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM; break; default: break; } } winRequireResidentKey = sel.requireResidentKey(); // AttestationConveyance AttestationConveyancePreference attestation = static_cast<AttestationConveyancePreference>( extra.attestationConveyancePreference()); DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY; switch (attestation) { case AttestationConveyancePreference::Direct: winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT; break; case AttestationConveyancePreference::Indirect: winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT; break; case AttestationConveyancePreference::None: winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE; break; default: winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY; break; } } else { userInfo.cbId = sizeof(BYTE); userInfo.pbId = &U2FUserId; WEBAUTHN_COSE_CREDENTIAL_PARAMETER coseAlgorithm = { WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION, WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256}; coseParams.AppendElement(coseAlgorithm); winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2; } 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 & U2F_AUTHENTICATOR_TRANSPORT_USB) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_USB; } if (transports & U2F_AUTHENTICATOR_TRANSPORT_NFC) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_NFC; } if (transports & U2F_AUTHENTICATOR_TRANSPORT_BLE) { winTransports |= WEBAUTHN_CTAP_TRANSPORT_BLE; } if (transports & CTAP_AUTHENTICATOR_TRANSPORT_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_CURRENT_VERSION, aInfo.TimeoutMS(), {0, NULL}, {0, NULL}, winAttachment, winRequireResidentKey, winUserVerificationReq, winAttestation, 0, // Flags NULL, // CancellationId pExcludeCredentialList}; GUID cancellationId = {0}; if (gWinWebauthnGetCancellationId(&cancellationId) == S_OK) { WebAuthNCredentialOptions.pCancellationId = &cancellationId; mCancellationIds.emplace(aTransactionId, &cancellationId); } 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> attObject; attObject.AppendElements( pWebAuthNCredentialAttestation->pbAttestationObject, pWebAuthNCredentialAttestation->cbAttestationObject); nsTArray<uint8_t> credentialId; credentialId.AppendElements(pWebAuthNCredentialAttestation->pbCredentialId, pWebAuthNCredentialAttestation->cbCredentialId); nsTArray<uint8_t> authenticatorData; if (aInfo.Extra().type() == WebAuthnMaybeMakeCredentialExtraInfo:: TWebAuthnMakeCredentialExtraInfo) { authenticatorData.AppendElements( pWebAuthNCredentialAttestation->pbAuthenticatorData, pWebAuthNCredentialAttestation->cbAuthenticatorData); } else { PWEBAUTHN_COMMON_ATTESTATION attestation = reinterpret_cast<PWEBAUTHN_COMMON_ATTESTATION>( pWebAuthNCredentialAttestation->pvAttestationDecode); DWORD coseKeyOffset = 32 + // RPIDHash 1 + // Flags 4 + // Counter 16 + // AAGuid 2 + // Credential ID Length field pWebAuthNCredentialAttestation->cbCredentialId; // Hardcoding as couldn't finder decoder and it is an ECC key. DWORD xOffset = coseKeyOffset + 10; DWORD yOffset = coseKeyOffset + 45; // Authenticator Data length check. if (pWebAuthNCredentialAttestation->cbAuthenticatorData < yOffset + 32) { MaybeAbortRegister(aTransactionId, NS_ERROR_DOM_INVALID_STATE_ERR); } authenticatorData.AppendElement(0x05); // Reserved Byte authenticatorData.AppendElement(0x04); // ECC Uncompressed Key authenticatorData.AppendElements( pWebAuthNCredentialAttestation->pbAuthenticatorData + xOffset, 32); // X Coordinate authenticatorData.AppendElements( pWebAuthNCredentialAttestation->pbAuthenticatorData + yOffset, 32); // Y Coordinate authenticatorData.AppendElement( pWebAuthNCredentialAttestation->cbCredentialId); authenticatorData.AppendElements( pWebAuthNCredentialAttestation->pbCredentialId, pWebAuthNCredentialAttestation->cbCredentialId); authenticatorData.AppendElements(attestation->pX5c->pbData, attestation->pX5c->cbData); authenticatorData.AppendElements(attestation->pbSignature, attestation->cbSignature); } WebAuthnMakeCredentialResult result(aInfo.ClientDataJSON(), attObject, credentialId, authenticatorData); 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); } }