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 28 virtual ~Notifier() {} 29 30 // NSSCertDatabase::Observer implementation: 31 virtual void OnCertAdded(const X509Certificate* cert) OVERRIDE { 32 cert_db_->NotifyObserversOfCertAdded(cert); 33 } 34 35 virtual void OnCertRemoved(const X509Certificate* cert) OVERRIDE { 36 cert_db_->NotifyObserversOfCertRemoved(cert); 37 } 38 39 virtual void OnCACertChanged(const X509Certificate* cert) OVERRIDE { 40 cert_db_->NotifyObserversOfCACertChanged(cert); 41 } 42 43 private: 44 CertDatabase* cert_db_; 45 46 DISALLOW_COPY_AND_ASSIGN(Notifier); 47 }; 48 49 CertDatabase::CertDatabase() 50 : observer_list_(new ObserverListThreadSafe<Observer>), 51 notifier_(new Notifier(this)) { 52 crypto::EnsureNSSInit(); 53 } 54 55 CertDatabase::~CertDatabase() {} 56 57 int CertDatabase::CheckUserCert(X509Certificate* cert_obj) { 58 if (!cert_obj) 59 return ERR_CERT_INVALID; 60 if (cert_obj->HasExpired()) 61 return ERR_CERT_DATE_INVALID; 62 63 // Check if the private key corresponding to the certificate exist 64 // We shouldn't accept any random client certificate sent by a CA. 65 66 // Note: The NSS source documentation wrongly suggests that this 67 // also imports the certificate if the private key exists. This 68 // doesn't seem to be the case. 69 70 CERTCertificate* cert = cert_obj->os_cert_handle(); 71 PK11SlotInfo* slot = PK11_KeyForCertExists(cert, NULL, NULL); 72 if (!slot) 73 return ERR_NO_PRIVATE_KEY_FOR_CERT; 74 75 PK11_FreeSlot(slot); 76 77 return OK; 78 } 79 80 int CertDatabase::AddUserCert(X509Certificate* cert_obj) { 81 CERTCertificate* cert = cert_obj->os_cert_handle(); 82 CK_OBJECT_HANDLE key; 83 crypto::ScopedPK11Slot slot(PK11_KeyForCertExists(cert, &key, NULL)); 84 if (!slot.get()) 85 return ERR_NO_PRIVATE_KEY_FOR_CERT; 86 87 std::string nickname = x509_util::GetUniqueNicknameForSlot( 88 cert_obj->GetDefaultNickname(USER_CERT), 89 &cert->derSubject, 90 slot.get()); 91 92 SECStatus rv; 93 { 94 crypto::AutoNSSWriteLock lock; 95 rv = PK11_ImportCert(slot.get(), cert, key, nickname.c_str(), PR_FALSE); 96 } 97 98 if (rv != SECSuccess) { 99 LOG(ERROR) << "Couldn't import user certificate. " << PORT_GetError(); 100 return ERR_ADD_USER_CERT_FAILED; 101 } 102 103 NotifyObserversOfCertAdded(cert_obj); 104 return OK; 105 } 106 107 void CertDatabase::ObserveNSSCertDatabase(NSSCertDatabase* source) { 108 source->AddObserver(this->notifier_.get()); 109 } 110 111 } // namespace net 112