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/logging.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/singleton.h" 16 #include "base/observer_list_threadsafe.h" 17 #include "crypto/nss_util.h" 18 #include "crypto/nss_util_internal.h" 19 #include "net/base/crypto_module.h" 20 #include "net/base/net_errors.h" 21 #include "net/cert/cert_database.h" 22 #include "net/cert/x509_certificate.h" 23 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h" 24 #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" 25 26 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use 27 // the new name of the macro. 28 #if !defined(CERTDB_TERMINAL_RECORD) 29 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER 30 #endif 31 32 // PSM = Mozilla's Personal Security Manager. 33 namespace psm = mozilla_security_manager; 34 35 namespace net { 36 37 NSSCertDatabase::ImportCertFailure::ImportCertFailure( 38 const scoped_refptr<X509Certificate>& cert, 39 int err) 40 : certificate(cert), net_error(err) {} 41 42 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {} 43 44 // static 45 NSSCertDatabase* NSSCertDatabase::GetInstance() { 46 return Singleton<NSSCertDatabase, 47 LeakySingletonTraits<NSSCertDatabase> >::get(); 48 } 49 50 NSSCertDatabase::NSSCertDatabase() 51 : observer_list_(new ObserverListThreadSafe<Observer>) { 52 crypto::EnsureNSSInit(); 53 psm::EnsurePKCS12Init(); 54 } 55 56 NSSCertDatabase::~NSSCertDatabase() {} 57 58 void NSSCertDatabase::ListCerts(CertificateList* certs) { 59 certs->clear(); 60 61 CERTCertList* cert_list = PK11_ListCerts(PK11CertListUnique, NULL); 62 CERTCertListNode* node; 63 for (node = CERT_LIST_HEAD(cert_list); 64 !CERT_LIST_END(node, cert_list); 65 node = CERT_LIST_NEXT(node)) { 66 certs->push_back(X509Certificate::CreateFromHandle( 67 node->cert, X509Certificate::OSCertHandles())); 68 } 69 CERT_DestroyCertList(cert_list); 70 } 71 72 CryptoModule* NSSCertDatabase::GetPublicModule() const { 73 CryptoModule* module = 74 CryptoModule::CreateFromHandle(crypto::GetPublicNSSKeySlot()); 75 // The module is already referenced when returned from 76 // GetPublicNSSKeySlot, so we need to deref it once. 77 PK11_FreeSlot(module->os_module_handle()); 78 79 return module; 80 } 81 82 CryptoModule* NSSCertDatabase::GetPrivateModule() const { 83 CryptoModule* module = 84 CryptoModule::CreateFromHandle(crypto::GetPrivateNSSKeySlot()); 85 // The module is already referenced when returned from 86 // GetPrivateNSSKeySlot, so we need to deref it once. 87 PK11_FreeSlot(module->os_module_handle()); 88 89 return module; 90 } 91 92 void NSSCertDatabase::ListModules(CryptoModuleList* modules, 93 bool need_rw) const { 94 modules->clear(); 95 96 PK11SlotList* slot_list = NULL; 97 // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. 98 slot_list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, 99 need_rw ? PR_TRUE : PR_FALSE, // needRW 100 PR_TRUE, // loadCerts (unused) 101 NULL); // wincx 102 if (!slot_list) { 103 LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError(); 104 return; 105 } 106 107 PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list); 108 while (slot_element) { 109 modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot)); 110 slot_element = PK11_GetNextSafe(slot_list, slot_element, 111 PR_FALSE); // restart 112 } 113 114 PK11_FreeSlotList(slot_list); 115 } 116 117 int NSSCertDatabase::ImportFromPKCS12( 118 CryptoModule* module, 119 const std::string& data, 120 const base::string16& password, 121 bool is_extractable, 122 net::CertificateList* imported_certs) { 123 int result = psm::nsPKCS12Blob_Import(module->os_module_handle(), 124 data.data(), data.size(), 125 password, 126 is_extractable, 127 imported_certs); 128 if (result == net::OK) 129 NotifyObserversOfCertAdded(NULL); 130 131 return result; 132 } 133 134 int NSSCertDatabase::ExportToPKCS12( 135 const CertificateList& certs, 136 const base::string16& password, 137 std::string* output) const { 138 return psm::nsPKCS12Blob_Export(output, certs, password); 139 } 140 141 X509Certificate* NSSCertDatabase::FindRootInList( 142 const CertificateList& certificates) const { 143 DCHECK_GT(certificates.size(), 0U); 144 145 if (certificates.size() == 1) 146 return certificates[0].get(); 147 148 X509Certificate* cert0 = certificates[0].get(); 149 X509Certificate* cert1 = certificates[1].get(); 150 X509Certificate* certn_2 = certificates[certificates.size() - 2].get(); 151 X509Certificate* certn_1 = certificates[certificates.size() - 1].get(); 152 153 if (CERT_CompareName(&cert1->os_cert_handle()->issuer, 154 &cert0->os_cert_handle()->subject) == SECEqual) 155 return cert0; 156 if (CERT_CompareName(&certn_2->os_cert_handle()->issuer, 157 &certn_1->os_cert_handle()->subject) == SECEqual) 158 return certn_1; 159 160 VLOG(1) << "certificate list is not a hierarchy"; 161 return cert0; 162 } 163 164 bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates, 165 TrustBits trust_bits, 166 ImportCertFailureList* not_imported) { 167 X509Certificate* root = FindRootInList(certificates); 168 bool success = psm::ImportCACerts(certificates, root, trust_bits, 169 not_imported); 170 if (success) 171 NotifyObserversOfCertTrustChanged(NULL); 172 173 return success; 174 } 175 176 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates, 177 TrustBits trust_bits, 178 ImportCertFailureList* not_imported) { 179 return psm::ImportServerCert(certificates, trust_bits, not_imported); 180 } 181 182 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust( 183 const X509Certificate* cert, 184 CertType type) const { 185 CERTCertTrust trust; 186 SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust); 187 if (srv != SECSuccess) { 188 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); 189 return TRUST_DEFAULT; 190 } 191 // We define our own more "friendly" TrustBits, which means we aren't able to 192 // round-trip all possible NSS trust flag combinations. We try to map them in 193 // a sensible way. 194 switch (type) { 195 case CA_CERT: { 196 const unsigned kTrustedCA = CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA; 197 const unsigned kCAFlags = kTrustedCA | CERTDB_TERMINAL_RECORD; 198 199 TrustBits trust_bits = TRUST_DEFAULT; 200 if ((trust.sslFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 201 trust_bits |= DISTRUSTED_SSL; 202 else if (trust.sslFlags & kTrustedCA) 203 trust_bits |= TRUSTED_SSL; 204 205 if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 206 trust_bits |= DISTRUSTED_EMAIL; 207 else if (trust.emailFlags & kTrustedCA) 208 trust_bits |= TRUSTED_EMAIL; 209 210 if ((trust.objectSigningFlags & kCAFlags) == CERTDB_TERMINAL_RECORD) 211 trust_bits |= DISTRUSTED_OBJ_SIGN; 212 else if (trust.objectSigningFlags & kTrustedCA) 213 trust_bits |= TRUSTED_OBJ_SIGN; 214 215 return trust_bits; 216 } 217 case SERVER_CERT: 218 if (trust.sslFlags & CERTDB_TERMINAL_RECORD) { 219 if (trust.sslFlags & CERTDB_TRUSTED) 220 return TRUSTED_SSL; 221 return DISTRUSTED_SSL; 222 } 223 return TRUST_DEFAULT; 224 default: 225 return TRUST_DEFAULT; 226 } 227 } 228 229 bool NSSCertDatabase::IsUntrusted(const X509Certificate* cert) const { 230 CERTCertTrust nsstrust; 231 SECStatus rv = CERT_GetCertTrust(cert->os_cert_handle(), &nsstrust); 232 if (rv != SECSuccess) { 233 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); 234 return false; 235 } 236 237 // The CERTCertTrust structure contains three trust records: 238 // sslFlags, emailFlags, and objectSigningFlags. The three 239 // trust records are independent of each other. 240 // 241 // If the CERTDB_TERMINAL_RECORD bit in a trust record is set, 242 // then that trust record is a terminal record. A terminal 243 // record is used for explicit trust and distrust of an 244 // end-entity or intermediate CA cert. 245 // 246 // In a terminal record, if neither CERTDB_TRUSTED_CA nor 247 // CERTDB_TRUSTED is set, then the terminal record means 248 // explicit distrust. On the other hand, if the terminal 249 // record has either CERTDB_TRUSTED_CA or CERTDB_TRUSTED bit 250 // set, then the terminal record means explicit trust. 251 // 252 // For a root CA, the trust record does not have 253 // the CERTDB_TERMINAL_RECORD bit set. 254 255 static const unsigned int kTrusted = CERTDB_TRUSTED_CA | CERTDB_TRUSTED; 256 if ((nsstrust.sslFlags & CERTDB_TERMINAL_RECORD) != 0 && 257 (nsstrust.sslFlags & kTrusted) == 0) { 258 return true; 259 } 260 if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 && 261 (nsstrust.emailFlags & kTrusted) == 0) { 262 return true; 263 } 264 if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 && 265 (nsstrust.objectSigningFlags & kTrusted) == 0) { 266 return true; 267 } 268 269 // Self-signed certificates that don't have any trust bits set are untrusted. 270 // Other certificates that don't have any trust bits set may still be trusted 271 // if they chain up to a trust anchor. 272 if (CERT_CompareName(&cert->os_cert_handle()->issuer, 273 &cert->os_cert_handle()->subject) == SECEqual) { 274 return (nsstrust.sslFlags & kTrusted) == 0 && 275 (nsstrust.emailFlags & kTrusted) == 0 && 276 (nsstrust.objectSigningFlags & kTrusted) == 0; 277 } 278 279 return false; 280 } 281 282 bool NSSCertDatabase::SetCertTrust(const X509Certificate* cert, 283 CertType type, 284 TrustBits trust_bits) { 285 bool success = psm::SetCertTrust(cert, type, trust_bits); 286 if (success) 287 NotifyObserversOfCertTrustChanged(cert); 288 289 return success; 290 } 291 292 bool NSSCertDatabase::DeleteCertAndKey(const X509Certificate* cert) { 293 // For some reason, PK11_DeleteTokenCertAndKey only calls 294 // SEC_DeletePermCertificate if the private key is found. So, we check 295 // whether a private key exists before deciding which function to call to 296 // delete the cert. 297 SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert->os_cert_handle(), 298 NULL); 299 if (privKey) { 300 SECKEY_DestroyPrivateKey(privKey); 301 if (PK11_DeleteTokenCertAndKey(cert->os_cert_handle(), NULL)) { 302 LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError(); 303 return false; 304 } 305 } else { 306 if (SEC_DeletePermCertificate(cert->os_cert_handle())) { 307 LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError(); 308 return false; 309 } 310 } 311 312 NotifyObserversOfCertRemoved(cert); 313 314 return true; 315 } 316 317 bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const { 318 PK11SlotInfo* slot = cert->os_cert_handle()->slot; 319 return slot && PK11_IsReadOnly(slot); 320 } 321 322 void NSSCertDatabase::AddObserver(Observer* observer) { 323 observer_list_->AddObserver(observer); 324 } 325 326 void NSSCertDatabase::RemoveObserver(Observer* observer) { 327 observer_list_->RemoveObserver(observer); 328 } 329 330 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) { 331 observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert)); 332 } 333 334 void NSSCertDatabase::NotifyObserversOfCertRemoved( 335 const X509Certificate* cert) { 336 observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert)); 337 } 338 339 void NSSCertDatabase::NotifyObserversOfCertTrustChanged( 340 const X509Certificate* cert) { 341 observer_list_->Notify( 342 &Observer::OnCertTrustChanged, make_scoped_refptr(cert)); 343 } 344 345 } // namespace net 346