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