Upstream version 5.34.104.0
[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/bind.h"
14 #include "base/callback.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/observer_list_threadsafe.h"
19 #include "base/task_runner.h"
20 #include "base/threading/worker_pool.h"
21 #include "crypto/nss_util.h"
22 #include "crypto/nss_util_internal.h"
23 #include "crypto/scoped_nss_types.h"
24 #include "net/base/crypto_module.h"
25 #include "net/base/net_errors.h"
26 #include "net/cert/cert_database.h"
27 #include "net/cert/x509_certificate.h"
28 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
29 #include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h"
30
31 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use
32 // the new name of the macro.
33 #if !defined(CERTDB_TERMINAL_RECORD)
34 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER
35 #endif
36
37 // PSM = Mozilla's Personal Security Manager.
38 namespace psm = mozilla_security_manager;
39
40 namespace net {
41
42 namespace {
43
44 base::LazyInstance<NSSCertDatabase>::Leaky
45     g_nss_cert_database = LAZY_INSTANCE_INITIALIZER;
46
47 }  // namespace
48
49 NSSCertDatabase::ImportCertFailure::ImportCertFailure(
50     const scoped_refptr<X509Certificate>& cert,
51     int err)
52     : certificate(cert), net_error(err) {}
53
54 NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {}
55
56 // static
57 NSSCertDatabase* NSSCertDatabase::GetInstance() {
58   // TODO(mattm): Remove this ifdef guard once the linux impl of
59   // GetNSSCertDatabaseForResourceContext does not call GetInstance.
60 #if defined(OS_CHROMEOS)
61   LOG(ERROR) << "NSSCertDatabase::GetInstance() is deprecated."
62              << "See http://crbug.com/329735.";
63 #endif
64   return &g_nss_cert_database.Get();
65 }
66
67 NSSCertDatabase::NSSCertDatabase()
68     : observer_list_(new ObserverListThreadSafe<Observer>) {
69   // This also makes sure that NSS has been initialized.
70   CertDatabase::GetInstance()->ObserveNSSCertDatabase(this);
71
72   psm::EnsurePKCS12Init();
73 }
74
75 NSSCertDatabase::~NSSCertDatabase() {}
76
77 void NSSCertDatabase::ListCertsSync(CertificateList* certs) {
78   ListCertsImpl(certs);
79 }
80
81 void NSSCertDatabase::ListCerts(
82     const base::Callback<void(scoped_ptr<CertificateList> certs)>& callback) {
83   scoped_ptr<CertificateList> certs(new CertificateList());
84
85   // base::Pased will NULL out |certs|, so cache the underlying pointer here.
86   CertificateList* raw_certs = certs.get();
87   GetSlowTaskRunner()->PostTaskAndReply(
88       FROM_HERE,
89       base::Bind(&NSSCertDatabase::ListCertsImpl,
90                  base::Unretained(raw_certs)),
91       base::Bind(callback, base::Passed(&certs)));
92 }
93
94 crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const {
95   return crypto::ScopedPK11Slot(crypto::GetPublicNSSKeySlot());
96 }
97
98 crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const {
99   return crypto::ScopedPK11Slot(crypto::GetPrivateNSSKeySlot());
100 }
101
102 CryptoModule* NSSCertDatabase::GetPublicModule() const {
103   crypto::ScopedPK11Slot slot(GetPublicSlot());
104   return CryptoModule::CreateFromHandle(slot.get());
105 }
106
107 CryptoModule* NSSCertDatabase::GetPrivateModule() const {
108   crypto::ScopedPK11Slot slot(GetPrivateSlot());
109   return CryptoModule::CreateFromHandle(slot.get());
110 }
111
112 void NSSCertDatabase::ListModules(CryptoModuleList* modules,
113                                   bool need_rw) const {
114   modules->clear();
115
116   // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
117   crypto::ScopedPK11SlotList slot_list(
118       PK11_GetAllTokens(CKM_INVALID_MECHANISM,
119                         need_rw ? PR_TRUE : PR_FALSE,  // needRW
120                         PR_TRUE,                       // loadCerts (unused)
121                         NULL));                        // wincx
122   if (!slot_list) {
123     LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError();
124     return;
125   }
126
127   PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get());
128   while (slot_element) {
129     modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot));
130     slot_element = PK11_GetNextSafe(slot_list.get(), slot_element,
131                                     PR_FALSE);  // restart
132   }
133 }
134
135 int NSSCertDatabase::ImportFromPKCS12(
136     CryptoModule* module,
137     const std::string& data,
138     const base::string16& password,
139     bool is_extractable,
140     net::CertificateList* imported_certs) {
141   DVLOG(1) << __func__ << " "
142            << PK11_GetModuleID(module->os_module_handle()) << ":"
143            << PK11_GetSlotID(module->os_module_handle());
144   int result = psm::nsPKCS12Blob_Import(module->os_module_handle(),
145                                         data.data(), data.size(),
146                                         password,
147                                         is_extractable,
148                                         imported_certs);
149   if (result == net::OK)
150     NotifyObserversOfCertAdded(NULL);
151
152   return result;
153 }
154
155 int NSSCertDatabase::ExportToPKCS12(
156     const CertificateList& certs,
157     const base::string16& password,
158     std::string* output) const {
159   return psm::nsPKCS12Blob_Export(output, certs, password);
160 }
161
162 X509Certificate* NSSCertDatabase::FindRootInList(
163     const CertificateList& certificates) const {
164   DCHECK_GT(certificates.size(), 0U);
165
166   if (certificates.size() == 1)
167     return certificates[0].get();
168
169   X509Certificate* cert0 = certificates[0].get();
170   X509Certificate* cert1 = certificates[1].get();
171   X509Certificate* certn_2 = certificates[certificates.size() - 2].get();
172   X509Certificate* certn_1 = certificates[certificates.size() - 1].get();
173
174   if (CERT_CompareName(&cert1->os_cert_handle()->issuer,
175                        &cert0->os_cert_handle()->subject) == SECEqual)
176     return cert0;
177   if (CERT_CompareName(&certn_2->os_cert_handle()->issuer,
178                        &certn_1->os_cert_handle()->subject) == SECEqual)
179     return certn_1;
180
181   LOG(WARNING) << "certificate list is not a hierarchy";
182   return cert0;
183 }
184
185 bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates,
186                                     TrustBits trust_bits,
187                                     ImportCertFailureList* not_imported) {
188   crypto::ScopedPK11Slot slot(GetPublicSlot());
189   X509Certificate* root = FindRootInList(certificates);
190   bool success = psm::ImportCACerts(
191       slot.get(), certificates, root, trust_bits, not_imported);
192   if (success)
193     NotifyObserversOfCACertChanged(NULL);
194
195   return success;
196 }
197
198 bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates,
199                                        TrustBits trust_bits,
200                                        ImportCertFailureList* not_imported) {
201   crypto::ScopedPK11Slot slot(GetPublicSlot());
202   return psm::ImportServerCert(
203       slot.get(), certificates, trust_bits, not_imported);
204 }
205
206 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust(
207     const X509Certificate* cert,
208     CertType type) const {
209   CERTCertTrust trust;
210   SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust);
211   if (srv != SECSuccess) {
212     LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
213     return TRUST_DEFAULT;
214   }
215   // We define our own more "friendly" TrustBits, which means we aren't able to
216   // round-trip all possible NSS trust flag combinations.  We try to map them in
217   // a sensible way.
218   switch (type) {
219     case CA_CERT: {
220       const unsigned kTrustedCA = CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
221       const unsigned kCAFlags = kTrustedCA | CERTDB_TERMINAL_RECORD;
222
223       TrustBits trust_bits = TRUST_DEFAULT;
224       if ((trust.sslFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
225         trust_bits |= DISTRUSTED_SSL;
226       else if (trust.sslFlags & kTrustedCA)
227         trust_bits |= TRUSTED_SSL;
228
229       if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
230         trust_bits |= DISTRUSTED_EMAIL;
231       else if (trust.emailFlags & kTrustedCA)
232         trust_bits |= TRUSTED_EMAIL;
233
234       if ((trust.objectSigningFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
235         trust_bits |= DISTRUSTED_OBJ_SIGN;
236       else if (trust.objectSigningFlags & kTrustedCA)
237         trust_bits |= TRUSTED_OBJ_SIGN;
238
239       return trust_bits;
240     }
241     case SERVER_CERT:
242       if (trust.sslFlags & CERTDB_TERMINAL_RECORD) {
243         if (trust.sslFlags & CERTDB_TRUSTED)
244           return TRUSTED_SSL;
245         return DISTRUSTED_SSL;
246       }
247       return TRUST_DEFAULT;
248     default:
249       return TRUST_DEFAULT;
250   }
251 }
252
253 bool NSSCertDatabase::IsUntrusted(const X509Certificate* cert) const {
254   CERTCertTrust nsstrust;
255   SECStatus rv = CERT_GetCertTrust(cert->os_cert_handle(), &nsstrust);
256   if (rv != SECSuccess) {
257     LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
258     return false;
259   }
260
261   // The CERTCertTrust structure contains three trust records:
262   // sslFlags, emailFlags, and objectSigningFlags.  The three
263   // trust records are independent of each other.
264   //
265   // If the CERTDB_TERMINAL_RECORD bit in a trust record is set,
266   // then that trust record is a terminal record.  A terminal
267   // record is used for explicit trust and distrust of an
268   // end-entity or intermediate CA cert.
269   //
270   // In a terminal record, if neither CERTDB_TRUSTED_CA nor
271   // CERTDB_TRUSTED is set, then the terminal record means
272   // explicit distrust.  On the other hand, if the terminal
273   // record has either CERTDB_TRUSTED_CA or CERTDB_TRUSTED bit
274   // set, then the terminal record means explicit trust.
275   //
276   // For a root CA, the trust record does not have
277   // the CERTDB_TERMINAL_RECORD bit set.
278
279   static const unsigned int kTrusted = CERTDB_TRUSTED_CA | CERTDB_TRUSTED;
280   if ((nsstrust.sslFlags & CERTDB_TERMINAL_RECORD) != 0 &&
281       (nsstrust.sslFlags & kTrusted) == 0) {
282     return true;
283   }
284   if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 &&
285       (nsstrust.emailFlags & kTrusted) == 0) {
286     return true;
287   }
288   if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 &&
289       (nsstrust.objectSigningFlags & kTrusted) == 0) {
290     return true;
291   }
292
293   // Self-signed certificates that don't have any trust bits set are untrusted.
294   // Other certificates that don't have any trust bits set may still be trusted
295   // if they chain up to a trust anchor.
296   if (CERT_CompareName(&cert->os_cert_handle()->issuer,
297                        &cert->os_cert_handle()->subject) == SECEqual) {
298     return (nsstrust.sslFlags & kTrusted) == 0 &&
299            (nsstrust.emailFlags & kTrusted) == 0 &&
300            (nsstrust.objectSigningFlags & kTrusted) == 0;
301   }
302
303   return false;
304 }
305
306 bool NSSCertDatabase::SetCertTrust(const X509Certificate* cert,
307                                 CertType type,
308                                 TrustBits trust_bits) {
309   bool success = psm::SetCertTrust(cert, type, trust_bits);
310   if (success)
311     NotifyObserversOfCACertChanged(cert);
312
313   return success;
314 }
315
316 bool NSSCertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
317   // For some reason, PK11_DeleteTokenCertAndKey only calls
318   // SEC_DeletePermCertificate if the private key is found.  So, we check
319   // whether a private key exists before deciding which function to call to
320   // delete the cert.
321   SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert->os_cert_handle(),
322                                                     NULL);
323   if (privKey) {
324     SECKEY_DestroyPrivateKey(privKey);
325     if (PK11_DeleteTokenCertAndKey(cert->os_cert_handle(), NULL)) {
326       LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError();
327       return false;
328     }
329   } else {
330     if (SEC_DeletePermCertificate(cert->os_cert_handle())) {
331       LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
332       return false;
333     }
334   }
335
336   NotifyObserversOfCertRemoved(cert);
337
338   return true;
339 }
340
341 bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const {
342   PK11SlotInfo* slot = cert->os_cert_handle()->slot;
343   return slot && PK11_IsReadOnly(slot);
344 }
345
346 bool NSSCertDatabase::IsHardwareBacked(const X509Certificate* cert) const {
347   PK11SlotInfo* slot = cert->os_cert_handle()->slot;
348   return slot && PK11_IsHW(slot);
349 }
350
351 void NSSCertDatabase::AddObserver(Observer* observer) {
352   observer_list_->AddObserver(observer);
353 }
354
355 void NSSCertDatabase::RemoveObserver(Observer* observer) {
356   observer_list_->RemoveObserver(observer);
357 }
358
359 void NSSCertDatabase::SetSlowTaskRunnerForTest(
360     const scoped_refptr<base::TaskRunner>& task_runner) {
361   slow_task_runner_for_test_ = task_runner;
362 }
363
364 // static
365 void NSSCertDatabase::ListCertsImpl(CertificateList* certs) {
366   certs->clear();
367
368   CERTCertList* cert_list = PK11_ListCerts(PK11CertListUnique, NULL);
369   CERTCertListNode* node;
370   for (node = CERT_LIST_HEAD(cert_list);
371        !CERT_LIST_END(node, cert_list);
372        node = CERT_LIST_NEXT(node)) {
373     certs->push_back(X509Certificate::CreateFromHandle(
374         node->cert, X509Certificate::OSCertHandles()));
375   }
376   CERT_DestroyCertList(cert_list);
377 }
378
379 scoped_refptr<base::TaskRunner> NSSCertDatabase::GetSlowTaskRunner() const {
380   if (slow_task_runner_for_test_)
381     return slow_task_runner_for_test_;
382   return base::WorkerPool::GetTaskRunner(true /*task is slow*/);
383 }
384
385 void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) {
386   observer_list_->Notify(&Observer::OnCertAdded, make_scoped_refptr(cert));
387 }
388
389 void NSSCertDatabase::NotifyObserversOfCertRemoved(
390     const X509Certificate* cert) {
391   observer_list_->Notify(&Observer::OnCertRemoved, make_scoped_refptr(cert));
392 }
393
394 void NSSCertDatabase::NotifyObserversOfCACertChanged(
395     const X509Certificate* cert) {
396   observer_list_->Notify(
397       &Observer::OnCACertChanged, make_scoped_refptr(cert));
398 }
399
400 }  // namespace net