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"
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
32 // PSM = Mozilla's Personal Security Manager.
33 namespace psm
= mozilla_security_manager
;
37 NSSCertDatabase::ImportCertFailure::ImportCertFailure(
38 X509Certificate
* cert
, int err
)
42 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {}
45 NSSCertDatabase
* NSSCertDatabase::GetInstance() {
46 return Singleton
<NSSCertDatabase
>::get();
49 NSSCertDatabase::NSSCertDatabase()
50 : observer_list_(new ObserverListThreadSafe
<Observer
>) {
51 crypto::EnsureNSSInit();
52 psm::EnsurePKCS12Init();
55 NSSCertDatabase::~NSSCertDatabase() {}
57 void NSSCertDatabase::ListCerts(CertificateList
* certs
) {
60 CERTCertList
* cert_list
= PK11_ListCerts(PK11CertListUnique
, NULL
);
61 CERTCertListNode
* node
;
62 for (node
= CERT_LIST_HEAD(cert_list
);
63 !CERT_LIST_END(node
, cert_list
);
64 node
= CERT_LIST_NEXT(node
)) {
65 certs
->push_back(X509Certificate::CreateFromHandle(
66 node
->cert
, X509Certificate::OSCertHandles()));
68 CERT_DestroyCertList(cert_list
);
71 CryptoModule
* NSSCertDatabase::GetPublicModule() const {
72 CryptoModule
* module
=
73 CryptoModule::CreateFromHandle(crypto::GetPublicNSSKeySlot());
74 // The module is already referenced when returned from
75 // GetPublicNSSKeySlot, so we need to deref it once.
76 PK11_FreeSlot(module
->os_module_handle());
81 CryptoModule
* NSSCertDatabase::GetPrivateModule() const {
82 CryptoModule
* module
=
83 CryptoModule::CreateFromHandle(crypto::GetPrivateNSSKeySlot());
84 // The module is already referenced when returned from
85 // GetPrivateNSSKeySlot, so we need to deref it once.
86 PK11_FreeSlot(module
->os_module_handle());
91 void NSSCertDatabase::ListModules(CryptoModuleList
* modules
,
95 PK11SlotList
* slot_list
= NULL
;
96 // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
97 slot_list
= PK11_GetAllTokens(CKM_INVALID_MECHANISM
,
98 need_rw
? PR_TRUE
: PR_FALSE
, // needRW
99 PR_TRUE
, // loadCerts (unused)
102 LOG(ERROR
) << "PK11_GetAllTokens failed: " << PORT_GetError();
106 PK11SlotListElement
* slot_element
= PK11_GetFirstSafe(slot_list
);
107 while (slot_element
) {
108 modules
->push_back(CryptoModule::CreateFromHandle(slot_element
->slot
));
109 slot_element
= PK11_GetNextSafe(slot_list
, slot_element
,
110 PR_FALSE
); // restart
113 PK11_FreeSlotList(slot_list
);
116 int NSSCertDatabase::ImportFromPKCS12(
117 CryptoModule
* module
,
118 const std::string
& data
,
119 const base::string16
& password
,
121 net::CertificateList
* imported_certs
) {
122 int result
= psm::nsPKCS12Blob_Import(module
->os_module_handle(),
123 data
.data(), data
.size(),
127 if (result
== net::OK
)
128 NotifyObserversOfCertAdded(NULL
);
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];
148 X509Certificate
* cert1
= certificates
[1];
149 X509Certificate
* certn_2
= certificates
[certificates
.size() - 2];
150 X509Certificate
* certn_1
= certificates
[certificates
.size() - 1];
152 if (CERT_CompareName(&cert1
->os_cert_handle()->issuer
,
153 &cert0
->os_cert_handle()->subject
) == SECEqual
)
155 if (CERT_CompareName(&certn_2
->os_cert_handle()->issuer
,
156 &certn_1
->os_cert_handle()->subject
) == SECEqual
)
159 VLOG(1) << "certificate list is not a hierarchy";
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
,
170 NotifyObserversOfCertTrustChanged(NULL
);
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 {
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
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
;
217 if (trust
.sslFlags
& CERTDB_TERMINAL_RECORD
) {
218 if (trust
.sslFlags
& CERTDB_TRUSTED
)
220 return DISTRUSTED_SSL
;
222 return TRUST_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();
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) {
259 if ((nsstrust
.emailFlags
& CERTDB_TERMINAL_RECORD
) != 0 &&
260 (nsstrust
.emailFlags
& kTrusted
) == 0) {
263 if ((nsstrust
.objectSigningFlags
& CERTDB_TERMINAL_RECORD
) != 0 &&
264 (nsstrust
.objectSigningFlags
& kTrusted
) == 0) {
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;
281 bool NSSCertDatabase::SetCertTrust(const X509Certificate
* cert
,
283 TrustBits trust_bits
) {
284 bool success
= psm::SetCertTrust(cert
, type
, trust_bits
);
286 NotifyObserversOfCertTrustChanged(cert
);
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
296 SECKEYPrivateKey
*privKey
= PK11_FindKeyByAnyCert(cert
->os_cert_handle(),
299 SECKEY_DestroyPrivateKey(privKey
);
300 if (PK11_DeleteTokenCertAndKey(cert
->os_cert_handle(), NULL
)) {
301 LOG(ERROR
) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError();
305 if (SEC_DeletePermCertificate(cert
->os_cert_handle())) {
306 LOG(ERROR
) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
311 NotifyObserversOfCertRemoved(cert
);
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::NotifyObserversOfCertTrustChanged(
339 const X509Certificate
* cert
) {
340 observer_list_
->Notify(
341 &Observer::OnCertTrustChanged
, make_scoped_refptr(cert
));