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

Side by Side Diff: chromeos/cert_loader.cc

Issue 2858113003: Enable device-wide EAP-TLS networks (Closed)
Patch Set: initial_load only true on initial load, added tests, fixed comments. 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/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/task_scheduler/post_task.h" 14 #include "base/task_scheduler/post_task.h"
15 #include "crypto/nss_util.h" 15 #include "crypto/nss_util.h"
16 #include "crypto/scoped_nss_types.h" 16 #include "crypto/scoped_nss_types.h"
17 #include "net/cert/cert_database.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
24 // Caches certificates from a NSSCertDatabase. Handles reloading of certificates
25 // on update notifications and provides status flags (loading / loaded).
26 class CertLoader::CertCache : public net::CertDatabase::Observer {
27 public:
28 explicit CertCache(base::RepeatingClosure certificates_updated_callback)
29 : certificates_updated_callback_(certificates_updated_callback),
30 cert_list_(base::MakeUnique<net::CertificateList>()),
31 weak_factory_(this) {}
32
33 ~CertCache() override {
34 net::CertDatabase::GetInstance()->RemoveObserver(this);
35 }
36
37 void StartWithNSSDB(net::NSSCertDatabase* database) {
38 CHECK(!database_);
39 database_ = database;
40
41 // Start observing cert database for changes.
42 // Observing net::CertDatabase is preferred over observing |database_|
43 // directly, as |database_| observers receive only events generated directly
44 // by |database_|, so they may miss a few relevant ones.
45 // TODO(tbarzic): Once singleton NSSCertDatabase is removed, investigate if
46 // it would be OK to observe |database_| directly; or change NSSCertDatabase
47 // to send notification on all relevant changes.
48 net::CertDatabase::GetInstance()->AddObserver(this);
49
50 LoadCertificates();
51 }
52
53 net::NSSCertDatabase* GetNSSDB() { return database_; }
stevenjb 2017/05/09 17:04:02 nit: database() (and maybe rename the member/acces
pmarko 2017/05/10 11:48:01 Done.
54
55 // Trigger a certificate load. If a certificate loading task is already in
56 // progress, will start a reload once the current task is finished.
57 void LoadCertificates() {
58 CHECK(thread_checker_.CalledOnValidThread());
59 VLOG(1) << "LoadCertificates: " << certificates_update_running_;
60
61 if (certificates_update_running_) {
62 certificates_update_required_ = true;
63 return;
64 }
65
66 certificates_update_running_ = true;
67 certificates_update_required_ = false;
68
69 if (database_) {
70 has_system_certificates_ = static_cast<bool>(database_->GetSystemSlot());
71 database_->ListCerts(base::Bind(&CertCache::UpdateCertificates,
72 weak_factory_.GetWeakPtr()));
73 }
74 }
75
76 // Called if a certificate load task is finished.
77 void UpdateCertificates(std::unique_ptr<net::CertificateList> cert_list) {
78 CHECK(thread_checker_.CalledOnValidThread());
79 DCHECK(certificates_update_running_);
80 VLOG(1) << "UpdateCertificates: " << cert_list->size();
81
82 // Ignore any existing certificates.
83 cert_list_ = std::move(cert_list);
84
85 certificates_loaded_ = true;
86 certificates_updated_callback_.Run();
87
88 certificates_update_running_ = false;
89 if (certificates_update_required_)
90 LoadCertificates();
91 }
92
93 // net::CertDatabase::Observer
94 void OnCertDBChanged() override {
95 VLOG(1) << "OnCertDBChanged";
96 LoadCertificates();
97 }
98
99 const net::CertificateList& cert_list() const { return *cert_list_; }
100
101 bool CertificatesLoading() const {
102 return database_ && !certificates_loaded_;
103 }
104
105 bool certificates_loaded() const { return certificates_loaded_; }
106 bool has_system_certificates() const { return has_system_certificates_; }
107
108 private:
109 // To be called when certificates have been updated.
110 base::RepeatingClosure certificates_updated_callback_;
111
112 bool has_system_certificates_ = false;
113
114 // Flags describing current CertLoader state.
115 bool certificates_loaded_ = false;
116 bool certificates_update_required_ = false;
117 bool certificates_update_running_ = false;
118
119 // The user-specific NSS certificate database from which the certificates
120 // should be loaded.
121 net::NSSCertDatabase* database_ = nullptr;
122
123 // Cached Certificates loaded from the database.
124 std::unique_ptr<net::CertificateList> cert_list_;
125
126 base::ThreadChecker thread_checker_;
127
128 base::WeakPtrFactory<CertCache> weak_factory_;
129 };
130
23 namespace { 131 namespace {
24 132
25 // Checks if |certificate| is on the given |slot|. 133 // Checks if |certificate| is on the given |slot|.
26 bool IsCertificateOnSlot(const net::X509Certificate* certificate, 134 bool IsCertificateOnSlot(const net::X509Certificate* certificate,
27 PK11SlotInfo* slot) { 135 PK11SlotInfo* slot) {
28 crypto::ScopedPK11SlotList slots_for_cert( 136 crypto::ScopedPK11SlotList slots_for_cert(
29 PK11_GetAllSlotsForCert(certificate->os_cert_handle(), nullptr)); 137 PK11_GetAllSlotsForCert(certificate->os_cert_handle(), nullptr));
30 if (!slots_for_cert) 138 if (!slots_for_cert)
31 return false; 139 return false;
32 140
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()"; 198 CHECK(g_cert_loader) << "CertLoader::Get() called before Initialize()";
91 return g_cert_loader; 199 return g_cert_loader;
92 } 200 }
93 201
94 // static 202 // static
95 bool CertLoader::IsInitialized() { 203 bool CertLoader::IsInitialized() {
96 return g_cert_loader; 204 return g_cert_loader;
97 } 205 }
98 206
99 CertLoader::CertLoader() 207 CertLoader::CertLoader()
100 : certificates_loaded_(false), 208 : pending_initial_load_(true),
101 certificates_update_required_(false), 209 system_cert_cache_(base::MakeUnique<CertCache>(
102 certificates_update_running_(false), 210 base::BindRepeating(&CertLoader::CacheUpdated,
103 database_(nullptr), 211 base::Unretained(this)))),
212 user_cert_cache_(base::MakeUnique<CertCache>(
213 base::BindRepeating(&CertLoader::CacheUpdated,
214 base::Unretained(this)))),
104 all_certs_(base::MakeUnique<net::CertificateList>()), 215 all_certs_(base::MakeUnique<net::CertificateList>()),
216 system_certs_(base::MakeUnique<net::CertificateList>()),
105 weak_factory_(this) {} 217 weak_factory_(this) {}
106 218
107 CertLoader::~CertLoader() { 219 CertLoader::~CertLoader() {
108 net::CertDatabase::GetInstance()->RemoveObserver(this);
109 } 220 }
110 221
111 void CertLoader::StartWithNSSDB(net::NSSCertDatabase* database) { 222 void CertLoader::StartWithSystemNSSDB(
112 CHECK(!database_); 223 net::NSSCertDatabase* system_slot_database) {
113 database_ = database; 224 system_cert_cache_->StartWithNSSDB(system_slot_database);
225 }
114 226
115 // Start observing cert database for changes. 227 void CertLoader::StartWithUserNSSDB(net::NSSCertDatabase* user_database) {
116 // Observing net::CertDatabase is preferred over observing |database_| 228 user_cert_cache_->StartWithNSSDB(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 } 229 }
126 230
127 void CertLoader::AddObserver(CertLoader::Observer* observer) { 231 void CertLoader::AddObserver(CertLoader::Observer* observer) {
128 observers_.AddObserver(observer); 232 observers_.AddObserver(observer);
129 } 233 }
130 234
131 void CertLoader::RemoveObserver(CertLoader::Observer* observer) { 235 void CertLoader::RemoveObserver(CertLoader::Observer* observer) {
132 observers_.RemoveObserver(observer); 236 observers_.RemoveObserver(observer);
133 } 237 }
134 238
135 // static 239 // static
136 bool CertLoader::IsCertificateHardwareBacked(const net::X509Certificate* cert) { 240 bool CertLoader::IsCertificateHardwareBacked(const net::X509Certificate* cert) {
137 if (g_force_hardware_backed_for_test) 241 if (g_force_hardware_backed_for_test)
138 return true; 242 return true;
139 PK11SlotInfo* slot = cert->os_cert_handle()->slot; 243 PK11SlotInfo* slot = cert->os_cert_handle()->slot;
140 return slot && PK11_IsHW(slot); 244 return slot && PK11_IsHW(slot);
141 } 245 }
142 246
143 bool CertLoader::CertificatesLoading() const { 247 bool CertLoader::CertificatesLoading() const {
144 return database_ && !certificates_loaded_; 248 return system_cert_cache_->CertificatesLoading() ||
249 user_cert_cache_->CertificatesLoading();
250 }
251
252 bool CertLoader::certificates_loaded() const {
253 return system_cert_cache_->certificates_loaded() ||
254 user_cert_cache_->certificates_loaded();
stevenjb 2017/05/09 17:04:02 Is this correct? I'm a bit fuzzy on whether both
pmarko 2017/05/10 11:48:01 CertLoader can be used with one or both - I've imp
145 } 255 }
146 256
147 // static 257 // static
148 void CertLoader::ForceHardwareBackedForTesting() { 258 void CertLoader::ForceHardwareBackedForTesting() {
149 g_force_hardware_backed_for_test = true; 259 g_force_hardware_backed_for_test = true;
150 } 260 }
151 261
152 // static 262 // static
153 // 263 //
154 // For background see this discussion on dev-tech-crypto.lists.mozilla.org: 264 // For background see this discussion on dev-tech-crypto.lists.mozilla.org:
(...skipping 21 matching lines...) Expand all
176 std::string pkcs11_id; 286 std::string pkcs11_id;
177 if (sec_item) { 287 if (sec_item) {
178 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len); 288 pkcs11_id = base::HexEncode(sec_item->data, sec_item->len);
179 SECITEM_FreeItem(sec_item, PR_TRUE); 289 SECITEM_FreeItem(sec_item, PR_TRUE);
180 } 290 }
181 SECKEY_DestroyPrivateKey(priv_key); 291 SECKEY_DestroyPrivateKey(priv_key);
182 292
183 return pkcs11_id; 293 return pkcs11_id;
184 } 294 }
185 295
186 void CertLoader::LoadCertificates() { 296 void CertLoader::CacheUpdated() {
187 DCHECK(thread_checker_.CalledOnValidThread()); 297 DCHECK(thread_checker_.CalledOnValidThread());
188 VLOG(1) << "LoadCertificates: " << certificates_update_running_; 298 VLOG(1) << "CacheUpdated";
189 299
190 if (certificates_update_running_) { 300 if (user_cert_cache_->has_system_certificates()) {
191 certificates_update_required_ = true; 301 // The user's cert cache also contains system certificates.
192 return; 302 // Filter those.
303 crypto::ScopedPK11Slot system_slot =
304 user_cert_cache_->GetNSSDB()->GetSystemSlot();
305 DCHECK(system_slot);
306 std::unique_ptr<net::CertificateList> all_certs =
307 base::MakeUnique<net::CertificateList>(user_cert_cache_->cert_list());
308 base::PostTaskWithTraitsAndReplyWithResult(
309 FROM_HERE,
310 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
311 base::BindOnce(&FilterSystemTokenCertificates,
312 base::Unretained(all_certs.get()),
313 std::move(system_slot)),
314 base::BindOnce(&CertLoader::UpdateCertificates,
315 weak_factory_.GetWeakPtr(), std::move(all_certs)));
316 } else {
317 // The user's cert cache does not contain system certificates.
318 std::unique_ptr<net::CertificateList> system_certs =
319 base::MakeUnique<net::CertificateList>(system_cert_cache_->cert_list());
320 std::unique_ptr<net::CertificateList> all_certs =
321 base::MakeUnique<net::CertificateList>(user_cert_cache_->cert_list());
322 all_certs->insert(all_certs->end(), system_certs->begin(),
323 system_certs->end());
324 UpdateCertificates(std::move(all_certs), std::move(system_certs));
193 } 325 }
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 } 326 }
216 327
217 void CertLoader::UpdateCertificates( 328 void CertLoader::UpdateCertificates(
218 std::unique_ptr<net::CertificateList> all_certs, 329 std::unique_ptr<net::CertificateList> all_certs,
219 std::unique_ptr<net::CertificateList> system_certs) { 330 std::unique_ptr<net::CertificateList> system_certs) {
220 DCHECK(thread_checker_.CalledOnValidThread()); 331 DCHECK(thread_checker_.CalledOnValidThread());
221 DCHECK(certificates_update_running_); 332 bool initial_load = pending_initial_load_;
333 pending_initial_load_ = false;
334
222 VLOG(1) << "UpdateCertificates: " << all_certs->size() << " (" 335 VLOG(1) << "UpdateCertificates: " << all_certs->size() << " ("
223 << system_certs->size() << " on system slot)"; 336 << system_certs->size() << " on system slot)"
337 << ", initial_load=" << initial_load;
224 338
225 // Ignore any existing certificates. 339 // Ignore any existing certificates.
226 all_certs_ = std::move(all_certs); 340 all_certs_ = std::move(all_certs);
227 system_certs_ = std::move(system_certs); 341 system_certs_ = std::move(system_certs);
228 342
229 bool initial_load = !certificates_loaded_;
230 certificates_loaded_ = true;
231 NotifyCertificatesLoaded(initial_load); 343 NotifyCertificatesLoaded(initial_load);
232
233 certificates_update_running_ = false;
234 if (certificates_update_required_)
235 LoadCertificates();
236 } 344 }
237 345
238 void CertLoader::NotifyCertificatesLoaded(bool initial_load) { 346 void CertLoader::NotifyCertificatesLoaded(bool initial_load) {
239 for (auto& observer : observers_) 347 for (auto& observer : observers_)
240 observer.OnCertificatesLoaded(*all_certs_, initial_load); 348 observer.OnCertificatesLoaded(*all_certs_, initial_load);
241 } 349 }
242 350
243 void CertLoader::OnCertDBChanged() {
244 VLOG(1) << "OnCertDBChanged";
245 LoadCertificates();
246 }
247
248 } // namespace chromeos 351 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698