| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/cert_loader.h" | 5 #include "chromeos/cert_loader.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/memory/ptr_util.h" |
| 12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/task_runner_util.h" | 14 #include "base/task_scheduler/post_task.h" |
| 14 #include "base/threading/worker_pool.h" | 15 #include "base/threading/worker_pool.h" |
| 15 #include "crypto/nss_util.h" | 16 #include "crypto/nss_util.h" |
| 16 #include "crypto/scoped_nss_types.h" | 17 #include "crypto/scoped_nss_types.h" |
| 17 #include "net/cert/nss_cert_database.h" | 18 #include "net/cert/nss_cert_database.h" |
| 18 #include "net/cert/nss_cert_database_chromeos.h" | 19 #include "net/cert/nss_cert_database_chromeos.h" |
| 19 #include "net/cert/x509_certificate.h" | 20 #include "net/cert/x509_certificate.h" |
| 20 | 21 |
| 21 namespace chromeos { | 22 namespace chromeos { |
| 22 | 23 |
| 23 static CertLoader* g_cert_loader = NULL; | 24 namespace { |
| 25 |
| 26 // Checks if |certificate| is on the given |slot|. |
| 27 bool IsCertificateOnSlot(const net::X509Certificate* certificate, |
| 28 PK11SlotInfo* slot) { |
| 29 crypto::ScopedPK11SlotList slots_for_cert( |
| 30 PK11_GetAllSlotsForCert(certificate->os_cert_handle(), nullptr)); |
| 31 if (!slots_for_cert) |
| 32 return false; |
| 33 |
| 34 for (PK11SlotListElement* slot_element = |
| 35 PK11_GetFirstSafe(slots_for_cert.get()); |
| 36 slot_element; slot_element = PK11_GetNextSafe(slots_for_cert.get(), |
| 37 slot_element, PR_FALSE)) { |
| 38 if (slot_element->slot == slot) { |
| 39 // All previously visited elements have been freed by PK11_GetNextSafe, |
| 40 // but we're not calling that for the last one, so free it explicitly. |
| 41 // The slots_for_cert list itself will be freed because ScopedPK11SlotList |
| 42 // is a unique_ptr. |
| 43 PK11_FreeSlotListElement(slots_for_cert.get(), slot_element); |
| 44 return true; |
| 45 } |
| 46 } |
| 47 return false; |
| 48 } |
| 49 |
| 50 // Goes through all certificates in |all_certs| and copies those certificates |
| 51 // which are on |system_slot| to a new list. |
| 52 std::unique_ptr<net::CertificateList> FilterSystemTokenCertificates( |
| 53 const net::CertificateList* all_certs, |
| 54 crypto::ScopedPK11Slot system_slot) { |
| 55 VLOG(1) << "FilterSystemTokenCertificates"; |
| 56 std::unique_ptr<net::CertificateList> system_certs = |
| 57 base::MakeUnique<net::CertificateList>(); |
| 58 if (!system_slot) |
| 59 return system_certs; |
| 60 |
| 61 // Extract certificates which are in the system token into the |
| 62 // |system_certs_| sublist. |
| 63 for (const auto& cert : *all_certs) { |
| 64 if (IsCertificateOnSlot(cert.get(), system_slot.get())) { |
| 65 system_certs->push_back(cert); |
| 66 } |
| 67 } |
| 68 return system_certs; |
| 69 } |
| 70 |
| 71 } // namespace |
| 72 |
| 73 static CertLoader* g_cert_loader = nullptr; |
| 24 static bool g_force_hardware_backed_for_test = false; | 74 static bool g_force_hardware_backed_for_test = false; |
| 25 | 75 |
| 26 // static | 76 // static |
| 27 void CertLoader::Initialize() { | 77 void CertLoader::Initialize() { |
| 28 CHECK(!g_cert_loader); | 78 CHECK(!g_cert_loader); |
| 29 g_cert_loader = new CertLoader(); | 79 g_cert_loader = new CertLoader(); |
| 30 } | 80 } |
| 31 | 81 |
| 32 // static | 82 // static |
| 33 void CertLoader::Shutdown() { | 83 void CertLoader::Shutdown() { |
| 34 CHECK(g_cert_loader); | 84 CHECK(g_cert_loader); |
| 35 delete g_cert_loader; | 85 delete g_cert_loader; |
| 36 g_cert_loader = NULL; | 86 g_cert_loader = nullptr; |
| 37 } | 87 } |
| 38 | 88 |
| 39 // static | 89 // static |
| 40 CertLoader* CertLoader::Get() { | 90 CertLoader* CertLoader::Get() { |
| 41 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()"; | 91 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()"; |
| 42 return g_cert_loader; | 92 return g_cert_loader; |
| 43 } | 93 } |
| 44 | 94 |
| 45 // static | 95 // static |
| 46 bool CertLoader::IsInitialized() { | 96 bool CertLoader::IsInitialized() { |
| 47 return g_cert_loader; | 97 return g_cert_loader; |
| 48 } | 98 } |
| 49 | 99 |
| 50 CertLoader::CertLoader() | 100 CertLoader::CertLoader() |
| 51 : certificates_loaded_(false), | 101 : certificates_loaded_(false), |
| 52 certificates_update_required_(false), | 102 certificates_update_required_(false), |
| 53 certificates_update_running_(false), | 103 certificates_update_running_(false), |
| 54 database_(NULL), | 104 database_(nullptr), |
| 55 cert_list_(new net::CertificateList), | 105 all_certs_(base::MakeUnique<net::CertificateList>()), |
| 56 weak_factory_(this) { | 106 weak_factory_(this) {} |
| 57 } | |
| 58 | 107 |
| 59 CertLoader::~CertLoader() { | 108 CertLoader::~CertLoader() { |
| 60 net::CertDatabase::GetInstance()->RemoveObserver(this); | 109 net::CertDatabase::GetInstance()->RemoveObserver(this); |
| 61 } | 110 } |
| 62 | 111 |
| 63 void CertLoader::StartWithNSSDB(net::NSSCertDatabase* database) { | 112 void CertLoader::StartWithNSSDB(net::NSSCertDatabase* database) { |
| 64 CHECK(!database_); | 113 CHECK(!database_); |
| 65 database_ = database; | 114 database_ = database; |
| 66 | 115 |
| 67 // Start observing cert database for changes. | 116 // Start observing cert database for changes. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 // NOTE: This function relies on the convention that the same PKCS#11 ID | 158 // NOTE: This function relies on the convention that the same PKCS#11 ID |
| 110 // is shared between a certificate and its associated private and public | 159 // is shared between a certificate and its associated private and public |
| 111 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), | 160 // keys. I tried to implement this with PK11_GetLowLevelKeyIDForCert(), |
| 112 // but that always returns NULL on Chrome OS for me. | 161 // but that always returns NULL on Chrome OS for me. |
| 113 std::string CertLoader::GetPkcs11IdAndSlotForCert( | 162 std::string CertLoader::GetPkcs11IdAndSlotForCert( |
| 114 const net::X509Certificate& cert, | 163 const net::X509Certificate& cert, |
| 115 int* slot_id) { | 164 int* slot_id) { |
| 116 DCHECK(slot_id); | 165 DCHECK(slot_id); |
| 117 | 166 |
| 118 CERTCertificateStr* cert_handle = cert.os_cert_handle(); | 167 CERTCertificateStr* cert_handle = cert.os_cert_handle(); |
| 119 SECKEYPrivateKey *priv_key = | 168 SECKEYPrivateKey* priv_key = |
| 120 PK11_FindKeyByAnyCert(cert_handle, NULL /* wincx */); | 169 PK11_FindKeyByAnyCert(cert_handle, nullptr /* wincx */); |
| 121 if (!priv_key) | 170 if (!priv_key) |
| 122 return std::string(); | 171 return std::string(); |
| 123 | 172 |
| 124 *slot_id = static_cast<int>(PK11_GetSlotID(priv_key->pkcs11Slot)); | 173 *slot_id = static_cast<int>(PK11_GetSlotID(priv_key->pkcs11Slot)); |
| 125 | 174 |
| 126 // Get the CKA_ID attribute for a key. | 175 // Get the CKA_ID attribute for a key. |
| 127 SECItem* sec_item = PK11_GetLowLevelKeyIDForPrivateKey(priv_key); | 176 SECItem* sec_item = PK11_GetLowLevelKeyIDForPrivateKey(priv_key); |
| 128 std::string pkcs11_id; | 177 std::string pkcs11_id; |
| 129 if (sec_item) { | 178 if (sec_item) { |
| 130 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len); | 179 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len); |
| 131 SECITEM_FreeItem(sec_item, PR_TRUE); | 180 SECITEM_FreeItem(sec_item, PR_TRUE); |
| 132 } | 181 } |
| 133 SECKEY_DestroyPrivateKey(priv_key); | 182 SECKEY_DestroyPrivateKey(priv_key); |
| 134 | 183 |
| 135 return pkcs11_id; | 184 return pkcs11_id; |
| 136 } | 185 } |
| 137 | 186 |
| 138 void CertLoader::LoadCertificates() { | 187 void CertLoader::LoadCertificates() { |
| 139 CHECK(thread_checker_.CalledOnValidThread()); | 188 DCHECK(thread_checker_.CalledOnValidThread()); |
| 140 VLOG(1) << "LoadCertificates: " << certificates_update_running_; | 189 VLOG(1) << "LoadCertificates: " << certificates_update_running_; |
| 141 | 190 |
| 142 if (certificates_update_running_) { | 191 if (certificates_update_running_) { |
| 143 certificates_update_required_ = true; | 192 certificates_update_required_ = true; |
| 144 return; | 193 return; |
| 145 } | 194 } |
| 146 | 195 |
| 147 certificates_update_running_ = true; | 196 certificates_update_running_ = true; |
| 148 certificates_update_required_ = false; | 197 certificates_update_required_ = false; |
| 149 | 198 |
| 150 database_->ListCerts( | 199 database_->ListCerts( |
| 151 base::Bind(&CertLoader::UpdateCertificates, weak_factory_.GetWeakPtr())); | 200 base::Bind(&CertLoader::CertificatesLoaded, weak_factory_.GetWeakPtr())); |
| 201 } |
| 202 |
| 203 void CertLoader::CertificatesLoaded( |
| 204 std::unique_ptr<net::CertificateList> all_certs) { |
| 205 DCHECK(thread_checker_.CalledOnValidThread()); |
| 206 VLOG(1) << "CertificatesLoaded: " << all_certs->size(); |
| 207 |
| 208 crypto::ScopedPK11Slot system_slot = database_->GetSystemSlot(); |
| 209 base::PostTaskWithTraitsAndReplyWithResult( |
| 210 FROM_HERE, |
| 211 base::TaskTraits() |
| 212 .WithShutdownBehavior( |
| 213 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) |
| 214 .MayBlock(), |
| 215 base::BindOnce(&FilterSystemTokenCertificates, |
| 216 base::Unretained(all_certs.get()), std::move(system_slot)), |
| 217 base::BindOnce(&CertLoader::UpdateCertificates, |
| 218 weak_factory_.GetWeakPtr(), std::move(all_certs))); |
| 152 } | 219 } |
| 153 | 220 |
| 154 void CertLoader::UpdateCertificates( | 221 void CertLoader::UpdateCertificates( |
| 155 std::unique_ptr<net::CertificateList> cert_list) { | 222 std::unique_ptr<net::CertificateList> all_certs, |
| 156 CHECK(thread_checker_.CalledOnValidThread()); | 223 std::unique_ptr<net::CertificateList> system_certs) { |
| 224 DCHECK(thread_checker_.CalledOnValidThread()); |
| 157 DCHECK(certificates_update_running_); | 225 DCHECK(certificates_update_running_); |
| 158 VLOG(1) << "UpdateCertificates: " << cert_list->size(); | 226 VLOG(1) << "UpdateCertificates: " << all_certs->size() << " (" |
| 227 << system_certs->size() << " on system slot)"; |
| 159 | 228 |
| 160 // Ignore any existing certificates. | 229 // Ignore any existing certificates. |
| 161 cert_list_ = std::move(cert_list); | 230 all_certs_ = std::move(all_certs); |
| 231 system_certs_ = std::move(system_certs); |
| 162 | 232 |
| 163 bool initial_load = !certificates_loaded_; | 233 bool initial_load = !certificates_loaded_; |
| 164 certificates_loaded_ = true; | 234 certificates_loaded_ = true; |
| 165 NotifyCertificatesLoaded(initial_load); | 235 NotifyCertificatesLoaded(initial_load); |
| 166 | 236 |
| 167 certificates_update_running_ = false; | 237 certificates_update_running_ = false; |
| 168 if (certificates_update_required_) | 238 if (certificates_update_required_) |
| 169 LoadCertificates(); | 239 LoadCertificates(); |
| 170 } | 240 } |
| 171 | 241 |
| 172 void CertLoader::NotifyCertificatesLoaded(bool initial_load) { | 242 void CertLoader::NotifyCertificatesLoaded(bool initial_load) { |
| 173 for (auto& observer : observers_) | 243 for (auto& observer : observers_) |
| 174 observer.OnCertificatesLoaded(*cert_list_, initial_load); | 244 observer.OnCertificatesLoaded(*all_certs_, initial_load); |
| 175 } | 245 } |
| 176 | 246 |
| 177 void CertLoader::OnCertDBChanged() { | 247 void CertLoader::OnCertDBChanged() { |
| 178 VLOG(1) << "OnCertDBChanged"; | 248 VLOG(1) << "OnCertDBChanged"; |
| 179 LoadCertificates(); | 249 LoadCertificates(); |
| 180 } | 250 } |
| 181 | 251 |
| 182 } // namespace chromeos | 252 } // namespace chromeos |
| OLD | NEW |