Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1051)

Side by Side Diff: chromeos/cert_loader.cc

Issue 2858113003: Enable device-wide EAP-TLS networks (Closed)
Patch Set: Fixed minor typo. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/logging.h"
12 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
14 #include "base/task_scheduler/post_task.h" 15 #include "base/task_scheduler/post_task.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"
18 #include "net/cert/cert_database.h"
17 #include "net/cert/nss_cert_database.h" 19 #include "net/cert/nss_cert_database.h"
18 #include "net/cert/nss_cert_database_chromeos.h" 20 #include "net/cert/nss_cert_database_chromeos.h"
19 #include "net/cert/x509_certificate.h" 21 #include "net/cert/x509_certificate.h"
20 22
21 namespace chromeos { 23 namespace chromeos {
22 24
25 // Caches certificates from a NSSCertDatabase. Handles reloading of certificates
26 // on update notifications and provides status flags (loading / loaded).
27 // CertLoader can use multiple CertCaches to combine certificates from multiple
28 // sources.
29 class CertLoader::CertCache : public net::CertDatabase::Observer {
30 public:
31 explicit CertCache(base::RepeatingClosure certificates_updated_callback)
32 : certificates_updated_callback_(certificates_updated_callback),
33 cert_list_(base::MakeUnique<net::CertificateList>()),
34 weak_factory_(this) {}
35
36 ~CertCache() override {
37 net::CertDatabase::GetInstance()->RemoveObserver(this);
38 }
39
40 void SetNSSDB(net::NSSCertDatabase* nss_database) {
41 CHECK(!nss_database_);
42 nss_database_ = nss_database;
43
44 // Start observing cert database for changes.
45 // Observing net::CertDatabase is preferred over observing |nss_database_|
46 // directly, as |nss_database_| observers receive only events generated
47 // directly by |nss_database_|, so they may miss a few relevant ones.
48 // TODO(tbarzic): Once singleton NSSCertDatabase is removed, investigate if
49 // it would be OK to observe |nss_database_| directly; or change
50 // NSSCertDatabase to send notification on all relevant changes.
51 net::CertDatabase::GetInstance()->AddObserver(this);
52
53 LoadCertificates();
54 }
55
56 net::NSSCertDatabase* nss_database() { return nss_database_; }
57
58 // net::CertDatabase::Observer
59 void OnCertDBChanged() override {
60 VLOG(1) << "OnCertDBChanged";
61 LoadCertificates();
62 }
63
64 const net::CertificateList& cert_list() const { return *cert_list_; }
65
66 bool initial_load_running() const {
67 return nss_database_ && !initial_load_finished_;
68 }
69
70 bool initial_load_finished() const { return initial_load_finished_; }
71
72 // Returns true if this CertCache has finished its initial load and the
73 // underlying NSSCertDatabase has access to the system slot.
74 bool has_system_certificates() const {
emaxx 2017/05/11 14:36:53 nit: It's a bit weird that this method returns a b
pmarko 2017/05/11 17:24:57 Agreed and Done. (combining at callsite)
75 return initial_load_finished_ && has_system_certificates_;
76 }
77
78 private:
79 // Trigger a certificate load. If a certificate loading task is already in
80 // progress, will start a reload once the current task is finished.
81 void LoadCertificates() {
82 CHECK(thread_checker_.CalledOnValidThread());
83 VLOG(1) << "LoadCertificates: " << certificates_update_running_;
84
85 if (certificates_update_running_) {
86 certificates_update_required_ = true;
87 return;
88 }
89
90 certificates_update_running_ = true;
91 certificates_update_required_ = false;
92
93 if (nss_database_) {
94 has_system_certificates_ =
95 static_cast<bool>(nss_database_->GetSystemSlot());
96 nss_database_->ListCerts(base::Bind(&CertCache::UpdateCertificates,
97 weak_factory_.GetWeakPtr()));
98 }
99 }
100
101 // Called if a certificate load task is finished.
102 void UpdateCertificates(std::unique_ptr<net::CertificateList> cert_list) {
103 CHECK(thread_checker_.CalledOnValidThread());
104 DCHECK(certificates_update_running_);
105 VLOG(1) << "UpdateCertificates: " << cert_list->size();
106
107 // Ignore any existing certificates.
108 cert_list_ = std::move(cert_list);
109
110 initial_load_finished_ = true;
111 certificates_updated_callback_.Run();
112
113 certificates_update_running_ = false;
114 if (certificates_update_required_)
115 LoadCertificates();
116 }
117
118 // To be called when certificates have been updated.
119 base::RepeatingClosure certificates_updated_callback_;
120
121 bool has_system_certificates_ = false;
122
123 // This is true after certificates have been loaded initially.
124 bool initial_load_finished_ = false;
125 // This is true if a notification about certificate DB changes arrived while
126 // loading certificates and means that we will have to trigger another
127 // certificates load after that.
128 bool certificates_update_required_ = false;
129 // This is true while certificates are being loaded.
130 bool certificates_update_running_ = false;
131
132 // The NSS certificate database from which the certificates should be loaded.
133 net::NSSCertDatabase* nss_database_ = nullptr;
134
135 // Cached Certificates loaded from the database.
136 std::unique_ptr<net::CertificateList> cert_list_;
137
138 base::ThreadChecker thread_checker_;
139
140 base::WeakPtrFactory<CertCache> weak_factory_;
141
142 DISALLOW_COPY_AND_ASSIGN(CertCache);
143 };
144
23 namespace { 145 namespace {
24 146
25 // Checks if |certificate| is on the given |slot|. 147 // Checks if |certificate| is on the given |slot|.
26 bool IsCertificateOnSlot(const net::X509Certificate* certificate, 148 bool IsCertificateOnSlot(const net::X509Certificate* certificate,
27 PK11SlotInfo* slot) { 149 PK11SlotInfo* slot) {
28 crypto::ScopedPK11SlotList slots_for_cert( 150 crypto::ScopedPK11SlotList slots_for_cert(
29 PK11_GetAllSlotsForCert(certificate->os_cert_handle(), nullptr)); 151 PK11_GetAllSlotsForCert(certificate->os_cert_handle(), nullptr));
30 if (!slots_for_cert) 152 if (!slots_for_cert)
31 return false; 153 return false;
32 154
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()"; 212 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()";
91 return g_cert_loader; 213 return g_cert_loader;
92 } 214 }
93 215
94 // static 216 // static
95 bool CertLoader::IsInitialized() { 217 bool CertLoader::IsInitialized() {
96 return g_cert_loader; 218 return g_cert_loader;
97 } 219 }
98 220
99 CertLoader::CertLoader() 221 CertLoader::CertLoader()
100 : certificates_loaded_(false), 222 : pending_initial_load_(true),
101 certificates_update_required_(false), 223 system_cert_cache_(base::MakeUnique<CertCache>(
102 certificates_update_running_(false), 224 base::BindRepeating(&CertLoader::CacheUpdated,
103 database_(nullptr), 225 base::Unretained(this)))),
226 user_cert_cache_(base::MakeUnique<CertCache>(
227 base::BindRepeating(&CertLoader::CacheUpdated,
228 base::Unretained(this)))),
104 all_certs_(base::MakeUnique<net::CertificateList>()), 229 all_certs_(base::MakeUnique<net::CertificateList>()),
230 system_certs_(base::MakeUnique<net::CertificateList>()),
105 weak_factory_(this) {} 231 weak_factory_(this) {}
106 232
107 CertLoader::~CertLoader() { 233 CertLoader::~CertLoader() {
108 net::CertDatabase::GetInstance()->RemoveObserver(this);
109 } 234 }
110 235
111 void CertLoader::StartWithNSSDB(net::NSSCertDatabase* database) { 236 void CertLoader::SetSystemNSSDB(net::NSSCertDatabase* system_slot_database) {
112 CHECK(!database_); 237 system_cert_cache_->SetNSSDB(system_slot_database);
113 database_ = database; 238 }
114 239
115 // Start observing cert database for changes. 240 void CertLoader::SetUserNSSDB(net::NSSCertDatabase* user_database) {
116 // Observing net::CertDatabase is preferred over observing |database_| 241 user_cert_cache_->SetNSSDB(user_database);
117 // directly, as |database_| observers receive only events generated directly
118 // by |database_|, so they may miss a few relevant ones.
119 // TODO(tbarzic): Once singleton NSSCertDatabase is removed, investigate if
120 // it would be OK to observe |database_| directly; or change NSSCertDatabase
121 // to send notification on all relevant changes.
122 net::CertDatabase::GetInstance()->AddObserver(this);
123
124 LoadCertificates();
125 } 242 }
126 243
127 void CertLoader::AddObserver(CertLoader::Observer* observer) { 244 void CertLoader::AddObserver(CertLoader::Observer* observer) {
128 observers_.AddObserver(observer); 245 observers_.AddObserver(observer);
129 } 246 }
130 247
131 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { 248 void CertLoader::RemoveObserver(CertLoader::Observer* observer) {
132 observers_.RemoveObserver(observer); 249 observers_.RemoveObserver(observer);
133 } 250 }
134 251
135 // static 252 // static
136 bool CertLoader::IsCertificateHardwareBacked(const net::X509Certificate* cert) { 253 bool CertLoader::IsCertificateHardwareBacked(const net::X509Certificate* cert) {
137 if (g_force_hardware_backed_for_test) 254 if (g_force_hardware_backed_for_test)
138 return true; 255 return true;
139 PK11SlotInfo* slot = cert->os_cert_handle()->slot; 256 PK11SlotInfo* slot = cert->os_cert_handle()->slot;
140 return slot && PK11_IsHW(slot); 257 return slot && PK11_IsHW(slot);
141 } 258 }
142 259
143 bool CertLoader::CertificatesLoading() const { 260 bool CertLoader::initial_load_of_any_database_running() const {
144 return database_ && !certificates_loaded_; 261 return system_cert_cache_->initial_load_running() ||
262 user_cert_cache_->initial_load_running();
263 }
264
265 bool CertLoader::initial_load_finished() const {
266 return system_cert_cache_->initial_load_finished() ||
267 user_cert_cache_->initial_load_finished();
145 } 268 }
146 269
147 // static 270 // static
148 void CertLoader::ForceHardwareBackedForTesting() { 271 void CertLoader::ForceHardwareBackedForTesting() {
149 g_force_hardware_backed_for_test = true; 272 g_force_hardware_backed_for_test = true;
150 } 273 }
151 274
152 // static 275 // static
153 // 276 //
154 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: 277 // For background see this discussion on dev-tech-crypto.lists.mozilla.org:
(...skipping 21 matching lines...) Expand all
176 std::string pkcs11_id; 299 std::string pkcs11_id;
177 if (sec_item) { 300 if (sec_item) {
178 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len); 301 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len);
179 SECITEM_FreeItem(sec_item, PR_TRUE); 302 SECITEM_FreeItem(sec_item, PR_TRUE);
180 } 303 }
181 SECKEY_DestroyPrivateKey(priv_key); 304 SECKEY_DestroyPrivateKey(priv_key);
182 305
183 return pkcs11_id; 306 return pkcs11_id;
184 } 307 }
185 308
186 void CertLoader::LoadCertificates() { 309 void CertLoader::CacheUpdated() {
187 DCHECK(thread_checker_.CalledOnValidThread()); 310 DCHECK(thread_checker_.CalledOnValidThread());
188 VLOG(1) << "LoadCertificates: " << certificates_update_running_; 311 VLOG(1) << "CacheUpdated";
189 312
190 if (certificates_update_running_) { 313 // has_system_certificates() only returns true if the user_cert_cache_ has
191 certificates_update_required_ = true; 314 // already finished its initial load and has access to system certificates.
192 return; 315 if (user_cert_cache_->has_system_certificates()) {
316 crypto::ScopedPK11Slot system_slot =
317 user_cert_cache_->nss_database()->GetSystemSlot();
318 DCHECK(system_slot);
319 std::unique_ptr<net::CertificateList> all_certs =
320 base::MakeUnique<net::CertificateList>(user_cert_cache_->cert_list());
321 net::CertificateList* all_certs_ptr = all_certs.get();
322 // We will transfer ownership of all_certs to the UpdateCertificates
323 // callback object. This is guaranteed to outlive
324 // FilterSystemTokenCertificates runtime, so we can pass a raw pointer
325 // there.
326 base::PostTaskWithTraitsAndReplyWithResult(
327 FROM_HERE,
328 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
329 base::BindOnce(&FilterSystemTokenCertificates,
330 base::Unretained(all_certs_ptr), std::move(system_slot)),
331 base::BindOnce(&CertLoader::UpdateCertificates,
332 weak_factory_.GetWeakPtr(), std::move(all_certs)));
333 } else {
334 // The user's cert cache does not contain system certificates.
335 std::unique_ptr<net::CertificateList> system_certs =
336 base::MakeUnique<net::CertificateList>(system_cert_cache_->cert_list());
337 std::unique_ptr<net::CertificateList> all_certs =
338 base::MakeUnique<net::CertificateList>(user_cert_cache_->cert_list());
339 all_certs->insert(all_certs->end(), system_certs->begin(),
340 system_certs->end());
341 UpdateCertificates(std::move(all_certs), std::move(system_certs));
193 } 342 }
194
195 certificates_update_running_ = true;
196 certificates_update_required_ = false;
197
198 database_->ListCerts(
199 base::Bind(&CertLoader::CertificatesLoaded, weak_factory_.GetWeakPtr()));
200 }
201
202 void CertLoader::CertificatesLoaded(
203 std::unique_ptr<net::CertificateList> all_certs) {
204 DCHECK(thread_checker_.CalledOnValidThread());
205 VLOG(1) << "CertificatesLoaded: " << all_certs->size();
206
207 crypto::ScopedPK11Slot system_slot = database_->GetSystemSlot();
208 base::PostTaskWithTraitsAndReplyWithResult(
209 FROM_HERE,
210 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
211 base::BindOnce(&FilterSystemTokenCertificates,
212 base::Unretained(all_certs.get()), std::move(system_slot)),
213 base::BindOnce(&CertLoader::UpdateCertificates,
214 weak_factory_.GetWeakPtr(), std::move(all_certs)));
215 } 343 }
216 344
217 void CertLoader::UpdateCertificates( 345 void CertLoader::UpdateCertificates(
218 std::unique_ptr<net::CertificateList> all_certs, 346 std::unique_ptr<net::CertificateList> all_certs,
219 std::unique_ptr<net::CertificateList> system_certs) { 347 std::unique_ptr<net::CertificateList> system_certs) {
220 DCHECK(thread_checker_.CalledOnValidThread()); 348 DCHECK(thread_checker_.CalledOnValidThread());
221 DCHECK(certificates_update_running_); 349 bool initial_load = pending_initial_load_;
350 pending_initial_load_ = false;
351
222 VLOG(1) << "UpdateCertificates: " << all_certs->size() << " (" 352 VLOG(1) << "UpdateCertificates: " << all_certs->size() << " ("
223 << system_certs->size() << " on system slot)"; 353 << system_certs->size() << " on system slot)"
354 << ", initial_load=" << initial_load;
224 355
225 // Ignore any existing certificates. 356 // Ignore any existing certificates.
226 all_certs_ = std::move(all_certs); 357 all_certs_ = std::move(all_certs);
227 system_certs_ = std::move(system_certs); 358 system_certs_ = std::move(system_certs);
228 359
229 bool initial_load = !certificates_loaded_;
230 certificates_loaded_ = true;
231 NotifyCertificatesLoaded(initial_load); 360 NotifyCertificatesLoaded(initial_load);
232
233 certificates_update_running_ = false;
234 if (certificates_update_required_)
235 LoadCertificates();
236 } 361 }
237 362
238 void CertLoader::NotifyCertificatesLoaded(bool initial_load) { 363 void CertLoader::NotifyCertificatesLoaded(bool initial_load) {
239 for (auto& observer : observers_) 364 for (auto& observer : observers_)
240 observer.OnCertificatesLoaded(*all_certs_, initial_load); 365 observer.OnCertificatesLoaded(*all_certs_, initial_load);
241 } 366 }
242 367
243 void CertLoader::OnCertDBChanged() {
244 VLOG(1) << "OnCertDBChanged";
245 LoadCertificates();
246 }
247
248 } // namespace chromeos 368 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698