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