Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/webauthn/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  WebAuthnService.cpp   Sprache: C

 
/* 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/Services.h"
#include "mozilla/StaticPrefs_security.h"
#include "nsIObserverService.h"
#include "nsTextFormatter.h"
#include "nsThreadUtils.h"
#include "WebAuthnEnumStrings.h"
#include "WebAuthnService.h"
#include "WebAuthnTransportIdentifiers.h"

namespace mozilla::dom {

already_AddRefed<nsIWebAuthnService> NewWebAuthnService() {
  nsCOMPtr<nsIWebAuthnService> webauthnService(new WebAuthnService());
  return webauthnService.forget();
}

NS_IMPL_ISUPPORTS(WebAuthnService, nsIWebAuthnService)

void WebAuthnService::ShowAttestationConsentPrompt(
    const nsString& aOrigin, uint64_t aTransactionId,
    uint64_t aBrowsingContextId) {
  RefPtr<WebAuthnService> self = this;
#ifdef MOZ_WIDGET_ANDROID
  // We don't have a way to prompt the user for consent on Android, so just
  // assume consent not granted.
  nsCOMPtr<nsIRunnable> runnable(
      NS_NewRunnableFunction(__func__, [self, aTransactionId]() {
        self->SetHasAttestationConsent(
            aTransactionId,
            StaticPrefs::
                security_webauth_webauthn_testing_allow_direct_attestation());
      }));
#else
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
      __func__, [self, aOrigin, aTransactionId, aBrowsingContextId]() {
        if (StaticPrefs::
                security_webauth_webauthn_testing_allow_direct_attestation()) {
          self->SetHasAttestationConsent(aTransactionId, true);
          return;
        }
        nsCOMPtr<nsIObserverService> os = services::GetObserverService();
        if (!os) {
          return;
        }
        const nsLiteralString jsonFmt =
            u"{\"prompt\": {\"type\":\"attestation-consent\"},"_ns
            u"\"origin\": \"%S\","_ns
            u"\"tid\": %llu, \"browsingContextId\": %llu}"_ns;
        nsString json;
        nsTextFormatter::ssprintf(json, jsonFmt.get(), aOrigin.get(),
                                  aTransactionId, aBrowsingContextId);
        MOZ_ALWAYS_SUCCEEDS(
            os->NotifyObservers(nullptr, "webauthn-prompt", json.get()));
      }));
#endif
  NS_DispatchToMainThread(runnable.forget());
}

NS_IMETHODIMP
WebAuthnService::MakeCredential(uint64_t aTransactionId,
                                uint64_t aBrowsingContextId,
                                nsIWebAuthnRegisterArgs* aArgs,
                                nsIWebAuthnRegisterPromise* aPromise) {
  MOZ_ASSERT(aArgs);
  MOZ_ASSERT(aPromise);

  auto guard = mTransactionState.Lock();
  ResetLocked(guard);
  *guard = Some(TransactionState{.service = DefaultService(),
                                 .transactionId = aTransactionId,
                                 .parentRegisterPromise = Some(aPromise)});

  // We may need to show an attestation consent prompt before we return a
  // credential to WebAuthnTransactionParent, so we insert a new promise that
  // chains to `aPromise` here.

  nsString attestation;
  Unused << aArgs->GetAttestationConveyancePreference(attestation);
  bool attestationRequested = !attestation.EqualsLiteral(
      MOZ_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE);

  nsString origin;
  Unused << aArgs->GetOrigin(origin);

  RefPtr<WebAuthnRegisterPromiseHolder> promiseHolder =
      new WebAuthnRegisterPromiseHolder(GetCurrentSerialEventTarget());

  RefPtr<WebAuthnService> self = this;
  RefPtr<WebAuthnRegisterPromise> promise = promiseHolder->Ensure();
  promise
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [self, origin, aTransactionId, aBrowsingContextId,
           attestationRequested](
              const WebAuthnRegisterPromise::ResolveOrRejectValue& aValue) {
            auto guard = self->mTransactionState.Lock();
            if (guard->isNothing()) {
              return;
            }
            MOZ_ASSERT(guard->ref().parentRegisterPromise.isSome());
            MOZ_ASSERT(guard->ref().registerResult.isNothing());
            MOZ_ASSERT(guard->ref().childRegisterRequest.Exists());

            guard->ref().childRegisterRequest.Complete();

            if (aValue.IsReject()) {
              guard->ref().parentRegisterPromise.ref()->Reject(
                  aValue.RejectValue());
              guard->reset();
              return;
            }

            nsIWebAuthnRegisterResult* result = aValue.ResolveValue();
            // If the RP requested attestation, we need to show a consent prompt
            // before returning any identifying information. The platform may
            // have already done this for us, so we need to inspect the
            // attestation object at this point.
            bool resultIsIdentifying = true;
            Unused << result->HasIdentifyingAttestation(&resultIsIdentifying);
            if (attestationRequested && resultIsIdentifying) {
              guard->ref().registerResult = Some(result);
              self->ShowAttestationConsentPrompt(origin, aTransactionId,
                                                 aBrowsingContextId);
              return;
            }
            result->Anonymize();
            guard->ref().parentRegisterPromise.ref()->Resolve(result);
            guard->reset();
          })
      ->Track(guard->ref().childRegisterRequest);

  nsresult rv = guard->ref().service->MakeCredential(
      aTransactionId, aBrowsingContextId, aArgs, promiseHolder);
  if (NS_FAILED(rv)) {
    promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
  }
  return NS_OK;
}

NS_IMETHODIMP
WebAuthnService::GetAssertion(uint64_t aTransactionId,
                              uint64_t aBrowsingContextId,
                              nsIWebAuthnSignArgs* aArgs,
                              nsIWebAuthnSignPromise* aPromise) {
  MOZ_ASSERT(aArgs);
  MOZ_ASSERT(aPromise);

  auto guard = mTransactionState.Lock();
  ResetLocked(guard);
  *guard = Some(TransactionState{.service = DefaultService(),
                                 .transactionId = aTransactionId});
  nsresult rv;

#if defined(XP_MACOSX)
  // The macOS security key API doesn't handle the AppID extension. So we'll
  // use authenticator-rs if it's likely that the request requires AppID. We
  // consider it likely if 1) the AppID extension is present, 2) the allow list
  // is non-empty, and 3) none of the allowed credentials use the
  // "internal" or "hybrid" transport.
  nsString appId;
  rv = aArgs->GetAppId(appId);
  if (rv == NS_OK) {  // AppID is set
    uint8_t transportSet = 0;
    nsTArray<uint8_t> allowListTransports;
    Unused << aArgs->GetAllowListTransports(allowListTransports);
    for (const uint8_t& transport : allowListTransports) {
      transportSet |= transport;
    }
    uint8_t passkeyTransportMask =
        MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_INTERNAL |
        MOZ_WEBAUTHN_AUTHENTICATOR_TRANSPORT_ID_HYBRID;
    if (allowListTransports.Length() > 0 &&
        (transportSet & passkeyTransportMask) == 0) {
      guard->ref().service = AuthrsService();
    }
  }
#endif

  rv = guard->ref().service->GetAssertion(aTransactionId, aBrowsingContextId,
                                          aArgs, aPromise);
  if (NS_FAILED(rv)) {
    return rv;
  }

  // If this is a conditionally mediated request, notify observers that there
  // is a pending transaction. This is mainly useful in tests.
  bool conditionallyMediated;
  Unused << aArgs->GetConditionallyMediated(&conditionallyMediated);
  if (conditionallyMediated) {
    nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(__func__, []() {
      nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
      if (os) {
        os->NotifyObservers(nullptr, "webauthn:conditional-get-pending",
                            nullptr);
      }
    }));
    NS_DispatchToMainThread(runnable.forget());
  }

  return NS_OK;
}

NS_IMETHODIMP
WebAuthnService::GetIsUVPAA(bool* aAvailable) {
  return DefaultService()->GetIsUVPAA(aAvailable);
}

NS_IMETHODIMP
WebAuthnService::HasPendingConditionalGet(uint64_t aBrowsingContextId,
                                          const nsAString& aOrigin,
                                          uint64_t* aRv) {
  return SelectedService()->HasPendingConditionalGet(aBrowsingContextId,
                                                     aOrigin, aRv);
}

NS_IMETHODIMP
WebAuthnService::GetAutoFillEntries(
    uint64_t aTransactionId, nsTArray<RefPtr<nsIWebAuthnAutoFillEntry>>& aRv) {
  return SelectedService()->GetAutoFillEntries(aTransactionId, aRv);
}

NS_IMETHODIMP
WebAuthnService::SelectAutoFillEntry(uint64_t aTransactionId,
                                     const nsTArray<uint8_t>& aCredentialId) {
  return SelectedService()->SelectAutoFillEntry(aTransactionId, aCredentialId);
}

NS_IMETHODIMP
WebAuthnService::ResumeConditionalGet(uint64_t aTransactionId) {
  return SelectedService()->ResumeConditionalGet(aTransactionId);
}

void WebAuthnService::ResetLocked(
    const TransactionStateMutex::AutoLock& aGuard) {
  if (aGuard->isSome()) {
    aGuard->ref().childRegisterRequest.DisconnectIfExists();
    if (aGuard->ref().parentRegisterPromise.isSome()) {
      aGuard->ref().parentRegisterPromise.ref()->Reject(NS_ERROR_DOM_ABORT_ERR);
    }
    aGuard->ref().service->Reset();
  }
  aGuard->reset();
}

NS_IMETHODIMP
WebAuthnService::Reset() {
  auto guard = mTransactionState.Lock();
  ResetLocked(guard);
  return NS_OK;
}

NS_IMETHODIMP
WebAuthnService::Cancel(uint64_t aTransactionId) {
  return SelectedService()->Cancel(aTransactionId);
}

NS_IMETHODIMP
WebAuthnService::PinCallback(uint64_t aTransactionId, const nsACString& aPin) {
  return SelectedService()->PinCallback(aTransactionId, aPin);
}

NS_IMETHODIMP
WebAuthnService::SetHasAttestationConsent(uint64_t aTransactionId,
                                          bool aHasConsent) {
  auto guard = this->mTransactionState.Lock();
  if (guard->isNothing() || guard->ref().transactionId != aTransactionId) {
    // This could happen if the transaction was reset just when the prompt was
    // receiving user input.
    return NS_OK;
  }

  MOZ_ASSERT(guard->ref().parentRegisterPromise.isSome());
  MOZ_ASSERT(guard->ref().registerResult.isSome());
  MOZ_ASSERT(!guard->ref().childRegisterRequest.Exists());

  if (!aHasConsent) {
    guard->ref().registerResult.ref()->Anonymize();
  }
  guard->ref().parentRegisterPromise.ref()->Resolve(
      guard->ref().registerResult.ref());

  guard->reset();
  return NS_OK;
}

NS_IMETHODIMP
WebAuthnService::SelectionCallback(uint64_t aTransactionId, uint64_t aIndex) {
  return SelectedService()->SelectionCallback(aTransactionId, aIndex);
}

NS_IMETHODIMP
WebAuthnService::AddVirtualAuthenticator(
    const nsACString& protocol, const nsACString& transport,
    bool hasResidentKey, bool hasUserVerification, bool isUserConsenting,
    bool isUserVerified, uint64_t* retval) {
  return SelectedService()->AddVirtualAuthenticator(
      protocol, transport, hasResidentKey, hasUserVerification,
      isUserConsenting, isUserVerified, retval);
}

NS_IMETHODIMP
WebAuthnService::RemoveVirtualAuthenticator(uint64_t authenticatorId) {
  return SelectedService()->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) {
  return SelectedService()->AddCredential(authenticatorId, credentialId,
                                          isResidentCredential, rpId,
                                          privateKey, userHandle, signCount);
}

NS_IMETHODIMP
WebAuthnService::GetCredentials(
    uint64_t authenticatorId,
    nsTArray<RefPtr<nsICredentialParameters>>& retval) {
  return SelectedService()->GetCredentials(authenticatorId, retval);
}

NS_IMETHODIMP
WebAuthnService::RemoveCredential(uint64_t authenticatorId,
                                  const nsACString& credentialId) {
  return SelectedService()->RemoveCredential(authenticatorId, credentialId);
}

NS_IMETHODIMP
WebAuthnService::RemoveAllCredentials(uint64_t authenticatorId) {
  return SelectedService()->RemoveAllCredentials(authenticatorId);
}

NS_IMETHODIMP
WebAuthnService::SetUserVerified(uint64_t authenticatorId,
                                 bool isUserVerified) {
  return SelectedService()->SetUserVerified(authenticatorId, isUserVerified);
}

NS_IMETHODIMP
WebAuthnService::Listen() { return SelectedService()->Listen(); }

NS_IMETHODIMP
WebAuthnService::RunCommand(const nsACString& cmd) {
  return SelectedService()->RunCommand(cmd);
}

}  // namespace mozilla::dom

Messung V0.5
C=89 H=97 G=93

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.