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