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