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 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); } }