xref: /aosp_15_r20/external/cronet/net/cert/nss_cert_database.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/cert/nss_cert_database.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <cert.h>
8*6777b538SAndroid Build Coastguard Worker #include <certdb.h>
9*6777b538SAndroid Build Coastguard Worker #include <certt.h>
10*6777b538SAndroid Build Coastguard Worker #include <dlfcn.h>
11*6777b538SAndroid Build Coastguard Worker #include <keyhi.h>
12*6777b538SAndroid Build Coastguard Worker #include <pk11pub.h>
13*6777b538SAndroid Build Coastguard Worker #include <secmod.h>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include <memory>
16*6777b538SAndroid Build Coastguard Worker #include <utility>
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/observer_list_threadsafe.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
25*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
26*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
27*6777b538SAndroid Build Coastguard Worker #include "crypto/nss_util_internal.h"
28*6777b538SAndroid Build Coastguard Worker #include "crypto/scoped_nss_types.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/cert/cert_database.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/cert/internal/trust_store_nss.h"
32*6777b538SAndroid Build Coastguard Worker #include "net/cert/x509_certificate.h"
33*6777b538SAndroid Build Coastguard Worker #include "net/cert/x509_util_nss.h"
34*6777b538SAndroid Build Coastguard Worker #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
35*6777b538SAndroid Build Coastguard Worker #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h"
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
38*6777b538SAndroid Build Coastguard Worker #include "crypto/chaps_support.h"
39*6777b538SAndroid Build Coastguard Worker #endif
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker // PSM = Mozilla's Personal Security Manager.
42*6777b538SAndroid Build Coastguard Worker namespace psm = mozilla_security_manager;
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker namespace net {
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker namespace {
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker using PK11HasAttributeSetFunction = CK_BBOOL (*)(PK11SlotInfo* slot,
49*6777b538SAndroid Build Coastguard Worker                                                  CK_OBJECT_HANDLE id,
50*6777b538SAndroid Build Coastguard Worker                                                  CK_ATTRIBUTE_TYPE type,
51*6777b538SAndroid Build Coastguard Worker                                                  PRBool haslock);
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker // TODO(pneubeck): Move this class out of NSSCertDatabase and to the caller of
54*6777b538SAndroid Build Coastguard Worker // the c'tor of NSSCertDatabase, see https://crbug.com/395983 .
55*6777b538SAndroid Build Coastguard Worker // Helper that observes events from the NSSCertDatabase and forwards them to
56*6777b538SAndroid Build Coastguard Worker // the given CertDatabase.
57*6777b538SAndroid Build Coastguard Worker class CertNotificationForwarder : public NSSCertDatabase::Observer {
58*6777b538SAndroid Build Coastguard Worker  public:
CertNotificationForwarder(CertDatabase * cert_db)59*6777b538SAndroid Build Coastguard Worker   explicit CertNotificationForwarder(CertDatabase* cert_db)
60*6777b538SAndroid Build Coastguard Worker       : cert_db_(cert_db) {}
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   CertNotificationForwarder(const CertNotificationForwarder&) = delete;
63*6777b538SAndroid Build Coastguard Worker   CertNotificationForwarder& operator=(const CertNotificationForwarder&) =
64*6777b538SAndroid Build Coastguard Worker       delete;
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   ~CertNotificationForwarder() override = default;
67*6777b538SAndroid Build Coastguard Worker 
OnTrustStoreChanged()68*6777b538SAndroid Build Coastguard Worker   void OnTrustStoreChanged() override {
69*6777b538SAndroid Build Coastguard Worker     cert_db_->NotifyObserversTrustStoreChanged();
70*6777b538SAndroid Build Coastguard Worker   }
OnClientCertStoreChanged()71*6777b538SAndroid Build Coastguard Worker   void OnClientCertStoreChanged() override {
72*6777b538SAndroid Build Coastguard Worker     cert_db_->NotifyObserversClientCertStoreChanged();
73*6777b538SAndroid Build Coastguard Worker   }
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker  private:
76*6777b538SAndroid Build Coastguard Worker   raw_ptr<CertDatabase> cert_db_;
77*6777b538SAndroid Build Coastguard Worker };
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1412591): once the other IsUntrusted impl is deleted,
80*6777b538SAndroid Build Coastguard Worker // rename this.
IsUntrustedUsingTrustStore(const CERTCertificate * cert,bssl::CertificateTrust trust)81*6777b538SAndroid Build Coastguard Worker bool IsUntrustedUsingTrustStore(const CERTCertificate* cert,
82*6777b538SAndroid Build Coastguard Worker                                 bssl::CertificateTrust trust) {
83*6777b538SAndroid Build Coastguard Worker   if (trust.IsDistrusted()) {
84*6777b538SAndroid Build Coastguard Worker     return true;
85*6777b538SAndroid Build Coastguard Worker   }
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker   // Self-signed certificates that don't have any trust bits set are untrusted.
88*6777b538SAndroid Build Coastguard Worker   // Other certificates that don't have any trust bits set may still be trusted
89*6777b538SAndroid Build Coastguard Worker   // if they chain up to a trust anchor.
90*6777b538SAndroid Build Coastguard Worker   // TODO(mattm): this is weird, but just match the behavior of the existing
91*6777b538SAndroid Build Coastguard Worker   // IsUntrusted function for now.
92*6777b538SAndroid Build Coastguard Worker   if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) {
93*6777b538SAndroid Build Coastguard Worker     return !trust.IsTrustAnchor();
94*6777b538SAndroid Build Coastguard Worker   }
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker   return false;
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker }  // namespace
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::CertInfo::CertInfo() = default;
102*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::CertInfo::CertInfo(CertInfo&& other) = default;
103*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::CertInfo::~CertInfo() = default;
104*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::CertInfo& NSSCertDatabase::CertInfo::operator=(
105*6777b538SAndroid Build Coastguard Worker     NSSCertDatabase::CertInfo&& other) = default;
106*6777b538SAndroid Build Coastguard Worker 
ImportCertFailure(ScopedCERTCertificate cert,int err)107*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::ImportCertFailure::ImportCertFailure(
108*6777b538SAndroid Build Coastguard Worker     ScopedCERTCertificate cert,
109*6777b538SAndroid Build Coastguard Worker     int err)
110*6777b538SAndroid Build Coastguard Worker     : certificate(std::move(cert)), net_error(err) {}
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::ImportCertFailure::ImportCertFailure(
113*6777b538SAndroid Build Coastguard Worker     ImportCertFailure&& other) = default;
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::ImportCertFailure::~ImportCertFailure() = default;
116*6777b538SAndroid Build Coastguard Worker 
NSSCertDatabase(crypto::ScopedPK11Slot public_slot,crypto::ScopedPK11Slot private_slot)117*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::NSSCertDatabase(crypto::ScopedPK11Slot public_slot,
118*6777b538SAndroid Build Coastguard Worker                                  crypto::ScopedPK11Slot private_slot)
119*6777b538SAndroid Build Coastguard Worker     : public_slot_(std::move(public_slot)),
120*6777b538SAndroid Build Coastguard Worker       private_slot_(std::move(private_slot)),
121*6777b538SAndroid Build Coastguard Worker       observer_list_(
122*6777b538SAndroid Build Coastguard Worker           base::MakeRefCounted<base::ObserverListThreadSafe<Observer>>()) {
123*6777b538SAndroid Build Coastguard Worker   CHECK(public_slot_);
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   CertDatabase* cert_db = CertDatabase::GetInstance();
126*6777b538SAndroid Build Coastguard Worker   cert_notification_forwarder_ =
127*6777b538SAndroid Build Coastguard Worker       std::make_unique<CertNotificationForwarder>(cert_db);
128*6777b538SAndroid Build Coastguard Worker   AddObserver(cert_notification_forwarder_.get());
129*6777b538SAndroid Build Coastguard Worker 
130*6777b538SAndroid Build Coastguard Worker   psm::EnsurePKCS12Init();
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::~NSSCertDatabase() = default;
134*6777b538SAndroid Build Coastguard Worker 
ListCerts(ListCertsCallback callback)135*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::ListCerts(ListCertsCallback callback) {
136*6777b538SAndroid Build Coastguard Worker   base::ThreadPool::PostTaskAndReplyWithResult(
137*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
138*6777b538SAndroid Build Coastguard Worker       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
139*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&NSSCertDatabase::ListCertsImpl, crypto::ScopedPK11Slot()),
140*6777b538SAndroid Build Coastguard Worker       std::move(callback));
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker 
ListCertsInSlot(ListCertsCallback callback,PK11SlotInfo * slot)143*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::ListCertsInSlot(ListCertsCallback callback,
144*6777b538SAndroid Build Coastguard Worker                                       PK11SlotInfo* slot) {
145*6777b538SAndroid Build Coastguard Worker   DCHECK(slot);
146*6777b538SAndroid Build Coastguard Worker   base::ThreadPool::PostTaskAndReplyWithResult(
147*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
148*6777b538SAndroid Build Coastguard Worker       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
149*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&NSSCertDatabase::ListCertsImpl,
150*6777b538SAndroid Build Coastguard Worker                      crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot))),
151*6777b538SAndroid Build Coastguard Worker       std::move(callback));
152*6777b538SAndroid Build Coastguard Worker }
153*6777b538SAndroid Build Coastguard Worker 
ListCertsInfo(ListCertsInfoCallback callback,NSSRootsHandling nss_roots_handling)154*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::ListCertsInfo(ListCertsInfoCallback callback,
155*6777b538SAndroid Build Coastguard Worker                                     NSSRootsHandling nss_roots_handling) {
156*6777b538SAndroid Build Coastguard Worker   base::ThreadPool::PostTaskAndReplyWithResult(
157*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
158*6777b538SAndroid Build Coastguard Worker       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
159*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&NSSCertDatabase::ListCertsInfoImpl,
160*6777b538SAndroid Build Coastguard Worker                      /*slot=*/nullptr,
161*6777b538SAndroid Build Coastguard Worker                      /*add_certs_info=*/true, nss_roots_handling),
162*6777b538SAndroid Build Coastguard Worker       std::move(callback));
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
GetSystemSlot() const166*6777b538SAndroid Build Coastguard Worker crypto::ScopedPK11Slot NSSCertDatabase::GetSystemSlot() const {
167*6777b538SAndroid Build Coastguard Worker   return crypto::ScopedPK11Slot();
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker // static
IsCertificateOnSlot(CERTCertificate * cert,PK11SlotInfo * slot)171*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::IsCertificateOnSlot(CERTCertificate* cert,
172*6777b538SAndroid Build Coastguard Worker                                           PK11SlotInfo* slot) {
173*6777b538SAndroid Build Coastguard Worker   if (!slot)
174*6777b538SAndroid Build Coastguard Worker     return false;
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker   return PK11_FindCertInSlot(slot, cert, nullptr) != CK_INVALID_HANDLE;
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS)
179*6777b538SAndroid Build Coastguard Worker 
GetPublicSlot() const180*6777b538SAndroid Build Coastguard Worker crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const {
181*6777b538SAndroid Build Coastguard Worker   return crypto::ScopedPK11Slot(PK11_ReferenceSlot(public_slot_.get()));
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker 
GetPrivateSlot() const184*6777b538SAndroid Build Coastguard Worker crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const {
185*6777b538SAndroid Build Coastguard Worker   if (!private_slot_)
186*6777b538SAndroid Build Coastguard Worker     return crypto::ScopedPK11Slot();
187*6777b538SAndroid Build Coastguard Worker   return crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker 
ListModules(std::vector<crypto::ScopedPK11Slot> * modules,bool need_rw) const190*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::ListModules(std::vector<crypto::ScopedPK11Slot>* modules,
191*6777b538SAndroid Build Coastguard Worker                                   bool need_rw) const {
192*6777b538SAndroid Build Coastguard Worker   modules->clear();
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
195*6777b538SAndroid Build Coastguard Worker   crypto::ScopedPK11SlotList slot_list(
196*6777b538SAndroid Build Coastguard Worker       PK11_GetAllTokens(CKM_INVALID_MECHANISM,
197*6777b538SAndroid Build Coastguard Worker                         need_rw ? PR_TRUE : PR_FALSE,  // needRW
198*6777b538SAndroid Build Coastguard Worker                         PR_TRUE,                       // loadCerts (unused)
199*6777b538SAndroid Build Coastguard Worker                         nullptr));                     // wincx
200*6777b538SAndroid Build Coastguard Worker   if (!slot_list) {
201*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError();
202*6777b538SAndroid Build Coastguard Worker     return;
203*6777b538SAndroid Build Coastguard Worker   }
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get());
206*6777b538SAndroid Build Coastguard Worker   while (slot_element) {
207*6777b538SAndroid Build Coastguard Worker     modules->push_back(
208*6777b538SAndroid Build Coastguard Worker         crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_element->slot)));
209*6777b538SAndroid Build Coastguard Worker     slot_element = PK11_GetNextSafe(slot_list.get(), slot_element,
210*6777b538SAndroid Build Coastguard Worker                                     PR_FALSE);  // restart
211*6777b538SAndroid Build Coastguard Worker   }
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker 
SetCertTrust(CERTCertificate * cert,CertType type,TrustBits trust_bits)214*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::SetCertTrust(CERTCertificate* cert,
215*6777b538SAndroid Build Coastguard Worker                                    CertType type,
216*6777b538SAndroid Build Coastguard Worker                                    TrustBits trust_bits) {
217*6777b538SAndroid Build Coastguard Worker   bool success = psm::SetCertTrust(cert, type, trust_bits);
218*6777b538SAndroid Build Coastguard Worker   if (success) {
219*6777b538SAndroid Build Coastguard Worker     NotifyObserversTrustStoreChanged();
220*6777b538SAndroid Build Coastguard Worker   }
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   return success;
223*6777b538SAndroid Build Coastguard Worker }
224*6777b538SAndroid Build Coastguard Worker 
ImportFromPKCS12(PK11SlotInfo * slot_info,const std::string & data,const std::u16string & password,bool is_extractable,ScopedCERTCertificateList * imported_certs)225*6777b538SAndroid Build Coastguard Worker int NSSCertDatabase::ImportFromPKCS12(
226*6777b538SAndroid Build Coastguard Worker     PK11SlotInfo* slot_info,
227*6777b538SAndroid Build Coastguard Worker     const std::string& data,
228*6777b538SAndroid Build Coastguard Worker     const std::u16string& password,
229*6777b538SAndroid Build Coastguard Worker     bool is_extractable,
230*6777b538SAndroid Build Coastguard Worker     ScopedCERTCertificateList* imported_certs) {
231*6777b538SAndroid Build Coastguard Worker   int result =
232*6777b538SAndroid Build Coastguard Worker       psm::nsPKCS12Blob_Import(slot_info, data.data(), data.size(), password,
233*6777b538SAndroid Build Coastguard Worker                                is_extractable, imported_certs);
234*6777b538SAndroid Build Coastguard Worker   if (result == OK) {
235*6777b538SAndroid Build Coastguard Worker     NotifyObserversClientCertStoreChanged();
236*6777b538SAndroid Build Coastguard Worker   }
237*6777b538SAndroid Build Coastguard Worker 
238*6777b538SAndroid Build Coastguard Worker   return result;
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker // static
ExportToPKCS12(const ScopedCERTCertificateList & certs,const std::u16string & password,std::string * output)242*6777b538SAndroid Build Coastguard Worker int NSSCertDatabase::ExportToPKCS12(const ScopedCERTCertificateList& certs,
243*6777b538SAndroid Build Coastguard Worker                                     const std::u16string& password,
244*6777b538SAndroid Build Coastguard Worker                                     std::string* output) {
245*6777b538SAndroid Build Coastguard Worker   return psm::nsPKCS12Blob_Export(output, certs, password);
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker 
FindRootInList(const ScopedCERTCertificateList & certificates) const248*6777b538SAndroid Build Coastguard Worker CERTCertificate* NSSCertDatabase::FindRootInList(
249*6777b538SAndroid Build Coastguard Worker     const ScopedCERTCertificateList& certificates) const {
250*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(certificates.size(), 0U);
251*6777b538SAndroid Build Coastguard Worker 
252*6777b538SAndroid Build Coastguard Worker   if (certificates.size() == 1)
253*6777b538SAndroid Build Coastguard Worker     return certificates[0].get();
254*6777b538SAndroid Build Coastguard Worker 
255*6777b538SAndroid Build Coastguard Worker   CERTCertificate* cert0 = certificates[0].get();
256*6777b538SAndroid Build Coastguard Worker   CERTCertificate* cert1 = certificates[1].get();
257*6777b538SAndroid Build Coastguard Worker   CERTCertificate* certn_2 = certificates[certificates.size() - 2].get();
258*6777b538SAndroid Build Coastguard Worker   CERTCertificate* certn_1 = certificates[certificates.size() - 1].get();
259*6777b538SAndroid Build Coastguard Worker 
260*6777b538SAndroid Build Coastguard Worker   // Using CERT_CompareName is an alternative, except that it is broken until
261*6777b538SAndroid Build Coastguard Worker   // NSS 3.32 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1361197 ).
262*6777b538SAndroid Build Coastguard Worker   if (SECITEM_CompareItem(&cert1->derIssuer, &cert0->derSubject) == SECEqual)
263*6777b538SAndroid Build Coastguard Worker     return cert0;
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker   if (SECITEM_CompareItem(&certn_2->derIssuer, &certn_1->derSubject) ==
266*6777b538SAndroid Build Coastguard Worker       SECEqual) {
267*6777b538SAndroid Build Coastguard Worker     return certn_1;
268*6777b538SAndroid Build Coastguard Worker   }
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker   LOG(WARNING) << "certificate list is not a hierarchy";
271*6777b538SAndroid Build Coastguard Worker   return cert0;
272*6777b538SAndroid Build Coastguard Worker }
273*6777b538SAndroid Build Coastguard Worker 
ImportUserCert(const std::string & data)274*6777b538SAndroid Build Coastguard Worker int NSSCertDatabase::ImportUserCert(const std::string& data) {
275*6777b538SAndroid Build Coastguard Worker   ScopedCERTCertificateList certificates =
276*6777b538SAndroid Build Coastguard Worker       x509_util::CreateCERTCertificateListFromBytes(
277*6777b538SAndroid Build Coastguard Worker           data.c_str(), data.size(), net::X509Certificate::FORMAT_AUTO);
278*6777b538SAndroid Build Coastguard Worker   if (certificates.empty())
279*6777b538SAndroid Build Coastguard Worker     return ERR_CERT_INVALID;
280*6777b538SAndroid Build Coastguard Worker 
281*6777b538SAndroid Build Coastguard Worker   int result = psm::ImportUserCert(certificates[0].get(), GetPublicSlot());
282*6777b538SAndroid Build Coastguard Worker 
283*6777b538SAndroid Build Coastguard Worker   if (result == OK) {
284*6777b538SAndroid Build Coastguard Worker     NotifyObserversClientCertStoreChanged();
285*6777b538SAndroid Build Coastguard Worker   }
286*6777b538SAndroid Build Coastguard Worker 
287*6777b538SAndroid Build Coastguard Worker   return result;
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker 
ImportUserCert(CERTCertificate * cert)290*6777b538SAndroid Build Coastguard Worker int NSSCertDatabase::ImportUserCert(CERTCertificate* cert) {
291*6777b538SAndroid Build Coastguard Worker   int result = psm::ImportUserCert(cert, GetPublicSlot());
292*6777b538SAndroid Build Coastguard Worker 
293*6777b538SAndroid Build Coastguard Worker   if (result == OK) {
294*6777b538SAndroid Build Coastguard Worker     NotifyObserversClientCertStoreChanged();
295*6777b538SAndroid Build Coastguard Worker   }
296*6777b538SAndroid Build Coastguard Worker 
297*6777b538SAndroid Build Coastguard Worker   return result;
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker 
ImportCACerts(const ScopedCERTCertificateList & certificates,TrustBits trust_bits,ImportCertFailureList * not_imported)300*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::ImportCACerts(
301*6777b538SAndroid Build Coastguard Worker     const ScopedCERTCertificateList& certificates,
302*6777b538SAndroid Build Coastguard Worker     TrustBits trust_bits,
303*6777b538SAndroid Build Coastguard Worker     ImportCertFailureList* not_imported) {
304*6777b538SAndroid Build Coastguard Worker   crypto::ScopedPK11Slot slot(GetPublicSlot());
305*6777b538SAndroid Build Coastguard Worker   CERTCertificate* root = FindRootInList(certificates);
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker   bool success = psm::ImportCACerts(slot.get(), certificates, root, trust_bits,
308*6777b538SAndroid Build Coastguard Worker                                     not_imported);
309*6777b538SAndroid Build Coastguard Worker   if (success) {
310*6777b538SAndroid Build Coastguard Worker     NotifyObserversTrustStoreChanged();
311*6777b538SAndroid Build Coastguard Worker   }
312*6777b538SAndroid Build Coastguard Worker 
313*6777b538SAndroid Build Coastguard Worker   return success;
314*6777b538SAndroid Build Coastguard Worker }
315*6777b538SAndroid Build Coastguard Worker 
ImportServerCert(const ScopedCERTCertificateList & certificates,TrustBits trust_bits,ImportCertFailureList * not_imported)316*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::ImportServerCert(
317*6777b538SAndroid Build Coastguard Worker     const ScopedCERTCertificateList& certificates,
318*6777b538SAndroid Build Coastguard Worker     TrustBits trust_bits,
319*6777b538SAndroid Build Coastguard Worker     ImportCertFailureList* not_imported) {
320*6777b538SAndroid Build Coastguard Worker   crypto::ScopedPK11Slot slot(GetPublicSlot());
321*6777b538SAndroid Build Coastguard Worker   return psm::ImportServerCert(slot.get(), certificates, trust_bits,
322*6777b538SAndroid Build Coastguard Worker                                not_imported);
323*6777b538SAndroid Build Coastguard Worker   // TODO(mattm): should generate OnTrustStoreChanged notification? The ability
324*6777b538SAndroid Build Coastguard Worker   // to set a server cert as trusted isn't hooked up anywhere currently, but
325*6777b538SAndroid Build Coastguard Worker   // technically we should generate a notification.
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker 
GetCertTrust(const CERTCertificate * cert,CertType type) const328*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust(
329*6777b538SAndroid Build Coastguard Worker     const CERTCertificate* cert,
330*6777b538SAndroid Build Coastguard Worker     CertType type) const {
331*6777b538SAndroid Build Coastguard Worker   CERTCertTrust trust;
332*6777b538SAndroid Build Coastguard Worker   SECStatus srv = CERT_GetCertTrust(cert, &trust);
333*6777b538SAndroid Build Coastguard Worker   if (srv != SECSuccess) {
334*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
335*6777b538SAndroid Build Coastguard Worker     return TRUST_DEFAULT;
336*6777b538SAndroid Build Coastguard Worker   }
337*6777b538SAndroid Build Coastguard Worker   // We define our own more "friendly" TrustBits, which means we aren't able to
338*6777b538SAndroid Build Coastguard Worker   // round-trip all possible NSS trust flag combinations.  We try to map them in
339*6777b538SAndroid Build Coastguard Worker   // a sensible way.
340*6777b538SAndroid Build Coastguard Worker   switch (type) {
341*6777b538SAndroid Build Coastguard Worker     case CA_CERT: {
342*6777b538SAndroid Build Coastguard Worker       const unsigned kTrustedCA = CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
343*6777b538SAndroid Build Coastguard Worker       const unsigned kCAFlags = kTrustedCA | CERTDB_TERMINAL_RECORD;
344*6777b538SAndroid Build Coastguard Worker 
345*6777b538SAndroid Build Coastguard Worker       TrustBits trust_bits = TRUST_DEFAULT;
346*6777b538SAndroid Build Coastguard Worker       if ((trust.sslFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
347*6777b538SAndroid Build Coastguard Worker         trust_bits |= DISTRUSTED_SSL;
348*6777b538SAndroid Build Coastguard Worker       else if (trust.sslFlags & kTrustedCA)
349*6777b538SAndroid Build Coastguard Worker         trust_bits |= TRUSTED_SSL;
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker       if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
352*6777b538SAndroid Build Coastguard Worker         trust_bits |= DISTRUSTED_EMAIL;
353*6777b538SAndroid Build Coastguard Worker       else if (trust.emailFlags & kTrustedCA)
354*6777b538SAndroid Build Coastguard Worker         trust_bits |= TRUSTED_EMAIL;
355*6777b538SAndroid Build Coastguard Worker 
356*6777b538SAndroid Build Coastguard Worker       if ((trust.objectSigningFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
357*6777b538SAndroid Build Coastguard Worker         trust_bits |= DISTRUSTED_OBJ_SIGN;
358*6777b538SAndroid Build Coastguard Worker       else if (trust.objectSigningFlags & kTrustedCA)
359*6777b538SAndroid Build Coastguard Worker         trust_bits |= TRUSTED_OBJ_SIGN;
360*6777b538SAndroid Build Coastguard Worker 
361*6777b538SAndroid Build Coastguard Worker       return trust_bits;
362*6777b538SAndroid Build Coastguard Worker     }
363*6777b538SAndroid Build Coastguard Worker     case SERVER_CERT:
364*6777b538SAndroid Build Coastguard Worker       if (trust.sslFlags & CERTDB_TERMINAL_RECORD) {
365*6777b538SAndroid Build Coastguard Worker         if (trust.sslFlags & CERTDB_TRUSTED)
366*6777b538SAndroid Build Coastguard Worker           return TRUSTED_SSL;
367*6777b538SAndroid Build Coastguard Worker         return DISTRUSTED_SSL;
368*6777b538SAndroid Build Coastguard Worker       }
369*6777b538SAndroid Build Coastguard Worker       return TRUST_DEFAULT;
370*6777b538SAndroid Build Coastguard Worker     default:
371*6777b538SAndroid Build Coastguard Worker       return TRUST_DEFAULT;
372*6777b538SAndroid Build Coastguard Worker   }
373*6777b538SAndroid Build Coastguard Worker }
374*6777b538SAndroid Build Coastguard Worker 
DeleteCertAndKey(CERTCertificate * cert)375*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::DeleteCertAndKey(CERTCertificate* cert) {
376*6777b538SAndroid Build Coastguard Worker   // This makes the assumption that if there was a matching private key, the
377*6777b538SAndroid Build Coastguard Worker   // cert was probably a client cert, and if not, it may have been a trust
378*6777b538SAndroid Build Coastguard Worker   // anchor or intemediate CA cert. This is used as a simple approximation as
379*6777b538SAndroid Build Coastguard Worker   // otherwise this requires checking and combining multiple things
380*6777b538SAndroid Build Coastguard Worker   // (basicConstraints if present, trust settings, etc).
381*6777b538SAndroid Build Coastguard Worker   switch (DeleteCertAndKeyImpl(cert)) {
382*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::OK_NO_KEY:
383*6777b538SAndroid Build Coastguard Worker       NotifyObserversTrustStoreChanged();
384*6777b538SAndroid Build Coastguard Worker       return true;
385*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::OK_FOUND_KEY:
386*6777b538SAndroid Build Coastguard Worker       NotifyObserversClientCertStoreChanged();
387*6777b538SAndroid Build Coastguard Worker       return true;
388*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::ERROR:
389*6777b538SAndroid Build Coastguard Worker       return false;
390*6777b538SAndroid Build Coastguard Worker   }
391*6777b538SAndroid Build Coastguard Worker }
392*6777b538SAndroid Build Coastguard Worker 
DeleteCertAndKeyAsync(ScopedCERTCertificate cert,DeleteCertCallback callback)393*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::DeleteCertAndKeyAsync(ScopedCERTCertificate cert,
394*6777b538SAndroid Build Coastguard Worker                                             DeleteCertCallback callback) {
395*6777b538SAndroid Build Coastguard Worker   base::ThreadPool::PostTaskAndReplyWithResult(
396*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
397*6777b538SAndroid Build Coastguard Worker       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
398*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&NSSCertDatabase::DeleteCertAndKeyImplScoped,
399*6777b538SAndroid Build Coastguard Worker                      std::move(cert)),
400*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&NSSCertDatabase::NotifyCertRemovalAndCallBack,
401*6777b538SAndroid Build Coastguard Worker                      weak_factory_.GetWeakPtr(), std::move(callback)));
402*6777b538SAndroid Build Coastguard Worker }
403*6777b538SAndroid Build Coastguard Worker 
404*6777b538SAndroid Build Coastguard Worker // static
IsUntrusted(const CERTCertificate * cert)405*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::IsUntrusted(const CERTCertificate* cert) {
406*6777b538SAndroid Build Coastguard Worker   CERTCertTrust nsstrust;
407*6777b538SAndroid Build Coastguard Worker   SECStatus rv = CERT_GetCertTrust(cert, &nsstrust);
408*6777b538SAndroid Build Coastguard Worker   if (rv != SECSuccess) {
409*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
410*6777b538SAndroid Build Coastguard Worker     return false;
411*6777b538SAndroid Build Coastguard Worker   }
412*6777b538SAndroid Build Coastguard Worker 
413*6777b538SAndroid Build Coastguard Worker   // The CERTCertTrust structure contains three trust records:
414*6777b538SAndroid Build Coastguard Worker   // sslFlags, emailFlags, and objectSigningFlags.  The three
415*6777b538SAndroid Build Coastguard Worker   // trust records are independent of each other.
416*6777b538SAndroid Build Coastguard Worker   //
417*6777b538SAndroid Build Coastguard Worker   // If the CERTDB_TERMINAL_RECORD bit in a trust record is set,
418*6777b538SAndroid Build Coastguard Worker   // then that trust record is a terminal record.  A terminal
419*6777b538SAndroid Build Coastguard Worker   // record is used for explicit trust and distrust of an
420*6777b538SAndroid Build Coastguard Worker   // end-entity or intermediate CA cert.
421*6777b538SAndroid Build Coastguard Worker   //
422*6777b538SAndroid Build Coastguard Worker   // In a terminal record, if neither CERTDB_TRUSTED_CA nor
423*6777b538SAndroid Build Coastguard Worker   // CERTDB_TRUSTED is set, then the terminal record means
424*6777b538SAndroid Build Coastguard Worker   // explicit distrust.  On the other hand, if the terminal
425*6777b538SAndroid Build Coastguard Worker   // record has either CERTDB_TRUSTED_CA or CERTDB_TRUSTED bit
426*6777b538SAndroid Build Coastguard Worker   // set, then the terminal record means explicit trust.
427*6777b538SAndroid Build Coastguard Worker   //
428*6777b538SAndroid Build Coastguard Worker   // For a root CA, the trust record does not have
429*6777b538SAndroid Build Coastguard Worker   // the CERTDB_TERMINAL_RECORD bit set.
430*6777b538SAndroid Build Coastguard Worker 
431*6777b538SAndroid Build Coastguard Worker   static const unsigned int kTrusted = CERTDB_TRUSTED_CA | CERTDB_TRUSTED;
432*6777b538SAndroid Build Coastguard Worker   if ((nsstrust.sslFlags & CERTDB_TERMINAL_RECORD) != 0 &&
433*6777b538SAndroid Build Coastguard Worker       (nsstrust.sslFlags & kTrusted) == 0) {
434*6777b538SAndroid Build Coastguard Worker     return true;
435*6777b538SAndroid Build Coastguard Worker   }
436*6777b538SAndroid Build Coastguard Worker   if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 &&
437*6777b538SAndroid Build Coastguard Worker       (nsstrust.emailFlags & kTrusted) == 0) {
438*6777b538SAndroid Build Coastguard Worker     return true;
439*6777b538SAndroid Build Coastguard Worker   }
440*6777b538SAndroid Build Coastguard Worker   if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 &&
441*6777b538SAndroid Build Coastguard Worker       (nsstrust.objectSigningFlags & kTrusted) == 0) {
442*6777b538SAndroid Build Coastguard Worker     return true;
443*6777b538SAndroid Build Coastguard Worker   }
444*6777b538SAndroid Build Coastguard Worker 
445*6777b538SAndroid Build Coastguard Worker   // Self-signed certificates that don't have any trust bits set are untrusted.
446*6777b538SAndroid Build Coastguard Worker   // Other certificates that don't have any trust bits set may still be trusted
447*6777b538SAndroid Build Coastguard Worker   // if they chain up to a trust anchor.
448*6777b538SAndroid Build Coastguard Worker   if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) {
449*6777b538SAndroid Build Coastguard Worker     return (nsstrust.sslFlags & kTrusted) == 0 &&
450*6777b538SAndroid Build Coastguard Worker            (nsstrust.emailFlags & kTrusted) == 0 &&
451*6777b538SAndroid Build Coastguard Worker            (nsstrust.objectSigningFlags & kTrusted) == 0;
452*6777b538SAndroid Build Coastguard Worker   }
453*6777b538SAndroid Build Coastguard Worker 
454*6777b538SAndroid Build Coastguard Worker   return false;
455*6777b538SAndroid Build Coastguard Worker }
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker // static
IsWebTrustAnchor(const CERTCertificate * cert)458*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::IsWebTrustAnchor(const CERTCertificate* cert) {
459*6777b538SAndroid Build Coastguard Worker   CERTCertTrust nsstrust;
460*6777b538SAndroid Build Coastguard Worker   SECStatus rv = CERT_GetCertTrust(cert, &nsstrust);
461*6777b538SAndroid Build Coastguard Worker   if (rv != SECSuccess) {
462*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
463*6777b538SAndroid Build Coastguard Worker     return false;
464*6777b538SAndroid Build Coastguard Worker   }
465*6777b538SAndroid Build Coastguard Worker 
466*6777b538SAndroid Build Coastguard Worker   // Note: This should return true iff a net::TrustStoreNSS instantiated with
467*6777b538SAndroid Build Coastguard Worker   // SECTrustType trustSSL would classify |cert| as a trust anchor.
468*6777b538SAndroid Build Coastguard Worker   const unsigned int ssl_trust_flags = nsstrust.sslFlags;
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker   // Determine if the certificate is a trust anchor.
471*6777b538SAndroid Build Coastguard Worker   if ((ssl_trust_flags & CERTDB_TRUSTED_CA) == CERTDB_TRUSTED_CA) {
472*6777b538SAndroid Build Coastguard Worker     return true;
473*6777b538SAndroid Build Coastguard Worker   }
474*6777b538SAndroid Build Coastguard Worker 
475*6777b538SAndroid Build Coastguard Worker   return false;
476*6777b538SAndroid Build Coastguard Worker }
477*6777b538SAndroid Build Coastguard Worker 
478*6777b538SAndroid Build Coastguard Worker // static
IsReadOnly(const CERTCertificate * cert)479*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::IsReadOnly(const CERTCertificate* cert) {
480*6777b538SAndroid Build Coastguard Worker   PK11SlotInfo* slot = cert->slot;
481*6777b538SAndroid Build Coastguard Worker   return slot && PK11_IsReadOnly(slot);
482*6777b538SAndroid Build Coastguard Worker }
483*6777b538SAndroid Build Coastguard Worker 
484*6777b538SAndroid Build Coastguard Worker // static
IsHardwareBacked(const CERTCertificate * cert)485*6777b538SAndroid Build Coastguard Worker bool NSSCertDatabase::IsHardwareBacked(const CERTCertificate* cert) {
486*6777b538SAndroid Build Coastguard Worker   PK11SlotInfo* slot = cert->slot;
487*6777b538SAndroid Build Coastguard Worker   if (!slot)
488*6777b538SAndroid Build Coastguard Worker     return false;
489*6777b538SAndroid Build Coastguard Worker 
490*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
491*6777b538SAndroid Build Coastguard Worker   // For keys in Chaps, it's possible that they are truly hardware backed, or
492*6777b538SAndroid Build Coastguard Worker   // they can be software-backed, such as if the creator requested it, or if the
493*6777b538SAndroid Build Coastguard Worker   // TPM does not support the key algorithm. Chaps sets a kKeyInSoftware
494*6777b538SAndroid Build Coastguard Worker   // attribute to true for private keys that aren't wrapped by the TPM.
495*6777b538SAndroid Build Coastguard Worker   if (crypto::IsSlotProvidedByChaps(slot)) {
496*6777b538SAndroid Build Coastguard Worker     constexpr CK_ATTRIBUTE_TYPE kKeyInSoftware = CKA_VENDOR_DEFINED + 5;
497*6777b538SAndroid Build Coastguard Worker     SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
498*6777b538SAndroid Build Coastguard Worker         slot, const_cast<CERTCertificate*>(cert), nullptr);
499*6777b538SAndroid Build Coastguard Worker     // PK11_HasAttributeSet returns true if the object in the given slot has
500*6777b538SAndroid Build Coastguard Worker     // the attribute set to true. Otherwise it returns false.
501*6777b538SAndroid Build Coastguard Worker     if (private_key &&
502*6777b538SAndroid Build Coastguard Worker         PK11_HasAttributeSet(slot, private_key->pkcs11ID, kKeyInSoftware,
503*6777b538SAndroid Build Coastguard Worker                              /*haslock=*/PR_FALSE)) {
504*6777b538SAndroid Build Coastguard Worker       return false;
505*6777b538SAndroid Build Coastguard Worker     }
506*6777b538SAndroid Build Coastguard Worker     // All keys in chaps without the attribute are hardware backed.
507*6777b538SAndroid Build Coastguard Worker     return true;
508*6777b538SAndroid Build Coastguard Worker   }
509*6777b538SAndroid Build Coastguard Worker #endif
510*6777b538SAndroid Build Coastguard Worker   return PK11_IsHW(slot);
511*6777b538SAndroid Build Coastguard Worker }
512*6777b538SAndroid Build Coastguard Worker 
AddObserver(Observer * observer)513*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::AddObserver(Observer* observer) {
514*6777b538SAndroid Build Coastguard Worker   observer_list_->AddObserver(observer);
515*6777b538SAndroid Build Coastguard Worker }
516*6777b538SAndroid Build Coastguard Worker 
RemoveObserver(Observer * observer)517*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::RemoveObserver(Observer* observer) {
518*6777b538SAndroid Build Coastguard Worker   observer_list_->RemoveObserver(observer);
519*6777b538SAndroid Build Coastguard Worker }
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker // static
ExtractCertificates(CertInfoList certs_info)522*6777b538SAndroid Build Coastguard Worker ScopedCERTCertificateList NSSCertDatabase::ExtractCertificates(
523*6777b538SAndroid Build Coastguard Worker     CertInfoList certs_info) {
524*6777b538SAndroid Build Coastguard Worker   ScopedCERTCertificateList certs;
525*6777b538SAndroid Build Coastguard Worker   certs.reserve(certs_info.size());
526*6777b538SAndroid Build Coastguard Worker 
527*6777b538SAndroid Build Coastguard Worker   for (auto& cert_info : certs_info)
528*6777b538SAndroid Build Coastguard Worker     certs.push_back(std::move(cert_info.cert));
529*6777b538SAndroid Build Coastguard Worker 
530*6777b538SAndroid Build Coastguard Worker   return certs;
531*6777b538SAndroid Build Coastguard Worker }
532*6777b538SAndroid Build Coastguard Worker 
533*6777b538SAndroid Build Coastguard Worker // static
ListCertsImpl(crypto::ScopedPK11Slot slot)534*6777b538SAndroid Build Coastguard Worker ScopedCERTCertificateList NSSCertDatabase::ListCertsImpl(
535*6777b538SAndroid Build Coastguard Worker     crypto::ScopedPK11Slot slot) {
536*6777b538SAndroid Build Coastguard Worker   CertInfoList certs_info = ListCertsInfoImpl(
537*6777b538SAndroid Build Coastguard Worker       std::move(slot), /*add_certs_info=*/false, NSSRootsHandling::kInclude);
538*6777b538SAndroid Build Coastguard Worker 
539*6777b538SAndroid Build Coastguard Worker   return ExtractCertificates(std::move(certs_info));
540*6777b538SAndroid Build Coastguard Worker }
541*6777b538SAndroid Build Coastguard Worker 
542*6777b538SAndroid Build Coastguard Worker // static
ListCertsInfoImpl(crypto::ScopedPK11Slot slot,bool add_certs_info,NSSRootsHandling nss_roots_handling)543*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::CertInfoList NSSCertDatabase::ListCertsInfoImpl(
544*6777b538SAndroid Build Coastguard Worker     crypto::ScopedPK11Slot slot,
545*6777b538SAndroid Build Coastguard Worker     bool add_certs_info,
546*6777b538SAndroid Build Coastguard Worker     NSSRootsHandling nss_roots_handling) {
547*6777b538SAndroid Build Coastguard Worker   // This method may acquire the NSS lock or reenter this code via extension
548*6777b538SAndroid Build Coastguard Worker   // hooks (such as smart card UI). To ensure threads are not starved or
549*6777b538SAndroid Build Coastguard Worker   // deadlocked, the base::ScopedBlockingCall below increments the thread pool
550*6777b538SAndroid Build Coastguard Worker   // capacity if this method takes too much time to run.
551*6777b538SAndroid Build Coastguard Worker   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
552*6777b538SAndroid Build Coastguard Worker                                                 base::BlockingType::MAY_BLOCK);
553*6777b538SAndroid Build Coastguard Worker 
554*6777b538SAndroid Build Coastguard Worker   if (nss_roots_handling == NSSRootsHandling::kExclude) {
555*6777b538SAndroid Build Coastguard Worker     // This assumes that using a new TrustStoreNSS instance on each
556*6777b538SAndroid Build Coastguard Worker     // ListCertsInfo call is not expensive. If that ever changes this might
557*6777b538SAndroid Build Coastguard Worker     // need to be rethought.
558*6777b538SAndroid Build Coastguard Worker     TrustStoreNSS trust_store_nss(
559*6777b538SAndroid Build Coastguard Worker         slot ? TrustStoreNSS::UserSlotTrustSetting(
560*6777b538SAndroid Build Coastguard Worker                    crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot.get())))
561*6777b538SAndroid Build Coastguard Worker              : TrustStoreNSS::UseTrustFromAllUserSlots());
562*6777b538SAndroid Build Coastguard Worker 
563*6777b538SAndroid Build Coastguard Worker     std::vector<TrustStoreNSS::ListCertsResult> cert_list(
564*6777b538SAndroid Build Coastguard Worker         trust_store_nss.ListCertsIgnoringNSSRoots());
565*6777b538SAndroid Build Coastguard Worker 
566*6777b538SAndroid Build Coastguard Worker     CertInfoList certs_info;
567*6777b538SAndroid Build Coastguard Worker     for (const auto& node : cert_list) {
568*6777b538SAndroid Build Coastguard Worker       CertInfo cert_info;
569*6777b538SAndroid Build Coastguard Worker       cert_info.cert = x509_util::DupCERTCertificate(node.cert.get());
570*6777b538SAndroid Build Coastguard Worker       if (add_certs_info) {
571*6777b538SAndroid Build Coastguard Worker         cert_info.untrusted =
572*6777b538SAndroid Build Coastguard Worker             IsUntrustedUsingTrustStore(cert_info.cert.get(), node.trust);
573*6777b538SAndroid Build Coastguard Worker         cert_info.web_trust_anchor = node.trust.IsTrustAnchor();
574*6777b538SAndroid Build Coastguard Worker         cert_info.on_read_only_slot = IsReadOnly(cert_info.cert.get());
575*6777b538SAndroid Build Coastguard Worker         cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
576*6777b538SAndroid Build Coastguard Worker       }
577*6777b538SAndroid Build Coastguard Worker       certs_info.push_back(std::move(cert_info));
578*6777b538SAndroid Build Coastguard Worker     }
579*6777b538SAndroid Build Coastguard Worker     return certs_info;
580*6777b538SAndroid Build Coastguard Worker   } else {
581*6777b538SAndroid Build Coastguard Worker     CertInfoList certs_info;
582*6777b538SAndroid Build Coastguard Worker     crypto::ScopedCERTCertList cert_list = nullptr;
583*6777b538SAndroid Build Coastguard Worker     if (slot) {
584*6777b538SAndroid Build Coastguard Worker       cert_list.reset(PK11_ListCertsInSlot(slot.get()));
585*6777b538SAndroid Build Coastguard Worker     } else {
586*6777b538SAndroid Build Coastguard Worker       cert_list.reset(PK11_ListCerts(PK11CertListUnique, nullptr));
587*6777b538SAndroid Build Coastguard Worker     }
588*6777b538SAndroid Build Coastguard Worker     // PK11_ListCerts[InSlot] can return nullptr, e.g. because the PKCS#11 token
589*6777b538SAndroid Build Coastguard Worker     // that was backing the specified slot is not available anymore.
590*6777b538SAndroid Build Coastguard Worker     // Treat it as no certificates being present on the slot.
591*6777b538SAndroid Build Coastguard Worker     if (!cert_list) {
592*6777b538SAndroid Build Coastguard Worker       LOG(WARNING) << (slot ? "PK11_ListCertsInSlot" : "PK11_ListCerts")
593*6777b538SAndroid Build Coastguard Worker                    << " returned null";
594*6777b538SAndroid Build Coastguard Worker       return certs_info;
595*6777b538SAndroid Build Coastguard Worker     }
596*6777b538SAndroid Build Coastguard Worker 
597*6777b538SAndroid Build Coastguard Worker     CERTCertListNode* node;
598*6777b538SAndroid Build Coastguard Worker     for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list);
599*6777b538SAndroid Build Coastguard Worker          node = CERT_LIST_NEXT(node)) {
600*6777b538SAndroid Build Coastguard Worker       CertInfo cert_info;
601*6777b538SAndroid Build Coastguard Worker       cert_info.cert = x509_util::DupCERTCertificate(node->cert);
602*6777b538SAndroid Build Coastguard Worker 
603*6777b538SAndroid Build Coastguard Worker       if (add_certs_info) {
604*6777b538SAndroid Build Coastguard Worker         cert_info.on_read_only_slot = IsReadOnly(cert_info.cert.get());
605*6777b538SAndroid Build Coastguard Worker         cert_info.untrusted = IsUntrusted(cert_info.cert.get());
606*6777b538SAndroid Build Coastguard Worker         cert_info.web_trust_anchor = IsWebTrustAnchor(cert_info.cert.get());
607*6777b538SAndroid Build Coastguard Worker         cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
608*6777b538SAndroid Build Coastguard Worker       }
609*6777b538SAndroid Build Coastguard Worker 
610*6777b538SAndroid Build Coastguard Worker       certs_info.push_back(std::move(cert_info));
611*6777b538SAndroid Build Coastguard Worker     }
612*6777b538SAndroid Build Coastguard Worker     return certs_info;
613*6777b538SAndroid Build Coastguard Worker   }
614*6777b538SAndroid Build Coastguard Worker }
615*6777b538SAndroid Build Coastguard Worker 
NotifyCertRemovalAndCallBack(DeleteCertCallback callback,DeleteCertAndKeyResult result)616*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::NotifyCertRemovalAndCallBack(
617*6777b538SAndroid Build Coastguard Worker     DeleteCertCallback callback,
618*6777b538SAndroid Build Coastguard Worker     DeleteCertAndKeyResult result) {
619*6777b538SAndroid Build Coastguard Worker   // This makes the assumption that if there was a matching private key, the
620*6777b538SAndroid Build Coastguard Worker   // cert was probably a client cert, and if not, it may have been a trust
621*6777b538SAndroid Build Coastguard Worker   // anchor or intemediate CA cert.
622*6777b538SAndroid Build Coastguard Worker   switch (result) {
623*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::OK_NO_KEY:
624*6777b538SAndroid Build Coastguard Worker       NotifyObserversTrustStoreChanged();
625*6777b538SAndroid Build Coastguard Worker       std::move(callback).Run(true);
626*6777b538SAndroid Build Coastguard Worker       break;
627*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::OK_FOUND_KEY:
628*6777b538SAndroid Build Coastguard Worker       NotifyObserversClientCertStoreChanged();
629*6777b538SAndroid Build Coastguard Worker       std::move(callback).Run(true);
630*6777b538SAndroid Build Coastguard Worker       break;
631*6777b538SAndroid Build Coastguard Worker     case DeleteCertAndKeyResult::ERROR:
632*6777b538SAndroid Build Coastguard Worker       std::move(callback).Run(false);
633*6777b538SAndroid Build Coastguard Worker       break;
634*6777b538SAndroid Build Coastguard Worker   }
635*6777b538SAndroid Build Coastguard Worker }
636*6777b538SAndroid Build Coastguard Worker 
NotifyObserversTrustStoreChanged()637*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::NotifyObserversTrustStoreChanged() {
638*6777b538SAndroid Build Coastguard Worker   observer_list_->Notify(FROM_HERE, &Observer::OnTrustStoreChanged);
639*6777b538SAndroid Build Coastguard Worker }
640*6777b538SAndroid Build Coastguard Worker 
NotifyObserversClientCertStoreChanged()641*6777b538SAndroid Build Coastguard Worker void NSSCertDatabase::NotifyObserversClientCertStoreChanged() {
642*6777b538SAndroid Build Coastguard Worker   observer_list_->Notify(FROM_HERE, &Observer::OnClientCertStoreChanged);
643*6777b538SAndroid Build Coastguard Worker }
644*6777b538SAndroid Build Coastguard Worker 
645*6777b538SAndroid Build Coastguard Worker // static
DeleteCertAndKeyImpl(CERTCertificate * cert)646*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::DeleteCertAndKeyResult NSSCertDatabase::DeleteCertAndKeyImpl(
647*6777b538SAndroid Build Coastguard Worker     CERTCertificate* cert) {
648*6777b538SAndroid Build Coastguard Worker   // This method may acquire the NSS lock or reenter this code via extension
649*6777b538SAndroid Build Coastguard Worker   // hooks (such as smart card UI). To ensure threads are not starved or
650*6777b538SAndroid Build Coastguard Worker   // deadlocked, the base::ScopedBlockingCall below increments the thread pool
651*6777b538SAndroid Build Coastguard Worker   // capacity if this method takes too much time to run.
652*6777b538SAndroid Build Coastguard Worker   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
653*6777b538SAndroid Build Coastguard Worker                                                 base::BlockingType::MAY_BLOCK);
654*6777b538SAndroid Build Coastguard Worker 
655*6777b538SAndroid Build Coastguard Worker   // For some reason, PK11_DeleteTokenCertAndKey only calls
656*6777b538SAndroid Build Coastguard Worker   // SEC_DeletePermCertificate if the private key is found.  So, we check
657*6777b538SAndroid Build Coastguard Worker   // whether a private key exists before deciding which function to call to
658*6777b538SAndroid Build Coastguard Worker   // delete the cert.
659*6777b538SAndroid Build Coastguard Worker   SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(cert, nullptr);
660*6777b538SAndroid Build Coastguard Worker   if (privKey) {
661*6777b538SAndroid Build Coastguard Worker     SECKEY_DestroyPrivateKey(privKey);
662*6777b538SAndroid Build Coastguard Worker     if (PK11_DeleteTokenCertAndKey(cert, nullptr)) {
663*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError();
664*6777b538SAndroid Build Coastguard Worker       return DeleteCertAndKeyResult::ERROR;
665*6777b538SAndroid Build Coastguard Worker     }
666*6777b538SAndroid Build Coastguard Worker     return DeleteCertAndKeyResult::OK_FOUND_KEY;
667*6777b538SAndroid Build Coastguard Worker   } else {
668*6777b538SAndroid Build Coastguard Worker     if (SEC_DeletePermCertificate(cert)) {
669*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
670*6777b538SAndroid Build Coastguard Worker       return DeleteCertAndKeyResult::ERROR;
671*6777b538SAndroid Build Coastguard Worker     }
672*6777b538SAndroid Build Coastguard Worker     return DeleteCertAndKeyResult::OK_NO_KEY;
673*6777b538SAndroid Build Coastguard Worker   }
674*6777b538SAndroid Build Coastguard Worker }
675*6777b538SAndroid Build Coastguard Worker 
676*6777b538SAndroid Build Coastguard Worker // static
677*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::DeleteCertAndKeyResult
DeleteCertAndKeyImplScoped(ScopedCERTCertificate cert)678*6777b538SAndroid Build Coastguard Worker NSSCertDatabase::DeleteCertAndKeyImplScoped(ScopedCERTCertificate cert) {
679*6777b538SAndroid Build Coastguard Worker   return NSSCertDatabase::DeleteCertAndKeyImpl(cert.get());
680*6777b538SAndroid Build Coastguard Worker }
681*6777b538SAndroid Build Coastguard Worker 
682*6777b538SAndroid Build Coastguard Worker }  // namespace net
683