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/cert_database.h"
      6 
      7 #include <cert.h>
      8 #include <pk11pub.h>
      9 #include <secmod.h>
     10 
     11 #include "base/logging.h"
     12 #include "base/observer_list_threadsafe.h"
     13 #include "crypto/nss_util.h"
     14 #include "crypto/scoped_nss_types.h"
     15 #include "net/base/net_errors.h"
     16 #include "net/cert/nss_cert_database.h"
     17 #include "net/cert/x509_certificate.h"
     18 #include "net/cert/x509_util_nss.h"
     19 
     20 namespace net {
     21 
     22 // Helper that observes events from the NSSCertDatabase and forwards them to
     23 // the given CertDatabase.
     24 class CertDatabase::Notifier : public NSSCertDatabase::Observer {
     25  public:
     26   explicit Notifier(CertDatabase* cert_db) : cert_db_(cert_db) {
     27     NSSCertDatabase::GetInstance()->AddObserver(this);
     28   }
     29 
     30   virtual ~Notifier() {
     31     NSSCertDatabase::GetInstance()->RemoveObserver(this);
     32   }
     33 
     34   // NSSCertDatabase::Observer implementation:
     35   virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE {
     36     cert_db_->NotifyObserversOfCertAdded(cert);
     37   }
     38 
     39   virtual void OnCertRemoved(const X509Certificate* cert) OVERRIDE {
     40     cert_db_->NotifyObserversOfCertRemoved(cert);
     41   }
     42 
     43   virtual void OnCertTrustChanged(const X509Certificate* cert) OVERRIDE {
     44     cert_db_->NotifyObserversOfCertTrustChanged(cert);
     45   }
     46 
     47  private:
     48   CertDatabase* cert_db_;
     49 
     50   DISALLOW_COPY_AND_ASSIGN(Notifier);
     51 };
     52 
     53 CertDatabase::CertDatabase()
     54     : observer_list_(new ObserverListThreadSafe<Observer>) {
     55   // Observe NSSCertDatabase events and forward them to observers of
     56   // CertDatabase. This also makes sure that NSS has been initialized.
     57   notifier_.reset(new Notifier(this));
     58 }
     59 
     60 CertDatabase::~CertDatabase() {}
     61 
     62 int CertDatabase::CheckUserCert(X509Certificate* cert_obj) {
     63   if (!cert_obj)
     64     return ERR_CERT_INVALID;
     65   if (cert_obj->HasExpired())
     66     return ERR_CERT_DATE_INVALID;
     67 
     68   // Check if the private key corresponding to the certificate exist
     69   // We shouldn't accept any random client certificate sent by a CA.
     70 
     71   // Note: The NSS source documentation wrongly suggests that this
     72   // also imports the certificate if the private key exists. This
     73   // doesn't seem to be the case.
     74 
     75   CERTCertificate* cert = cert_obj->os_cert_handle();
     76   PK11SlotInfo* slot = PK11_KeyForCertExists(cert, NULL, NULL);
     77   if (!slot)
     78     return ERR_NO_PRIVATE_KEY_FOR_CERT;
     79 
     80   PK11_FreeSlot(slot);
     81 
     82   return OK;
     83 }
     84 
     85 int CertDatabase::AddUserCert(X509Certificate* cert_obj) {
     86   CERTCertificate* cert = cert_obj->os_cert_handle();
     87   CK_OBJECT_HANDLE key;
     88   crypto::ScopedPK11Slot slot(PK11_KeyForCertExists(cert, &key, NULL));
     89   if (!slot.get())
     90     return ERR_NO_PRIVATE_KEY_FOR_CERT;
     91 
     92   std::string nickname = x509_util::GetUniqueNicknameForSlot(
     93       cert_obj->GetDefaultNickname(USER_CERT),
     94       &cert->derSubject,
     95       slot.get());
     96 
     97   SECStatus rv;
     98   {
     99     crypto::AutoNSSWriteLock lock;
    100     rv = PK11_ImportCert(slot.get(), cert, key, nickname.c_str(), PR_FALSE);
    101   }
    102 
    103   if (rv != SECSuccess) {
    104     LOG(ERROR) << "Couldn't import user certificate. " << PORT_GetError();
    105     return ERR_ADD_USER_CERT_FAILED;
    106   }
    107 
    108   NotifyObserversOfCertAdded(cert_obj);
    109   return OK;
    110 }
    111 
    112 }  // namespace net
    113