- add sources.
[platform/framework/web/crosswalk.git] / src / net / cert / nss_cert_database.cc
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/cert/nss_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 "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"
26
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
32
33 // PSM = Mozilla's Personal Security Manager.
34 namespace psm = mozilla_security_manager;
35
36 namespace net {
37
38 NSSCertDatabase::ImportCertFailure::ImportCertFailure(
39     const scoped_refptr<X509Certificate>& cert,
40     int err)
41     : certificate(cert), net_error(err) {}
42
43 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {}
44
45 // static
46 NSSCertDatabase* NSSCertDatabase::GetInstance() {
47   return Singleton<NSSCertDatabase,
48                    LeakySingletonTraits<NSSCertDatabase> >::get();
49 }
50
51 NSSCertDatabase::NSSCertDatabase()
52     : observer_list_(new ObserverListThreadSafe<Observer>) {
53   crypto::EnsureNSSInit();
54   psm::EnsurePKCS12Init();
55 }
56
57 NSSCertDatabase::~NSSCertDatabase() {}
58
59 void NSSCertDatabase::ListCerts(CertificateList* certs) {
60   certs->clear();
61
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()));
69   }
70   CERT_DestroyCertList(cert_list);
71 }
72
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());
79
80   return module;
81 }
82
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());
89
90   return module;
91 }
92
93 void NSSCertDatabase::ListModules(CryptoModuleList* modules,
94                                   bool need_rw) const {
95   modules->clear();
96
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;
106   }
107
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
113   }
114 }
115
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);
129
130   return result;
131 }
132
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);
138 }
139
140 X509Certificate* NSSCertDatabase::FindRootInList(
141     const CertificateList& certificates) const {
142   DCHECK_GT(certificates.size(), 0U);
143
144   if (certificates.size() == 1)
145     return certificates[0].get();
146
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();
151
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;
158
159   VLOG(1) << "certificate list is not a hierarchy";
160   return cert0;
161 }
162
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);
171
172   return success;
173 }
174
175 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates,
176                                        TrustBits trust_bits,
177                                        ImportCertFailureList* not_imported) {
178   return psm::ImportServerCert(certificates, trust_bits, not_imported);
179 }
180
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;
189   }
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;
197
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;
203
204       if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
205         trust_bits |= DISTRUSTED_EMAIL;
206       else if (trust.emailFlags & kTrustedCA)
207         trust_bits |= TRUSTED_EMAIL;
208
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;
213
214       return trust_bits;
215     }
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;
221       }
222       return TRUST_DEFAULT;
223     default:
224       return TRUST_DEFAULT;
225   }
226 }
227
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;
234   }
235
236   // The CERTCertTrust structure contains three trust records:
237   // sslFlags, emailFlags, and objectSigningFlags.  The three
238   // trust records are independent of each other.
239   //
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.
244   //
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.
250   //
251   // For a root CA, the trust record does not have
252   // the CERTDB_TERMINAL_RECORD bit set.
253
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;
258   }
259   if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 &&
260       (nsstrust.emailFlags & kTrusted) == 0) {
261     return true;
262   }
263   if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 &&
264       (nsstrust.objectSigningFlags & kTrusted) == 0) {
265     return true;
266   }
267
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;
276   }
277
278   return false;
279 }
280
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);
287
288   return success;
289 }
290
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;
303     }
304   } else {
305     if (SEC_DeletePermCertificate(cert->os_cert_handle())) {
306       LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
307       return false;
308     }
309   }
310
311   NotifyObserversOfCertRemoved(cert);
312
313   return true;
314 }
315
316 bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const {
317   PK11SlotInfo* slot = cert->os_cert_handle()->slot;
318   return slot && PK11_IsReadOnly(slot);
319 }
320
321 void NSSCertDatabase::AddObserver(Observer* observer) {
322   observer_list_->AddObserver(observer);
323 }
324
325 void NSSCertDatabase::RemoveObserver(Observer* observer) {
326   observer_list_->RemoveObserver(observer);
327 }
328
329 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) {
330   observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert));
331 }
332
333 void NSSCertDatabase::NotifyObserversOfCertRemoved(
334     const X509Certificate* cert) {
335   observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert));
336 }
337
338 void NSSCertDatabase::NotifyObserversOfCACertChanged(
339     const X509Certificate* cert) {
340   observer_list_->Notify(
341       &Observer::OnCACertChanged, make_scoped_refptr(cert));
342 }
343
344 }  // namespace net