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