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

Quelle  nsClientAuthRemember.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * 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 "nsClientAuthRemember.h"

#include "mozilla/BasePrincipal.h"
#include "mozilla/RefPtr.h"
#include "nsCRT.h"
#include "nsINSSComponent.h"
#include "nsPrintfCString.h"
#include "nsNSSComponent.h"
#include "nsIDataStorage.h"
#include "nsIObserverService.h"
#include "nsNetUtil.h"
#include "nsPromiseFlatString.h"
#include "nsThreadUtils.h"
#include "cert.h"
#include "nspr.h"
#include "pk11pub.h"
#include "certdb.h"
#include "sechash.h"

#include "nsJSUtils.h"

#ifdef XP_MACOSX
#  include <CoreFoundation/CoreFoundation.h>
#  include <Security/Security.h>
#  include "KeychainSecret.h"  // for ScopedCFType
#endif                         // XP_MACOSX

using namespace mozilla;
using namespace mozilla::psm;

NS_IMPL_ISUPPORTS(nsClientAuthRememberService, nsIClientAuthRememberService)
NS_IMPL_ISUPPORTS(nsClientAuthRemember, nsIClientAuthRememberRecord)

NS_IMETHODIMP
nsClientAuthRemember::GetAsciiHost(/*out*/ nsACString& aAsciiHost) {
  aAsciiHost = mAsciiHost;
  return NS_OK;
}

NS_IMETHODIMP
nsClientAuthRemember::GetDbKey(/*out*/ nsACString& aDBKey) {
  aDBKey = mDBKey;
  return NS_OK;
}

NS_IMETHODIMP
nsClientAuthRemember::GetEntryKey(/*out*/ nsACString& aEntryKey) {
  aEntryKey.Assign(mAsciiHost);
  aEntryKey.Append(',');
  // This used to include the SHA-256 hash of the server certificate.
  aEntryKey.Append(',');
  aEntryKey.Append(mOriginAttributesSuffix);
  return NS_OK;
}

nsresult nsClientAuthRememberService::Init() {
  if (!NS_IsMainThread()) {
    NS_ERROR("nsClientAuthRememberService::Init called off the main thread");
    return NS_ERROR_NOT_SAME_THREAD;
  }

  nsCOMPtr<nsIDataStorageManager> dataStorageManager(
      do_GetService("@mozilla.org/security/datastoragemanager;1"));
  if (!dataStorageManager) {
    return NS_ERROR_FAILURE;
  }
  nsresult rv =
      dataStorageManager->Get(nsIDataStorageManager::ClientAuthRememberList,
                              getter_AddRefs(mClientAuthRememberList));
  if (NS_FAILED(rv)) {
    return rv;
  }
  if (!mClientAuthRememberList) {
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}

NS_IMETHODIMP
nsClientAuthRememberService::ForgetRememberedDecision(const nsACString& key) {
  nsresult rv = mClientAuthRememberList->Remove(
      PromiseFlatCString(key), nsIDataStorage::DataType::Persistent);
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(NS_NSSCOMPONENT_CID));
  if (!nssComponent) {
    return NS_ERROR_NOT_AVAILABLE;
  }
  return nssComponent->ClearSSLExternalAndInternalSessionCache();
}

NS_IMETHODIMP
nsClientAuthRememberService::GetDecisions(
    nsTArray<RefPtr<nsIClientAuthRememberRecord>>& results) {
  nsTArray<RefPtr<nsIDataStorageItem>> decisions;
  nsresult rv = mClientAuthRememberList->GetAll(decisions);
  if (NS_FAILED(rv)) {
    return rv;
  }

  for (const auto& decision : decisions) {
    nsIDataStorage::DataType type;
    rv = decision->GetType(&type);
    if (NS_FAILED(rv)) {
      return rv;
    }
    if (type == nsIDataStorage::DataType::Persistent) {
      nsAutoCString key;
      rv = decision->GetKey(key);
      if (NS_FAILED(rv)) {
        return rv;
      }
      nsAutoCString value;
      rv = decision->GetValue(value);
      if (NS_FAILED(rv)) {
        return rv;
      }
      RefPtr<nsIClientAuthRememberRecord> tmp =
          new nsClientAuthRemember(key, value);

      results.AppendElement(tmp);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP
nsClientAuthRememberService::ClearRememberedDecisions() {
  nsresult rv = mClientAuthRememberList->Clear();
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(NS_NSSCOMPONENT_CID));
  if (!nssComponent) {
    return NS_ERROR_NOT_AVAILABLE;
  }
  return nssComponent->ClearSSLExternalAndInternalSessionCache();
}

NS_IMETHODIMP
nsClientAuthRememberService::DeleteDecisionsByHost(
    const nsACString& aHostName, JS::Handle<JS::Value> aOriginAttributes,
    JSContext* aCx) {
  OriginAttributes attrs;
  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    return NS_ERROR_INVALID_ARG;
  }
  nsIDataStorage::DataType storageType = GetDataStorageType(attrs);

  nsTArray<RefPtr<nsIDataStorageItem>> decisions;
  nsresult rv = mClientAuthRememberList->GetAll(decisions);
  if (NS_FAILED(rv)) {
    return rv;
  }

  for (const auto& decision : decisions) {
    nsIDataStorage::DataType type;
    nsresult rv = decision->GetType(&type);
    if (NS_FAILED(rv)) {
      return rv;
    }
    if (type == storageType) {
      nsAutoCString key;
      rv = decision->GetKey(key);
      if (NS_FAILED(rv)) {
        return rv;
      }
      nsAutoCString value;
      rv = decision->GetValue(value);
      if (NS_FAILED(rv)) {
        return rv;
      }
      RefPtr<nsIClientAuthRememberRecord> tmp =
          new nsClientAuthRemember(key, value);
      nsAutoCString asciiHost;
      tmp->GetAsciiHost(asciiHost);
      if (asciiHost.Equals(aHostName)) {
        rv = mClientAuthRememberList->Remove(key, type);
        if (NS_FAILED(rv)) {
          return rv;
        }
      }
    }
  }
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(NS_NSSCOMPONENT_CID));
  if (!nssComponent) {
    return NS_ERROR_NOT_AVAILABLE;
  }
  return nssComponent->ClearSSLExternalAndInternalSessionCache();
}

NS_IMETHODIMP
nsClientAuthRememberService::RememberDecisionScriptable(
    const nsACString& aHostName, JS::Handle<JS::Value> aOriginAttributes,
    nsIX509Cert* aClientCert, JSContext* aCx) {
  OriginAttributes attrs;
  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    return NS_ERROR_INVALID_ARG;
  }
  return RememberDecision(aHostName, attrs, aClientCert);
}

NS_IMETHODIMP
nsClientAuthRememberService::RememberDecision(
    const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
    nsIX509Cert* aClientCert) {
  if (aHostName.IsEmpty()) {
    return NS_ERROR_INVALID_ARG;
  }

  // aClientCert == nullptr means: remember that user does not want to use a
  // cert
  if (aClientCert) {
    nsAutoCString dbkey;
    nsresult rv = aClientCert->GetDbKey(dbkey);
    if (NS_FAILED(rv)) {
      return rv;
    }
    return AddEntryToList(aHostName, aOriginAttributes, dbkey);
  }
  return AddEntryToList(aHostName, aOriginAttributes,
                        nsClientAuthRemember::SentinelValue);
}

#ifdef XP_MACOSX
// On macOS, users can add "identity preference" items in the keychain. These
// can be added via the Keychain Access tool. These specify mappings from
// URLs/wildcards like "*.mozilla.org" to specific client certificates. This
// function retrieves the preferred client certificate for a hostname by
// querying a system API that checks for these identity preferences.
nsresult CheckForPreferredCertificate(const nsACString& aHostName,
                                      nsACString& aCertDBKey) {
  aCertDBKey.Truncate();
  // SecIdentityCopyPreferred seems to expect a proper URI which it can use
  // for prefix and wildcard matches.
  // We don't have the full URL but we can turn the hostname into a URI with
  // an authority section, so that it matches against macOS identity preferences
  // like `*.foo.com`. If we know that this connection is always going to be
  // https, then we should put that in the URI as well, so that it matches
  // identity preferences like `https://foo.com/` as well. If we can plumb
  // the path or the full URL into this function we could also match identity
  // preferences like `https://foo.com/bar/` but for now we cannot.
  nsPrintfCString fakeUrl("//%s/", PromiseFlatCString(aHostName).get());
  ScopedCFType<CFStringRef> host(::CFStringCreateWithCString(
      kCFAllocatorDefault, fakeUrl.get(), kCFStringEncodingUTF8));
  if (!host) {
    return NS_ERROR_UNEXPECTED;
  }
  ScopedCFType<SecIdentityRef> identity(
      ::SecIdentityCopyPreferred(host.get(), NULL, NULL));
  if (!identity) {
    // No preferred identity for this hostname, leave aCertDBKey empty and
    // return
    return NS_OK;
  }
  SecCertificateRef certRefRaw = NULL;
  OSStatus copyResult =
      ::SecIdentityCopyCertificate(identity.get(), &certRefRaw);
  ScopedCFType<SecCertificateRef> certRef(certRefRaw);
  if (copyResult != errSecSuccess || certRef.get() == NULL) {
    return NS_ERROR_UNEXPECTED;
  }
  ScopedCFType<CFDataRef> der(::SecCertificateCopyData(certRef.get()));
  if (!der) {
    return NS_ERROR_UNEXPECTED;
  }

  nsTArray<uint8_t> derArray(::CFDataGetBytePtr(der.get()),
                             ::CFDataGetLength(der.get()));
  nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(derArray)));
  return cert->GetDbKey(aCertDBKey);
}
#endif

void nsClientAuthRememberService::Migrate() {
  auto migrated = mMigrated.Lock();
  if (*migrated) {
    return;
  }
  *migrated = true;

  nsTArray<RefPtr<nsIDataStorageItem>> decisions;
  nsresult rv = mClientAuthRememberList->GetAll(decisions);
  if (NS_FAILED(rv)) {
    return;
  }
  for (const auto& decision : decisions) {
    nsIDataStorage::DataType type;
    if (NS_FAILED(decision->GetType(&type))) {
      continue;
    }
    if (type != nsIDataStorage::DataType::Persistent) {
      continue;
    }
    nsAutoCString key;
    if (NS_FAILED(decision->GetKey(key))) {
      continue;
    }
    nsAutoCString value;
    if (NS_FAILED(decision->GetValue(value))) {
      continue;
    }
    RefPtr<nsClientAuthRemember> entry(new nsClientAuthRemember(key, value));
    nsAutoCString newKey;
    if (NS_FAILED(entry->GetEntryKey(newKey))) {
      continue;
    }
    if (newKey != key) {
      if (NS_FAILED(mClientAuthRememberList->Remove(
              key, nsIDataStorage::DataType::Persistent))) {
        continue;
      }
      if (NS_FAILED(mClientAuthRememberList->Put(
              newKey, value, nsIDataStorage::DataType::Persistent))) {
        continue;
      }
    }
  }
}

NS_IMETHODIMP
nsClientAuthRememberService::HasRememberedDecision(
    const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
    nsACString& aCertDBKey, bool* aRetVal) {
  NS_ENSURE_ARG_POINTER(aRetVal);
  if (aHostName.IsEmpty()) {
    return NS_ERROR_INVALID_ARG;
  }

  *aRetVal = false;
  aCertDBKey.Truncate();

  Migrate();

  nsAutoCString entryKey;
  RefPtr<nsClientAuthRemember> entry(
      new nsClientAuthRemember(aHostName, aOriginAttributes));
  nsresult rv = entry->GetEntryKey(entryKey);
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsIDataStorage::DataType storageType = GetDataStorageType(aOriginAttributes);

  nsAutoCString listEntry;
  rv = mClientAuthRememberList->Get(entryKey, storageType, listEntry);
  if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) {
    return rv;
  }
  if (NS_SUCCEEDED(rv) && !listEntry.IsEmpty()) {
    if (!listEntry.Equals(nsClientAuthRemember::SentinelValue)) {
      aCertDBKey = listEntry;
    }
    *aRetVal = true;
    return NS_OK;
  }

#ifdef XP_MACOSX
  rv = CheckForPreferredCertificate(aHostName, aCertDBKey);
  if (NS_FAILED(rv)) {
    return rv;
  }
  if (!aCertDBKey.IsEmpty()) {
    *aRetVal = true;
    return NS_OK;
  }
#endif

  return NS_OK;
}

NS_IMETHODIMP
nsClientAuthRememberService::HasRememberedDecisionScriptable(
    const nsACString& aHostName, JS::Handle<JS::Value> aOriginAttributes,
    nsACString& aCertDBKey, JSContext* aCx, bool* aRetVal) {
  OriginAttributes attrs;
  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    return NS_ERROR_INVALID_ARG;
  }
  return HasRememberedDecision(aHostName, attrs, aCertDBKey, aRetVal);
}

nsresult nsClientAuthRememberService::AddEntryToList(
    const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
    const nsACString& aDBKey) {
  nsAutoCString entryKey;
  RefPtr<nsClientAuthRemember> entry(
      new nsClientAuthRemember(aHostName, aOriginAttributes));
  nsresult rv = entry->GetEntryKey(entryKey);
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsIDataStorage::DataType storageType = GetDataStorageType(aOriginAttributes);

  nsCString tmpDbKey(aDBKey);
  rv = mClientAuthRememberList->Put(entryKey, tmpDbKey, storageType);
  if (NS_FAILED(rv)) {
    return rv;
  }

  return NS_OK;
}

bool nsClientAuthRememberService::IsPrivateBrowsingKey(
    const nsCString& entryKey) {
  const int32_t separator = entryKey.Find(":");
  nsCString suffix;
  if (separator >= 0) {
    entryKey.Left(suffix, separator);
  } else {
    suffix = entryKey;
  }
  return OriginAttributes::IsPrivateBrowsing(suffix);
}

nsIDataStorage::DataType nsClientAuthRememberService::GetDataStorageType(
    const OriginAttributes& aOriginAttributes) {
  if (aOriginAttributes.IsPrivateBrowsing()) {
    return nsIDataStorage::DataType::Private;
  }
  return nsIDataStorage::DataType::Persistent;
}

95%


¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© 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 ist noch experimentell.