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/x509_certificate.h"
     17 #include "net/cert/x509_util_nss.h"
     18 
     19 namespace net {
     20 
     21 CertDatabase::CertDatabase()
     22     : observer_list_(new ObserverListThreadSafe<Observer>) {
     23   crypto::EnsureNSSInit();
     24 }
     25 
     26 CertDatabase::~CertDatabase() {}
     27 
     28 int CertDatabase::CheckUserCert(X509Certificate* cert_obj) {
     29   if (!cert_obj)
     30     return ERR_CERT_INVALID;
     31   if (cert_obj->HasExpired())
     32     return ERR_CERT_DATE_INVALID;
     33 
     34   // Check if the private key corresponding to the certificate exist
     35   // We shouldn't accept any random client certificate sent by a CA.
     36 
     37   // Note: The NSS source documentation wrongly suggests that this
     38   // also imports the certificate if the private key exists. This
     39   // doesn't seem to be the case.
     40 
     41   CERTCertificate* cert = cert_obj->os_cert_handle();
     42   PK11SlotInfo* slot = PK11_KeyForCertExists(cert, NULL, NULL);
     43   if (!slot)
     44     return ERR_NO_PRIVATE_KEY_FOR_CERT;
     45 
     46   PK11_FreeSlot(slot);
     47 
     48   return OK;
     49 }
     50 
     51 int CertDatabase::AddUserCert(X509Certificate* cert_obj) {
     52   CERTCertificate* cert = cert_obj->os_cert_handle();
     53   CK_OBJECT_HANDLE key;
     54   crypto::ScopedPK11Slot slot(PK11_KeyForCertExists(cert, &key, NULL));
     55   if (!slot.get())
     56     return ERR_NO_PRIVATE_KEY_FOR_CERT;
     57 
     58   std::string nickname = x509_util::GetUniqueNicknameForSlot(
     59       cert_obj->GetDefaultNickname(USER_CERT),
     60       &cert->derSubject,
     61       slot.get());
     62 
     63   SECStatus rv;
     64   {
     65     crypto::AutoNSSWriteLock lock;
     66     rv = PK11_ImportCert(slot.get(), cert, key, nickname.c_str(), PR_FALSE);
     67   }
     68 
     69   if (rv != SECSuccess) {
     70     LOG(ERROR) << "Couldn't import user certificate. " << PORT_GetError();
     71     return ERR_ADD_USER_CERT_FAILED;
     72   }
     73 
     74   NotifyObserversOfCertAdded(cert_obj);
     75   return OK;
     76 }
     77 
     78 }  // namespace net
     79