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