diff --git a/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html index 73a8b2bf4e29..b77a86839297 100644 --- a/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html +++ b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html @@ -72,8 +72,7 @@ async function addVirtualAuthenticator() { add_task(async () => { await SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], - ["security.webauth.webauthn_enable_usbtoken", false], - ["security.webauth.webauthn_enable_android_fido2", false]]}); + ["security.webauth.webauthn_enable_usbtoken", false]]}); await addVirtualAuthenticator(); }); diff --git a/dom/webauthn/AndroidWebAuthnService.cpp b/dom/webauthn/AndroidWebAuthnService.cpp new file mode 100644 index 000000000000..5005e93a58fc --- /dev/null +++ b/dom/webauthn/AndroidWebAuthnService.cpp @@ -0,0 +1,384 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/StaticPtr.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/jni/GeckoBundleUtils.h" + +#include "AndroidWebAuthnService.h" +#include "JavaBuiltins.h" +#include "JavaExceptions.h" +#include "WebAuthnPromiseHolder.h" +#include "WebAuthnEnumStrings.h" +#include "WebAuthnResult.h" +#include "mozilla/StaticPrefs_security.h" +#include "mozilla/java/WebAuthnTokenManagerWrappers.h" +#include "mozilla/jni/Conversions.h" + +namespace mozilla { +namespace jni { +template <> +dom::AndroidWebAuthnError Java2Native(mozilla::jni::Object::Param aData, + JNIEnv* aEnv) { + MOZ_ASSERT(aData.IsInstanceOf()); + java::sdk::Throwable::LocalRef throwable(aData); + return dom::AndroidWebAuthnError(throwable->GetMessage()->ToString()); +} +} // namespace jni + +namespace dom { + +NS_IMPL_ISUPPORTS(AndroidWebAuthnService, nsIWebAuthnService) + +NS_IMETHODIMP +AndroidWebAuthnService::MakeCredential(uint64_t aTransactionId, + uint64_t browsingContextId, + nsIWebAuthnRegisterArgs* aArgs, + nsIWebAuthnRegisterPromise* aPromise) { + Reset(); + + GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( + "java::WebAuthnTokenManager::WebAuthnMakeCredential", + [aArgs = RefPtr{aArgs}, aPromise = RefPtr{aPromise}]() { + AssertIsOnMainThread(); + + GECKOBUNDLE_START(credentialBundle); + GECKOBUNDLE_PUT(credentialBundle, "isWebAuthn", + java::sdk::Integer::ValueOf(1)); + + nsString rpId; + Unused << aArgs->GetRpId(rpId); + GECKOBUNDLE_PUT(credentialBundle, "rpId", jni::StringParam(rpId)); + + nsString rpName; + Unused << aArgs->GetRpName(rpName); + GECKOBUNDLE_PUT(credentialBundle, "rpName", jni::StringParam(rpName)); + + nsString userName; + Unused << aArgs->GetUserName(userName); + GECKOBUNDLE_PUT(credentialBundle, "userName", + jni::StringParam(userName)); + + nsString userDisplayName; + Unused << aArgs->GetUserDisplayName(userDisplayName); + GECKOBUNDLE_PUT(credentialBundle, "userDisplayName", + jni::StringParam(userDisplayName)); + + nsString origin; + Unused << aArgs->GetOrigin(origin); + GECKOBUNDLE_PUT(credentialBundle, "origin", jni::StringParam(origin)); + + uint32_t timeout; + Unused << aArgs->GetTimeoutMS(&timeout); + GECKOBUNDLE_PUT(credentialBundle, "timeoutMS", + java::sdk::Double::New(timeout)); + GECKOBUNDLE_FINISH(credentialBundle); + + nsTArray userId; + Unused << aArgs->GetUserId(userId); + jni::ByteBuffer::LocalRef uid = jni::ByteBuffer::New( + const_cast(static_cast(userId.Elements())), + userId.Length()); + + nsTArray challBuf; + nsresult rv = aArgs->GetClientDataHash(challBuf); + if (NS_FAILED(rv)) { + aPromise->Reject(rv); + return; + } + jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New( + const_cast(static_cast(challBuf.Elements())), + challBuf.Length()); + + nsTArray> excludeList; + Unused << aArgs->GetExcludeList(excludeList); + jni::ObjectArray::LocalRef idList = + jni::ObjectArray::New(excludeList.Length()); + int ix = 0; + for (const nsTArray& credId : excludeList) { + jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New( + const_cast(static_cast(credId.Elements())), + credId.Length()); + + idList->SetElement(ix, id); + + ix += 1; + } + + nsTArray transportBuf; + /* Bug 1857335 - nsIWebAuthnRegisterArgs doesn't expose the transports + * associated with the allowList entries. They're optional, so it's + * not critical that we include them. */ + jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New( + const_cast( + static_cast(transportBuf.Elements())), + transportBuf.Length()); + + GECKOBUNDLE_START(authSelBundle); + // Add UI support to consent to attestation, bug 1550164 + GECKOBUNDLE_PUT(authSelBundle, "attestationPreference", + jni::StringParam(u"none"_ns)); + + nsString residentKey; + Unused << aArgs->GetResidentKey(residentKey); + + // Get extensions + bool requestedCredProps; + Unused << aArgs->GetCredProps(&requestedCredProps); + + // Unfortunately, GMS's FIDO2 API has no option for Passkey. If using + // residentKey, credential will be synced with Passkey via Google + // account or credential provider service. So this is experimental. + Maybe credPropsResponse; + if (requestedCredProps && + StaticPrefs:: + security_webauthn_webauthn_enable_android_fido2_residentkey()) { + GECKOBUNDLE_PUT(authSelBundle, "residentKey", + jni::StringParam(residentKey)); + bool residentKeyRequired = residentKey.EqualsLiteral( + MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED); + credPropsResponse = Some(residentKeyRequired); + } + + nsString userVerification; + Unused << aArgs->GetUserVerification(userVerification); + if (userVerification.EqualsLiteral( + MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) { + GECKOBUNDLE_PUT(authSelBundle, "requireUserVerification", + java::sdk::Integer::ValueOf(1)); + } + + nsString authenticatorAttachment; + rv = aArgs->GetAuthenticatorAttachment(authenticatorAttachment); + if (rv != NS_ERROR_NOT_AVAILABLE) { + if (NS_FAILED(rv)) { + aPromise->Reject(rv); + return; + } + if (authenticatorAttachment.EqualsLiteral( + MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) { + GECKOBUNDLE_PUT(authSelBundle, "requirePlatformAttachment", + java::sdk::Integer::ValueOf(1)); + } else if ( + authenticatorAttachment.EqualsLiteral( + MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) { + GECKOBUNDLE_PUT(authSelBundle, "requireCrossPlatformAttachment", + java::sdk::Integer::ValueOf(1)); + } + } + GECKOBUNDLE_FINISH(authSelBundle); + + GECKOBUNDLE_START(extensionsBundle); + GECKOBUNDLE_FINISH(extensionsBundle); + + auto result = java::WebAuthnTokenManager::WebAuthnMakeCredential( + credentialBundle, uid, challenge, idList, transportList, + authSelBundle, extensionsBundle); + + auto geckoResult = java::GeckoResult::LocalRef(std::move(result)); + + MozPromise, AndroidWebAuthnError, + true>::FromGeckoResult(geckoResult) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [aPromise, credPropsResponse = std::move(credPropsResponse)]( + RefPtr&& aValue) { + if (credPropsResponse.isSome()) { + Unused << aValue->SetCredPropsRk(credPropsResponse.ref()); + } + aPromise->Resolve(aValue); + }, + [aPromise](AndroidWebAuthnError&& aValue) { + aPromise->Reject(aValue.GetError()); + }); + })); + + return NS_OK; +} + +NS_IMETHODIMP +AndroidWebAuthnService::GetAssertion(uint64_t aTransactionId, + uint64_t browsingContextId, + nsIWebAuthnSignArgs* aArgs, + nsIWebAuthnSignPromise* aPromise) { + Reset(); + + GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( + "java::WebAuthnTokenManager::WebAuthnGetAssertion", + [self = RefPtr{this}, aArgs = RefPtr{aArgs}, + aPromise = RefPtr{aPromise}]() { + AssertIsOnMainThread(); + + nsTArray challBuf; + nsresult rv = aArgs->GetClientDataHash(challBuf); + if (NS_FAILED(rv)) { + aPromise->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR); + return; + } + jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New( + const_cast(static_cast(challBuf.Elements())), + challBuf.Length()); + + nsTArray> allowList; + Unused << aArgs->GetAllowList(allowList); + jni::ObjectArray::LocalRef idList = + jni::ObjectArray::New(allowList.Length()); + int ix = 0; + for (const nsTArray& credId : allowList) { + jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New( + const_cast(static_cast(credId.Elements())), + credId.Length()); + + idList->SetElement(ix, id); + + ix += 1; + } + + nsTArray transportBuf; + /* Bug 1857335 - nsIWebAuthnSignArgs doesn't expose the transports + * associated with the allowList entries. They're optional, so it's + * not critical that we include them. */ + jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New( + const_cast( + static_cast(transportBuf.Elements())), + transportBuf.Length()); + + GECKOBUNDLE_START(assertionBundle); + + GECKOBUNDLE_PUT(assertionBundle, "isWebAuthn", + java::sdk::Integer::ValueOf(1)); + + nsString rpId; + Unused << aArgs->GetRpId(rpId); + GECKOBUNDLE_PUT(assertionBundle, "rpId", jni::StringParam(rpId)); + + nsString origin; + Unused << aArgs->GetOrigin(origin); + GECKOBUNDLE_PUT(assertionBundle, "origin", jni::StringParam(origin)); + + uint32_t timeout; + Unused << aArgs->GetTimeoutMS(&timeout); + GECKOBUNDLE_PUT(assertionBundle, "timeoutMS", + java::sdk::Double::New(timeout)); + + // User Verification Requirement is not currently used in the + // Android FIDO API. + + GECKOBUNDLE_FINISH(assertionBundle); + + GECKOBUNDLE_START(extensionsBundle); + + nsString appId; + rv = aArgs->GetAppId(appId); + if (rv != NS_ERROR_NOT_AVAILABLE) { + if (NS_FAILED(rv)) { + aPromise->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR); + return; + } + GECKOBUNDLE_PUT(extensionsBundle, "fidoAppId", + jni::StringParam(appId)); + } + + GECKOBUNDLE_FINISH(extensionsBundle); + + auto result = java::WebAuthnTokenManager::WebAuthnGetAssertion( + challenge, idList, transportList, assertionBundle, + extensionsBundle); + auto geckoResult = java::GeckoResult::LocalRef(std::move(result)); + MozPromise, AndroidWebAuthnError, + true>::FromGeckoResult(geckoResult) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [aPromise](RefPtr&& aValue) { + aPromise->Resolve(aValue); + }, + [aPromise](AndroidWebAuthnError&& aValue) { + aPromise->Reject(aValue.GetError()); + }); + })); + + return NS_OK; +} + +NS_IMETHODIMP +AndroidWebAuthnService::Reset() { + mRegisterCredPropsRk = Nothing(); + return NS_OK; +} + +NS_IMETHODIMP +AndroidWebAuthnService::Cancel(uint64_t aTransactionId) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::PinCallback(uint64_t aTransactionId, + const nsACString& aPin) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::ResumeMakeCredential(uint64_t aTransactionId, + bool aForceNoneAttestation) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::SelectionCallback(uint64_t aTransactionId, + uint64_t aIndex) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::AddVirtualAuthenticator( + const nsACString& protocol, const nsACString& transport, + bool hasResidentKey, bool hasUserVerification, bool isUserConsenting, + bool isUserVerified, uint64_t* _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::AddCredential(uint64_t authenticatorId, + const nsACString& credentialId, + bool isResidentCredential, + const nsACString& rpId, + const nsACString& privateKey, + const nsACString& userHandle, + uint32_t signCount) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::GetCredentials( + uint64_t authenticatorId, + nsTArray>& _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::RemoveCredential(uint64_t authenticatorId, + const nsACString& credentialId) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AndroidWebAuthnService::SetUserVerified(uint64_t authenticatorId, + bool isUserVerified) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/webauthn/AndroidWebAuthnTokenManager.h b/dom/webauthn/AndroidWebAuthnService.h similarity index 56% rename from dom/webauthn/AndroidWebAuthnTokenManager.h rename to dom/webauthn/AndroidWebAuthnService.h index ebb0ac033e0b..ab48be486733 100644 --- a/dom/webauthn/AndroidWebAuthnTokenManager.h +++ b/dom/webauthn/AndroidWebAuthnService.h @@ -4,13 +4,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_dom_AndroidWebAuthnTokenManager_h -#define mozilla_dom_AndroidWebAuthnTokenManager_h +#ifndef mozilla_dom_AndroidWebAuthnService_h_ +#define mozilla_dom_AndroidWebAuthnService_h_ -#include "mozilla/dom/U2FTokenTransport.h" #include "mozilla/java/WebAuthnTokenManagerNatives.h" +#include "nsIWebAuthnService.h" namespace mozilla { + namespace dom { // Collected from @@ -27,27 +28,13 @@ constexpr auto kTimeoutError = u"TIMEOUT_ERR"_ns; constexpr auto kNetworkError = u"NETWORK_ERR"_ns; constexpr auto kUnknownError = u"UNKNOWN_ERR"_ns; -class AndroidWebAuthnResult { +class AndroidWebAuthnError { public: - explicit AndroidWebAuthnResult(const nsAString& aErrorCode) + explicit AndroidWebAuthnError(const nsAString& aErrorCode) : mErrorCode(aErrorCode) {} - explicit AndroidWebAuthnResult( - const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef& - aResponse); - - explicit AndroidWebAuthnResult( - const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef& - aResponse); - - AndroidWebAuthnResult() = delete; - - bool IsError() const { return NS_FAILED(GetError()); } - nsresult GetError() const { - if (mErrorCode.IsEmpty()) { - return NS_OK; - } else if (mErrorCode.Equals(kSecurityError)) { + if (mErrorCode.Equals(kSecurityError)) { return NS_ERROR_DOM_SECURITY_ERR; } else if (mErrorCode.Equals(kConstraintError)) { // TODO: The message is right, but it's not about indexeddb. @@ -79,63 +66,19 @@ class AndroidWebAuthnResult { } } - AndroidWebAuthnResult(const AndroidWebAuthnResult&) = delete; - AndroidWebAuthnResult(AndroidWebAuthnResult&&) = default; - - // Attestation-only - nsTArray mAttObj; - nsTArray mTransports; - - // Attestations and assertions - nsTArray mKeyHandle; - nsCString mClientDataJSON; - - // Assertions-only - nsTArray mAuthData; - nsTArray mSignature; - nsTArray mUserHandle; - private: const nsString mErrorCode; }; -/* - * WebAuthnAndroidTokenManager is a token implementation communicating with - * Android Fido2 APIs. - */ -class AndroidWebAuthnTokenManager final : public U2FTokenTransport { +class AndroidWebAuthnService final : public nsIWebAuthnService { public: - explicit AndroidWebAuthnTokenManager(); - ~AndroidWebAuthnTokenManager() {} + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNSERVICE - virtual RefPtr Register( - const WebAuthnMakeCredentialInfo& aInfo, - bool aForceNoneAttestation) override; - - virtual RefPtr Sign( - const WebAuthnGetAssertionInfo& aInfo) override; - - void Cancel() override; - - void Drop() override; - - static AndroidWebAuthnTokenManager* GetInstance(); + AndroidWebAuthnService() = default; private: - void HandleRegisterResult(AndroidWebAuthnResult&& aResult); - - void HandleSignResult(AndroidWebAuthnResult&& aResult); - - void ClearPromises() { - mRegisterPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__); - mSignPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__); - mRegisterCredPropsRk = Nothing(); - } - - void AssertIsOnOwningThread() const; - - MozPromiseHolder mRegisterPromise; - MozPromiseHolder mSignPromise; + ~AndroidWebAuthnService() = default; // The Android FIDO2 API doesn't accept the credProps extension. However, the // appropriate value for CredentialPropertiesOutput.rk can be determined @@ -147,4 +90,4 @@ class AndroidWebAuthnTokenManager final : public U2FTokenTransport { } // namespace dom } // namespace mozilla -#endif // mozilla_dom_AndroidWebAuthnTokenManager_h +#endif // mozilla_dom_AndroidWebAuthnService_h_ diff --git a/dom/webauthn/AndroidWebAuthnTokenManager.cpp b/dom/webauthn/AndroidWebAuthnTokenManager.cpp deleted file mode 100644 index 0c1a697f5993..000000000000 --- a/dom/webauthn/AndroidWebAuthnTokenManager.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ipc/BackgroundParent.h" -#include "mozilla/jni/GeckoBundleUtils.h" -#include "mozilla/StaticPtr.h" - -#include "AndroidWebAuthnTokenManager.h" -#include "JavaBuiltins.h" -#include "JavaExceptions.h" -#include "mozilla/java/WebAuthnTokenManagerWrappers.h" -#include "mozilla/jni/Conversions.h" -#include "mozilla/StaticPrefs_security.h" -#include "WebAuthnEnumStrings.h" - -namespace mozilla { -namespace jni { - -template <> -dom::AndroidWebAuthnResult Java2Native(mozilla::jni::Object::Param aData, - JNIEnv* aEnv) { - // TODO: - // AndroidWebAuthnResult stores successful both result and failure result. - // We should split it into success and failure (Bug 1754157) - if (aData.IsInstanceOf()) { - java::sdk::Throwable::LocalRef throwable(aData); - return dom::AndroidWebAuthnResult(throwable->GetMessage()->ToString()); - } - - if (aData - .IsInstanceOf()) { - java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef response( - aData); - return dom::AndroidWebAuthnResult(response); - } - - MOZ_ASSERT( - aData.IsInstanceOf()); - java::WebAuthnTokenManager::GetAssertionResponse::LocalRef response(aData); - return dom::AndroidWebAuthnResult(response); -} -} // namespace jni - -namespace dom { - -static nsIThread* gAndroidPBackgroundThread; - -StaticRefPtr gAndroidWebAuthnManager; - -/* static */ AndroidWebAuthnTokenManager* -AndroidWebAuthnTokenManager::GetInstance() { - if (!gAndroidWebAuthnManager) { - mozilla::ipc::AssertIsOnBackgroundThread(); - gAndroidWebAuthnManager = new AndroidWebAuthnTokenManager(); - } - return gAndroidWebAuthnManager; -} - -AndroidWebAuthnTokenManager::AndroidWebAuthnTokenManager() { - mozilla::ipc::AssertIsOnBackgroundThread(); - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(!gAndroidWebAuthnManager); - - gAndroidPBackgroundThread = NS_GetCurrentThread(); - MOZ_ASSERT(gAndroidPBackgroundThread, "This should never be null!"); - gAndroidWebAuthnManager = this; -} - -void AndroidWebAuthnTokenManager::AssertIsOnOwningThread() const { - mozilla::ipc::AssertIsOnBackgroundThread(); - MOZ_ASSERT(gAndroidPBackgroundThread); -#ifdef DEBUG - bool current; - MOZ_ASSERT( - NS_SUCCEEDED(gAndroidPBackgroundThread->IsOnCurrentThread(¤t))); - MOZ_ASSERT(current); -#endif -} - -void AndroidWebAuthnTokenManager::Drop() { - AssertIsOnOwningThread(); - - ClearPromises(); - gAndroidWebAuthnManager = nullptr; - gAndroidPBackgroundThread = nullptr; -} - -RefPtr AndroidWebAuthnTokenManager::Register( - const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) { - AssertIsOnOwningThread(); - - ClearPromises(); - - GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( - "java::WebAuthnTokenManager::WebAuthnMakeCredential", - [self = RefPtr{this}, aInfo, aForceNoneAttestation]() { - AssertIsOnMainThread(); - - // Produce the credential exclusion list - jni::ObjectArray::LocalRef idList = - jni::ObjectArray::New(aInfo.ExcludeList().Length()); - - nsTArray transportBuf; - int ix = 0; - - for (const WebAuthnScopedCredential& cred : aInfo.ExcludeList()) { - jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New( - const_cast(static_cast(cred.id().Elements())), - cred.id().Length()); - - idList->SetElement(ix, id); - transportBuf.AppendElement(cred.transports()); - - ix += 1; - } - - jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New( - const_cast( - static_cast(transportBuf.Elements())), - transportBuf.Length()); - - const nsTArray& challBuf = aInfo.Challenge(); - jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New( - const_cast(static_cast(challBuf.Elements())), - challBuf.Length()); - - nsTArray uidBuf; - - // Get authenticator selection criteria - GECKOBUNDLE_START(authSelBundle); - GECKOBUNDLE_START(extensionsBundle); - GECKOBUNDLE_START(credentialBundle); - - const auto& rp = aInfo.Rp(); - const auto& user = aInfo.User(); - - GECKOBUNDLE_PUT(credentialBundle, "isWebAuthn", - java::sdk::Integer::ValueOf(1)); - - // Get the attestation preference and override if the user asked - if (aForceNoneAttestation) { - // Add UI support to trigger this, bug 1550164 - GECKOBUNDLE_PUT(authSelBundle, "attestationPreference", - jni::StringParam(u"none"_ns)); - } else { - const nsString& attestation = aInfo.attestationConveyancePreference(); - GECKOBUNDLE_PUT(authSelBundle, "attestationPreference", - jni::StringParam(attestation)); - } - - const WebAuthnAuthenticatorSelection& sel = - aInfo.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's FIDO2 API has no option for Passkey. If using - // residentKey, credential will be synced with Passkey via Google - // account or credential provider service. So this is experimental. - if (StaticPrefs:: - security_webauthn_webauthn_enable_android_fido2_residentkey()) { - GECKOBUNDLE_PUT(authSelBundle, "residentKey", - jni::StringParam(sel.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 (sel.userVerificationRequirement().EqualsLiteral( - MOZ_WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED)) { - GECKOBUNDLE_PUT(authSelBundle, "requireUserVerification", - java::sdk::Integer::ValueOf(1)); - } - - if (sel.authenticatorAttachment().isSome()) { - const nsString& authenticatorAttachment = - sel.authenticatorAttachment().value(); - if (authenticatorAttachment.EqualsLiteral( - MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM)) { - GECKOBUNDLE_PUT(authSelBundle, "requirePlatformAttachment", - java::sdk::Integer::ValueOf(1)); - } else if ( - authenticatorAttachment.EqualsLiteral( - MOZ_WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM)) { - GECKOBUNDLE_PUT(authSelBundle, "requireCrossPlatformAttachment", - java::sdk::Integer::ValueOf(1)); - } - } - - uidBuf.Assign(user.Id()); - - GECKOBUNDLE_PUT(credentialBundle, "rpName", - jni::StringParam(rp.Name())); - GECKOBUNDLE_PUT(credentialBundle, "userName", - jni::StringParam(user.Name())); - GECKOBUNDLE_PUT(credentialBundle, "userDisplayName", - jni::StringParam(user.DisplayName())); - - GECKOBUNDLE_PUT(credentialBundle, "rpId", - jni::StringParam(aInfo.RpId())); - GECKOBUNDLE_PUT(credentialBundle, "origin", - jni::StringParam(aInfo.Origin())); - GECKOBUNDLE_PUT(credentialBundle, "timeoutMS", - java::sdk::Double::New(aInfo.TimeoutMS())); - - GECKOBUNDLE_FINISH(authSelBundle); - GECKOBUNDLE_FINISH(extensionsBundle); - GECKOBUNDLE_FINISH(credentialBundle); - - // For non-WebAuthn cases, uidBuf is empty (and unused) - jni::ByteBuffer::LocalRef uid = jni::ByteBuffer::New( - const_cast(static_cast(uidBuf.Elements())), - uidBuf.Length()); - - auto result = java::WebAuthnTokenManager::WebAuthnMakeCredential( - credentialBundle, uid, challenge, idList, transportList, - authSelBundle, extensionsBundle); - auto geckoResult = java::GeckoResult::LocalRef(std::move(result)); - // This is likely running on the main thread, so we'll always dispatch - // to the background for state updates. - MozPromise::FromGeckoResult(geckoResult) - ->Then( - GetMainThreadSerialEventTarget(), __func__, - [self = std::move(self)](AndroidWebAuthnResult&& aValue) { - self->HandleRegisterResult(std::move(aValue)); - }, - [self = std::move(self)](AndroidWebAuthnResult&& aValue) { - self->HandleRegisterResult(std::move(aValue)); - }); - })); - - return mRegisterPromise.Ensure(__func__); -} - -void AndroidWebAuthnTokenManager::HandleRegisterResult( - AndroidWebAuthnResult&& aResult) { - if (!gAndroidPBackgroundThread) { - // Promise is already rejected when shutting down background thread - return; - } - // This is likely running on the main thread, so we'll always dispatch to the - // background for state updates. - if (aResult.IsError()) { - nsresult aError = aResult.GetError(); - - gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction( - "AndroidWebAuthnTokenManager::RegisterAbort", - [self = RefPtr(this), aError]() { - self->mRegisterPromise.RejectIfExists(aError, __func__); - })); - } else { - gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction( - "AndroidWebAuthnTokenManager::RegisterComplete", - [self = RefPtr(this), - aResult = std::move(aResult)]() { - nsTArray extensions; - if (self->mRegisterCredPropsRk.isSome()) { - extensions.AppendElement(WebAuthnExtensionResultCredProps( - self->mRegisterCredPropsRk.value())); - } - WebAuthnMakeCredentialResult result( - aResult.mClientDataJSON, aResult.mAttObj, aResult.mKeyHandle, - aResult.mTransports, extensions); - self->mRegisterPromise.Resolve(std::move(result), __func__); - })); - } -} - -RefPtr AndroidWebAuthnTokenManager::Sign( - const WebAuthnGetAssertionInfo& aInfo) { - AssertIsOnOwningThread(); - - ClearPromises(); - - GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( - "java::WebAuthnTokenManager::WebAuthnGetAssertion", - [self = RefPtr{this}, aInfo]() { - AssertIsOnMainThread(); - - jni::ObjectArray::LocalRef idList = - jni::ObjectArray::New(aInfo.AllowList().Length()); - - nsTArray transportBuf; - - int ix = 0; - for (const WebAuthnScopedCredential& cred : aInfo.AllowList()) { - jni::ByteBuffer::LocalRef id = jni::ByteBuffer::New( - const_cast(static_cast(cred.id().Elements())), - cred.id().Length()); - - idList->SetElement(ix, id); - transportBuf.AppendElement(cred.transports()); - - ix += 1; - } - - jni::ByteBuffer::LocalRef transportList = jni::ByteBuffer::New( - const_cast( - static_cast(transportBuf.Elements())), - transportBuf.Length()); - - const nsTArray& challBuf = aInfo.Challenge(); - jni::ByteBuffer::LocalRef challenge = jni::ByteBuffer::New( - const_cast(static_cast(challBuf.Elements())), - challBuf.Length()); - - // Get extensions - GECKOBUNDLE_START(assertionBundle); - GECKOBUNDLE_START(extensionsBundle); - - GECKOBUNDLE_PUT(assertionBundle, "isWebAuthn", - java::sdk::Integer::ValueOf(1)); - - // User Verification Requirement is not currently used in the - // Android FIDO API. Adding it should look like - // AttestationConveyancePreference - - for (const WebAuthnExtension& ext : aInfo.Extensions()) { - if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) { - GECKOBUNDLE_PUT( - extensionsBundle, "fidoAppId", - jni::StringParam( - ext.get_WebAuthnExtensionAppId().appIdentifier())); - } - } - - GECKOBUNDLE_PUT(assertionBundle, "rpId", - jni::StringParam(aInfo.RpId())); - GECKOBUNDLE_PUT(assertionBundle, "origin", - jni::StringParam(aInfo.Origin())); - GECKOBUNDLE_PUT(assertionBundle, "timeoutMS", - java::sdk::Double::New(aInfo.TimeoutMS())); - - GECKOBUNDLE_FINISH(assertionBundle); - GECKOBUNDLE_FINISH(extensionsBundle); - - auto result = java::WebAuthnTokenManager::WebAuthnGetAssertion( - challenge, idList, transportList, assertionBundle, - extensionsBundle); - auto geckoResult = java::GeckoResult::LocalRef(std::move(result)); - MozPromise::FromGeckoResult(geckoResult) - ->Then( - GetMainThreadSerialEventTarget(), __func__, - [self = std::move(self)](AndroidWebAuthnResult&& aValue) { - self->HandleSignResult(std::move(aValue)); - }, - [self = std::move(self)](AndroidWebAuthnResult&& aValue) { - self->HandleSignResult(std::move(aValue)); - }); - })); - - return mSignPromise.Ensure(__func__); -} - -void AndroidWebAuthnTokenManager::HandleSignResult( - AndroidWebAuthnResult&& aResult) { - if (!gAndroidPBackgroundThread) { - // Promise is already rejected when shutting down background thread - return; - } - // This is likely running on the main thread, so we'll always dispatch to the - // background for state updates. - if (aResult.IsError()) { - nsresult aError = aResult.GetError(); - - gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction( - "AndroidWebAuthnTokenManager::SignAbort", - [self = RefPtr(this), aError]() { - self->mSignPromise.RejectIfExists(aError, __func__); - })); - } else { - gAndroidPBackgroundThread->Dispatch(NS_NewRunnableFunction( - "AndroidWebAuthnTokenManager::SignComplete", - [self = RefPtr(this), - aResult = std::move(aResult)]() { - nsTArray emptyExtensions; - WebAuthnGetAssertionResult result( - aResult.mClientDataJSON, aResult.mKeyHandle, aResult.mSignature, - aResult.mAuthData, emptyExtensions, aResult.mUserHandle); - nsTArray results = { - {result, mozilla::Nothing()}}; - self->mSignPromise.Resolve(std::move(results), __func__); - })); - } -} - -void AndroidWebAuthnTokenManager::Cancel() { - AssertIsOnOwningThread(); - - ClearPromises(); -} - -AndroidWebAuthnResult::AndroidWebAuthnResult( - const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef& - aResponse) { - mClientDataJSON.Assign( - reinterpret_cast( - aResponse->ClientDataJson()->GetElements().Elements()), - aResponse->ClientDataJson()->Length()); - mKeyHandle.Clear(); - mKeyHandle.AppendElements( - reinterpret_cast( - aResponse->KeyHandle()->GetElements().Elements()), - aResponse->KeyHandle()->Length()); - mAttObj.Clear(); - mAttObj.AppendElements( - reinterpret_cast( - aResponse->AttestationObject()->GetElements().Elements()), - aResponse->AttestationObject()->Length()); - auto transports = aResponse->Transports(); - for (size_t i = 0; i < transports->Length(); i++) { - mTransports.AppendElement( - jni::String::LocalRef(transports->GetElement(i))->ToString()); - } -} - -AndroidWebAuthnResult::AndroidWebAuthnResult( - const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef& - aResponse) { - mClientDataJSON.Assign( - reinterpret_cast( - aResponse->ClientDataJson()->GetElements().Elements()), - aResponse->ClientDataJson()->Length()); - mKeyHandle.Clear(); - mKeyHandle.AppendElements( - reinterpret_cast( - aResponse->KeyHandle()->GetElements().Elements()), - aResponse->KeyHandle()->Length()); - mAuthData.Clear(); - mAuthData.AppendElements(reinterpret_cast( - aResponse->AuthData()->GetElements().Elements()), - aResponse->AuthData()->Length()); - mSignature.Clear(); - mSignature.AppendElements( - reinterpret_cast( - aResponse->Signature()->GetElements().Elements()), - aResponse->Signature()->Length()); - mUserHandle.Clear(); - mUserHandle.AppendElements( - reinterpret_cast( - aResponse->UserHandle()->GetElements().Elements()), - aResponse->UserHandle()->Length()); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/webauthn/AuthrsService.cpp b/dom/webauthn/AuthrsService.cpp deleted file mode 100644 index 311cc239dc9c..000000000000 --- a/dom/webauthn/AuthrsService.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AuthrsService.h" -#include "AuthrsBridge_ffi.h" -#include "nsIWebAuthnService.h" -#include "nsCOMPtr.h" - -namespace mozilla::dom { - -already_AddRefed NewAuthrsService() { - nsCOMPtr webauthnService; - nsresult rv = authrs_service_constructor(getter_AddRefs(webauthnService)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - return webauthnService.forget(); -} - -} // namespace mozilla::dom diff --git a/dom/webauthn/AuthrsService.h b/dom/webauthn/AuthrsService.h deleted file mode 100644 index b9308a9e335c..000000000000 --- a/dom/webauthn/AuthrsService.h +++ /dev/null @@ -1,17 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef DOM_WEBAUTHN_AUTHRS_BRIDGE_H_ -#define DOM_WEBAUTHN_AUTHRS_BRIDGE_H_ - -#include "mozilla/AlreadyAddRefed.h" -#include "nsIWebAuthnService.h" - -namespace mozilla::dom { - -already_AddRefed NewAuthrsService(); - -} // namespace mozilla::dom - -#endif // DOM_WEBAUTHN_AUTHRS_BRIDGE_H_ diff --git a/dom/webauthn/U2FTokenManager.cpp b/dom/webauthn/U2FTokenManager.cpp deleted file mode 100644 index 1937b9ffe63d..000000000000 --- a/dom/webauthn/U2FTokenManager.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "json/json.h" -#include "mozilla/dom/U2FTokenManager.h" -#include "mozilla/dom/U2FTokenTransport.h" -#include "mozilla/dom/PWebAuthnTransactionParent.h" -#include "mozilla/MozPromise.h" -#include "mozilla/ipc/BackgroundParent.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Services.h" -#include "mozilla/Unused.h" -#include "nsEscape.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIThread.h" -#include "nsTextFormatter.h" -#include "mozilla/Telemetry.h" -#include "WebAuthnEnumStrings.h" - -#include "mozilla/dom/AndroidWebAuthnTokenManager.h" - -namespace mozilla::dom { - -/*********************************************************************** - * Statics - **********************************************************************/ - -namespace { -static mozilla::LazyLogModule gU2FTokenManagerLog("u2fkeymanager"); -StaticAutoPtr gU2FTokenManager; -static nsIThread* gBackgroundThread; -} // namespace - -/*********************************************************************** - * U2FManager Implementation - **********************************************************************/ - -U2FTokenManager::U2FTokenManager() - : mTransactionParent(nullptr), mLastTransactionId(0) { - MOZ_ASSERT(XRE_IsParentProcess()); - // Create on the main thread to make sure ClearOnShutdown() works. - MOZ_ASSERT(NS_IsMainThread()); -} - -// static -void U2FTokenManager::Initialize() { - if (!XRE_IsParentProcess()) { - return; - } - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!gU2FTokenManager); - gU2FTokenManager = new U2FTokenManager(); - ClearOnShutdown(&gU2FTokenManager); -} - -// static -U2FTokenManager* U2FTokenManager::Get() { - MOZ_ASSERT(XRE_IsParentProcess()); - // We should only be accessing this on the background thread - MOZ_ASSERT(!NS_IsMainThread()); - return gU2FTokenManager; -} - -void U2FTokenManager::AbortTransaction(const uint64_t& aTransactionId, - const nsresult& aError) { - Unused << mTransactionParent->SendAbort(aTransactionId, aError); - ClearTransaction(); -} - -void U2FTokenManager::AbortOngoingTransaction() { - if (mLastTransactionId > 0 && mTransactionParent) { - // Send an abort to any other ongoing transaction - Unused << mTransactionParent->SendAbort(mLastTransactionId, - NS_ERROR_DOM_ABORT_ERR); - } - ClearTransaction(); -} - -void U2FTokenManager::MaybeClearTransaction( - PWebAuthnTransactionParent* aParent) { - // Only clear if we've been requested to do so by our current transaction - // parent. - if (mTransactionParent == aParent) { - ClearTransaction(); - } -} - -void U2FTokenManager::ClearTransaction() { - mTransactionParent = nullptr; - - // Drop managers at the end of all transactions - if (mTokenManagerImpl) { - mTokenManagerImpl->Drop(); - mTokenManagerImpl = nullptr; - } - - // Forget promises, if necessary. - mRegisterPromise.DisconnectIfExists(); - mSignPromise.DisconnectIfExists(); - - // Clear transaction id. - mLastTransactionId = 0; -} - -RefPtr U2FTokenManager::GetTokenManagerImpl() { - mozilla::ipc::AssertIsOnBackgroundThread(); - - if (mTokenManagerImpl) { - return mTokenManagerImpl; - } - - if (!gBackgroundThread) { - gBackgroundThread = NS_GetCurrentThread(); - MOZ_ASSERT(gBackgroundThread, "This should never be null!"); - } - - return AndroidWebAuthnTokenManager::GetInstance(); -} - -void U2FTokenManager::Register( - PWebAuthnTransactionParent* aTransactionParent, - const uint64_t& aTransactionId, - const WebAuthnMakeCredentialInfo& aTransactionInfo) { - MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister")); - - AbortOngoingTransaction(); - mTransactionParent = aTransactionParent; - mTokenManagerImpl = GetTokenManagerImpl(); - - if (!mTokenManagerImpl) { - AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); - return; - } - - mLastTransactionId = aTransactionId; - - mozilla::ipc::AssertIsOnBackgroundThread(); - MOZ_ASSERT(mLastTransactionId > 0); - - uint64_t tid = mLastTransactionId; - - mTokenManagerImpl - ->Register(aTransactionInfo, /* aForceNoneAttestation */ true) - ->Then( - GetCurrentSerialEventTarget(), __func__, - [tid](WebAuthnMakeCredentialResult&& aResult) { - Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, - u"U2FRegisterFinish"_ns, 1); - U2FTokenManager* mgr = U2FTokenManager::Get(); - mgr->MaybeConfirmRegister(tid, aResult); - }, - [tid](nsresult rv) { - MOZ_ASSERT(NS_FAILED(rv)); - U2FTokenManager* mgr = U2FTokenManager::Get(); - Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, - u"U2FRegisterAbort"_ns, 1); - mgr->MaybeAbortRegister(tid, rv); - }) - ->Track(mRegisterPromise); -} - -void U2FTokenManager::MaybeConfirmRegister( - const uint64_t& aTransactionId, - const WebAuthnMakeCredentialResult& aResult) { - MOZ_ASSERT(mLastTransactionId == aTransactionId); - mRegisterPromise.Complete(); - - Unused << mTransactionParent->SendConfirmRegister(aTransactionId, aResult); - ClearTransaction(); -} - -void U2FTokenManager::MaybeAbortRegister(const uint64_t& aTransactionId, - const nsresult& aError) { - MOZ_ASSERT(mLastTransactionId == aTransactionId); - mRegisterPromise.Complete(); - AbortTransaction(aTransactionId, aError); -} - -void U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent, - const uint64_t& aTransactionId, - const WebAuthnGetAssertionInfo& aTransactionInfo) { - MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign")); - - AbortOngoingTransaction(); - mTransactionParent = aTransactionParent; - mTokenManagerImpl = GetTokenManagerImpl(); - - if (!mTokenManagerImpl) { - AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR); - return; - } - - mLastTransactionId = aTransactionId; - - mozilla::ipc::AssertIsOnBackgroundThread(); - MOZ_ASSERT(mLastTransactionId > 0); - uint64_t tid = mLastTransactionId; - - mTokenManagerImpl->Sign(aTransactionInfo) - ->Then( - GetCurrentSerialEventTarget(), __func__, - [tid](nsTArray&& aResult) { - U2FTokenManager* mgr = U2FTokenManager::Get(); - Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, - u"U2FSignFinish"_ns, 1); - if (aResult.Length() == 1) { - WebAuthnGetAssertionResult result = aResult[0].assertion; - mgr->MaybeConfirmSign(tid, result); - } - }, - [tid](nsresult rv) { - MOZ_ASSERT(NS_FAILED(rv)); - U2FTokenManager* mgr = U2FTokenManager::Get(); - Telemetry::ScalarAdd(Telemetry::ScalarID::SECURITY_WEBAUTHN_USED, - u"U2FSignAbort"_ns, 1); - mgr->MaybeAbortSign(tid, rv); - }) - ->Track(mSignPromise); -} - -void U2FTokenManager::MaybeConfirmSign( - const uint64_t& aTransactionId, const WebAuthnGetAssertionResult& aResult) { - MOZ_ASSERT(mLastTransactionId == aTransactionId); - mSignPromise.Complete(); - - Unused << mTransactionParent->SendConfirmSign(aTransactionId, aResult); - ClearTransaction(); -} - -void U2FTokenManager::MaybeAbortSign(const uint64_t& aTransactionId, - const nsresult& aError) { - MOZ_ASSERT(mLastTransactionId == aTransactionId); - mSignPromise.Complete(); - AbortTransaction(aTransactionId, aError); -} - -void U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent, - const Tainted& aTransactionId) { - // The last transaction ID also suffers from the issue described in Bug - // 1696159. A content process could cancel another content processes - // transaction by guessing the last transaction ID. - if (mTransactionParent != aParent || - !MOZ_IS_VALID(aTransactionId, mLastTransactionId == aTransactionId)) { - return; - } - - mTokenManagerImpl->Cancel(); - ClearTransaction(); -} - -} // namespace mozilla::dom diff --git a/dom/webauthn/U2FTokenManager.h b/dom/webauthn/U2FTokenManager.h deleted file mode 100644 index 936683eaf2a7..000000000000 --- a/dom/webauthn/U2FTokenManager.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_U2FTokenManager_h -#define mozilla_dom_U2FTokenManager_h - -#include "mozilla/dom/U2FTokenTransport.h" -#include "mozilla/dom/PWebAuthnTransaction.h" -#include "mozilla/Tainting.h" - -/* - * Parent process manager for U2F and WebAuthn API transactions. Handles process - * transactions from all content processes, make sure only one transaction is - * live at any time. Manages access to hardware and software based key systems. - * - * U2FTokenManager is created on the first access to functions of either the U2F - * or WebAuthn APIs that require key registration or signing. It lives until the - * end of the browser process. - */ - -namespace mozilla::dom { - -class U2FSoftTokenManager; -class WebAuthnTransactionParent; - -class U2FTokenManager final { - public: - static U2FTokenManager* Get(); - void Register(PWebAuthnTransactionParent* aTransactionParent, - const uint64_t& aTransactionId, - const WebAuthnMakeCredentialInfo& aTransactionInfo); - void Sign(PWebAuthnTransactionParent* aTransactionParent, - const uint64_t& aTransactionId, - const WebAuthnGetAssertionInfo& aTransactionInfo); - void Cancel(PWebAuthnTransactionParent* aTransactionParent, - const Tainted& aTransactionId); - void MaybeClearTransaction(PWebAuthnTransactionParent* aParent); - static void Initialize(); - - U2FTokenManager(); - ~U2FTokenManager() = default; - - private: - RefPtr GetTokenManagerImpl(); - void AbortTransaction(const uint64_t& aTransactionId, const nsresult& aError); - void AbortOngoingTransaction(); - void ClearTransaction(); - void MaybeConfirmRegister(const uint64_t& aTransactionId, - const WebAuthnMakeCredentialResult& aResult); - void MaybeAbortRegister(const uint64_t& aTransactionId, - const nsresult& aError); - void MaybeConfirmSign(const uint64_t& aTransactionId, - const WebAuthnGetAssertionResult& aResult); - void MaybeAbortSign(const uint64_t& aTransactionId, const nsresult& aError); - // Using a raw pointer here, as the lifetime of the IPC object is managed by - // the PBackground protocol code. This means we cannot be left holding an - // invalid IPC protocol object after the transaction is finished. - PWebAuthnTransactionParent* mTransactionParent; - RefPtr mTokenManagerImpl; - MozPromiseRequestHolder mRegisterPromise; - MozPromiseRequestHolder mSignPromise; - // The last transaction id, non-zero if there's an active transaction. This - // guards any cancel messages to ensure we don't cancel newer transactions - // due to a stale message. - uint64_t mLastTransactionId; -}; - -} // namespace mozilla::dom - -#endif // mozilla_dom_U2FTokenManager_h diff --git a/dom/webauthn/U2FTokenTransport.h b/dom/webauthn/U2FTokenTransport.h deleted file mode 100644 index 0c6d80bdf31c..000000000000 --- a/dom/webauthn/U2FTokenTransport.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_U2FTokenTransport_h -#define mozilla_dom_U2FTokenTransport_h - -#include "mozilla/dom/PWebAuthnTransaction.h" -#include "mozilla/MozPromise.h" - -/* - * Abstract class representing a transport manager for U2F Keys (software, - * bluetooth, usb, etc.). Hides the implementation details for specific key - * transport types. - */ - -namespace mozilla::dom { - -class WebAuthnGetAssertionResultWrapper { - public: - WebAuthnGetAssertionResult assertion; - mozilla::Maybe username; -}; - -typedef MozPromise - U2FRegisterPromise; -typedef MozPromise, nsresult, true> - U2FSignPromise; - -class U2FTokenTransport { - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FTokenTransport); - U2FTokenTransport() = default; - - virtual RefPtr Register( - const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) = 0; - - virtual RefPtr Sign( - const WebAuthnGetAssertionInfo& aInfo) = 0; - - virtual void Cancel() = 0; - - virtual void Drop() {} - - protected: - virtual ~U2FTokenTransport() = default; -}; - -} // namespace mozilla::dom - -#endif // mozilla_dom_U2FTokenTransport_h diff --git a/dom/webauthn/CtapArgs.cpp b/dom/webauthn/WebAuthnArgs.cpp similarity index 56% rename from dom/webauthn/CtapArgs.cpp rename to dom/webauthn/WebAuthnArgs.cpp index dde26aa3661a..2aa0b0d9ecf9 100644 --- a/dom/webauthn/CtapArgs.cpp +++ b/dom/webauthn/WebAuthnArgs.cpp @@ -4,26 +4,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "CtapArgs.h" +#include "WebAuthnArgs.h" #include "WebAuthnEnumStrings.h" #include "WebAuthnUtil.h" #include "mozilla/dom/PWebAuthnTransactionParent.h" namespace mozilla::dom { -NS_IMPL_ISUPPORTS(CtapRegisterArgs, nsICtapRegisterArgs) +NS_IMPL_ISUPPORTS(WebAuthnRegisterArgs, nsIWebAuthnRegisterArgs) NS_IMETHODIMP -CtapRegisterArgs::GetOrigin(nsAString& aOrigin) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetOrigin(nsAString& aOrigin) { aOrigin = mInfo.Origin(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetClientDataHash(nsTArray& aClientDataHash) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnRegisterArgs::GetClientDataHash(nsTArray& aClientDataHash) { nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; @@ -33,44 +30,37 @@ CtapRegisterArgs::GetClientDataHash(nsTArray& aClientDataHash) { } NS_IMETHODIMP -CtapRegisterArgs::GetRpId(nsAString& aRpId) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetRpId(nsAString& aRpId) { aRpId = mInfo.RpId(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetRpName(nsAString& aRpName) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetRpName(nsAString& aRpName) { aRpName = mInfo.Rp().Name(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetUserId(nsTArray& aUserId) { - mozilla::ipc::AssertIsOnBackgroundThread(); - aUserId.Clear(); - aUserId.AppendElements(mInfo.User().Id()); +WebAuthnRegisterArgs::GetUserId(nsTArray& aUserId) { + aUserId.Assign(mInfo.User().Id()); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetUserName(nsAString& aUserName) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetUserName(nsAString& aUserName) { aUserName = mInfo.User().Name(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetUserDisplayName(nsAString& aUserDisplayName) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetUserDisplayName(nsAString& aUserDisplayName) { aUserDisplayName = mInfo.User().DisplayName(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetCoseAlgs(nsTArray& aCoseAlgs) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetCoseAlgs(nsTArray& aCoseAlgs) { aCoseAlgs.Clear(); for (const CoseAlg& coseAlg : mInfo.coseAlgs()) { aCoseAlgs.AppendElement(coseAlg.alg()); @@ -79,8 +69,8 @@ CtapRegisterArgs::GetCoseAlgs(nsTArray& aCoseAlgs) { } NS_IMETHODIMP -CtapRegisterArgs::GetExcludeList(nsTArray >& aExcludeList) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetExcludeList( + nsTArray >& aExcludeList) { aExcludeList.Clear(); for (const WebAuthnScopedCredential& cred : mInfo.ExcludeList()) { aExcludeList.AppendElement(cred.id().Clone()); @@ -89,51 +79,43 @@ CtapRegisterArgs::GetExcludeList(nsTArray >& aExcludeList) { } NS_IMETHODIMP -CtapRegisterArgs::GetCredProps(bool* aCredProps) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnRegisterArgs::GetCredProps(bool* aCredProps) { *aCredProps = mCredProps; return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnRegisterArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) { *aHmacCreateSecret = mHmacCreateSecret; return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetMinPinLength(bool* aMinPinLength) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnRegisterArgs::GetMinPinLength(bool* aMinPinLength) { *aMinPinLength = mMinPinLength; return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetResidentKey(nsAString& aResidentKey) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetResidentKey(nsAString& aResidentKey) { aResidentKey = mInfo.AuthenticatorSelection().residentKey(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetUserVerification(nsAString& aUserVerificationRequirement) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetUserVerification( + nsAString& aUserVerificationRequirement) { aUserVerificationRequirement = mInfo.AuthenticatorSelection().userVerificationRequirement(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetAuthenticatorAttachment( +WebAuthnRegisterArgs::GetAuthenticatorAttachment( nsAString& aAuthenticatorAttachment) { - mozilla::ipc::AssertIsOnBackgroundThread(); if (mInfo.AuthenticatorSelection().authenticatorAttachment().isNothing()) { return NS_ERROR_NOT_AVAILABLE; } @@ -143,40 +125,34 @@ CtapRegisterArgs::GetAuthenticatorAttachment( } NS_IMETHODIMP -CtapRegisterArgs::GetTimeoutMS(uint32_t* aTimeoutMS) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnRegisterArgs::GetTimeoutMS(uint32_t* aTimeoutMS) { *aTimeoutMS = mInfo.TimeoutMS(); return NS_OK; } NS_IMETHODIMP -CtapRegisterArgs::GetAttestationConveyancePreference( +WebAuthnRegisterArgs::GetAttestationConveyancePreference( nsAString& aAttestationConveyancePreference) { - mozilla::ipc::AssertIsOnBackgroundThread(); aAttestationConveyancePreference = mInfo.attestationConveyancePreference(); return NS_OK; } -NS_IMPL_ISUPPORTS(CtapSignArgs, nsICtapSignArgs) +NS_IMPL_ISUPPORTS(WebAuthnSignArgs, nsIWebAuthnSignArgs) NS_IMETHODIMP -CtapSignArgs::GetOrigin(nsAString& aOrigin) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnSignArgs::GetOrigin(nsAString& aOrigin) { aOrigin = mInfo.Origin(); return NS_OK; } NS_IMETHODIMP -CtapSignArgs::GetRpId(nsAString& aRpId) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnSignArgs::GetRpId(nsAString& aRpId) { aRpId = mInfo.RpId(); return NS_OK; } NS_IMETHODIMP -CtapSignArgs::GetClientDataHash(nsTArray& aClientDataHash) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnSignArgs::GetClientDataHash(nsTArray& aClientDataHash) { nsresult rv = HashCString(mInfo.ClientDataJSON(), aClientDataHash); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; @@ -186,8 +162,7 @@ CtapSignArgs::GetClientDataHash(nsTArray& aClientDataHash) { } NS_IMETHODIMP -CtapSignArgs::GetAllowList(nsTArray >& aAllowList) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnSignArgs::GetAllowList(nsTArray >& aAllowList) { aAllowList.Clear(); for (const WebAuthnScopedCredential& cred : mInfo.AllowList()) { aAllowList.AppendElement(cred.id().Clone()); @@ -196,9 +171,7 @@ CtapSignArgs::GetAllowList(nsTArray >& aAllowList) { } NS_IMETHODIMP -CtapSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) { for (const WebAuthnExtension& ext : mInfo.Extensions()) { if (ext.type() == WebAuthnExtension::TWebAuthnExtensionHmacSecret) { *aHmacCreateSecret = @@ -211,9 +184,7 @@ CtapSignArgs::GetHmacCreateSecret(bool* aHmacCreateSecret) { } NS_IMETHODIMP -CtapSignArgs::GetAppId(nsAString& aAppId) { - mozilla::ipc::AssertIsOnBackgroundThread(); - +WebAuthnSignArgs::GetAppId(nsAString& aAppId) { for (const WebAuthnExtension& ext : mInfo.Extensions()) { if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) { aAppId = ext.get_WebAuthnExtensionAppId().appIdentifier(); @@ -225,15 +196,13 @@ CtapSignArgs::GetAppId(nsAString& aAppId) { } NS_IMETHODIMP -CtapSignArgs::GetUserVerification(nsAString& aUserVerificationRequirement) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnSignArgs::GetUserVerification(nsAString& aUserVerificationRequirement) { aUserVerificationRequirement = mInfo.userVerificationRequirement(); return NS_OK; } NS_IMETHODIMP -CtapSignArgs::GetTimeoutMS(uint32_t* aTimeoutMS) { - mozilla::ipc::AssertIsOnBackgroundThread(); +WebAuthnSignArgs::GetTimeoutMS(uint32_t* aTimeoutMS) { *aTimeoutMS = mInfo.TimeoutMS(); return NS_OK; } diff --git a/dom/webauthn/CtapArgs.h b/dom/webauthn/WebAuthnArgs.h similarity index 58% rename from dom/webauthn/CtapArgs.h rename to dom/webauthn/WebAuthnArgs.h index e0cfef566e85..8510562feda4 100644 --- a/dom/webauthn/CtapArgs.h +++ b/dom/webauthn/WebAuthnArgs.h @@ -4,8 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef CtapArgs_h -#define CtapArgs_h +#ifndef mozilla_dom_WebAuthnArgs_H_ +#define mozilla_dom_WebAuthnArgs_H_ #include "mozilla/dom/WebAuthnTransactionChild.h" #include "mozilla/ipc/BackgroundParent.h" @@ -13,24 +13,16 @@ namespace mozilla::dom { -// These classes provide an FFI between C++ and Rust for the getters of IPC -// objects (WebAuthnMakeCredentialInfo and WebAuthnGetAssertionInfo). They hold -// non-owning references to IPC objects, and must only be used within the -// lifetime of the IPC transaction that created them. There are runtime -// assertions to ensure that these types are created and used on the IPC -// background thread, but that alone does not guarantee safety. - -class CtapRegisterArgs final : public nsICtapRegisterArgs { +class WebAuthnRegisterArgs final : public nsIWebAuthnRegisterArgs { public: - NS_DECL_ISUPPORTS - NS_DECL_NSICTAPREGISTERARGS + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNREGISTERARGS - explicit CtapRegisterArgs(const WebAuthnMakeCredentialInfo& aInfo) + explicit WebAuthnRegisterArgs(const WebAuthnMakeCredentialInfo& aInfo) : mInfo(aInfo), mCredProps(false), mHmacCreateSecret(false), mMinPinLength(false) { - mozilla::ipc::AssertIsOnBackgroundThread(); for (const WebAuthnExtension& ext : mInfo.Extensions()) { switch (ext.type()) { case WebAuthnExtension::TWebAuthnExtensionCredProps: @@ -53,9 +45,9 @@ class CtapRegisterArgs final : public nsICtapRegisterArgs { } private: - ~CtapRegisterArgs() = default; + ~WebAuthnRegisterArgs() = default; - const WebAuthnMakeCredentialInfo& mInfo; + const WebAuthnMakeCredentialInfo mInfo; // Flags to indicate whether an extension is being requested. bool mCredProps; @@ -63,21 +55,20 @@ class CtapRegisterArgs final : public nsICtapRegisterArgs { bool mMinPinLength; }; -class CtapSignArgs final : public nsICtapSignArgs { +class WebAuthnSignArgs final : public nsIWebAuthnSignArgs { public: - NS_DECL_ISUPPORTS - NS_DECL_NSICTAPSIGNARGS + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNSIGNARGS - explicit CtapSignArgs(const WebAuthnGetAssertionInfo& aInfo) : mInfo(aInfo) { - mozilla::ipc::AssertIsOnBackgroundThread(); - } + explicit WebAuthnSignArgs(const WebAuthnGetAssertionInfo& aInfo) + : mInfo(aInfo) {} private: - ~CtapSignArgs() = default; + ~WebAuthnSignArgs() = default; - const WebAuthnGetAssertionInfo& mInfo; + const WebAuthnGetAssertionInfo mInfo; }; } // namespace mozilla::dom -#endif // CtapArgs_h +#endif // mozilla_dom_WebAuthnArgs_H_ diff --git a/dom/webauthn/WebAuthnPromiseHolder.cpp b/dom/webauthn/WebAuthnPromiseHolder.cpp index b8c880b91fec..60dff7f1c282 100644 --- a/dom/webauthn/WebAuthnPromiseHolder.cpp +++ b/dom/webauthn/WebAuthnPromiseHolder.cpp @@ -15,14 +15,14 @@ WebAuthnRegisterPromiseHolder::Ensure() { } NS_IMETHODIMP -WebAuthnRegisterPromiseHolder::Resolve(nsICtapRegisterResult* aResult) { +WebAuthnRegisterPromiseHolder::Resolve(nsIWebAuthnRegisterResult* aResult) { if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; } // Resolve the promise on its owning thread if Disconnect() has not been // called. - RefPtr result(aResult); + RefPtr result(aResult); mEventTarget->Dispatch(NS_NewRunnableFunction( "WebAuthnRegisterPromiseHolder::Resolve", [self = RefPtr{this}, result]() { @@ -54,14 +54,14 @@ already_AddRefed WebAuthnSignPromiseHolder::Ensure() { } NS_IMETHODIMP -WebAuthnSignPromiseHolder::Resolve(nsICtapSignResult* aResult) { +WebAuthnSignPromiseHolder::Resolve(nsIWebAuthnSignResult* aResult) { if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; } // Resolve the promise on its owning thread if Disconnect() has not been // called. - RefPtr result(aResult); + RefPtr result(aResult); mEventTarget->Dispatch(NS_NewRunnableFunction( "WebAuthnSignPromiseHolder::Resolve", [self = RefPtr{this}, result]() { self->mSignPromise.ResolveIfExists(result, __func__); diff --git a/dom/webauthn/WebAuthnPromiseHolder.h b/dom/webauthn/WebAuthnPromiseHolder.h index 21a78af6739d..ca70fedb147a 100644 --- a/dom/webauthn/WebAuthnPromiseHolder.h +++ b/dom/webauthn/WebAuthnPromiseHolder.h @@ -24,11 +24,11 @@ namespace mozilla::dom { * at least one of Resolve(), Reject(), or Disconnect(). */ -typedef MozPromise, nsresult, true> - WebAuthnRegisterPromise; +using WebAuthnRegisterPromise = + MozPromise, nsresult, true>; -typedef MozPromise, nsresult, true> - WebAuthnSignPromise; +using WebAuthnSignPromise = + MozPromise, nsresult, true>; class WebAuthnRegisterPromiseHolder final : public nsIWebAuthnRegisterPromise { public: diff --git a/dom/webauthn/WebAuthnResult.cpp b/dom/webauthn/WebAuthnResult.cpp new file mode 100644 index 000000000000..28464df6192b --- /dev/null +++ b/dom/webauthn/WebAuthnResult.cpp @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsString.h" +#include "WebAuthnResult.h" + +#ifdef MOZ_WIDGET_ANDROID +namespace mozilla::jni { + +template <> +RefPtr Java2Native( + mozilla::jni::Object::Param aData, JNIEnv* aEnv) { + MOZ_ASSERT( + aData.IsInstanceOf()); + java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef response(aData); + RefPtr result = + new dom::WebAuthnRegisterResult(response); + return result; +} + +template <> +RefPtr Java2Native(mozilla::jni::Object::Param aData, + JNIEnv* aEnv) { + MOZ_ASSERT( + aData.IsInstanceOf()); + java::WebAuthnTokenManager::GetAssertionResponse::LocalRef response(aData); + RefPtr result = + new dom::WebAuthnSignResult(response); + return result; +} + +} // namespace mozilla::jni +#endif + +namespace mozilla::dom { + +NS_IMPL_ISUPPORTS(WebAuthnRegisterResult, nsIWebAuthnRegisterResult) + +NS_IMETHODIMP +WebAuthnRegisterResult::GetAttestationObject( + nsTArray& aAttestationObject) { + aAttestationObject.Assign(mAttestationObject); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnRegisterResult::GetCredentialId(nsTArray& aCredentialId) { + aCredentialId.Assign(mCredentialId); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnRegisterResult::GetTransports(nsTArray& aTransports) { + aTransports.Assign(mTransports); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnRegisterResult::GetCredPropsRk(bool* aCredPropsRk) { + if (mCredPropsRk.isSome()) { + *aCredPropsRk = mCredPropsRk.ref(); + return NS_OK; + } + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +WebAuthnRegisterResult::SetCredPropsRk(bool aCredPropsRk) { + mCredPropsRk = Some(aCredPropsRk); + return NS_OK; +} + +NS_IMPL_ISUPPORTS(WebAuthnSignResult, nsIWebAuthnSignResult) + +NS_IMETHODIMP +WebAuthnSignResult::GetAuthenticatorData( + nsTArray& aAuthenticatorData) { + aAuthenticatorData.Assign(mAuthenticatorData); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnSignResult::GetCredentialId(nsTArray& aCredentialId) { + aCredentialId.Assign(mCredentialId); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnSignResult::GetSignature(nsTArray& aSignature) { + aSignature.Assign(mSignature); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnSignResult::GetUserHandle(nsTArray& aUserHandle) { + aUserHandle.Assign(mUserHandle); + return NS_OK; +} + +NS_IMETHODIMP +WebAuthnSignResult::GetUserName(nsACString& aUserName) { + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +WebAuthnSignResult::GetUsedAppId(bool* aUsedAppId) { + return NS_ERROR_NOT_AVAILABLE; +} + +} // namespace mozilla::dom diff --git a/dom/webauthn/WebAuthnResult.h b/dom/webauthn/WebAuthnResult.h new file mode 100644 index 000000000000..3c259546dcb4 --- /dev/null +++ b/dom/webauthn/WebAuthnResult.h @@ -0,0 +1,120 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_WebAuthnResult_h_ +#define mozilla_dom_WebAuthnResult_h_ + +#include "nsIWebAuthnResult.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/java/WebAuthnTokenManagerNatives.h" +#endif + +namespace mozilla::dom { + +class WebAuthnRegisterResult final : public nsIWebAuthnRegisterResult { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNREGISTERRESULT + + WebAuthnRegisterResult(const nsTArray& aAttestationObject, + const nsCString& aClientDataJSON, + const nsTArray& aCredentialId, + const nsTArray& aTransports) + : mClientDataJSON(aClientDataJSON), mCredPropsRk(Nothing()) { + mAttestationObject.AppendElements(aAttestationObject); + mCredentialId.AppendElements(aCredentialId); + mTransports.AppendElements(aTransports); + } + +#ifdef MOZ_WIDGET_ANDROID + explicit WebAuthnRegisterResult( + const java::WebAuthnTokenManager::MakeCredentialResponse::LocalRef& + aResponse) { + mAttestationObject.AppendElements( + reinterpret_cast( + aResponse->AttestationObject()->GetElements().Elements()), + aResponse->AttestationObject()->Length()); + mClientDataJSON.Assign( + reinterpret_cast( + aResponse->ClientDataJson()->GetElements().Elements()), + aResponse->ClientDataJson()->Length()); + mCredentialId.AppendElements( + reinterpret_cast( + aResponse->KeyHandle()->GetElements().Elements()), + aResponse->KeyHandle()->Length()); + auto transports = aResponse->Transports(); + for (size_t i = 0; i < transports->Length(); i++) { + mTransports.AppendElement( + jni::String::LocalRef(transports->GetElement(i))->ToString()); + } + } +#endif + + private: + ~WebAuthnRegisterResult() = default; + + nsTArray mAttestationObject; + nsTArray mCredentialId; + nsTArray mTransports; + nsCString mClientDataJSON; + Maybe mCredPropsRk; +}; + +class WebAuthnSignResult final : public nsIWebAuthnSignResult { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNSIGNRESULT + + WebAuthnSignResult(const nsTArray& aAuthenticatorData, + const nsCString& aClientDataJSON, + const nsTArray& aCredentialId, + const nsTArray& aSignature, + const nsTArray& aUserHandle) + : mClientDataJSON(aClientDataJSON) { + mAuthenticatorData.AppendElements(aAuthenticatorData); + mCredentialId.AppendElements(aCredentialId); + mSignature.AppendElements(aSignature); + mUserHandle.AppendElements(aUserHandle); + } + +#ifdef MOZ_WIDGET_ANDROID + explicit WebAuthnSignResult( + const java::WebAuthnTokenManager::GetAssertionResponse::LocalRef& + aResponse) { + mAuthenticatorData.AppendElements( + reinterpret_cast( + aResponse->AuthData()->GetElements().Elements()), + aResponse->AuthData()->Length()); + mClientDataJSON.Assign( + reinterpret_cast( + aResponse->ClientDataJson()->GetElements().Elements()), + aResponse->ClientDataJson()->Length()); + mCredentialId.AppendElements( + reinterpret_cast( + aResponse->KeyHandle()->GetElements().Elements()), + aResponse->KeyHandle()->Length()); + mSignature.AppendElements( + reinterpret_cast( + aResponse->Signature()->GetElements().Elements()), + aResponse->Signature()->Length()); + mUserHandle.AppendElements( + reinterpret_cast( + aResponse->UserHandle()->GetElements().Elements()), + aResponse->UserHandle()->Length()); + } +#endif + + private: + ~WebAuthnSignResult() = default; + + nsTArray mAuthenticatorData; + nsCString mClientDataJSON; + nsTArray mCredentialId; + nsTArray mSignature; + nsTArray mUserHandle; +}; + +} // namespace mozilla::dom +#endif // mozilla_dom_WebAuthnResult_h diff --git a/dom/webauthn/WebAuthnService.cpp b/dom/webauthn/WebAuthnService.cpp new file mode 100644 index 000000000000..de0a9556d058 --- /dev/null +++ b/dom/webauthn/WebAuthnService.cpp @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/StaticPrefs_security.h" +#include "WebAuthnService.h" + +namespace mozilla::dom { + +already_AddRefed NewWebAuthnService() { + nsCOMPtr webauthnService(new WebAuthnService()); + return webauthnService.forget(); +} + +NS_IMPL_ISUPPORTS(WebAuthnService, nsIWebAuthnService) + +NS_IMETHODIMP +WebAuthnService::MakeCredential(uint64_t aTransactionId, + uint64_t browsingContextId, + nsIWebAuthnRegisterArgs* aArgs, + nsIWebAuthnRegisterPromise* aPromise) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->MakeCredential(aTransactionId, browsingContextId, + aArgs, aPromise); + } + return mPlatformService->MakeCredential(aTransactionId, browsingContextId, + aArgs, aPromise); +} + +NS_IMETHODIMP +WebAuthnService::GetAssertion(uint64_t aTransactionId, + uint64_t browsingContextId, + nsIWebAuthnSignArgs* aArgs, + nsIWebAuthnSignPromise* aPromise) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->GetAssertion(aTransactionId, browsingContextId, aArgs, + aPromise); + } + return mPlatformService->GetAssertion(aTransactionId, browsingContextId, + aArgs, aPromise); +} + +NS_IMETHODIMP +WebAuthnService::Reset() { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->Reset(); + } + return mPlatformService->Reset(); +} + +NS_IMETHODIMP +WebAuthnService::Cancel(uint64_t aTransactionId) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->Cancel(aTransactionId); + } + return mPlatformService->Cancel(aTransactionId); +} + +NS_IMETHODIMP +WebAuthnService::PinCallback(uint64_t aTransactionId, const nsACString& aPin) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->PinCallback(aTransactionId, aPin); + } + return mPlatformService->PinCallback(aTransactionId, aPin); +} + +NS_IMETHODIMP +WebAuthnService::ResumeMakeCredential(uint64_t aTransactionId, + bool aForceNoneAttestation) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->ResumeMakeCredential(aTransactionId, + aForceNoneAttestation); + } + return mPlatformService->ResumeMakeCredential(aTransactionId, + aForceNoneAttestation); +} + +NS_IMETHODIMP +WebAuthnService::SelectionCallback(uint64_t aTransactionId, uint64_t aIndex) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->SelectionCallback(aTransactionId, aIndex); + } + return mPlatformService->SelectionCallback(aTransactionId, aIndex); +} + +NS_IMETHODIMP +WebAuthnService::AddVirtualAuthenticator( + const nsACString& protocol, const nsACString& transport, + bool hasResidentKey, bool hasUserVerification, bool isUserConsenting, + bool isUserVerified, uint64_t* retval) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->AddVirtualAuthenticator( + protocol, transport, hasResidentKey, hasUserVerification, + isUserConsenting, isUserVerified, retval); + } + return mPlatformService->AddVirtualAuthenticator( + protocol, transport, hasResidentKey, hasUserVerification, + isUserConsenting, isUserVerified, retval); +} + +NS_IMETHODIMP +WebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->RemoveVirtualAuthenticator(authenticatorId); + } + return mPlatformService->RemoveVirtualAuthenticator(authenticatorId); +} + +NS_IMETHODIMP +WebAuthnService::AddCredential(uint64_t authenticatorId, + const nsACString& credentialId, + bool isResidentCredential, + const nsACString& rpId, + const nsACString& privateKey, + const nsACString& userHandle, + uint32_t signCount) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->AddCredential(authenticatorId, credentialId, + isResidentCredential, rpId, privateKey, + userHandle, signCount); + } + return mPlatformService->AddCredential(authenticatorId, credentialId, + isResidentCredential, rpId, privateKey, + userHandle, signCount); +} + +NS_IMETHODIMP +WebAuthnService::GetCredentials( + uint64_t authenticatorId, + nsTArray>& retval) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->GetCredentials(authenticatorId, retval); + } + return mPlatformService->GetCredentials(authenticatorId, retval); +} + +NS_IMETHODIMP +WebAuthnService::RemoveCredential(uint64_t authenticatorId, + const nsACString& credentialId) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->RemoveCredential(authenticatorId, credentialId); + } + return mPlatformService->RemoveCredential(authenticatorId, credentialId); +} + +NS_IMETHODIMP +WebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->RemoveAllCredentials(authenticatorId); + } + return mPlatformService->RemoveAllCredentials(authenticatorId); +} + +NS_IMETHODIMP +WebAuthnService::SetUserVerified(uint64_t authenticatorId, + bool isUserVerified) { + if (StaticPrefs::security_webauth_webauthn_enable_softtoken()) { + return mTestService->SetUserVerified(authenticatorId, isUserVerified); + } + return mPlatformService->SetUserVerified(authenticatorId, isUserVerified); +} + +} // namespace mozilla::dom diff --git a/dom/webauthn/WebAuthnService.h b/dom/webauthn/WebAuthnService.h new file mode 100644 index 000000000000..7369da7f87ac --- /dev/null +++ b/dom/webauthn/WebAuthnService.h @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_WebAuthnService_h_ +#define mozilla_dom_WebAuthnService_h_ + +#include "nsIWebAuthnService.h" +#include "AuthrsBridge_ffi.h" + +#ifdef MOZ_WIDGET_ANDROID +# include "AndroidWebAuthnService.h" +#endif + +namespace mozilla::dom { + +already_AddRefed NewWebAuthnService(); + +class WebAuthnService final : public nsIWebAuthnService { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWEBAUTHNSERVICE + + WebAuthnService() { + Unused << authrs_service_constructor(getter_AddRefs(mTestService)); +#ifdef MOZ_WIDGET_ANDROID + mPlatformService = new AndroidWebAuthnService(); +#else + mPlatformService = mTestService; +#endif + } + + private: + ~WebAuthnService() = default; + + nsCOMPtr mPlatformService; + nsCOMPtr mTestService; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_WebAuthnService_h_ diff --git a/dom/webauthn/WebAuthnTransactionParent.cpp b/dom/webauthn/WebAuthnTransactionParent.cpp index c186f86f4b2b..35598d8d99f0 100644 --- a/dom/webauthn/WebAuthnTransactionParent.cpp +++ b/dom/webauthn/WebAuthnTransactionParent.cpp @@ -9,13 +9,9 @@ #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/StaticPrefs_security.h" -#include "CtapArgs.h" #include "nsIWebAuthnService.h" #include "nsThreadUtils.h" - -#ifdef MOZ_WIDGET_ANDROID -# include "mozilla/dom/U2FTokenManager.h" -#endif +#include "WebAuthnArgs.h" #ifdef XP_WIN # include "WinWebAuthnManager.h" @@ -40,23 +36,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister( } #endif -// Bug 1819414 will reroute requests on Android through WebAuthnController and -// allow us to remove this. -#ifdef MOZ_WIDGET_ANDROID - bool usingTestToken = - StaticPrefs::security_webauth_webauthn_enable_softtoken(); - bool androidFido2 = - StaticPrefs::security_webauth_webauthn_enable_android_fido2(); - - if (!usingTestToken && androidFido2) { - U2FTokenManager* mgr = U2FTokenManager::Get(); - if (mgr) { - mgr->Register(this, aTransactionId, aTransactionInfo); - } - return IPC_OK(); - } -#endif - // If there's an ongoing transaction, abort it. if (mTransactionId.isSome()) { mRegisterPromiseRequest.DisconnectIfExists(); @@ -142,11 +121,11 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister( nsCOMPtr webauthnService( do_GetService("@mozilla.org/webauthn/service;1")); - RefPtr args(new CtapRegisterArgs(aTransactionInfo)); + uint64_t browsingContextId = aTransactionInfo.BrowsingContextId(); + RefPtr args(new WebAuthnRegisterArgs(aTransactionInfo)); nsresult rv = webauthnService->MakeCredential( - aTransactionId, aTransactionInfo.BrowsingContextId(), args, - promiseHolder); + aTransactionId, browsingContextId, args, promiseHolder); if (NS_FAILED(rv)) { promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR); } @@ -171,23 +150,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign( } #endif -// Bug 1819414 will reroute requests on Android through WebAuthnController and -// allow us to remove this. -#ifdef MOZ_WIDGET_ANDROID - bool usingTestToken = - StaticPrefs::security_webauth_webauthn_enable_softtoken(); - bool androidFido2 = - StaticPrefs::security_webauth_webauthn_enable_android_fido2(); - - if (!usingTestToken && androidFido2) { - U2FTokenManager* mgr = U2FTokenManager::Get(); - if (mgr) { - mgr->Sign(this, aTransactionId, aTransactionInfo); - } - return IPC_OK(); - } -#endif - if (mTransactionId.isSome()) { mRegisterPromiseRequest.DisconnectIfExists(); mSignPromiseRequest.DisconnectIfExists(); @@ -272,7 +234,7 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign( }) ->Track(mSignPromiseRequest); - RefPtr args(new CtapSignArgs(aTransactionInfo)); + RefPtr args(new WebAuthnSignArgs(aTransactionInfo)); nsCOMPtr webauthnService( do_GetService("@mozilla.org/webauthn/service;1")); @@ -300,16 +262,6 @@ mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestCancel( // fall through in case the virtual token was used. #endif -// Bug 1819414 will reroute requests on Android through WebAuthnController and -// allow us to remove this. -#ifdef MOZ_WIDGET_ANDROID - U2FTokenManager* mgr = U2FTokenManager::Get(); - if (mgr) { - mgr->Cancel(this, aTransactionId); - } - // fall through in case the virtual token was used. -#endif - if (mTransactionId.isNothing() || !MOZ_IS_VALID(aTransactionId, mTransactionId.ref() == aTransactionId)) { return IPC_OK(); @@ -362,16 +314,6 @@ void WebAuthnTransactionParent::ActorDestroy(ActorDestroyReason aWhy) { // fall through in case the virtual token was used. #endif -// Bug 1819414 will reroute requests on Android through WebAuthnController and -// allow us to remove this. -#ifdef MOZ_WIDGET_ANDROID - U2FTokenManager* mgr = U2FTokenManager::Get(); - if (mgr) { - mgr->MaybeClearTransaction(this); - } - // fall through in case the virtual token was used. -#endif - mRegisterPromiseRequest.DisconnectIfExists(); mSignPromiseRequest.DisconnectIfExists(); mTransactionId.reset(); diff --git a/dom/webauthn/WinWebAuthnManager.h b/dom/webauthn/WinWebAuthnManager.h index bee143ddd076..4e43762d47bd 100644 --- a/dom/webauthn/WinWebAuthnManager.h +++ b/dom/webauthn/WinWebAuthnManager.h @@ -7,7 +7,6 @@ #ifndef mozilla_dom_WinWebAuthnManager_h #define mozilla_dom_WinWebAuthnManager_h -#include "mozilla/dom/U2FTokenTransport.h" #include "mozilla/dom/PWebAuthnTransaction.h" #include "mozilla/Tainting.h" diff --git a/dom/webauthn/authrs_bridge/src/lib.rs b/dom/webauthn/authrs_bridge/src/lib.rs index f8add25a4631..423daca56f75 100644 --- a/dom/webauthn/authrs_bridge/src/lib.rs +++ b/dom/webauthn/authrs_bridge/src/lib.rs @@ -26,7 +26,8 @@ use cstr::cstr; use moz_task::{get_main_thread, RunnableBuilder}; use nserror::{ nsresult, NS_ERROR_DOM_ABORT_ERR, NS_ERROR_DOM_INVALID_STATE_ERR, NS_ERROR_DOM_NOT_ALLOWED_ERR, - NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NULL_POINTER, NS_OK, + NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE, NS_ERROR_NOT_IMPLEMENTED, + NS_ERROR_NULL_POINTER, NS_OK, }; use nsstring::{nsACString, nsCString, nsString}; use serde::Serialize; @@ -38,9 +39,9 @@ use std::sync::mpsc::{channel, Receiver, RecvError, Sender}; use std::sync::{Arc, Mutex}; use thin_vec::{thin_vec, ThinVec}; use xpcom::interfaces::{ - nsICredentialParameters, nsICtapRegisterArgs, nsICtapRegisterResult, nsICtapSignArgs, - nsICtapSignResult, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnRegisterPromise, - nsIWebAuthnService, nsIWebAuthnSignPromise, + nsICredentialParameters, nsIObserverService, nsIWebAuthnAttObj, nsIWebAuthnRegisterArgs, + nsIWebAuthnRegisterPromise, nsIWebAuthnRegisterResult, nsIWebAuthnService, nsIWebAuthnSignArgs, + nsIWebAuthnSignPromise, nsIWebAuthnSignResult, }; use xpcom::{xpcom_method, RefPtr}; @@ -135,12 +136,12 @@ fn cancel_prompts(tid: u64) -> Result<(), nsresult> { Ok(()) } -#[xpcom(implement(nsICtapRegisterResult), atomic)] -pub struct CtapRegisterResult { +#[xpcom(implement(nsIWebAuthnRegisterResult), atomic)] +pub struct WebAuthnRegisterResult { result: RegisterResult, } -impl CtapRegisterResult { +impl WebAuthnRegisterResult { xpcom_method!(get_attestation_object => GetAttestationObject() -> ThinVec); fn get_attestation_object(&self) -> Result, nsresult> { let mut out = ThinVec::new(); @@ -172,6 +173,11 @@ impl CtapRegisterResult { }; Ok(cred_props.rk) } + + xpcom_method!(set_cred_props_rk => SetCredPropsRk(aCredPropsRk: bool)); + fn set_cred_props_rk(&self, _cred_props_rk: bool) -> Result<(), nsresult> { + Err(NS_ERROR_NOT_IMPLEMENTED) + } } #[xpcom(implement(nsIWebAuthnAttObj), atomic)] @@ -215,12 +221,12 @@ impl WebAuthnAttObj { } } -#[xpcom(implement(nsICtapSignResult), atomic)] -pub struct CtapSignResult { +#[xpcom(implement(nsIWebAuthnSignResult), atomic)] +pub struct WebAuthnSignResult { result: SignResult, } -impl CtapSignResult { +impl WebAuthnSignResult { xpcom_method!(get_credential_id => GetCredentialId() -> ThinVec); fn get_credential_id(&self) -> Result, nsresult> { let Some(cred) = &self.result.assertion.credentials else { @@ -396,8 +402,8 @@ impl RegisterPromise { match result { Ok(result) => { let wrapped_result = - CtapRegisterResult::allocate(InitCtapRegisterResult { result }) - .query_interface::() + WebAuthnRegisterResult::allocate(InitWebAuthnRegisterResult { result }) + .query_interface::() .ok_or(NS_ERROR_FAILURE)?; unsafe { self.0.Resolve(wrapped_result.coerce()) }; } @@ -416,9 +422,10 @@ impl SignPromise { fn resolve_or_reject(&self, result: Result) -> Result<(), nsresult> { match result { Ok(result) => { - let wrapped_result = CtapSignResult::allocate(InitCtapSignResult { result }) - .query_interface::() - .ok_or(NS_ERROR_FAILURE)?; + let wrapped_result = + WebAuthnSignResult::allocate(InitWebAuthnSignResult { result }) + .query_interface::() + .ok_or(NS_ERROR_FAILURE)?; unsafe { self.0.Resolve(wrapped_result.coerce()) }; } Err(result) => { @@ -504,12 +511,12 @@ impl AuthrsService { // // This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at // most one WebAuthn transaction is active at any given time. - xpcom_method!(make_credential => MakeCredential(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsICtapRegisterArgs, aPromise: *const nsIWebAuthnRegisterPromise)); + xpcom_method!(make_credential => MakeCredential(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsIWebAuthnRegisterArgs, aPromise: *const nsIWebAuthnRegisterPromise)); fn make_credential( &self, tid: u64, browsing_context_id: u64, - args: &nsICtapRegisterArgs, + args: &nsIWebAuthnRegisterArgs, promise: &nsIWebAuthnRegisterPromise, ) -> Result<(), nsresult> { self.reset()?; @@ -762,12 +769,12 @@ impl AuthrsService { // // This will mutably borrow usb_token_manager through a RefCell. The caller must ensure that at // most one WebAuthn transaction is active at any given time. - xpcom_method!(get_assertion => GetAssertion(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsICtapSignArgs, aPromise: *const nsIWebAuthnSignPromise)); + xpcom_method!(get_assertion => GetAssertion(aTid: u64, aBrowsingContextId: u64, aArgs: *const nsIWebAuthnSignArgs, aPromise: *const nsIWebAuthnSignPromise)); fn get_assertion( &self, tid: u64, browsing_context_id: u64, - args: &nsICtapSignArgs, + args: &nsIWebAuthnSignArgs, promise: &nsIWebAuthnSignPromise, ) -> Result<(), nsresult> { self.reset()?; diff --git a/dom/webauthn/components.conf b/dom/webauthn/components.conf index be2352ba534c..f49a7833e6e9 100644 --- a/dom/webauthn/components.conf +++ b/dom/webauthn/components.conf @@ -8,7 +8,7 @@ Classes = [ { 'cid': '{ebe8a51d-bd54-4838-b031-cd2289990e14}', 'contract_ids': ['@mozilla.org/webauthn/service;1'], - 'headers': ['/dom/webauthn/AuthrsService.h'], - 'constructor': 'mozilla::dom::NewAuthrsService', + 'headers': ['/dom/webauthn/WebAuthnService.h'], + 'constructor': 'mozilla::dom::NewWebAuthnService', }, ] diff --git a/dom/webauthn/moz.build b/dom/webauthn/moz.build index 6c45db5a6f82..7c1fe03d3ef3 100644 --- a/dom/webauthn/moz.build +++ b/dom/webauthn/moz.build @@ -28,7 +28,6 @@ EXPORTS.mozilla.dom += [ "AuthenticatorAttestationResponse.h", "AuthenticatorResponse.h", "PublicKeyCredential.h", - "U2FTokenTransport.h", "WebAuthnManager.h", "WebAuthnManagerBase.h", "WebAuthnPromiseHolder.h", @@ -42,12 +41,13 @@ UNIFIED_SOURCES += [ "AuthenticatorAssertionResponse.cpp", "AuthenticatorAttestationResponse.cpp", "AuthenticatorResponse.cpp", - "AuthrsService.cpp", - "CtapArgs.cpp", "PublicKeyCredential.cpp", + "WebAuthnArgs.cpp", "WebAuthnManager.cpp", "WebAuthnManagerBase.cpp", "WebAuthnPromiseHolder.cpp", + "WebAuthnResult.cpp", + "WebAuthnService.cpp", "WebAuthnTransactionChild.cpp", "WebAuthnTransactionParent.cpp", "WebAuthnUtil.cpp", @@ -62,21 +62,11 @@ LOCAL_INCLUDES += [ "/dom/crypto", "/security/manager/ssl", "/third_party/rust", - "/toolkit/components/jsoncpp/include", -] - -USE_LIBS += [ - "jsoncpp", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": - EXPORTS.mozilla.dom += [ - "AndroidWebAuthnTokenManager.h", - "U2FTokenManager.h", - ] UNIFIED_SOURCES += [ - "AndroidWebAuthnTokenManager.cpp", - "U2FTokenManager.cpp", + "AndroidWebAuthnService.cpp", ] if CONFIG["OS_ARCH"] == "WINNT": diff --git a/dom/webauthn/nsIWebAuthnArgs.idl b/dom/webauthn/nsIWebAuthnArgs.idl index ba5be7df1c97..edb137d1b9a3 100644 --- a/dom/webauthn/nsIWebAuthnArgs.idl +++ b/dom/webauthn/nsIWebAuthnArgs.idl @@ -7,15 +7,8 @@ typedef long COSEAlgorithmIdentifier; -// The nsICtapRegisterArgs interface encapsulates the arguments to the CTAP -// authenticatorMakeCredential command as defined in -// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorMakeCredential -// It is essentially a shim that allows data to be copied from an IPDL-defined -// WebAuthnMakeCredentialInfo C++ struct to an authenticator-rs defined -// RegisterArgsCtap2 Rust struct. -// [uuid(2fc8febe-a277-11ed-bda2-8f6495a5e75c)] -interface nsICtapRegisterArgs : nsISupports { +interface nsIWebAuthnRegisterArgs : nsISupports { // TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove. readonly attribute AString origin; @@ -48,8 +41,8 @@ interface nsICtapRegisterArgs : nsISupports { [must_use] readonly attribute bool minPinLength; // Options. - [must_use] readonly attribute AString residentKey; - [must_use] readonly attribute AString userVerification; + readonly attribute AString residentKey; + readonly attribute AString userVerification; [must_use] readonly attribute AString authenticatorAttachment; // This is the WebAuthn PublicKeyCredentialCreationOptions timeout. @@ -63,15 +56,8 @@ interface nsICtapRegisterArgs : nsISupports { [must_use] readonly attribute AString attestationConveyancePreference; }; -// The nsICtapSignArgs interface encapsulates the arguments to the CTAP -// authenticatorGetAssertion command as defined in -// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetAssertion -// It is essentially a shim that allows data to be copied from an IPDL-defined -// WebAuthnGetAssertionInfo C++ struct to an authenticator-rs defined -// SignArgsCtap2 Rust struct. -// [uuid(2e621cf4-a277-11ed-ae00-bf41a54ef553)] -interface nsICtapSignArgs : nsISupports { +interface nsIWebAuthnSignArgs : nsISupports { // TODO(Bug 1820035) The origin is only used for prompt callbacks. Refactor and remove. readonly attribute AString origin; diff --git a/dom/webauthn/nsIWebAuthnPromise.idl b/dom/webauthn/nsIWebAuthnPromise.idl index 0d52f67f51c2..245515be3f0e 100644 --- a/dom/webauthn/nsIWebAuthnPromise.idl +++ b/dom/webauthn/nsIWebAuthnPromise.idl @@ -9,13 +9,13 @@ [rust_sync, uuid(3c969aec-e0e0-4aa4-9422-394b321e6918)] interface nsIWebAuthnRegisterPromise : nsISupports { - [noscript] void resolve(in nsICtapRegisterResult aResult); + [noscript] void resolve(in nsIWebAuthnRegisterResult aResult); [noscript] void reject(in nsresult error); }; [rust_sync, uuid(35e35bdc-5369-4bfe-8d5c-bdf7b782b735)] interface nsIWebAuthnSignPromise : nsISupports { - [noscript] void resolve(in nsICtapSignResult aResult); + [noscript] void resolve(in nsIWebAuthnSignResult aResult); [noscript] void reject(in nsresult error); }; diff --git a/dom/webauthn/nsIWebAuthnResult.idl b/dom/webauthn/nsIWebAuthnResult.idl index e3ff4dc8afa4..de9d5dff7d1f 100644 --- a/dom/webauthn/nsIWebAuthnResult.idl +++ b/dom/webauthn/nsIWebAuthnResult.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" [uuid(0567c384-a728-11ed-85f7-030324a370f0)] -interface nsICtapRegisterResult : nsISupports { +interface nsIWebAuthnRegisterResult : nsISupports { // The serialied attestation object as defined in // https://www.w3.org/TR/webauthn-2/#sctn-attestation // Includes the format, the attestation statement, and @@ -24,14 +24,14 @@ interface nsICtapRegisterResult : nsISupports { // bug 1593571 // readonly attribute bool hmacCreateSecret; - readonly attribute bool credPropsRk; + [must_use] attribute bool credPropsRk; }; -// The nsICtapSignResult interface is used to construct IPDL-defined +// The nsIWebAuthnSignResult interface is used to construct IPDL-defined // WebAuthnGetAssertionResult from either Rust or C++. // [uuid(05fff816-a728-11ed-b9ac-ff38cc2c8c28)] -interface nsICtapSignResult : nsISupports { +interface nsIWebAuthnSignResult : nsISupports { // The ID field of the PublicKeyCredentialDescriptor returned // from authenticatorGetAssertion. readonly attribute Array credentialId; diff --git a/dom/webauthn/nsIWebAuthnService.idl b/dom/webauthn/nsIWebAuthnService.idl index e8609b8381cd..65f4a6ddd18b 100644 --- a/dom/webauthn/nsIWebAuthnService.idl +++ b/dom/webauthn/nsIWebAuthnService.idl @@ -25,13 +25,13 @@ interface nsIWebAuthnService : nsISupports void makeCredential( in uint64_t aTransactionId, in uint64_t browsingContextId, - in nsICtapRegisterArgs args, + in nsIWebAuthnRegisterArgs args, in nsIWebAuthnRegisterPromise promise); void getAssertion( in uint64_t aTransactionId, in uint64_t browsingContextId, - in nsICtapSignArgs args, + in nsIWebAuthnSignArgs args, in nsIWebAuthnSignPromise promise); // Cancel the ongoing transaction and any prompts that are shown, but do not reject diff --git a/dom/webauthn/tests/browser/browser.toml b/dom/webauthn/tests/browser/browser.toml index 6629cb2fdb6a..b2cd7586c429 100644 --- a/dom/webauthn/tests/browser/browser.toml +++ b/dom/webauthn/tests/browser/browser.toml @@ -9,7 +9,6 @@ support-files = [ prefs = [ "security.webauth.webauthn=true", "security.webauth.webauthn_enable_softtoken=true", - "security.webauth.webauthn_enable_android_fido2=false", "security.webauth.webauthn_enable_usbtoken=false", "security.webauthn.ctap2=true", ] diff --git a/dom/webauthn/tests/browser/browser_webauthn_telemetry.js b/dom/webauthn/tests/browser/browser_webauthn_telemetry.js index 2d8b7c9458a5..043df1566eb3 100644 --- a/dom/webauthn/tests/browser/browser_webauthn_telemetry.js +++ b/dom/webauthn/tests/browser/browser_webauthn_telemetry.js @@ -46,7 +46,6 @@ add_task(async function test_setup() { ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], - ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_testing_allow_direct_attestation", true], ], }); diff --git a/dom/webauthn/tests/mochitest.ini b/dom/webauthn/tests/mochitest.ini index d0fb118297c8..43a5a4dab633 100644 --- a/dom/webauthn/tests/mochitest.ini +++ b/dom/webauthn/tests/mochitest.ini @@ -10,7 +10,6 @@ prefs = dom.security.featurePolicy.webidl.enabled=true security.webauth.webauthn=true security.webauth.webauthn_enable_softtoken=true - security.webauth.webauthn_enable_android_fido2=false security.webauth.webauthn_enable_usbtoken=false security.webauthn.ctap2=true diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 25e49376d2a5..c63aad325214 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -104,9 +104,6 @@ #include "mozilla/dom/AbstractRange.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/WebIDLGlobalNameHash.h" -#ifdef MOZ_WIDGET_ANDROID -# include "mozilla/dom/U2FTokenManager.h" -#endif #ifdef XP_WIN # include "mozilla/dom/WinWebAuthnManager.h" #endif @@ -260,10 +257,6 @@ nsresult nsLayoutStatics::Initialize() { // This must be initialized on the main-thread. mozilla::RemoteLazyInputStreamStorage::Initialize(); -#ifdef MOZ_WIDGET_ANDROID - mozilla::dom::U2FTokenManager::Initialize(); -#endif - #ifdef XP_WIN mozilla::dom::WinWebAuthnManager::Initialize(); #endif diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 1ea91d7b3c21..58e86c7a144e 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -13709,20 +13709,14 @@ mirror: always rust: true -# Dispatch WebAuthn requests to virtual authenticators. (mutually exclusive -# with webauthn_enable_android_fido2, and webauthn_enable_usbtoken) +# Dispatch WebAuthn requests to virtual authenticators (mutually exclusive +# with and webauthn_enable_usbtoken) - name: security.webauth.webauthn_enable_softtoken type: RelaxedAtomicBool value: false mirror: always rust: true -# Dispatch WebAuthn requests to the Android platform API -- name: security.webauth.webauthn_enable_android_fido2 - type: RelaxedAtomicBool - value: @IS_ANDROID@ - mirror: always - # residentKey support when using Android platform API - name: security.webauthn.webauthn_enable_android_fido2.residentkey type: RelaxedAtomicBool diff --git a/testing/profiles/web-platform/user.js b/testing/profiles/web-platform/user.js index 625bcc519fd6..65db50a14b75 100644 --- a/testing/profiles/web-platform/user.js +++ b/testing/profiles/web-platform/user.js @@ -87,7 +87,6 @@ user_pref("gecko.handlerService.defaultHandlersVersion", 100); user_pref("security.webauth.webauthn_enable_softtoken", true); // Disable hardware WebAuthn authenticators. user_pref("security.webauth.webauthn_enable_usbtoken", false); -user_pref("security.webauth.webauthn_enable_android_fido2", false); // Disable the WebAuthn direct attestation consent prompt. user_pref("security.webauth.webauthn_testing_allow_direct_attestation", true); // Disable captive portal service