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