Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / cert / nss_cert_database.cc
blob8e9ef4e6f0159078fc8462002d53f5e0f4b3a592
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 "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"
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
32 // PSM = Mozilla's Personal Security Manager.
33 namespace psm = mozilla_security_manager;
35 namespace net {
37 NSSCertDatabase::ImportCertFailure::ImportCertFailure(
38 const scoped_refptr<X509Certificate>& cert,
39 int err)
40 : certificate(cert), net_error(err) {}
42 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {}
44 // static
45 NSSCertDatabase* NSSCertDatabase::GetInstance() {
46 return Singleton<NSSCertDatabase,
47 LeakySingletonTraits<NSSCertDatabase> >::get();
50 NSSCertDatabase::NSSCertDatabase()
51 : observer_list_(new ObserverListThreadSafe<Observer>) {
52 crypto::EnsureNSSInit();
53 psm::EnsurePKCS12Init();
56 NSSCertDatabase::~NSSCertDatabase() {}
58 void NSSCertDatabase::ListCerts(CertificateList* certs) {
59 certs->clear();
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()));
69 CERT_DestroyCertList(cert_list);
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());
79 return module;
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());
89 return module;
92 void NSSCertDatabase::ListModules(CryptoModuleList* modules,
93 bool need_rw) const {
94 modules->clear();
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;
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
114 PK11_FreeSlotList(slot_list);
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);
131 return result;
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);
141 X509Certificate* NSSCertDatabase::FindRootInList(
142 const CertificateList& certificates) const {
143 DCHECK_GT(certificates.size(), 0U);
145 if (certificates.size() == 1)
146 return certificates[0].get();
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();
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;
160 VLOG(1) << "certificate list is not a hierarchy";
161 return cert0;
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);
173 return success;
176 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates,
177 TrustBits trust_bits,
178 ImportCertFailureList* not_imported) {
179 return psm::ImportServerCert(certificates, trust_bits, not_imported);
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;
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;
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;
205 if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
206 trust_bits |= DISTRUSTED_EMAIL;
207 else if (trust.emailFlags & kTrustedCA)
208 trust_bits |= TRUSTED_EMAIL;
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;
215 return trust_bits;
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;
223 return TRUST_DEFAULT;
224 default:
225 return TRUST_DEFAULT;
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;
237 // The CERTCertTrust structure contains three trust records:
238 // sslFlags, emailFlags, and objectSigningFlags. The three
239 // trust records are independent of each other.
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.
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.
252 // For a root CA, the trust record does not have
253 // the CERTDB_TERMINAL_RECORD bit set.
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;
260 if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 &&
261 (nsstrust.emailFlags & kTrusted) == 0) {
262 return true;
264 if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 &&
265 (nsstrust.objectSigningFlags & kTrusted) == 0) {
266 return true;
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;
279 return false;
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);
289 return success;
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;
305 } else {
306 if (SEC_DeletePermCertificate(cert->os_cert_handle())) {
307 LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
308 return false;
312 NotifyObserversOfCertRemoved(cert);
314 return true;
317 bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const {
318 PK11SlotInfo* slot = cert->os_cert_handle()->slot;
319 return slot && PK11_IsReadOnly(slot);
322 void NSSCertDatabase::AddObserver(Observer* observer) {
323 observer_list_->AddObserver(observer);
326 void NSSCertDatabase::RemoveObserver(Observer* observer) {
327 observer_list_->RemoveObserver(observer);
330 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) {
331 observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert));
334 void NSSCertDatabase::NotifyObserversOfCertRemoved(
335 const X509Certificate* cert) {
336 observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert));
339 void NSSCertDatabase::NotifyObserversOfCertTrustChanged(
340 const X509Certificate* cert) {
341 observer_list_->Notify(
342 &Observer::OnCertTrustChanged, make_scoped_refptr(cert));
345 } // namespace net