| Index: net/cert/nss_cert_database.cc
|
| diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
|
| deleted file mode 100644
|
| index e1b3198d1646f44ef7fcb504e493ae2e627cb446..0000000000000000000000000000000000000000
|
| --- a/net/cert/nss_cert_database.cc
|
| +++ /dev/null
|
| @@ -1,481 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/cert/nss_cert_database.h"
|
| -
|
| -#include <cert.h>
|
| -#include <certdb.h>
|
| -#include <keyhi.h>
|
| -#include <pk11pub.h>
|
| -#include <secmod.h>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/observer_list_threadsafe.h"
|
| -#include "base/task_runner.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/threading/worker_pool.h"
|
| -#include "crypto/scoped_nss_types.h"
|
| -#include "net/base/crypto_module.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/cert/cert_database.h"
|
| -#include "net/cert/x509_certificate.h"
|
| -#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
|
| -#include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h"
|
| -
|
| -// In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use
|
| -// the new name of the macro.
|
| -#if !defined(CERTDB_TERMINAL_RECORD)
|
| -#define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER
|
| -#endif
|
| -
|
| -// PSM = Mozilla's Personal Security Manager.
|
| -namespace psm = mozilla_security_manager;
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// TODO(pneubeck): Move this class out of NSSCertDatabase and to the caller of
|
| -// the c'tor of NSSCertDatabase, see https://crbug.com/395983 .
|
| -// Helper that observes events from the NSSCertDatabase and forwards them to
|
| -// the given CertDatabase.
|
| -class CertNotificationForwarder : public NSSCertDatabase::Observer {
|
| - public:
|
| - explicit CertNotificationForwarder(CertDatabase* cert_db)
|
| - : cert_db_(cert_db) {}
|
| -
|
| - ~CertNotificationForwarder() override {}
|
| -
|
| - // NSSCertDatabase::Observer implementation:
|
| - void OnCertAdded(const X509Certificate* cert) override {
|
| - cert_db_->NotifyObserversOfCertAdded(cert);
|
| - }
|
| -
|
| - void OnCertRemoved(const X509Certificate* cert) override {
|
| - cert_db_->NotifyObserversOfCertRemoved(cert);
|
| - }
|
| -
|
| - void OnCACertChanged(const X509Certificate* cert) override {
|
| - cert_db_->NotifyObserversOfCACertChanged(cert);
|
| - }
|
| -
|
| - private:
|
| - CertDatabase* cert_db_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(CertNotificationForwarder);
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -NSSCertDatabase::ImportCertFailure::ImportCertFailure(
|
| - const scoped_refptr<X509Certificate>& cert,
|
| - int err)
|
| - : certificate(cert), net_error(err) {}
|
| -
|
| -NSSCertDatabase::ImportCertFailure::~ImportCertFailure() {}
|
| -
|
| -NSSCertDatabase::NSSCertDatabase(crypto::ScopedPK11Slot public_slot,
|
| - crypto::ScopedPK11Slot private_slot)
|
| - : public_slot_(public_slot.Pass()),
|
| - private_slot_(private_slot.Pass()),
|
| - observer_list_(new ObserverListThreadSafe<Observer>),
|
| - weak_factory_(this) {
|
| - CHECK(public_slot_);
|
| -
|
| - // This also makes sure that NSS has been initialized.
|
| - CertDatabase* cert_db = CertDatabase::GetInstance();
|
| - cert_notification_forwarder_.reset(new CertNotificationForwarder(cert_db));
|
| - AddObserver(cert_notification_forwarder_.get());
|
| -
|
| - psm::EnsurePKCS12Init();
|
| -}
|
| -
|
| -NSSCertDatabase::~NSSCertDatabase() {}
|
| -
|
| -void NSSCertDatabase::ListCertsSync(CertificateList* certs) {
|
| - ListCertsImpl(crypto::ScopedPK11Slot(), certs);
|
| -}
|
| -
|
| -void NSSCertDatabase::ListCerts(
|
| - const base::Callback<void(scoped_ptr<CertificateList> certs)>& callback) {
|
| - scoped_ptr<CertificateList> certs(new CertificateList());
|
| -
|
| - // base::Passed will NULL out |certs|, so cache the underlying pointer here.
|
| - CertificateList* raw_certs = certs.get();
|
| - GetSlowTaskRunner()->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(&NSSCertDatabase::ListCertsImpl,
|
| - base::Passed(crypto::ScopedPK11Slot()),
|
| - base::Unretained(raw_certs)),
|
| - base::Bind(callback, base::Passed(&certs)));
|
| -}
|
| -
|
| -void NSSCertDatabase::ListCertsInSlot(const ListCertsCallback& callback,
|
| - PK11SlotInfo* slot) {
|
| - DCHECK(slot);
|
| - scoped_ptr<CertificateList> certs(new CertificateList());
|
| -
|
| - // base::Passed will NULL out |certs|, so cache the underlying pointer here.
|
| - CertificateList* raw_certs = certs.get();
|
| - GetSlowTaskRunner()->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(&NSSCertDatabase::ListCertsImpl,
|
| - base::Passed(crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot))),
|
| - base::Unretained(raw_certs)),
|
| - base::Bind(callback, base::Passed(&certs)));
|
| -}
|
| -
|
| -#if defined(OS_CHROMEOS)
|
| -crypto::ScopedPK11Slot NSSCertDatabase::GetSystemSlot() const {
|
| - return crypto::ScopedPK11Slot();
|
| -}
|
| -#endif
|
| -
|
| -crypto::ScopedPK11Slot NSSCertDatabase::GetPublicSlot() const {
|
| - return crypto::ScopedPK11Slot(PK11_ReferenceSlot(public_slot_.get()));
|
| -}
|
| -
|
| -crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const {
|
| - if (!private_slot_)
|
| - return crypto::ScopedPK11Slot();
|
| - return crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
|
| -}
|
| -
|
| -CryptoModule* NSSCertDatabase::GetPublicModule() const {
|
| - crypto::ScopedPK11Slot slot(GetPublicSlot());
|
| - return CryptoModule::CreateFromHandle(slot.get());
|
| -}
|
| -
|
| -CryptoModule* NSSCertDatabase::GetPrivateModule() const {
|
| - crypto::ScopedPK11Slot slot(GetPrivateSlot());
|
| - return CryptoModule::CreateFromHandle(slot.get());
|
| -}
|
| -
|
| -void NSSCertDatabase::ListModules(CryptoModuleList* modules,
|
| - bool need_rw) const {
|
| - modules->clear();
|
| -
|
| - // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc.
|
| - crypto::ScopedPK11SlotList slot_list(
|
| - PK11_GetAllTokens(CKM_INVALID_MECHANISM,
|
| - need_rw ? PR_TRUE : PR_FALSE, // needRW
|
| - PR_TRUE, // loadCerts (unused)
|
| - NULL)); // wincx
|
| - if (!slot_list) {
|
| - LOG(ERROR) << "PK11_GetAllTokens failed: " << PORT_GetError();
|
| - return;
|
| - }
|
| -
|
| - PK11SlotListElement* slot_element = PK11_GetFirstSafe(slot_list.get());
|
| - while (slot_element) {
|
| - modules->push_back(CryptoModule::CreateFromHandle(slot_element->slot));
|
| - slot_element = PK11_GetNextSafe(slot_list.get(), slot_element,
|
| - PR_FALSE); // restart
|
| - }
|
| -}
|
| -
|
| -int NSSCertDatabase::ImportFromPKCS12(
|
| - CryptoModule* module,
|
| - const std::string& data,
|
| - const base::string16& password,
|
| - bool is_extractable,
|
| - net::CertificateList* imported_certs) {
|
| - DVLOG(1) << __func__ << " "
|
| - << PK11_GetModuleID(module->os_module_handle()) << ":"
|
| - << PK11_GetSlotID(module->os_module_handle());
|
| - int result = psm::nsPKCS12Blob_Import(module->os_module_handle(),
|
| - data.data(), data.size(),
|
| - password,
|
| - is_extractable,
|
| - imported_certs);
|
| - if (result == net::OK)
|
| - NotifyObserversOfCertAdded(NULL);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -int NSSCertDatabase::ExportToPKCS12(
|
| - const CertificateList& certs,
|
| - const base::string16& password,
|
| - std::string* output) const {
|
| - return psm::nsPKCS12Blob_Export(output, certs, password);
|
| -}
|
| -
|
| -X509Certificate* NSSCertDatabase::FindRootInList(
|
| - const CertificateList& certificates) const {
|
| - DCHECK_GT(certificates.size(), 0U);
|
| -
|
| - if (certificates.size() == 1)
|
| - return certificates[0].get();
|
| -
|
| - X509Certificate* cert0 = certificates[0].get();
|
| - X509Certificate* cert1 = certificates[1].get();
|
| - X509Certificate* certn_2 = certificates[certificates.size() - 2].get();
|
| - X509Certificate* certn_1 = certificates[certificates.size() - 1].get();
|
| -
|
| - if (CERT_CompareName(&cert1->os_cert_handle()->issuer,
|
| - &cert0->os_cert_handle()->subject) == SECEqual)
|
| - return cert0;
|
| - if (CERT_CompareName(&certn_2->os_cert_handle()->issuer,
|
| - &certn_1->os_cert_handle()->subject) == SECEqual)
|
| - return certn_1;
|
| -
|
| - LOG(WARNING) << "certificate list is not a hierarchy";
|
| - return cert0;
|
| -}
|
| -
|
| -bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates,
|
| - TrustBits trust_bits,
|
| - ImportCertFailureList* not_imported) {
|
| - crypto::ScopedPK11Slot slot(GetPublicSlot());
|
| - X509Certificate* root = FindRootInList(certificates);
|
| - bool success = psm::ImportCACerts(
|
| - slot.get(), certificates, root, trust_bits, not_imported);
|
| - if (success)
|
| - NotifyObserversOfCACertChanged(NULL);
|
| -
|
| - return success;
|
| -}
|
| -
|
| -bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates,
|
| - TrustBits trust_bits,
|
| - ImportCertFailureList* not_imported) {
|
| - crypto::ScopedPK11Slot slot(GetPublicSlot());
|
| - return psm::ImportServerCert(
|
| - slot.get(), certificates, trust_bits, not_imported);
|
| -}
|
| -
|
| -NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust(
|
| - const X509Certificate* cert,
|
| - CertType type) const {
|
| - CERTCertTrust trust;
|
| - SECStatus srv = CERT_GetCertTrust(cert->os_cert_handle(), &trust);
|
| - if (srv != SECSuccess) {
|
| - LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
|
| - return TRUST_DEFAULT;
|
| - }
|
| - // We define our own more "friendly" TrustBits, which means we aren't able to
|
| - // round-trip all possible NSS trust flag combinations. We try to map them in
|
| - // a sensible way.
|
| - switch (type) {
|
| - case CA_CERT: {
|
| - const unsigned kTrustedCA = CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
|
| - const unsigned kCAFlags = kTrustedCA | CERTDB_TERMINAL_RECORD;
|
| -
|
| - TrustBits trust_bits = TRUST_DEFAULT;
|
| - if ((trust.sslFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
|
| - trust_bits |= DISTRUSTED_SSL;
|
| - else if (trust.sslFlags & kTrustedCA)
|
| - trust_bits |= TRUSTED_SSL;
|
| -
|
| - if ((trust.emailFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
|
| - trust_bits |= DISTRUSTED_EMAIL;
|
| - else if (trust.emailFlags & kTrustedCA)
|
| - trust_bits |= TRUSTED_EMAIL;
|
| -
|
| - if ((trust.objectSigningFlags & kCAFlags) == CERTDB_TERMINAL_RECORD)
|
| - trust_bits |= DISTRUSTED_OBJ_SIGN;
|
| - else if (trust.objectSigningFlags & kTrustedCA)
|
| - trust_bits |= TRUSTED_OBJ_SIGN;
|
| -
|
| - return trust_bits;
|
| - }
|
| - case SERVER_CERT:
|
| - if (trust.sslFlags & CERTDB_TERMINAL_RECORD) {
|
| - if (trust.sslFlags & CERTDB_TRUSTED)
|
| - return TRUSTED_SSL;
|
| - return DISTRUSTED_SSL;
|
| - }
|
| - return TRUST_DEFAULT;
|
| - default:
|
| - return TRUST_DEFAULT;
|
| - }
|
| -}
|
| -
|
| -bool NSSCertDatabase::IsUntrusted(const X509Certificate* cert) const {
|
| - CERTCertTrust nsstrust;
|
| - SECStatus rv = CERT_GetCertTrust(cert->os_cert_handle(), &nsstrust);
|
| - if (rv != SECSuccess) {
|
| - LOG(ERROR) << "CERT_GetCertTrust failed with error " << PORT_GetError();
|
| - return false;
|
| - }
|
| -
|
| - // The CERTCertTrust structure contains three trust records:
|
| - // sslFlags, emailFlags, and objectSigningFlags. The three
|
| - // trust records are independent of each other.
|
| - //
|
| - // If the CERTDB_TERMINAL_RECORD bit in a trust record is set,
|
| - // then that trust record is a terminal record. A terminal
|
| - // record is used for explicit trust and distrust of an
|
| - // end-entity or intermediate CA cert.
|
| - //
|
| - // In a terminal record, if neither CERTDB_TRUSTED_CA nor
|
| - // CERTDB_TRUSTED is set, then the terminal record means
|
| - // explicit distrust. On the other hand, if the terminal
|
| - // record has either CERTDB_TRUSTED_CA or CERTDB_TRUSTED bit
|
| - // set, then the terminal record means explicit trust.
|
| - //
|
| - // For a root CA, the trust record does not have
|
| - // the CERTDB_TERMINAL_RECORD bit set.
|
| -
|
| - static const unsigned int kTrusted = CERTDB_TRUSTED_CA | CERTDB_TRUSTED;
|
| - if ((nsstrust.sslFlags & CERTDB_TERMINAL_RECORD) != 0 &&
|
| - (nsstrust.sslFlags & kTrusted) == 0) {
|
| - return true;
|
| - }
|
| - if ((nsstrust.emailFlags & CERTDB_TERMINAL_RECORD) != 0 &&
|
| - (nsstrust.emailFlags & kTrusted) == 0) {
|
| - return true;
|
| - }
|
| - if ((nsstrust.objectSigningFlags & CERTDB_TERMINAL_RECORD) != 0 &&
|
| - (nsstrust.objectSigningFlags & kTrusted) == 0) {
|
| - return true;
|
| - }
|
| -
|
| - // Self-signed certificates that don't have any trust bits set are untrusted.
|
| - // Other certificates that don't have any trust bits set may still be trusted
|
| - // if they chain up to a trust anchor.
|
| - if (CERT_CompareName(&cert->os_cert_handle()->issuer,
|
| - &cert->os_cert_handle()->subject) == SECEqual) {
|
| - return (nsstrust.sslFlags & kTrusted) == 0 &&
|
| - (nsstrust.emailFlags & kTrusted) == 0 &&
|
| - (nsstrust.objectSigningFlags & kTrusted) == 0;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool NSSCertDatabase::SetCertTrust(const X509Certificate* cert,
|
| - CertType type,
|
| - TrustBits trust_bits) {
|
| - bool success = psm::SetCertTrust(cert, type, trust_bits);
|
| - if (success)
|
| - NotifyObserversOfCACertChanged(cert);
|
| -
|
| - return success;
|
| -}
|
| -
|
| -bool NSSCertDatabase::DeleteCertAndKey(X509Certificate* cert) {
|
| - if (!DeleteCertAndKeyImpl(cert))
|
| - return false;
|
| - NotifyObserversOfCertRemoved(cert);
|
| - return true;
|
| -}
|
| -
|
| -void NSSCertDatabase::DeleteCertAndKeyAsync(
|
| - const scoped_refptr<X509Certificate>& cert,
|
| - const DeleteCertCallback& callback) {
|
| - base::PostTaskAndReplyWithResult(
|
| - GetSlowTaskRunner().get(),
|
| - FROM_HERE,
|
| - base::Bind(&NSSCertDatabase::DeleteCertAndKeyImpl, cert),
|
| - base::Bind(&NSSCertDatabase::NotifyCertRemovalAndCallBack,
|
| - weak_factory_.GetWeakPtr(),
|
| - cert,
|
| - callback));
|
| -}
|
| -
|
| -bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const {
|
| - PK11SlotInfo* slot = cert->os_cert_handle()->slot;
|
| - return slot && PK11_IsReadOnly(slot);
|
| -}
|
| -
|
| -bool NSSCertDatabase::IsHardwareBacked(const X509Certificate* cert) const {
|
| - PK11SlotInfo* slot = cert->os_cert_handle()->slot;
|
| - return slot && PK11_IsHW(slot);
|
| -}
|
| -
|
| -void NSSCertDatabase::AddObserver(Observer* observer) {
|
| - observer_list_->AddObserver(observer);
|
| -}
|
| -
|
| -void NSSCertDatabase::RemoveObserver(Observer* observer) {
|
| - observer_list_->RemoveObserver(observer);
|
| -}
|
| -
|
| -void NSSCertDatabase::SetSlowTaskRunnerForTest(
|
| - const scoped_refptr<base::TaskRunner>& task_runner) {
|
| - slow_task_runner_for_test_ = task_runner;
|
| -}
|
| -
|
| -// static
|
| -void NSSCertDatabase::ListCertsImpl(crypto::ScopedPK11Slot slot,
|
| - CertificateList* certs) {
|
| - certs->clear();
|
| -
|
| - CERTCertList* cert_list = NULL;
|
| - if (slot)
|
| - cert_list = PK11_ListCertsInSlot(slot.get());
|
| - else
|
| - cert_list = PK11_ListCerts(PK11CertListUnique, NULL);
|
| -
|
| - CERTCertListNode* node;
|
| - for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list);
|
| - node = CERT_LIST_NEXT(node)) {
|
| - certs->push_back(X509Certificate::CreateFromHandle(
|
| - node->cert, X509Certificate::OSCertHandles()));
|
| - }
|
| - CERT_DestroyCertList(cert_list);
|
| -}
|
| -
|
| -scoped_refptr<base::TaskRunner> NSSCertDatabase::GetSlowTaskRunner() const {
|
| - if (slow_task_runner_for_test_.get())
|
| - return slow_task_runner_for_test_;
|
| - return base::WorkerPool::GetTaskRunner(true /*task is slow*/);
|
| -}
|
| -
|
| -void NSSCertDatabase::NotifyCertRemovalAndCallBack(
|
| - scoped_refptr<X509Certificate> cert,
|
| - const DeleteCertCallback& callback,
|
| - bool success) {
|
| - if (success)
|
| - NotifyObserversOfCertRemoved(cert.get());
|
| - callback.Run(success);
|
| -}
|
| -
|
| -void NSSCertDatabase::NotifyObserversOfCertAdded(const X509Certificate* cert) {
|
| - observer_list_->Notify(FROM_HERE, &Observer::OnCertAdded,
|
| - make_scoped_refptr(cert));
|
| -}
|
| -
|
| -void NSSCertDatabase::NotifyObserversOfCertRemoved(
|
| - const X509Certificate* cert) {
|
| - observer_list_->Notify(FROM_HERE, &Observer::OnCertRemoved,
|
| - make_scoped_refptr(cert));
|
| -}
|
| -
|
| -void NSSCertDatabase::NotifyObserversOfCACertChanged(
|
| - const X509Certificate* cert) {
|
| - observer_list_->Notify(FROM_HERE, &Observer::OnCACertChanged,
|
| - make_scoped_refptr(cert));
|
| -}
|
| -
|
| -// static
|
| -bool NSSCertDatabase::DeleteCertAndKeyImpl(
|
| - scoped_refptr<X509Certificate> cert) {
|
| - // For some reason, PK11_DeleteTokenCertAndKey only calls
|
| - // SEC_DeletePermCertificate if the private key is found. So, we check
|
| - // whether a private key exists before deciding which function to call to
|
| - // delete the cert.
|
| - SECKEYPrivateKey* privKey =
|
| - PK11_FindKeyByAnyCert(cert->os_cert_handle(), NULL);
|
| - if (privKey) {
|
| - SECKEY_DestroyPrivateKey(privKey);
|
| - if (PK11_DeleteTokenCertAndKey(cert->os_cert_handle(), NULL)) {
|
| - LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError();
|
| - return false;
|
| - }
|
| - } else {
|
| - if (SEC_DeletePermCertificate(cert->os_cert_handle())) {
|
| - LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -} // namespace net
|
|
|