tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IPCClientCertsParent.cpp (5155B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et tw=80 : */
      3 
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "IPCClientCertsParent.h"
      9 #include "ScopedNSSTypes.h"
     10 #include "nsNetCID.h"
     11 #include "nsNSSComponent.h"
     12 #include "nsNSSIOLayer.h"
     13 
     14 #include "mozilla/SyncRunnable.h"
     15 
     16 namespace mozilla::psm {
     17 
     18 IPCClientCertsParent::IPCClientCertsParent() = default;
     19 
     20 // When the IPC client certs module needs to find certificate and key objects
     21 // in the socket process, it will cause this function to be called in the
     22 // parent process. The parent process needs to find all certificates with
     23 // private keys (because these are potential client certificates).
     24 mozilla::ipc::IPCResult IPCClientCertsParent::RecvFindObjects(
     25    nsTArray<IPCClientCertObject>* aObjects) {
     26  nsCOMPtr<nsIEventTarget> socketThread(
     27      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID));
     28  if (!socketThread) {
     29    return IPC_OK();
     30  }
     31  // Look for client certificates on the socket thread.
     32  UniqueCERTCertList certList;
     33  mozilla::SyncRunnable::DispatchToThread(
     34      socketThread, NS_NewRunnableFunction(
     35                        "IPCClientCertsParent::RecvFindObjects", [&certList]() {
     36                          certList =
     37                              psm::FindClientCertificatesWithPrivateKeys();
     38                        }));
     39  if (!certList) {
     40    return IPC_OK();
     41  }
     42  CERTCertListNode* n = CERT_LIST_HEAD(certList);
     43  while (!CERT_LIST_END(n, certList)) {
     44    nsTArray<uint8_t> certDER(n->cert->derCert.data, n->cert->derCert.len);
     45    UniqueSECKEYPublicKey pubkey(CERT_ExtractPublicKey(n->cert));
     46    if (!pubkey) {
     47      return IPC_OK();
     48    }
     49    switch (SECKEY_GetPublicKeyType(pubkey.get())) {
     50      case rsaKey:
     51      case rsaPssKey: {
     52        nsTArray<uint8_t> modulus(pubkey->u.rsa.modulus.data,
     53                                  pubkey->u.rsa.modulus.len);
     54        RSAKey rsakey(modulus, certDER);
     55        aObjects->AppendElement(std::move(rsakey));
     56        break;
     57      }
     58      case ecKey: {
     59        nsTArray<uint8_t> params(pubkey->u.ec.DEREncodedParams.data,
     60                                 pubkey->u.ec.DEREncodedParams.len);
     61        ECKey eckey(params, certDER);
     62        aObjects->AppendElement(std::move(eckey));
     63        break;
     64      }
     65      default:
     66        n = CERT_LIST_NEXT(n);
     67        continue;
     68    }
     69    Certificate cert(certDER);
     70    aObjects->AppendElement(std::move(cert));
     71 
     72    n = CERT_LIST_NEXT(n);
     73  }
     74  return IPC_OK();
     75 }
     76 
     77 // When the IPC client certs module needs to sign data using a key managed by
     78 // the parent process, it will cause this function to be called in the parent
     79 // process. The parent process needs to find the key corresponding to the
     80 // given certificate and sign the given data with the given parameters.
     81 mozilla::ipc::IPCResult IPCClientCertsParent::RecvSign(ByteArray aCert,
     82                                                       ByteArray aData,
     83                                                       ByteArray aParams,
     84                                                       ByteArray* aSignature) {
     85  SECItem certItem = {siBuffer, const_cast<uint8_t*>(aCert.data().Elements()),
     86                      static_cast<unsigned int>(aCert.data().Length())};
     87  aSignature->data().Clear();
     88 
     89  UniqueCERTCertificate cert(CERT_NewTempCertificate(
     90      CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
     91  if (!cert) {
     92    return IPC_OK();
     93  }
     94  UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
     95  if (!key) {
     96    return IPC_OK();
     97  }
     98  SECItem hash = {siBuffer, aData.data().Elements(),
     99                  static_cast<unsigned int>(aData.data().Length())};
    100  SECItem params = {siBuffer, aParams.data().Elements(),
    101                    static_cast<unsigned int>(aParams.data().Length())};
    102  SECItem* paramsPtr = aParams.data().Length() > 0 ? &params : nullptr;
    103  CK_MECHANISM_TYPE mechanism;
    104  switch (key->keyType) {
    105    case ecKey:
    106      mechanism = CKM_ECDSA;
    107      break;
    108    case rsaKey:
    109      // If we have params, this is RSA-PSS.
    110      if (aParams.data().Length() > 0) {
    111        mechanism = CKM_RSA_PKCS_PSS;
    112      } else {
    113        // If this is a DigestInfo or a TLS 1.0 MD5/SHA1 hash, this is RSA-PKCS.
    114        // Otherwise, this is an emsa-pss-encoded digest that should be signed
    115        // with raw RSA.
    116        UniqueSGNDigestInfo digestInfo(SGN_DecodeDigestInfo(&hash));
    117        if (digestInfo || aData.data().Length() == 36) {
    118          mechanism = CKM_RSA_PKCS;
    119        } else {
    120          mechanism = CKM_RSA_X_509;
    121        }
    122      }
    123      break;
    124    default:
    125      return IPC_OK();
    126  }
    127  uint32_t len = PK11_SignatureLen(key.get());
    128  UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
    129  SECStatus srv =
    130      PK11_SignWithMechanism(key.get(), mechanism, paramsPtr, sig.get(), &hash);
    131  if (srv != SECSuccess) {
    132    return IPC_OK();
    133  }
    134  aSignature->data().AppendElements(sig->data, sig->len);
    135  return IPC_OK();
    136 }
    137 
    138 }  // namespace mozilla::psm