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 ? ¶ms : 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