tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 47aa4a24ba2dc325b254112f2c571644cf1d62fa
parent 654639947879cebd1776509f4fd08b114f0339d1
Author: John M. Schanck <jschanck@mozilla.com>
Date:   Mon, 10 Nov 2025 18:16:08 +0000

Bug 1993280 - support WebAuthn PRF evaluation at registration on Windows. r=keeler

Differential Revision: https://phabricator.services.mozilla.com/D271515

Diffstat:
Mdom/webauthn/PublicKeyCredential.cpp | 26++++++++++++++++++++++++++
Mdom/webauthn/WebAuthnResult.h | 15+++++++++++++++
Mdom/webauthn/WinWebAuthnService.cpp | 18+++++++++++++++++-
3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/dom/webauthn/PublicKeyCredential.cpp b/dom/webauthn/PublicKeyCredential.cpp @@ -369,6 +369,32 @@ void PublicKeyCredential::ToJSON(JSContext* aCx, json.mClientExtensionResults.mPrf.Value().mEnabled.Construct( mClientExtensionOutputs.mPrf.Value().mEnabled.Value()); } + if (mPrfResultsFirst.isSome()) { + AuthenticationExtensionsPRFValuesJSON& dest = + json.mClientExtensionResults.mPrf.Value().mResults.Construct(); + nsCString prfFirst; + nsresult rv = mozilla::Base64URLEncode( + mPrfResultsFirst->Length(), mPrfResultsFirst->Elements(), + Base64URLEncodePaddingPolicy::Omit, prfFirst); + if (NS_FAILED(rv)) { + aError.ThrowEncodingError( + "could not encode first prf output as urlsafe base64"); + return; + } + dest.mFirst.Assign(NS_ConvertUTF8toUTF16(prfFirst)); + if (mPrfResultsSecond.isSome()) { + nsCString prfSecond; + nsresult rv = mozilla::Base64URLEncode( + mPrfResultsSecond->Length(), mPrfResultsSecond->Elements(), + Base64URLEncodePaddingPolicy::Omit, prfSecond); + if (NS_FAILED(rv)) { + aError.ThrowEncodingError( + "could not encode second prf output as urlsafe base64"); + return; + } + dest.mSecond.Construct(NS_ConvertUTF8toUTF16(prfSecond)); + } + } } if (mClientExtensionOutputs.mLargeBlob.WasPassed()) { const AuthenticationExtensionsLargeBlobOutputs& src = diff --git a/dom/webauthn/WebAuthnResult.h b/dom/webauthn/WebAuthnResult.h @@ -124,6 +124,21 @@ class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult { } } + if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_7) { + if (aResponse->pHmacSecret) { + if (aResponse->pHmacSecret->cbFirst > 0) { + mPrfFirst.emplace(); + mPrfFirst->AppendElements(aResponse->pHmacSecret->pbFirst, + aResponse->pHmacSecret->cbFirst); + } + if (aResponse->pHmacSecret->cbSecond > 0) { + mPrfSecond.emplace(); + mPrfSecond->AppendElements(aResponse->pHmacSecret->pbSecond, + aResponse->pHmacSecret->cbSecond); + } + } + } + if (aResponse->dwVersion >= WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) { if (aResponse->dwUsedTransport & WEBAUTHN_CTAP_TRANSPORT_USB) { mTransports.AppendElement(u"usb"_ns); diff --git a/dom/webauthn/WinWebAuthnService.cpp b/dom/webauthn/WinWebAuthnService.cpp @@ -526,6 +526,22 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId, }); } + nsTArray<uint8_t> prfEvalFirst; + nsTArray<uint8_t> prfEvalSecond; + WEBAUTHN_HMAC_SECRET_SALT prfGlobalEval = {0}; + if (requestedPrf) { + rv = aArgs->GetPrfEvalFirst(prfEvalFirst); + if (rv == NS_OK) { + prfGlobalEval.cbFirst = prfEvalFirst.Length(); + prfGlobalEval.pbFirst = prfEvalFirst.Elements(); + } + rv = aArgs->GetPrfEvalSecond(prfEvalSecond); + if (rv == NS_OK) { + prfGlobalEval.cbSecond = prfEvalSecond.Length(); + prfGlobalEval.pbSecond = prfEvalSecond.Elements(); + } + } + bool requestedMinPinLength; if (NS_SUCCEEDED(aArgs->GetMinPinLength(&requestedMinPinLength)) && requestedMinPinLength) { @@ -636,7 +652,7 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId, NULL, // LinkedDevice 0, // size of JsonExt NULL, // JsonExt - NULL, // PRFGlobalEval + &prfGlobalEval, // PRFGlobalEval (DWORD)hints.Length(), // Size of CredentialHints hints.Elements(), // CredentialHints };