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 <keyhi.h> 10 #include <pk11pub.h> 11 #include <secmod.h> 12 13 #include "base/bind.h" 14 #include "base/callback.h" 15 #include "base/logging.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/observer_list_threadsafe.h" 18 #include "base/task_runner.h" 19 #include "base/task_runner_util.h" 20 #include "base/threading/worker_pool.h" 21 #include "crypto/scoped_nss_types.h" 22 #include "net/base/crypto_module.h" 23 #include "net/base/net_errors.h" 24 #include "net/cert/cert_database.h" 25 #include "net/cert/x509_certificate.h" 26 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h" 27 #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" 28 29 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use 30 // the new name of the macro. 31 #if !defined(CERTDB_TERMINAL_RECORD) 32 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER 33 #endif 34 35 // PSM = Mozilla's Personal Security Manager. 36 namespace psm = mozilla_security_manager; 37 38 namespace net { 39 40 namespace { 41 42 // TODO(pneubeck): Move this class out of NSSCertDatabase and to the caller of 43 // the c'tor of NSSCertDatabase, see https://crbug.com/395983 . 44 // Helper that observes events from the NSSCertDatabase and forwards them to 45 // the given CertDatabase. 46 class CertNotificationForwarder : public NSSCertDatabase::Observer { 47 public: 48 explicit CertNotificationForwarder(CertDatabase* cert_db) 49 : cert_db_(cert_db) {} 50 51 virtual ~CertNotificationForwarder() {} 52 53 // NSSCertDatabase::Observer implementation: 54 virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE { 55 cert_db_->NotifyObserversOfCertAdded(cert); 56 } 57 58 virtual void OnCertRemoved(const X509Certificate* cert) OVERRIDE { 59 cert_db_->NotifyObserversOfCertRemoved(cert); 60 } 61 62 virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE { 63 cert_db_->NotifyObserversOfCACertChanged(cert); 64 } 65 66 private: 67 CertDatabase* cert_db_; 68 69 DISALLOW_COPY_AND_ASSIGN(CertNotificationForwarder); 70 }; 71 72 } // namespace 73 74 NSSCertDatabase::ImportCertFailure::ImportCertFailure( 75 const scoped_refptr<X509Certificate>& cert, 76 int err) 77 : certificate(cert), net_error(err) {} 78 79 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {} 80 81 NSSCertDatabase::NSSCertDatabase(crypto::ScopedPK11Slot public_slot, 82 crypto::ScopedPK11Slot private_slot) 83 : public_slot_(public_slot.Pass()), 84 private_slot_(private_slot.Pass()), 85 observer_list_(new ObserverListThreadSafe<Observer>), 86 weak_factory_(this) { 87 CHECK(public_slot_); 88 89 // This also makes sure that NSS has been initialized. 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() {} 98 99 void NSSCertDatabase::ListCertsSync(CertificateList* certs) { 100 ListCertsImpl(crypto::ScopedPK11Slot(), certs); 101 } 102 103 void NSSCertDatabase::ListCerts( 104 const base::Callback<void(scoped_ptr<CertificateList> certs)>& callback) { 105 scoped_ptr<CertificateList> certs(new CertificateList()); 106 107 // base::Passed will NULL out |certs|, so cache the underlying pointer here. 108 CertificateList* raw_certs = certs.get(); 109 GetSlowTaskRunner()->PostTaskAndReply( 110 FROM_HERE, 111 base::Bind(&NSSCertDatabase::ListCertsImpl, 112 base::Passed(crypto::ScopedPK11Slot()), 113 base::Unretained(raw_certs)), 114 base::Bind(callback, base::Passed(&certs))); 115 } 116 117 void NSSCertDatabase::ListCertsInSlot(const ListCertsCallback& callback, 118 PK11SlotInfo* slot) { 119 DCHECK(slot); 120 scoped_ptr<CertificateList> certs(new CertificateList()); 121 122 // base::Passed will NULL out |certs|, so cache the underlying pointer here. 123 CertificateList* raw_certs = certs.get(); 124 GetSlowTaskRunner()->PostTaskAndReply( 125 FROM_HERE, 126 base::Bind(&NSSCertDatabase::ListCertsImpl, 127 base::Passed(crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot))), 128 base::Unretained(raw_certs)), 129 base::Bind(callback, base::Passed(&certs))); 130 } 131 132 #if defined(OS_CHROMEOS) 133 crypto::ScopedPK11Slot NSSCertDatabase::GetSystemSlot() const { 134 return crypto::ScopedPK11Slot(); 135 } 136 #endif 137 138 crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const { 139 return crypto::ScopedPK11Slot(PK11_ReferenceSlot(public_slot_.get())); 140 } 141 142 crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const { 143 if (!private_slot_) 144 return crypto::ScopedPK11Slot(); 145 return crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); 146 } 147 148 CryptoModule* NSSCertDatabase::GetPublicModule() const { 149 crypto::ScopedPK11Slot slot(GetPublicSlot()); 150 return CryptoModule::CreateFromHandle(slot.get()); 151 } 152 153 CryptoModule* NSSCertDatabase::GetPrivateModule() const { 154 crypto::ScopedPK11Slot slot(GetPrivateSlot()); 155 return CryptoModule::CreateFromHandle(slot.get()); 156 } 157 158 void NSSCertDatabase::ListModules(CryptoModuleList* modules, 159 bool need_rw) const { 160 modules->clear(); 161 162 // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. 163 crypto::ScopedPK11SlotList slot_list( 164 PK11_GetAllTokens(CKM_INVALID_MECHANISM, 165 need_rw ? PR_TRUE : PR_FALSE, // needRW 166 PR_TRUE, // loadCerts (unused) 167 NULL)); // wincx 168 if (!slot_list) { 169 LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError(); 170 return; 171 } 172 173 PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get()); 174 while (slot_element) { 175 modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot)); 176 slot_element = PK11_GetNextSafe(slot_list.get(), slot_element, 177 PR_FALSE); // restart 178 } 179 } 180 181 int NSSCertDatabase::ImportFromPKCS12( 182 CryptoModule* module, 183 const std::string& data, 184 const base::string16& password, 185 bool is_extractable, 186 net::CertificateList* imported_certs) { 187 DVLOG(1) << __func__ << " " 188 << PK11_GetModuleID(module->os_module_handle()) << ":" 189 << PK11_GetSlotID(module->os_module_handle()); 190 int result = psm::nsPKCS12Blob_Import(module->os_module_handle(), 191 data.data(), data.size(), 192 password, 193 is_extractable, 194 imported_certs); 195 if (result == net::OK) 196 NotifyObserversOfCertAdded(NULL); 197 198 return result; 199 } 200 201 int NSSCertDatabase::ExportToPKCS12( 202 const CertificateList& certs, 203 const base::string16& password, 204 std::string* output) const { 205 return psm::nsPKCS12Blob_Export(output, certs, password); 206 } 207 208 X509Certificate* NSSCertDatabase::FindRootInList( 209 const CertificateList& certificates) const { 210 DCHECK_GT(certificates.size(), 0U); 211 212 if (certificates.size() == 1) 213 return certificates[0].get(); 214 215 X509Certificate* cert0 = certificates[0].get(); 216 X509Certificate* cert1 = certificates[1].get(); 217 X509Certificate* certn_2 = certificates[certificates.size() - 2].get(); 218 X509Certificate* certn_1 = certificates[certificates.size() - 1].get(); 219 220 if (CERT_CompareName(&cert1->os_cert_handle()->issuer, 221 &cert0->os_cert_handle()->subject) == SECEqual) 222 return cert0; 223 if (CERT_CompareName(&certn_2->os_cert_handle()->issuer, 224 &certn_1->os_cert_handle()->subject) == SECEqual) 225 return certn_1; 226 227 LOG(WARNING) << "certificate list is not a hierarchy"; 228 return cert0; 229 } 230 231 bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates, 232 TrustBits trust_bits, 233 ImportCertFailureList* not_imported) { 234 crypto::ScopedPK11Slot slot(GetPublicSlot()); 235 X509Certificate* root = FindRootInList(certificates); 236 bool success = psm::ImportCACerts( 237 slot.get(), certificates, root, trust_bits, not_imported); 238 if (success) 239 NotifyObserversOfCACertChanged(NULL); 240 241 return success; 242 } 243 244 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates, 245 TrustBits trust_bits, 246 ImportCertFailureList* not_imported) { 247 crypto::ScopedPK11Slot slot(GetPublicSlot()); 248 return psm::ImportServerCert( 249 slot.get(), certificates, trust_bits, not_imported); 250 } 251 252 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust( 253 const X509Certificate* cert, 254 CertType type) const { 255 CERTCertTrust trust; 256 SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust); 257 if (srv != SECSuccess) { 258 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); 259 return TRUST_DEFAULT; 260 } 261 // We define our own more "friendly" TrustBits, which means we aren't able to 262 // round-trip all possible NSS trust flag combinations. We try to map them in 263 // a sensible way. 264 switch (type) { 265 case CA_CERT: { 266 const unsigned kTrustedCA = CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA; 267 const unsigned kCAFlags = kTrustedCA | CERTDB_TERMINAL_RECORD; 268 269 TrustBits trust_bits = TRUST_DEFAULT; 270 if ((trust.sslFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 271 trust_bits |= DISTRUSTED_SSL; 272 else if (trust.sslFlags & kTrustedCA) 273 trust_bits |= TRUSTED_SSL; 274 275 if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 276 trust_bits |= DISTRUSTED_EMAIL; 277 else if (trust.emailFlags & kTrustedCA) 278 trust_bits |= TRUSTED_EMAIL; 279 280 if ((trust.objectSigningFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 281 trust_bits |= DISTRUSTED_OBJ_SIGN; 282 else if (trust.objectSigningFlags & kTrustedCA) 283 trust_bits |= TRUSTED_OBJ_SIGN; 284 285 return trust_bits; 286 } 287 case SERVER_CERT: 288 if (trust.sslFlags & CERTDB_TERMINAL_RECORD) { 289 if (trust.sslFlags & CERTDB_TRUSTED) 290 return TRUSTED_SSL; 291 return DISTRUSTED_SSL; 292 } 293 return TRUST_DEFAULT; 294 default: 295 return TRUST_DEFAULT; 296 } 297 } 298 299 bool NSSCertDatabase::IsUntrusted(const X509Certificate* cert) const { 300 CERTCertTrust nsstrust; 301 SECStatus rv = CERT_GetCertTrust(cert->os_cert_handle(), &nsstrust); 302 if (rv != SECSuccess) { 303 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); 304 return false; 305 } 306 307 // The CERTCertTrust structure contains three trust records: 308 // sslFlags, emailFlags, and objectSigningFlags. The three 309 // trust records are independent of each other. 310 // 311 // If the CERTDB_TERMINAL_RECORD bit in a trust record is set, 312 // then that trust record is a terminal record. A terminal 313 // record is used for explicit trust and distrust of an 314 // end-entity or intermediate CA cert. 315 // 316 // In a terminal record, if neither CERTDB_TRUSTED_CA nor 317 // CERTDB_TRUSTED is set, then the terminal record means 318 // explicit distrust. On the other hand, if the terminal 319 // record has either CERTDB_TRUSTED_CA or CERTDB_TRUSTED bit 320 // set, then the terminal record means explicit trust. 321 // 322 // For a root CA, the trust record does not have 323 // the CERTDB_TERMINAL_RECORD bit set. 324 325 static const unsigned int kTrusted = CERTDB_TRUSTED_CA | CERTDB_TRUSTED; 326 if ((nsstrust.sslFlags & CERTDB_TERMINAL_RECORD) != 0 && 327 (nsstrust.sslFlags & kTrusted) == 0) { 328 return true; 329 } 330 if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 && 331 (nsstrust.emailFlags & kTrusted) == 0) { 332 return true; 333 } 334 if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 && 335 (nsstrust.objectSigningFlags & kTrusted) == 0) { 336 return true; 337 } 338 339 // Self-signed certificates that don't have any trust bits set are untrusted. 340 // Other certificates that don't have any trust bits set may still be trusted 341 // if they chain up to a trust anchor. 342 if (CERT_CompareName(&cert->os_cert_handle()->issuer, 343 &cert->os_cert_handle()->subject) == SECEqual) { 344 return (nsstrust.sslFlags & kTrusted) == 0 && 345 (nsstrust.emailFlags & kTrusted) == 0 && 346 (nsstrust.objectSigningFlags & kTrusted) == 0; 347 } 348 349 return false; 350 } 351 352 bool NSSCertDatabase::SetCertTrust(const X509Certificate* cert, 353 CertType type, 354 TrustBits trust_bits) { 355 bool success = psm::SetCertTrust(cert, type, trust_bits); 356 if (success) 357 NotifyObserversOfCACertChanged(cert); 358 359 return success; 360 } 361 362 bool NSSCertDatabase::DeleteCertAndKey(X509Certificate* cert) { 363 if (!DeleteCertAndKeyImpl(cert)) 364 return false; 365 NotifyObserversOfCertRemoved(cert); 366 return true; 367 } 368 369 void NSSCertDatabase::DeleteCertAndKeyAsync( 370 const scoped_refptr<X509Certificate>& cert, 371 const DeleteCertCallback& callback) { 372 base::PostTaskAndReplyWithResult( 373 GetSlowTaskRunner().get(), 374 FROM_HERE, 375 base::Bind(&NSSCertDatabase::DeleteCertAndKeyImpl, cert), 376 base::Bind(&NSSCertDatabase::NotifyCertRemovalAndCallBack, 377 weak_factory_.GetWeakPtr(), 378 cert, 379 callback)); 380 } 381 382 bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const { 383 PK11SlotInfo* slot = cert->os_cert_handle()->slot; 384 return slot && PK11_IsReadOnly(slot); 385 } 386 387 bool NSSCertDatabase::IsHardwareBacked(const X509Certificate* cert) const { 388 PK11SlotInfo* slot = cert->os_cert_handle()->slot; 389 return slot && PK11_IsHW(slot); 390 } 391 392 void NSSCertDatabase::AddObserver(Observer* observer) { 393 observer_list_->AddObserver(observer); 394 } 395 396 void NSSCertDatabase::RemoveObserver(Observer* observer) { 397 observer_list_->RemoveObserver(observer); 398 } 399 400 void NSSCertDatabase::SetSlowTaskRunnerForTest( 401 const scoped_refptr<base::TaskRunner>& task_runner) { 402 slow_task_runner_for_test_ = task_runner; 403 } 404 405 // static 406 void NSSCertDatabase::ListCertsImpl(crypto::ScopedPK11Slot slot, 407 CertificateList* certs) { 408 certs->clear(); 409 410 CERTCertList* cert_list = NULL; 411 if (slot) 412 cert_list = PK11_ListCertsInSlot(slot.get()); 413 else 414 cert_list = PK11_ListCerts(PK11CertListUnique, NULL); 415 416 CERTCertListNode* node; 417 for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list); 418 node = CERT_LIST_NEXT(node)) { 419 certs->push_back(X509Certificate::CreateFromHandle( 420 node->cert, X509Certificate::OSCertHandles())); 421 } 422 CERT_DestroyCertList(cert_list); 423 } 424 425 scoped_refptr<base::TaskRunner> NSSCertDatabase::GetSlowTaskRunner() const { 426 if (slow_task_runner_for_test_.get()) 427 return slow_task_runner_for_test_; 428 return base::WorkerPool::GetTaskRunner(true /*task is slow*/); 429 } 430 431 void NSSCertDatabase::NotifyCertRemovalAndCallBack( 432 scoped_refptr<X509Certificate> cert, 433 const DeleteCertCallback& callback, 434 bool success) { 435 if (success) 436 NotifyObserversOfCertRemoved(cert.get()); 437 callback.Run(success); 438 } 439 440 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) { 441 observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert)); 442 } 443 444 void NSSCertDatabase::NotifyObserversOfCertRemoved( 445 const X509Certificate* cert) { 446 observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert)); 447 } 448 449 void NSSCertDatabase::NotifyObserversOfCACertChanged( 450 const X509Certificate* cert) { 451 observer_list_->Notify( 452 &Observer::OnCACertChanged, make_scoped_refptr(cert)); 453 } 454 455 // static 456 bool NSSCertDatabase::DeleteCertAndKeyImpl( 457 scoped_refptr<X509Certificate> cert) { 458 // For some reason, PK11_DeleteTokenCertAndKey only calls 459 // SEC_DeletePermCertificate if the private key is found. So, we check 460 // whether a private key exists before deciding which function to call to 461 // delete the cert. 462 SECKEYPrivateKey* privKey = 463 PK11_FindKeyByAnyCert(cert->os_cert_handle(), NULL); 464 if (privKey) { 465 SECKEY_DestroyPrivateKey(privKey); 466 if (PK11_DeleteTokenCertAndKey(cert->os_cert_handle(), NULL)) { 467 LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError(); 468 return false; 469 } 470 } else { 471 if (SEC_DeletePermCertificate(cert->os_cert_handle())) { 472 LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError(); 473 return false; 474 } 475 } 476 return true; 477 } 478 479 } // namespace net 480