diff --git a/dom/webauthn/AndroidWebAuthnTokenManager.cpp b/dom/webauthn/AndroidWebAuthnTokenManager.cpp index 7e6579e3adb6f..c69ae65c3e94a 100644 --- a/dom/webauthn/AndroidWebAuthnTokenManager.cpp +++ b/dom/webauthn/AndroidWebAuthnTokenManager.cpp @@ -1052,6 +1052,97 @@ AuthenticatorSelection ; / / +Get +extensions +bool +requestedCredProps += +false +; +for +( +const +WebAuthnExtension +& +ext +: +aInfo +. +Extensions +( +) +) +{ +if +( +ext +. +type +( +) += += +WebAuthnExtension +: +: +TWebAuthnExtensionCredProps +) +{ +requestedCredProps += +ext +. +get_WebAuthnExtensionCredProps +( +) +. +credProps +( +) +; +} +if +( +ext +. +type +( +) += += +WebAuthnExtension +: +: +TWebAuthnExtensionAppId +) +{ +GECKOBUNDLE_PUT +( +extensionsBundle +" +fidoAppId +" +jni +: +: +StringParam +( +ext +. +get_WebAuthnExtensionAppId +( +) +. +appIdentifier +( +) +) +) +; +} +} +/ +/ Unfortunately GMS ' @@ -1119,6 +1210,70 @@ residentKey ) ) ; +if +( +requestedCredProps +) +{ +/ +/ +In +WebAuthnTokenManager +. +java +we +set +the +" +requireResidentKey +" +/ +/ +parameter +to +true +if +and +only +if +" +residentKey +" +here +is +/ +/ +" +required +" +. +This +determines +the +credProps +extension +output +. +self +- +> +mRegisterCredPropsRk +. +emplace +( +sel +. +residentKey +( +) +. +EqualsLiteral +( +MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED +) +) +; +} } if ( @@ -1250,64 +1405,6 @@ ValueOf ; } } -/ -/ -Get -extensions -for -( -const -WebAuthnExtension -& -ext -: -aInfo -. -Extensions -( -) -) -{ -if -( -ext -. -type -( -) -= -= -WebAuthnExtension -: -: -TWebAuthnExtensionAppId -) -{ -GECKOBUNDLE_PUT -( -extensionsBundle -" -fidoAppId -" -jni -: -: -StringParam -( -ext -. -get_WebAuthnExtensionAppId -( -) -. -appIdentifier -( -) -) -) -; -} -} uidBuf . Assign @@ -1841,6 +1938,36 @@ WebAuthnExtensionResult > extensions ; +if +( +self +- +> +mRegisterCredPropsRk +. +isSome +( +) +) +{ +extensions +. +AppendElement +( +WebAuthnExtensionResultCredProps +( +self +- +> +mRegisterCredPropsRk +. +value +( +) +) +) +; +} WebAuthnMakeCredentialResult result ( diff --git a/dom/webauthn/AndroidWebAuthnTokenManager.h b/dom/webauthn/AndroidWebAuthnTokenManager.h index 89424434c4379..f34a1e847828a 100644 --- a/dom/webauthn/AndroidWebAuthnTokenManager.h +++ b/dom/webauthn/AndroidWebAuthnTokenManager.h @@ -827,6 +827,12 @@ NS_ERROR_DOM_UNKNOWN_ERR __func__ ) ; +mRegisterCredPropsRk += +Nothing +( +) +; } void AssertIsOnOwningThread @@ -846,6 +852,56 @@ U2FSignPromise > mSignPromise ; +/ +/ +The +Android +FIDO2 +API +doesn +' +t +accept +the +credProps +extension +. +However +the +/ +/ +appropriate +value +for +CredentialPropertiesOutput +. +rk +can +be +determined +/ +/ +entirely +from +the +input +so +we +cache +it +here +until +mRegisterPromise +/ +/ +resolves +. +Maybe +< +bool +> +mRegisterCredPropsRk +; } ; } diff --git a/dom/webauthn/CtapArgs.cpp b/dom/webauthn/CtapArgs.cpp index 0bdbf2d1af5f8..63fbeab829f42 100644 --- a/dom/webauthn/CtapArgs.cpp +++ b/dom/webauthn/CtapArgs.cpp @@ -570,6 +570,82 @@ NS_IMETHODIMP CtapRegisterArgs : : +GetCredProps +( +bool +* +aCredProps +) +{ +mozilla +: +: +ipc +: +: +AssertIsOnBackgroundThread +( +) +; +* +aCredProps += +false +; +for +( +const +WebAuthnExtension +& +ext +: +mInfo +. +Extensions +( +) +) +{ +if +( +ext +. +type +( +) += += +WebAuthnExtension +: +: +TWebAuthnExtensionCredProps +) +{ +* +aCredProps += +ext +. +get_WebAuthnExtensionCredProps +( +) +. +credProps +( +) +; +break +; +} +} +return +NS_OK +; +} +NS_IMETHODIMP +CtapRegisterArgs +: +: GetHmacCreateSecret ( bool diff --git a/dom/webauthn/PWebAuthnTransaction.ipdl b/dom/webauthn/PWebAuthnTransaction.ipdl index 831195e46f22b..75c6b923caf7e 100644 --- a/dom/webauthn/PWebAuthnTransaction.ipdl +++ b/dom/webauthn/PWebAuthnTransaction.ipdl @@ -244,6 +244,14 @@ appIdentifier } ; struct +WebAuthnExtensionCredProps +{ +bool +credProps +; +} +; +struct WebAuthnExtensionHmacSecret { bool @@ -256,6 +264,8 @@ WebAuthnExtension { WebAuthnExtensionAppId ; +WebAuthnExtensionCredProps +; WebAuthnExtensionHmacSecret ; } @@ -269,6 +279,14 @@ AppId } ; struct +WebAuthnExtensionResultCredProps +{ +bool +rk +; +} +; +struct WebAuthnExtensionResultHmacSecret { bool @@ -281,6 +299,8 @@ WebAuthnExtensionResult { WebAuthnExtensionResultAppId ; +WebAuthnExtensionResultCredProps +; WebAuthnExtensionResultHmacSecret ; } diff --git a/dom/webauthn/PublicKeyCredential.cpp b/dom/webauthn/PublicKeyCredential.cpp index 36dea71533a3d..2686a035b0fef 100644 --- a/dom/webauthn/PublicKeyCredential.cpp +++ b/dom/webauthn/PublicKeyCredential.cpp @@ -1204,6 +1204,35 @@ if ( mClientExtensionOutputs . +mCredProps +. +WasPassed +( +) +) +{ +json +. +mClientExtensionResults +. +mCredProps +. +Construct +( +mClientExtensionOutputs +. +mCredProps +. +Value +( +) +) +; +} +if +( +mClientExtensionOutputs +. mHmacCreateSecret . WasPassed @@ -1465,6 +1494,55 @@ void PublicKeyCredential : : +SetClientExtensionResultCredPropsRk +( +bool +aResult +) +{ +mClientExtensionOutputs +. +mCredProps +. +Construct +( +) +; +mClientExtensionOutputs +. +mCredProps +. +Value +( +) +. +mRk +. +Construct +( +) +; +mClientExtensionOutputs +. +mCredProps +. +Value +( +) +. +mRk +. +Value +( +) += +aResult +; +} +void +PublicKeyCredential +: +: SetClientExtensionResultHmacSecret ( bool @@ -2016,6 +2094,47 @@ Value ( ) . +mCredProps +. +WasPassed +( +) +) +{ +aResult +. +mExtensions +. +mCredProps +. +Construct +( +aOptions +. +mExtensions +. +Value +( +) +. +mCredProps +. +Value +( +) +) +; +} +if +( +aOptions +. +mExtensions +. +Value +( +) +. mHmacCreateSecret . WasPassed @@ -2352,6 +2471,47 @@ Value ( ) . +mCredProps +. +WasPassed +( +) +) +{ +aResult +. +mExtensions +. +mCredProps +. +Construct +( +aOptions +. +mExtensions +. +Value +( +) +. +mCredProps +. +Value +( +) +) +; +} +if +( +aOptions +. +mExtensions +. +Value +( +) +. mHmacCreateSecret . WasPassed diff --git a/dom/webauthn/PublicKeyCredential.h b/dom/webauthn/PublicKeyCredential.h index 17d49aa761a0d..ee4202461fed4 100644 --- a/dom/webauthn/PublicKeyCredential.h +++ b/dom/webauthn/PublicKeyCredential.h @@ -401,6 +401,13 @@ aResult ) ; void +SetClientExtensionResultCredPropsRk +( +bool +aResult +) +; +void SetClientExtensionResultHmacSecret ( bool diff --git a/dom/webauthn/WebAuthnController.cpp b/dom/webauthn/WebAuthnController.cpp index 7a1bdb2d53b8a..99c5ff3fd9c48 100644 --- a/dom/webauthn/WebAuthnController.cpp +++ b/dom/webauthn/WebAuthnController.cpp @@ -2882,6 +2882,60 @@ WebAuthnExtensionResult > extensions ; +bool +credPropsRk +; +rv += +aResult +- +> +GetCredPropsRk +( +& +credPropsRk +) +; +if +( +rv +! += +NS_ERROR_NOT_AVAILABLE +) +{ +if +( +NS_WARN_IF +( +NS_FAILED +( +rv +) +) +) +{ +AbortTransaction +( +aTransactionId +NS_ERROR_DOM_NOT_ALLOWED_ERR +true +) +; +return +; +} +extensions +. +AppendElement +( +WebAuthnExtensionResultCredProps +( +credPropsRk +) +) +; +} WebAuthnMakeCredentialResult result ( diff --git a/dom/webauthn/WebAuthnController.h b/dom/webauthn/WebAuthnController.h index 02167f3022518..ad284039fecab 100644 --- a/dom/webauthn/WebAuthnController.h +++ b/dom/webauthn/WebAuthnController.h @@ -705,10 +705,6 @@ const nsCString & aClientDataJSON -bool -aForceNoneAttestation -= -false ) : mTransactionId @@ -784,6 +780,9 @@ mAppIdHash nsCString mClientDataJSON ; +bool +mCredProps +; } ; Maybe diff --git a/dom/webauthn/WebAuthnManager.cpp b/dom/webauthn/WebAuthnManager.cpp index c00cce9126f33..9aabb58a51a0c 100644 --- a/dom/webauthn/WebAuthnManager.cpp +++ b/dom/webauthn/WebAuthnManager.cpp @@ -2988,6 +2988,49 @@ hmacCreateSecret ; } } +if +( +aOptions +. +mExtensions +. +mCredProps +. +WasPassed +( +) +) +{ +bool +credProps += +aOptions +. +mExtensions +. +mCredProps +. +Value +( +) +; +if +( +credProps +) +{ +extensions +. +AppendElement +( +WebAuthnExtensionCredProps +( +credProps +) +) +; +} +} const auto & @@ -4462,6 +4505,43 @@ extensions ; / / +credProps +is +only +supported +in +MakeCredentials +if +( +aOptions +. +mExtensions +. +mCredProps +. +WasPassed +( +) +) +{ +promise +- +> +MaybeReject +( +NS_ERROR_DOM_NOT_SUPPORTED_ERR +) +; +return +promise +. +forget +( +) +; +} +/ +/ < https : @@ -5191,6 +5271,43 @@ type WebAuthnExtensionResult : : +TWebAuthnExtensionResultCredProps +) +{ +bool +credPropsRk += +ext +. +get_WebAuthnExtensionResultCredProps +( +) +. +rk +( +) +; +credential +- +> +SetClientExtensionResultCredPropsRk +( +credPropsRk +) +; +} +if +( +ext +. +type +( +) += += +WebAuthnExtensionResult +: +: TWebAuthnExtensionResultHmacSecret ) { diff --git a/dom/webauthn/WinWebAuthnManager.cpp b/dom/webauthn/WinWebAuthnManager.cpp index 837ead9253a1d..572730e545b85 100644 --- a/dom/webauthn/WinWebAuthnManager.cpp +++ b/dom/webauthn/WinWebAuthnManager.cpp @@ -1105,20 +1105,6 @@ mTransactionParent = aTransactionParent ; -WEBAUTHN_EXTENSION -rgExtension -[ -1 -] -= -{ -} -; -DWORD -cExtensions -= -0 -; BOOL HmacCreateSecret = @@ -1829,6 +1815,53 @@ winAttestation WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY ; } +bool +requestedCredProps += +FALSE +; +/ +/ +The +number +of +entries +in +rgExtension +should +match +the +number +of +supported +/ +/ +extensions +. +/ +/ +Supported +extensions +: +credProps +hmac +- +secret +. +WEBAUTHN_EXTENSION +rgExtension +[ +2 +] += +{ +} +; +DWORD +cExtensions += +0 +; if ( aInfo @@ -1900,6 +1933,34 @@ type WebAuthnExtension : : +TWebAuthnExtensionCredProps +) +{ +requestedCredProps += +ext +. +get_WebAuthnExtensionCredProps +( +) +. +credProps +( +) +; +} +if +( +ext +. +type +( +) += += +WebAuthnExtension +: +: TWebAuthnExtensionHmacSecret ) { @@ -2747,6 +2808,88 @@ true } } } +/ +/ +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 +; +extensions +. +AppendElement +( +WebAuthnExtensionResultCredProps +( +rk += += +TRUE +) +) +; +} nsTArray < nsString diff --git a/dom/webauthn/authrs_bridge/src/lib.rs b/dom/webauthn/authrs_bridge/src/lib.rs index 42382a173ad57..f5f2053faebd6 100644 --- a/dom/webauthn/authrs_bridge/src/lib.rs +++ b/dom/webauthn/authrs_bridge/src/lib.rs @@ -971,6 +971,80 @@ usb xpcom_method ! ( +get_cred_props_rk += +> +GetCredPropsRk +( +) +- +> +bool +) +; +fn +get_cred_props_rk +( +& +self +) +- +> +Result +< +bool +nsresult +> +{ +let +result += +self +. +result +. +as_ref +( +) +. +or +( +Err +( +NS_ERROR_FAILURE +) +) +? +; +let +cred_props += +result +. +extensions +. +cred_props +. +as_ref +( +) +. +ok_or +( +NS_ERROR_NOT_AVAILABLE +) +? +; +Ok +( +cred_props +. +rk +) +} +xpcom_method +! +( get_status = > @@ -4417,6 +4491,29 @@ none " ) ; +let +mut +cred_props += +false +; +unsafe +{ +args +. +GetCredProps +( +& +mut +cred_props +) +} +. +to_result +( +) +? +; / / TODO @@ -4550,12 +4647,23 @@ user_verification_req resident_key_req extensions : +AuthenticationExtensionsClientInputs +{ +cred_props +: +Some +( +cred_props +) +. +. Default : : default ( ) +} pin : None diff --git a/dom/webauthn/authrs_bridge/src/test_token.rs b/dom/webauthn/authrs_bridge/src/test_token.rs index ed130a51a099d..5089453b816de 100644 --- a/dom/webauthn/authrs_bridge/src/test_token.rs +++ b/dom/webauthn/authrs_bridge/src/test_token.rs @@ -2499,17 +2499,26 @@ options : AuthenticatorOptions { +resident_key +: +self +. +has_resident_key pin_uv_auth_token : Some ( -true +self +. +has_user_verification ) user_verification : Some ( -true +self +. +has_user_verification ) . . diff --git a/dom/webauthn/nsIWebAuthnController.idl b/dom/webauthn/nsIWebAuthnController.idl index aad5f03d718ac..09fb179fdd7aa 100644 --- a/dom/webauthn/nsIWebAuthnController.idl +++ b/dom/webauthn/nsIWebAuthnController.idl @@ -455,6 +455,14 @@ must_use readonly attribute bool +credProps +; +[ +must_use +] +readonly +attribute +bool hmacCreateSecret ; / @@ -1069,6 +1077,11 @@ attribute bool hmacCreateSecret ; +readonly +attribute +bool +credPropsRk +; } ; [ diff --git a/dom/webauthn/tests/test_webauthn_make_credential.html b/dom/webauthn/tests/test_webauthn_make_credential.html index 1dee9a38682b1..62b3abf1b10f2 100644 --- a/dom/webauthn/tests/test_webauthn_make_credential.html +++ b/dom/webauthn/tests/test_webauthn_make_credential.html @@ -633,6 +633,21 @@ test_unknown_selection_criteria ) ; +add_task +( +test_no_unexpected_extensions +) +; +add_task +( +test_cred_props_with_rk_required +) +; +add_task +( +test_cred_props_with_rk_discouraged +) +; function arrivingHereIsGood ( @@ -2723,6 +2738,253 @@ ) ; } +async +function +test_no_unexpected_extensions +( +) +{ +let +makeCredentialOptions += +{ +rp +user +challenge +: +gCredentialChallenge +pubKeyCredParams +: +[ +param +] +} +; +let +cred += +await +credm +. +create +( +{ +publicKey +: +makeCredentialOptions +} +) +. +catch +( +arrivingHereIsBad +) +; +let +extensionResults += +cred +. +getClientExtensionResults +( +) +; +is +( +extensionResults +. +credProps +undefined +" +no +credProps +output +" +) +; +} +async +function +test_cred_props_with_rk_required +( +) +{ +let +makeCredentialOptions += +{ +rp +user +challenge +: +gCredentialChallenge +pubKeyCredParams +: +[ +param +] +authenticatorSelection +: +{ +authenticatorAttachment +: +" +cross +- +platform +" +residentKey +: +" +required +" +} +extensions +: +{ +credProps +: +true +} +} +; +let +cred += +await +credm +. +create +( +{ +publicKey +: +makeCredentialOptions +} +) +. +catch +( +arrivingHereIsBad +) +; +let +extensionResults += +cred +. +getClientExtensionResults +( +) +; +is +( +extensionResults +. +credProps +? +. +rk +true +" +rk +is +true +" +) +; +} +async +function +test_cred_props_with_rk_discouraged +( +) +{ +let +makeCredentialOptions += +{ +rp +user +challenge +: +gCredentialChallenge +pubKeyCredParams +: +[ +param +] +authenticatorSelection +: +{ +authenticatorAttachment +: +" +cross +- +platform +" +residentKey +: +" +discouraged +" +} +extensions +: +{ +credProps +: +true +} +} +; +let +cred += +await +credm +. +create +( +{ +publicKey +: +makeCredentialOptions +} +) +. +catch +( +arrivingHereIsBad +) +; +let +extensionResults += +cred +. +getClientExtensionResults +( +) +; +is +( +extensionResults +. +credProps +? +. +rk +false +" +rk +is +false +" +) +; +} < / script diff --git a/dom/webauthn/tests/test_webauthn_serialization.html b/dom/webauthn/tests/test_webauthn_serialization.html index c555599e620bc..3c8b5a4ceb2d8 100644 --- a/dom/webauthn/tests/test_webauthn_serialization.html +++ b/dom/webauthn/tests/test_webauthn_serialization.html @@ -2874,6 +2874,22 @@ cose_alg_ECDSA_w_SHA256 } ] +authenticatorSelection +: +{ +residentKey +: +" +discouraged +" +} +extensions +: +{ +credProps +: +true +} } ; let @@ -3157,6 +3173,32 @@ ( registrationResponseJSON . +clientExtensionResults +? +. +credProps +? +. +rk +false +" +registrationResponseJSON +. +clientExtensionResults +. +credProps +. +rk +should +be +false +" +) +; +is +( +registrationResponseJSON +. type " public diff --git a/dom/webidl/WebAuthentication.webidl b/dom/webidl/WebAuthentication.webidl index cc26c07747d78..2568dd1e79082 100644 --- a/dom/webidl/WebAuthentication.webidl +++ b/dom/webidl/WebAuthentication.webidl @@ -1280,6 +1280,50 @@ appid ; } ; +partial +dictionary +AuthenticationExtensionsClientInputs +{ +boolean +credProps +; +} +; +partial +dictionary +AuthenticationExtensionsClientInputsJSON +{ +boolean +credProps +; +} +; +dictionary +CredentialPropertiesOutput +{ +boolean +rk +; +} +; +partial +dictionary +AuthenticationExtensionsClientOutputs +{ +CredentialPropertiesOutput +credProps +; +} +; +partial +dictionary +AuthenticationExtensionsClientOutputsJSON +{ +CredentialPropertiesOutput +credProps +; +} +; / * * diff --git a/testing/web-platform/meta/webauthn/createcredential-resident-key.https.html.ini b/testing/web-platform/meta/webauthn/createcredential-resident-key.https.html.ini index acaea7378d084..93e7a1ca20f80 100644 --- a/testing/web-platform/meta/webauthn/createcredential-resident-key.https.html.ini +++ b/testing/web-platform/meta/webauthn/createcredential-resident-key.https.html.ini @@ -10,100 +10,6 @@ https html ] [ -U2F -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -discouraged -] -expected -: -FAIL -[ -U2F -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -preferred -] -expected -: -FAIL -[ -CTAP -2 -. -0 -without -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -discouraged -] -expected -: -FAIL -[ -CTAP -2 -. -0 -without -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -preferred -] -expected -: -FAIL -[ CTAP 2 . @@ -130,192 +36,3 @@ discouraged expected : FAIL -[ -CTAP -2 -. -0 -with -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -preferred -] -expected -: -FAIL -[ -CTAP -2 -. -0 -with -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -required -] -expected -: -FAIL -[ -CTAP -2 -. -1 -without -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -discouraged -] -expected -: -FAIL -[ -CTAP -2 -. -1 -without -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -preferred -] -expected -: -FAIL -[ -CTAP -2 -. -1 -with -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -discouraged -] -expected -: -FAIL -[ -CTAP -2 -. -1 -with -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -preferred -] -expected -: -FAIL -[ -CTAP -2 -. -1 -with -resident -key -support -: -navigator -. -credentials -. -create -( -) -with -credProps -extension -rk -= -required -] -expected -: -FAIL diff --git a/testing/web-platform/meta/webauthn/getcredential-extensions.https.html.ini b/testing/web-platform/meta/webauthn/getcredential-extensions.https.html.ini index ff89e0fb526f0..f829fbaf57686 100644 --- a/testing/web-platform/meta/webauthn/getcredential-extensions.https.html.ini +++ b/testing/web-platform/meta/webauthn/getcredential-extensions.https.html.ini @@ -8,17 +8,6 @@ https html ] [ -credProps -is -only -supported -at -registration -] -expected -: -FAIL -[ navigator . credentials diff --git a/testing/web-platform/meta/webauthn/remote-desktop-client-override.tentative.https.html.ini b/testing/web-platform/meta/webauthn/remote-desktop-client-override.tentative.https.html.ini index 62a88b09bb6e9..dfb35353dcada 100644 --- a/testing/web-platform/meta/webauthn/remote-desktop-client-override.tentative.https.html.ini +++ b/testing/web-platform/meta/webauthn/remote-desktop-client-override.tentative.https.html.ini @@ -27,3 +27,13 @@ site expected : FAIL +[ +create +( +) +with +remoteDesktopClientOverride +] +expected +: +FAIL