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