OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/nss_cert_database.h" | 5 #include "net/cert/nss_cert_database.h" |
6 | 6 |
7 #include <cert.h> | 7 #include <cert.h> |
8 #include <certdb.h> | 8 #include <certdb.h> |
9 #include <keyhi.h> | 9 #include <keyhi.h> |
10 #include <pk11pub.h> | 10 #include <pk11pub.h> |
11 #include <secmod.h> | 11 #include <secmod.h> |
12 | 12 |
| 13 #include "base/lazy_instance.h" |
13 #include "base/logging.h" | 14 #include "base/logging.h" |
14 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
15 #include "base/memory/singleton.h" | |
16 #include "base/observer_list_threadsafe.h" | 16 #include "base/observer_list_threadsafe.h" |
17 #include "crypto/nss_util.h" | 17 #include "crypto/nss_util.h" |
18 #include "crypto/nss_util_internal.h" | 18 #include "crypto/nss_util_internal.h" |
19 #include "crypto/scoped_nss_types.h" | 19 #include "crypto/scoped_nss_types.h" |
20 #include "net/base/crypto_module.h" | 20 #include "net/base/crypto_module.h" |
21 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
22 #include "net/cert/cert_database.h" | 22 #include "net/cert/cert_database.h" |
23 #include "net/cert/x509_certificate.h" | 23 #include "net/cert/x509_certificate.h" |
24 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h" | 24 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h" |
25 #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" | 25 #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h" |
26 | 26 |
27 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use | 27 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use |
28 // the new name of the macro. | 28 // the new name of the macro. |
29 #if !defined(CERTDB_TERMINAL_RECORD) | 29 #if !defined(CERTDB_TERMINAL_RECORD) |
30 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER | 30 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER |
31 #endif | 31 #endif |
32 | 32 |
33 // PSM = Mozilla's Personal Security Manager. | 33 // PSM = Mozilla's Personal Security Manager. |
34 namespace psm = mozilla_security_manager; | 34 namespace psm = mozilla_security_manager; |
35 | 35 |
36 namespace net { | 36 namespace net { |
37 | 37 |
| 38 namespace { |
| 39 base::LazyInstance<NSSCertDatabase>::Leaky |
| 40 g_nss_cert_database = LAZY_INSTANCE_INITIALIZER; |
| 41 } // namespace |
| 42 |
| 43 |
38 NSSCertDatabase::ImportCertFailure::ImportCertFailure( | 44 NSSCertDatabase::ImportCertFailure::ImportCertFailure( |
39 const scoped_refptr<X509Certificate>& cert, | 45 const scoped_refptr<X509Certificate>& cert, |
40 int err) | 46 int err) |
41 : certificate(cert), net_error(err) {} | 47 : certificate(cert), net_error(err) {} |
42 | 48 |
43 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {} | 49 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {} |
44 | 50 |
| 51 // Helper that observes events from a CertDatabaseSource and forwards them to |
| 52 // the given CertDatabase. |
| 53 class NSSCertDatabase::Notifier : public CertDatabaseSource::Observer { |
| 54 public: |
| 55 Notifier(NSSCertDatabase* cert_db) : cert_db_(cert_db) {} |
| 56 |
| 57 virtual ~Notifier() {} |
| 58 |
| 59 // CertDatabaseSource::Observer implementation: |
| 60 virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE { |
| 61 cert_db_->NotifyObserversOfCertAdded(cert); |
| 62 } |
| 63 |
| 64 virtual void OnCertRemoved(const X509Certificate* cert) OVERRIDE { |
| 65 cert_db_->NotifyObserversOfCertRemoved(cert); |
| 66 } |
| 67 |
| 68 virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE { |
| 69 cert_db_->NotifyObserversOfCACertChanged(cert); |
| 70 } |
| 71 |
| 72 private: |
| 73 NSSCertDatabase* cert_db_; |
| 74 |
| 75 DISALLOW_COPY_AND_ASSIGN(Notifier); |
| 76 }; |
| 77 |
| 78 // static |
| 79 NSSCertDatabase* NSSCertDatabase::GetInstanceNoWarn() { |
| 80 return &g_nss_cert_database.Get(); |
| 81 //return Singleton<NSSCertDatabase, |
| 82 // LeakySingletonTraits<NSSCertDatabase> >::get(); |
| 83 } |
| 84 |
45 // static | 85 // static |
46 NSSCertDatabase* NSSCertDatabase::GetInstance() { | 86 NSSCertDatabase* NSSCertDatabase::GetInstance() { |
47 return Singleton<NSSCertDatabase, | 87 #if defined(OS_CHROMEOS) |
48 LeakySingletonTraits<NSSCertDatabase> >::get(); | 88 LOG(WARNING) << "Using global NSSCertDatabase. Consider using " |
| 89 << "NSSCertDatabaseChromeOS::GetForUser instead."; |
| 90 #endif |
| 91 return NSSCertDatabase::GetInstanceNoWarn(); |
49 } | 92 } |
50 | 93 |
51 NSSCertDatabase::NSSCertDatabase() | 94 NSSCertDatabase::NSSCertDatabase() |
52 : observer_list_(new ObserverListThreadSafe<Observer>) { | 95 : observer_list_(new ObserverListThreadSafe<Observer>), |
53 crypto::EnsureNSSInit(); | 96 notifier_(new Notifier(this)) { |
| 97 // This also makes sure that NSS has been initialized. |
| 98 CertDatabase::GetInstance()->AddSource(this); |
| 99 |
54 psm::EnsurePKCS12Init(); | 100 psm::EnsurePKCS12Init(); |
55 } | 101 } |
56 | 102 |
57 NSSCertDatabase::~NSSCertDatabase() {} | 103 NSSCertDatabase::~NSSCertDatabase() {} |
58 | 104 |
59 void NSSCertDatabase::ListCerts(CertificateList* certs) { | 105 void NSSCertDatabase::ListCerts(CertificateList* certs) { |
60 certs->clear(); | 106 certs->clear(); |
61 | 107 |
62 CERTCertList* cert_list = PK11_ListCerts(PK11CertListUnique, NULL); | 108 CERTCertList* cert_list = PK11_ListCerts(PK11CertListUnique, NULL); |
63 CERTCertListNode* node; | 109 CERTCertListNode* node; |
64 for (node = CERT_LIST_HEAD(cert_list); | 110 for (node = CERT_LIST_HEAD(cert_list); |
65 !CERT_LIST_END(node, cert_list); | 111 !CERT_LIST_END(node, cert_list); |
66 node = CERT_LIST_NEXT(node)) { | 112 node = CERT_LIST_NEXT(node)) { |
67 certs->push_back(X509Certificate::CreateFromHandle( | 113 certs->push_back(X509Certificate::CreateFromHandle( |
68 node->cert, X509Certificate::OSCertHandles())); | 114 node->cert, X509Certificate::OSCertHandles())); |
69 } | 115 } |
70 CERT_DestroyCertList(cert_list); | 116 CERT_DestroyCertList(cert_list); |
71 } | 117 } |
72 | 118 |
73 CryptoModule* NSSCertDatabase::GetPublicModule() const { | 119 CryptoModule* NSSCertDatabase::GetPublicModule() const { |
74 CryptoModule* module = | 120 crypto::ScopedPK11Slot slot(GetPublicSlot()); |
75 CryptoModule::CreateFromHandle(crypto::GetPublicNSSKeySlot()); | 121 CryptoModule* module = CryptoModule::CreateFromHandle(slot.get()); |
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()); | |
79 | 122 |
80 return module; | 123 return module; |
81 } | 124 } |
82 | 125 |
83 CryptoModule* NSSCertDatabase::GetPrivateModule() const { | 126 CryptoModule* NSSCertDatabase::GetPrivateModule() const { |
84 CryptoModule* module = | 127 crypto::ScopedPK11Slot slot(GetPrivateSlot()); |
85 CryptoModule::CreateFromHandle(crypto::GetPrivateNSSKeySlot()); | 128 CryptoModule* module = CryptoModule::CreateFromHandle(slot.get()); |
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()); | |
89 | 129 |
90 return module; | 130 return module; |
91 } | 131 } |
92 | 132 |
| 133 crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const { |
| 134 return crypto::ScopedPK11Slot(crypto::GetPublicNSSKeySlot()); |
| 135 } |
| 136 |
| 137 crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const { |
| 138 return crypto::ScopedPK11Slot(crypto::GetPrivateNSSKeySlot()); |
| 139 } |
| 140 |
93 void NSSCertDatabase::ListModules(CryptoModuleList* modules, | 141 void NSSCertDatabase::ListModules(CryptoModuleList* modules, |
94 bool need_rw) const { | 142 bool need_rw) const { |
95 modules->clear(); | 143 modules->clear(); |
96 | 144 |
97 // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. | 145 // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. |
98 crypto::ScopedPK11SlotList slot_list( | 146 crypto::ScopedPK11SlotList slot_list( |
99 PK11_GetAllTokens(CKM_INVALID_MECHANISM, | 147 PK11_GetAllTokens(CKM_INVALID_MECHANISM, |
100 need_rw ? PR_TRUE : PR_FALSE, // needRW | 148 need_rw ? PR_TRUE : PR_FALSE, // needRW |
101 PR_TRUE, // loadCerts (unused) | 149 PR_TRUE, // loadCerts (unused) |
102 NULL)); // wincx | 150 NULL)); // wincx |
103 if (!slot_list) { | 151 if (!slot_list) { |
104 LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError(); | 152 LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError(); |
105 return; | 153 return; |
106 } | 154 } |
107 | 155 |
108 PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get()); | 156 PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get()); |
109 while (slot_element) { | 157 while (slot_element) { |
110 modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot)); | 158 modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot)); |
111 slot_element = PK11_GetNextSafe(slot_list.get(), slot_element, | 159 slot_element = PK11_GetNextSafe(slot_list.get(), slot_element, |
112 PR_FALSE); // restart | 160 PR_FALSE); // restart |
113 } | 161 } |
114 } | 162 } |
115 | 163 |
116 int NSSCertDatabase::ImportFromPKCS12( | 164 int NSSCertDatabase::ImportFromPKCS12( |
117 CryptoModule* module, | 165 CryptoModule* module, |
118 const std::string& data, | 166 const std::string& data, |
119 const base::string16& password, | 167 const base::string16& password, |
120 bool is_extractable, | 168 bool is_extractable, |
121 net::CertificateList* imported_certs) { | 169 net::CertificateList* imported_certs) { |
| 170 DVLOG(1) << __func__ << " " |
| 171 << PK11_GetModuleID(module->os_module_handle()) << ":" |
| 172 << PK11_GetSlotID(module->os_module_handle()); |
122 int result = psm::nsPKCS12Blob_Import(module->os_module_handle(), | 173 int result = psm::nsPKCS12Blob_Import(module->os_module_handle(), |
123 data.data(), data.size(), | 174 data.data(), data.size(), |
124 password, | 175 password, |
125 is_extractable, | 176 is_extractable, |
126 imported_certs); | 177 imported_certs); |
127 if (result == net::OK) | 178 if (result == net::OK) |
128 NotifyObserversOfCertAdded(NULL); | 179 NotifyObserversOfCertAdded(NULL); |
129 | 180 |
130 return result; | 181 return result; |
131 } | 182 } |
(...skipping 17 matching lines...) Expand all Loading... |
149 X509Certificate* certn_2 = certificates[certificates.size() - 2].get(); | 200 X509Certificate* certn_2 = certificates[certificates.size() - 2].get(); |
150 X509Certificate* certn_1 = certificates[certificates.size() - 1].get(); | 201 X509Certificate* certn_1 = certificates[certificates.size() - 1].get(); |
151 | 202 |
152 if (CERT_CompareName(&cert1->os_cert_handle()->issuer, | 203 if (CERT_CompareName(&cert1->os_cert_handle()->issuer, |
153 &cert0->os_cert_handle()->subject) == SECEqual) | 204 &cert0->os_cert_handle()->subject) == SECEqual) |
154 return cert0; | 205 return cert0; |
155 if (CERT_CompareName(&certn_2->os_cert_handle()->issuer, | 206 if (CERT_CompareName(&certn_2->os_cert_handle()->issuer, |
156 &certn_1->os_cert_handle()->subject) == SECEqual) | 207 &certn_1->os_cert_handle()->subject) == SECEqual) |
157 return certn_1; | 208 return certn_1; |
158 | 209 |
159 VLOG(1) << "certificate list is not a hierarchy"; | 210 DVLOG(1) << "certificate list is not a hierarchy"; |
160 return cert0; | 211 return cert0; |
161 } | 212 } |
162 | 213 |
163 bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates, | 214 bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates, |
164 TrustBits trust_bits, | 215 TrustBits trust_bits, |
165 ImportCertFailureList* not_imported) { | 216 ImportCertFailureList* not_imported) { |
166 X509Certificate* root = FindRootInList(certificates); | 217 X509Certificate* root = FindRootInList(certificates); |
167 bool success = psm::ImportCACerts(certificates, root, trust_bits, | 218 bool success = psm::ImportCACerts( |
168 not_imported); | 219 GetPublicSlot(), |
| 220 certificates, |
| 221 root, |
| 222 trust_bits, |
| 223 not_imported); |
169 if (success) | 224 if (success) |
170 NotifyObserversOfCACertChanged(NULL); | 225 NotifyObserversOfCACertChanged(NULL); |
171 | 226 |
172 return success; | 227 return success; |
173 } | 228 } |
174 | 229 |
175 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates, | 230 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates, |
176 TrustBits trust_bits, | 231 TrustBits trust_bits, |
177 ImportCertFailureList* not_imported) { | 232 ImportCertFailureList* not_imported) { |
178 return psm::ImportServerCert(certificates, trust_bits, not_imported); | 233 return psm::ImportServerCert( |
| 234 GetPublicSlot(), |
| 235 certificates, |
| 236 trust_bits, |
| 237 not_imported); |
179 } | 238 } |
180 | 239 |
181 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust( | 240 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust( |
182 const X509Certificate* cert, | 241 const X509Certificate* cert, |
183 CertType type) const { | 242 CertType type) const { |
184 CERTCertTrust trust; | 243 CERTCertTrust trust; |
185 SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust); | 244 SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust); |
186 if (srv != SECSuccess) { | 245 if (srv != SECSuccess) { |
187 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); | 246 LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError(); |
188 return TRUST_DEFAULT; | 247 return TRUST_DEFAULT; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } | 383 } |
325 | 384 |
326 void NSSCertDatabase::AddObserver(Observer* observer) { | 385 void NSSCertDatabase::AddObserver(Observer* observer) { |
327 observer_list_->AddObserver(observer); | 386 observer_list_->AddObserver(observer); |
328 } | 387 } |
329 | 388 |
330 void NSSCertDatabase::RemoveObserver(Observer* observer) { | 389 void NSSCertDatabase::RemoveObserver(Observer* observer) { |
331 observer_list_->RemoveObserver(observer); | 390 observer_list_->RemoveObserver(observer); |
332 } | 391 } |
333 | 392 |
| 393 void NSSCertDatabase::AddSource(CertDatabaseSource* source) { |
| 394 source->AddObserver(this->notifier_.get()); |
| 395 } |
| 396 |
334 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) { | 397 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) { |
335 observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert)); | 398 observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert)); |
336 } | 399 } |
337 | 400 |
338 void NSSCertDatabase::NotifyObserversOfCertRemoved( | 401 void NSSCertDatabase::NotifyObserversOfCertRemoved( |
339 const X509Certificate* cert) { | 402 const X509Certificate* cert) { |
340 observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert)); | 403 observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert)); |
341 } | 404 } |
342 | 405 |
343 void NSSCertDatabase::NotifyObserversOfCACertChanged( | 406 void NSSCertDatabase::NotifyObserversOfCACertChanged( |
344 const X509Certificate* cert) { | 407 const X509Certificate* cert) { |
345 observer_list_->Notify( | 408 observer_list_->Notify( |
346 &Observer::OnCACertChanged, make_scoped_refptr(cert)); | 409 &Observer::OnCACertChanged, make_scoped_refptr(cert)); |
347 } | 410 } |
348 | 411 |
349 } // namespace net | 412 } // namespace net |
OLD | NEW |