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 18 kB image not shown  

Impressum WebAuthnTransactionParent.cpp   Sprache: C

 
/* -*- 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/dom/WebAuthnTransactionParent.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/StaticPrefs_security.h"

#include "nsThreadUtils.h"
#include "WebAuthnArgs.h"

namespace mozilla::dom {

void WebAuthnTransactionParent::CompleteTransaction() {
  if (mTransactionId.isSome()) {
    if (mRegisterPromiseRequest.Exists()) {
      mRegisterPromiseRequest.Complete();
    }
    if (mSignPromiseRequest.Exists()) {
      mSignPromiseRequest.Complete();
    }
    if (mWebAuthnService) {
      // We have to do this to work around Bug 1864526.
      mWebAuthnService->Cancel(mTransactionId.ref());
    }
    mTransactionId.reset();
  }
}

void WebAuthnTransactionParent::DisconnectTransaction() {
  mTransactionId.reset();
  mRegisterPromiseRequest.DisconnectIfExists();
  mSignPromiseRequest.DisconnectIfExists();
  if (mWebAuthnService) {
    mWebAuthnService->Reset();
  }
}

mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestRegister(
    const uint64_t& aTransactionId,
    const WebAuthnMakeCredentialInfo& aTransactionInfo) {
  ::mozilla::ipc::AssertIsOnBackgroundThread();

  if (!mWebAuthnService) {
    mWebAuthnService = do_GetService("@mozilla.org/webauthn/service;1");
    if (!mWebAuthnService) {
      return IPC_FAIL_NO_REASON(this);
    }
  }

  // If there's an ongoing transaction, abort it.
  if (mTransactionId.isSome()) {
    DisconnectTransaction();
    Unused << SendAbort(mTransactionId.ref(), NS_ERROR_DOM_ABORT_ERR);
  }
  mTransactionId = Some(aTransactionId);

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

  PWebAuthnTransactionParent* parent = this;
  RefPtr<WebAuthnRegisterPromise> promise = promiseHolder->Ensure();
  promise
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [this, parent, aTransactionId,
           inputClientData = aTransactionInfo.ClientDataJSON()](
              const WebAuthnRegisterPromise::ResolveValueType& aValue) {
            CompleteTransaction();

            nsCString clientData;
            nsresult rv = aValue->GetClientDataJSON(clientData);
            if (rv == NS_ERROR_NOT_AVAILABLE) {
              clientData = inputClientData;
            } else if (NS_FAILED(rv)) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> attObj;
            rv = aValue->GetAttestationObject(attObj);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> credentialId;
            rv = aValue->GetCredentialId(credentialId);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<nsString> transports;
            rv = aValue->GetTransports(transports);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            Maybe<nsString> authenticatorAttachment;
            nsString maybeAuthenticatorAttachment;
            rv = aValue->GetAuthenticatorAttachment(
                maybeAuthenticatorAttachment);
            if (rv != NS_ERROR_NOT_AVAILABLE) {
              if (NS_WARN_IF(NS_FAILED(rv))) {
                Unused << parent->SendAbort(aTransactionId,
                                            NS_ERROR_DOM_NOT_ALLOWED_ERR);
                return;
              }
              authenticatorAttachment = Some(maybeAuthenticatorAttachment);
            }

            nsTArray<WebAuthnExtensionResult> extensions;
            bool credPropsRk;
            rv = aValue->GetCredPropsRk(&credPropsRk);
            if (rv != NS_ERROR_NOT_AVAILABLE) {
              if (NS_WARN_IF(NS_FAILED(rv))) {
                Unused << parent->SendAbort(aTransactionId,
                                            NS_ERROR_DOM_NOT_ALLOWED_ERR);
                return;
              }
              extensions.AppendElement(
                  WebAuthnExtensionResultCredProps(credPropsRk));
            }

            bool hmacCreateSecret;
            rv = aValue->GetHmacCreateSecret(&hmacCreateSecret);
            if (rv != NS_ERROR_NOT_AVAILABLE) {
              if (NS_WARN_IF(NS_FAILED(rv))) {
                Unused << parent->SendAbort(aTransactionId,
                                            NS_ERROR_DOM_NOT_ALLOWED_ERR);
                return;
              }
              extensions.AppendElement(
                  WebAuthnExtensionResultHmacSecret(hmacCreateSecret));
            }

            {
              Maybe<bool> prfEnabledMaybe = Nothing();
              Maybe<WebAuthnExtensionPrfValues> prfResults = Nothing();

              bool prfEnabled;
              rv = aValue->GetPrfEnabled(&prfEnabled);
              if (rv != NS_ERROR_NOT_AVAILABLE) {
                if (NS_WARN_IF(NS_FAILED(rv))) {
                  Unused << parent->SendAbort(aTransactionId,
                                              NS_ERROR_DOM_NOT_ALLOWED_ERR);
                  return;
                }
                prfEnabledMaybe = Some(prfEnabled);
              }

              nsTArray<uint8_t> prfResultsFirst;
              rv = aValue->GetPrfResultsFirst(prfResultsFirst);
              if (rv != NS_ERROR_NOT_AVAILABLE) {
                if (NS_WARN_IF(NS_FAILED(rv))) {
                  Unused << parent->SendAbort(aTransactionId,
                                              NS_ERROR_DOM_NOT_ALLOWED_ERR);
                  return;
                }

                bool prfResultsSecondMaybe = false;
                nsTArray<uint8_t> prfResultsSecond;
                rv = aValue->GetPrfResultsSecond(prfResultsSecond);
                if (rv != NS_ERROR_NOT_AVAILABLE) {
                  if (NS_WARN_IF(NS_FAILED(rv))) {
                    Unused << parent->SendAbort(aTransactionId,
                                                NS_ERROR_DOM_NOT_ALLOWED_ERR);
                    return;
                  }
                  prfResultsSecondMaybe = true;
                }

                prfResults = Some(WebAuthnExtensionPrfValues(
                    prfResultsFirst, prfResultsSecondMaybe, prfResultsSecond));
              }

              if (prfEnabledMaybe.isSome() || prfResults.isSome()) {
                extensions.AppendElement(
                    WebAuthnExtensionResultPrf(prfEnabledMaybe, prfResults));
              }
            }

            WebAuthnMakeCredentialResult result(
                clientData, attObj, credentialId, transports, extensions,
                authenticatorAttachment);

            Unused << parent->SendConfirmRegister(aTransactionId, result);
          },
          [this, parent, aTransactionId](
              const WebAuthnRegisterPromise::RejectValueType aValue) {
            CompleteTransaction();
            Unused << parent->SendAbort(aTransactionId, aValue);
          })
      ->Track(mRegisterPromiseRequest);

  uint64_t browsingContextId = aTransactionInfo.BrowsingContextId();
  RefPtr<WebAuthnRegisterArgs> args(new WebAuthnRegisterArgs(aTransactionInfo));

  nsresult rv = mWebAuthnService->MakeCredential(
      aTransactionId, browsingContextId, args, promiseHolder);
  if (NS_FAILED(rv)) {
    promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
  }

  return IPC_OK();
}

mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestSign(
    const uint64_t& aTransactionId,
    const WebAuthnGetAssertionInfo& aTransactionInfo) {
  ::mozilla::ipc::AssertIsOnBackgroundThread();

  if (!mWebAuthnService) {
    mWebAuthnService = do_GetService("@mozilla.org/webauthn/service;1");
    if (!mWebAuthnService) {
      return IPC_FAIL_NO_REASON(this);
    }
  }

  if (mTransactionId.isSome()) {
    DisconnectTransaction();
    Unused << SendAbort(mTransactionId.ref(), NS_ERROR_DOM_ABORT_ERR);
  }
  mTransactionId = Some(aTransactionId);

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

  PWebAuthnTransactionParent* parent = this;
  RefPtr<WebAuthnSignPromise> promise = promiseHolder->Ensure();
  promise
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [this, parent, aTransactionId,
           inputClientData = aTransactionInfo.ClientDataJSON()](
              const WebAuthnSignPromise::ResolveValueType& aValue) {
            CompleteTransaction();

            nsCString clientData;
            nsresult rv = aValue->GetClientDataJSON(clientData);
            if (rv == NS_ERROR_NOT_AVAILABLE) {
              clientData = inputClientData;
            } else if (NS_FAILED(rv)) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> credentialId;
            rv = aValue->GetCredentialId(credentialId);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> signature;
            rv = aValue->GetSignature(signature);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> authenticatorData;
            rv = aValue->GetAuthenticatorData(authenticatorData);
            if (NS_WARN_IF(NS_FAILED(rv))) {
              Unused << parent->SendAbort(aTransactionId,
                                          NS_ERROR_DOM_NOT_ALLOWED_ERR);
              return;
            }

            nsTArray<uint8_t> userHandle;
            Unused << aValue->GetUserHandle(userHandle);  // optional

            Maybe<nsString> authenticatorAttachment;
            nsString maybeAuthenticatorAttachment;
            rv = aValue->GetAuthenticatorAttachment(
                maybeAuthenticatorAttachment);
            if (rv != NS_ERROR_NOT_AVAILABLE) {
              if (NS_WARN_IF(NS_FAILED(rv))) {
                Unused << parent->SendAbort(aTransactionId,
                                            NS_ERROR_DOM_NOT_ALLOWED_ERR);
                return;
              }
              authenticatorAttachment = Some(maybeAuthenticatorAttachment);
            }

            nsTArray<WebAuthnExtensionResult> extensions;
            bool usedAppId;
            rv = aValue->GetUsedAppId(&usedAppId);
            if (rv != NS_ERROR_NOT_AVAILABLE) {
              if (NS_FAILED(rv)) {
                Unused << parent->SendAbort(aTransactionId,
                                            NS_ERROR_DOM_NOT_ALLOWED_ERR);
                return;
              }
              extensions.AppendElement(WebAuthnExtensionResultAppId(usedAppId));
            }

            {
              Maybe<WebAuthnExtensionPrfValues> prfResults;
              bool prfMaybe = false;
              rv = aValue->GetPrfMaybe(&prfMaybe);
              if (rv == NS_OK && prfMaybe) {
                nsTArray<uint8_t> prfResultsFirst;
                rv = aValue->GetPrfResultsFirst(prfResultsFirst);
                if (rv != NS_ERROR_NOT_AVAILABLE) {
                  if (NS_WARN_IF(NS_FAILED(rv))) {
                    Unused << parent->SendAbort(aTransactionId,
                                                NS_ERROR_DOM_NOT_ALLOWED_ERR);
                    return;
                  }

                  bool prfResultsSecondMaybe = false;
                  nsTArray<uint8_t> prfResultsSecond;
                  rv = aValue->GetPrfResultsSecond(prfResultsSecond);
                  if (rv != NS_ERROR_NOT_AVAILABLE) {
                    if (NS_WARN_IF(NS_FAILED(rv))) {
                      Unused << parent->SendAbort(aTransactionId,
                                                  NS_ERROR_DOM_NOT_ALLOWED_ERR);
                      return;
                    }
                    prfResultsSecondMaybe = true;
                  }

                  prfResults = Some(WebAuthnExtensionPrfValues(
                      prfResultsFirst, prfResultsSecondMaybe,
                      prfResultsSecond));
                } else {
                  prfResults = Nothing();
                }

                extensions.AppendElement(
                    WebAuthnExtensionResultPrf(Nothing(), prfResults));
              }
            }

            WebAuthnGetAssertionResult result(
                clientData, credentialId, signature, authenticatorData,
                extensions, userHandle, authenticatorAttachment);

            Unused << parent->SendConfirmSign(aTransactionId, result);
          },
          [this, parent,
           aTransactionId](const WebAuthnSignPromise::RejectValueType aValue) {
            CompleteTransaction();
            Unused << parent->SendAbort(aTransactionId, aValue);
          })
      ->Track(mSignPromiseRequest);

  RefPtr<WebAuthnSignArgs> args(new WebAuthnSignArgs(aTransactionInfo));

  nsresult rv = mWebAuthnService->GetAssertion(
      aTransactionId, aTransactionInfo.BrowsingContextId(), args,
      promiseHolder);
  if (NS_FAILED(rv)) {
    promiseHolder->Reject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
  }

  return IPC_OK();
}

mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestCancel(
    const Tainted<uint64_t>& aTransactionId) {
  ::mozilla::ipc::AssertIsOnBackgroundThread();

  if (mTransactionId.isNothing() ||
      !MOZ_IS_VALID(aTransactionId, mTransactionId.ref() == aTransactionId)) {
    return IPC_OK();
  }

  DisconnectTransaction();
  return IPC_OK();
}

mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvRequestIsUVPAA(
    RequestIsUVPAAResolver&& aResolver) {
#ifdef MOZ_WIDGET_ANDROID
  // Try the nsIWebAuthnService. If we're configured for tests we
  // will get a result. Otherwise we expect NS_ERROR_NOT_IMPLEMENTED.
  nsCOMPtr<nsIWebAuthnService> service(
      do_GetService("@mozilla.org/webauthn/service;1"));
  bool available;
  nsresult rv = service->GetIsUVPAA(&available);
  if (NS_SUCCEEDED(rv)) {
    aResolver(available);
    return IPC_OK();
  }

  // Don't consult the platform API if resident key support is disabled.
  if (!StaticPrefs::
          security_webauthn_webauthn_enable_android_fido2_residentkey()) {
    aResolver(false);
    return IPC_OK();
  }

  // The GeckoView implementation of
  // isUserVerifiyingPlatformAuthenticatorAvailable does not block, but we must
  // call it on the main thread. It returns a MozPromise which we can ->Then to
  // call aResolver on the IPDL background thread.
  //
  // Bug 1550788: there is an unnecessary layer of dispatching here: ipdl ->
  // main -> a background thread. Other platforms just do ipdl -> a background
  // thread.
  nsCOMPtr<nsISerialEventTarget> target = GetCurrentSerialEventTarget();
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
      __func__, [target, resolver = std::move(aResolver)]() {
        auto result = java::WebAuthnTokenManager::
            WebAuthnIsUserVerifyingPlatformAuthenticatorAvailable();
        auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
        MozPromise<boolboolfalse>::FromGeckoResult(geckoResult)
            ->Then(
                target, __func__,
                [resolver](
                    const MozPromise<boolboolfalse>::ResolveOrRejectValue&
                        aValue) {
                  if (aValue.IsResolve()) {
                    resolver(aValue.ResolveValue());
                  } else {
                    resolver(false);
                  }
                });
      }));
  NS_DispatchToMainThread(runnable.forget());
  return IPC_OK();

#else

  nsCOMPtr<nsISerialEventTarget> target = GetCurrentSerialEventTarget();
  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
      __func__, [target, resolver = std::move(aResolver)]() {
        bool available;
        nsCOMPtr<nsIWebAuthnService> service(
            do_GetService("@mozilla.org/webauthn/service;1"));
        nsresult rv = service->GetIsUVPAA(&available);
        if (NS_FAILED(rv)) {
          available = false;
        }
        BoolPromise::CreateAndResolve(available, __func__)
            ->Then(target, __func__,
                   [resolver](const BoolPromise::ResolveOrRejectValue& value) {
                     if (value.IsResolve()) {
                       resolver(value.ResolveValue());
                     } else {
                       resolver(false);
                     }
                   });
      }));
  NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCK);
  return IPC_OK();
#endif
}

mozilla::ipc::IPCResult WebAuthnTransactionParent::RecvDestroyMe() {
  ::mozilla::ipc::AssertIsOnBackgroundThread();

  // The child was disconnected from the WebAuthnManager instance and will send
  // no further messages. It is kept alive until we delete it explicitly.

  // The child should have cancelled any active transaction. This means
  // we expect no more messages to the child. We'll crash otherwise.

  // The IPC roundtrip is complete. No more messages, hopefully.
  IProtocol* mgr = Manager();
  if (!Send__delete__(this)) {
    return IPC_FAIL_NO_REASON(mgr);
  }

  return IPC_OK();
}

void WebAuthnTransactionParent::ActorDestroy(ActorDestroyReason aWhy) {
  ::mozilla::ipc::AssertIsOnBackgroundThread();

  // Called either by Send__delete__() in RecvDestroyMe() above, or when
  // the channel disconnects. Ensure the token manager forgets about us.

  if (mTransactionId.isSome()) {
    DisconnectTransaction();
  }
}

}  // namespace mozilla::dom

Messung V0.5
C=88 H=97 G=92

¤ 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.0.14Bemerkung:  (vorverarbeitet)  ¤

*Bot Zugriff






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.