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