OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "net/http/transport_security_persister.h" | 5 #include "net/http/transport_security_persister.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/base64.h" | 10 #include "base/base64.h" |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/feature_list.h" | |
12 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
13 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
14 #include "base/json/json_reader.h" | 15 #include "base/json/json_reader.h" |
15 #include "base/json/json_writer.h" | 16 #include "base/json/json_writer.h" |
16 #include "base/location.h" | 17 #include "base/location.h" |
17 #include "base/sequenced_task_runner.h" | 18 #include "base/sequenced_task_runner.h" |
18 #include "base/task_runner_util.h" | 19 #include "base/task_runner_util.h" |
19 #include "base/threading/thread_task_runner_handle.h" | 20 #include "base/threading/thread_task_runner_handle.h" |
20 #include "base/values.h" | 21 #include "base/values.h" |
21 #include "crypto/sha2.h" | 22 #include "crypto/sha2.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 const char kDynamicSPKIHashesExpiry[] = "dynamic_spki_hashes_expiry"; | 75 const char kDynamicSPKIHashesExpiry[] = "dynamic_spki_hashes_expiry"; |
75 const char kDynamicSPKIHashes[] = "dynamic_spki_hashes"; | 76 const char kDynamicSPKIHashes[] = "dynamic_spki_hashes"; |
76 const char kForceHTTPS[] = "force-https"; | 77 const char kForceHTTPS[] = "force-https"; |
77 const char kStrict[] = "strict"; | 78 const char kStrict[] = "strict"; |
78 const char kDefault[] = "default"; | 79 const char kDefault[] = "default"; |
79 const char kPinningOnly[] = "pinning-only"; | 80 const char kPinningOnly[] = "pinning-only"; |
80 const char kCreated[] = "created"; | 81 const char kCreated[] = "created"; |
81 const char kStsObserved[] = "sts_observed"; | 82 const char kStsObserved[] = "sts_observed"; |
82 const char kPkpObserved[] = "pkp_observed"; | 83 const char kPkpObserved[] = "pkp_observed"; |
83 const char kReportUri[] = "report-uri"; | 84 const char kReportUri[] = "report-uri"; |
85 const char kExpectCTExpiry[] = "expect_ct_expiry"; | |
86 const char kExpectCTObserved[] = "expect_ct_observed"; | |
87 const char kExpectCTEnforce[] = "expect_ct_enforce"; | |
88 const char kExpectCTReportUri[] = "expect_ct_report_uri"; | |
84 | 89 |
85 std::string LoadState(const base::FilePath& path) { | 90 std::string LoadState(const base::FilePath& path) { |
86 std::string result; | 91 std::string result; |
87 if (!base::ReadFileToString(path, &result)) { | 92 if (!base::ReadFileToString(path, &result)) { |
88 return ""; | 93 return ""; |
89 } | 94 } |
90 return result; | 95 return result; |
91 } | 96 } |
92 | 97 |
93 } // namespace | 98 bool IsDynamicExpectCTEnabled() { |
94 | 99 return base::FeatureList::IsEnabled( |
95 TransportSecurityPersister::TransportSecurityPersister( | 100 TransportSecurityState::kDynamicExpectCTFeature); |
96 TransportSecurityState* state, | |
97 const base::FilePath& profile_path, | |
98 const scoped_refptr<base::SequencedTaskRunner>& background_runner, | |
99 bool readonly) | |
100 : transport_security_state_(state), | |
101 writer_(profile_path.AppendASCII("TransportSecurity"), background_runner), | |
102 foreground_runner_(base::ThreadTaskRunnerHandle::Get()), | |
103 background_runner_(background_runner), | |
104 readonly_(readonly), | |
105 weak_ptr_factory_(this) { | |
106 transport_security_state_->SetDelegate(this); | |
107 | |
108 base::PostTaskAndReplyWithResult( | |
109 background_runner_.get(), FROM_HERE, | |
110 base::Bind(&LoadState, writer_.path()), | |
111 base::Bind(&TransportSecurityPersister::CompleteLoad, | |
112 weak_ptr_factory_.GetWeakPtr())); | |
113 } | 101 } |
114 | 102 |
115 TransportSecurityPersister::~TransportSecurityPersister() { | 103 // Populates |host| with default values for the STS and PKP states. |
116 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | 104 // These default values represent "null" states and are only useful to keep |
105 // the entries in the resulting JSON consistent. The deserializer will ignore | |
106 // "null" states. | |
107 // TODO(davidben): This can be removed when the STS and PKP states are stored | |
mattm
2017/04/15 04:45:01
I don't know the history here, but is there anythi
| |
108 // independently on disk. https://crbug.com/470295 | |
109 void PopulateEntryWithDefaults(base::DictionaryValue* host) { | |
110 host->Clear(); | |
117 | 111 |
118 if (writer_.HasPendingWrite()) | 112 // STS default values. |
119 writer_.DoScheduledWrite(); | 113 host->SetBoolean(kStsIncludeSubdomains, false); |
114 host->SetDouble(kStsObserved, 0.0); | |
115 host->SetDouble(kExpiry, 0.0); | |
116 host->SetString(kMode, kDefault); | |
120 | 117 |
121 transport_security_state_->SetDelegate(NULL); | 118 // PKP default values. |
119 host->SetBoolean(kPkpIncludeSubdomains, false); | |
120 host->SetDouble(kPkpObserved, 0.0); | |
121 host->SetDouble(kDynamicSPKIHashesExpiry, 0.0); | |
122 | |
123 // Expect-CT default values. | |
mattm
2017/04/15 04:45:01
Should kExpectCTReportUri be in here?
estark
2017/04/15 20:18:03
Removed this section per your comment below.
| |
124 if (IsDynamicExpectCTEnabled()) { | |
125 host->SetBoolean(kExpectCTObserved, 0.0); | |
126 host->SetBoolean(kExpectCTExpiry, 0.0); | |
127 host->SetBoolean(kExpectCTEnforce, false); | |
128 } | |
122 } | 129 } |
123 | 130 |
124 void TransportSecurityPersister::StateIsDirty( | 131 // Serializes STS data from |state| into |toplevel|. Any existing state in |
125 TransportSecurityState* state) { | 132 // |toplevel| for each item is overwritten. |
126 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | 133 void SerializeSTSData(TransportSecurityState* state, |
127 DCHECK_EQ(transport_security_state_, state); | 134 base::DictionaryValue* toplevel) { |
128 | 135 TransportSecurityState::STSStateIterator sts_iterator(*state); |
129 if (!readonly_) | |
130 writer_.ScheduleWrite(this); | |
131 } | |
132 | |
133 bool TransportSecurityPersister::SerializeData(std::string* output) { | |
134 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | |
135 | |
136 base::DictionaryValue toplevel; | |
137 base::Time now = base::Time::Now(); | |
138 | |
139 // TODO(davidben): Fix the serialization format by splitting the on-disk | |
140 // representation of the STS and PKP states. https://crbug.com/470295. | |
141 TransportSecurityState::STSStateIterator sts_iterator( | |
142 *transport_security_state_); | |
143 for (; sts_iterator.HasNext(); sts_iterator.Advance()) { | 136 for (; sts_iterator.HasNext(); sts_iterator.Advance()) { |
144 const std::string& hostname = sts_iterator.hostname(); | 137 const std::string& hostname = sts_iterator.hostname(); |
145 const TransportSecurityState::STSState& sts_state = | 138 const TransportSecurityState::STSState& sts_state = |
146 sts_iterator.domain_state(); | 139 sts_iterator.domain_state(); |
147 | 140 |
148 const std::string key = HashedDomainToExternalString(hostname); | 141 const std::string key = HashedDomainToExternalString(hostname); |
149 std::unique_ptr<base::DictionaryValue> serialized( | 142 std::unique_ptr<base::DictionaryValue> serialized( |
150 new base::DictionaryValue); | 143 new base::DictionaryValue); |
151 PopulateEntryWithDefaults(serialized.get()); | 144 PopulateEntryWithDefaults(serialized.get()); |
152 | 145 |
153 serialized->SetBoolean(kStsIncludeSubdomains, sts_state.include_subdomains); | 146 serialized->SetBoolean(kStsIncludeSubdomains, sts_state.include_subdomains); |
154 serialized->SetDouble(kStsObserved, sts_state.last_observed.ToDoubleT()); | 147 serialized->SetDouble(kStsObserved, sts_state.last_observed.ToDoubleT()); |
155 serialized->SetDouble(kExpiry, sts_state.expiry.ToDoubleT()); | 148 serialized->SetDouble(kExpiry, sts_state.expiry.ToDoubleT()); |
156 | 149 |
157 switch (sts_state.upgrade_mode) { | 150 switch (sts_state.upgrade_mode) { |
158 case TransportSecurityState::STSState::MODE_FORCE_HTTPS: | 151 case TransportSecurityState::STSState::MODE_FORCE_HTTPS: |
159 serialized->SetString(kMode, kForceHTTPS); | 152 serialized->SetString(kMode, kForceHTTPS); |
160 break; | 153 break; |
161 case TransportSecurityState::STSState::MODE_DEFAULT: | 154 case TransportSecurityState::STSState::MODE_DEFAULT: |
162 serialized->SetString(kMode, kDefault); | 155 serialized->SetString(kMode, kDefault); |
163 break; | 156 break; |
164 default: | 157 default: |
165 NOTREACHED() << "STSState with unknown mode"; | 158 NOTREACHED() << "STSState with unknown mode"; |
166 continue; | 159 continue; |
167 } | 160 } |
168 | 161 |
169 toplevel.Set(key, std::move(serialized)); | 162 toplevel->Set(key, std::move(serialized)); |
170 } | 163 } |
164 } | |
171 | 165 |
172 TransportSecurityState::PKPStateIterator pkp_iterator( | 166 // Serializes PKP data from |state| into |toplevel|. For each PKP item in |
173 *transport_security_state_); | 167 // |state|, if |toplevel| already contains an item for that hostname, the item |
168 // is updated with the PKP data. | |
169 void SerializePKPData(TransportSecurityState* state, | |
170 base::DictionaryValue* toplevel) { | |
171 base::Time now = base::Time::Now(); | |
172 TransportSecurityState::PKPStateIterator pkp_iterator(*state); | |
174 for (; pkp_iterator.HasNext(); pkp_iterator.Advance()) { | 173 for (; pkp_iterator.HasNext(); pkp_iterator.Advance()) { |
175 const std::string& hostname = pkp_iterator.hostname(); | 174 const std::string& hostname = pkp_iterator.hostname(); |
176 const TransportSecurityState::PKPState& pkp_state = | 175 const TransportSecurityState::PKPState& pkp_state = |
177 pkp_iterator.domain_state(); | 176 pkp_iterator.domain_state(); |
178 | 177 |
179 // See if the current |hostname| already has STS state and, if so, update | 178 // See if the current |hostname| already has STS state and, if so, update |
180 // that entry. | 179 // that entry. |
181 const std::string key = HashedDomainToExternalString(hostname); | 180 const std::string key = HashedDomainToExternalString(hostname); |
182 base::DictionaryValue* serialized = nullptr; | 181 base::DictionaryValue* serialized = nullptr; |
183 if (!toplevel.GetDictionary(key, &serialized)) { | 182 if (!toplevel->GetDictionary(key, &serialized)) { |
184 std::unique_ptr<base::DictionaryValue> serialized_scoped( | 183 std::unique_ptr<base::DictionaryValue> serialized_scoped( |
185 new base::DictionaryValue); | 184 new base::DictionaryValue); |
186 serialized = serialized_scoped.get(); | 185 serialized = serialized_scoped.get(); |
187 PopulateEntryWithDefaults(serialized); | 186 PopulateEntryWithDefaults(serialized); |
188 toplevel.Set(key, std::move(serialized_scoped)); | 187 toplevel->Set(key, std::move(serialized_scoped)); |
189 } | 188 } |
190 | 189 |
191 serialized->SetBoolean(kPkpIncludeSubdomains, pkp_state.include_subdomains); | 190 serialized->SetBoolean(kPkpIncludeSubdomains, pkp_state.include_subdomains); |
192 serialized->SetDouble(kPkpObserved, pkp_state.last_observed.ToDoubleT()); | 191 serialized->SetDouble(kPkpObserved, pkp_state.last_observed.ToDoubleT()); |
193 serialized->SetDouble(kDynamicSPKIHashesExpiry, | 192 serialized->SetDouble(kDynamicSPKIHashesExpiry, |
194 pkp_state.expiry.ToDoubleT()); | 193 pkp_state.expiry.ToDoubleT()); |
195 | 194 |
196 // TODO(svaldez): Historically, both SHA-1 and SHA-256 hashes were | 195 // TODO(svaldez): Historically, both SHA-1 and SHA-256 hashes were |
197 // accepted in pins. Per spec, only SHA-256 is accepted now, however | 196 // accepted in pins. Per spec, only SHA-256 is accepted now, however |
198 // existing serialized pins are still processed. Migrate historical pins | 197 // existing serialized pins are still processed. Migrate historical pins |
199 // with SHA-1 hashes properly, either by dropping just the bad hashes or | 198 // with SHA-1 hashes properly, either by dropping just the bad hashes or |
200 // the entire pin. See https://crbug.com/448501. | 199 // the entire pin. See https://crbug.com/448501. |
201 if (now < pkp_state.expiry) { | 200 if (now < pkp_state.expiry) { |
202 serialized->Set(kDynamicSPKIHashes, | 201 serialized->Set(kDynamicSPKIHashes, |
203 SPKIHashesToListValue(pkp_state.spki_hashes)); | 202 SPKIHashesToListValue(pkp_state.spki_hashes)); |
204 } | 203 } |
205 | 204 |
206 serialized->SetString(kReportUri, pkp_state.report_uri.spec()); | 205 serialized->SetString(kReportUri, pkp_state.report_uri.spec()); |
207 } | 206 } |
207 } | |
208 | |
209 // Serializes Expect-CT data from |state| into |toplevel|. For each Expect-CT | |
210 // item in |state|, if |toplevel| already contains an item for that hostname, | |
211 // the item is updated with the Expect-CT data. | |
212 void SerializeExpectCTData(TransportSecurityState* state, | |
213 base::DictionaryValue* toplevel) { | |
214 if (!IsDynamicExpectCTEnabled()) | |
215 return; | |
216 TransportSecurityState::ExpectCTStateIterator expect_ct_iterator(*state); | |
217 for (; expect_ct_iterator.HasNext(); expect_ct_iterator.Advance()) { | |
218 const std::string& hostname = expect_ct_iterator.hostname(); | |
219 const TransportSecurityState::ExpectCTState& expect_ct_state = | |
220 expect_ct_iterator.domain_state(); | |
221 | |
222 // See if the current |hostname| already has STS/PKP state and, if so, | |
223 // update that entry. | |
224 const std::string key = HashedDomainToExternalString(hostname); | |
225 base::DictionaryValue* serialized = nullptr; | |
226 if (!toplevel->GetDictionary(key, &serialized)) { | |
227 std::unique_ptr<base::DictionaryValue> serialized_scoped( | |
228 new base::DictionaryValue); | |
229 serialized = serialized_scoped.get(); | |
230 PopulateEntryWithDefaults(serialized); | |
231 toplevel->Set(key, std::move(serialized_scoped)); | |
232 } | |
233 | |
234 serialized->SetDouble(kExpectCTObserved, | |
235 expect_ct_state.last_observed.ToDoubleT()); | |
236 serialized->SetDouble(kExpectCTExpiry, expect_ct_state.expiry.ToDoubleT()); | |
237 serialized->SetBoolean(kExpectCTEnforce, expect_ct_state.enforce); | |
238 serialized->SetString(kExpectCTReportUri, | |
239 expect_ct_state.report_uri.spec()); | |
240 } | |
241 } | |
242 | |
243 bool DeserializeExpectCTState(const base::DictionaryValue* parsed, | |
244 TransportSecurityState::ExpectCTState* state) { | |
245 double observed; | |
246 bool has_observed = parsed->GetDouble(kExpectCTObserved, &observed); | |
247 double expiry; | |
248 bool has_expiry = parsed->GetDouble(kExpectCTExpiry, &expiry); | |
249 bool enforce; | |
250 bool has_enforce = parsed->GetBoolean(kExpectCTEnforce, &enforce); | |
251 std::string report_uri_str; | |
252 bool has_report_uri = parsed->GetString(kExpectCTReportUri, &report_uri_str); | |
253 | |
254 // Entries are not required to have Expect-CT data. | |
255 if (!has_observed && !has_expiry && !has_enforce) | |
mattm
2017/04/15 04:45:01
Is the PopulateEntryWithDefaults change necessary
estark
2017/04/15 20:18:03
Hmm no it's not, removed.
| |
256 return true; | |
257 | |
258 // If there is Expect-CT data, the default keys (kExpectCTObserved, | |
259 // kExpectCTExpiry, kExpectCTEnforce) are expected to be present. | |
260 if (!has_observed || !has_expiry || !has_enforce) | |
261 return false; | |
262 | |
263 state->last_observed = base::Time::FromDoubleT(observed); | |
264 state->expiry = base::Time::FromDoubleT(expiry); | |
265 state->enforce = enforce; | |
266 if (has_report_uri) { | |
267 GURL report_uri(report_uri_str); | |
268 if (report_uri.is_valid()) | |
269 state->report_uri = report_uri; | |
270 } | |
271 return true; | |
272 } | |
273 | |
274 } // namespace | |
275 | |
276 TransportSecurityPersister::TransportSecurityPersister( | |
277 TransportSecurityState* state, | |
278 const base::FilePath& profile_path, | |
279 const scoped_refptr<base::SequencedTaskRunner>& background_runner, | |
280 bool readonly) | |
281 : transport_security_state_(state), | |
282 writer_(profile_path.AppendASCII("TransportSecurity"), background_runner), | |
283 foreground_runner_(base::ThreadTaskRunnerHandle::Get()), | |
284 background_runner_(background_runner), | |
285 readonly_(readonly), | |
286 weak_ptr_factory_(this) { | |
287 transport_security_state_->SetDelegate(this); | |
288 | |
289 base::PostTaskAndReplyWithResult( | |
290 background_runner_.get(), FROM_HERE, | |
291 base::Bind(&LoadState, writer_.path()), | |
292 base::Bind(&TransportSecurityPersister::CompleteLoad, | |
293 weak_ptr_factory_.GetWeakPtr())); | |
294 } | |
295 | |
296 TransportSecurityPersister::~TransportSecurityPersister() { | |
297 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | |
298 | |
299 if (writer_.HasPendingWrite()) | |
300 writer_.DoScheduledWrite(); | |
301 | |
302 transport_security_state_->SetDelegate(NULL); | |
303 } | |
304 | |
305 void TransportSecurityPersister::StateIsDirty(TransportSecurityState* state) { | |
306 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | |
307 DCHECK_EQ(transport_security_state_, state); | |
308 | |
309 if (!readonly_) | |
310 writer_.ScheduleWrite(this); | |
311 } | |
312 | |
313 bool TransportSecurityPersister::SerializeData(std::string* output) { | |
314 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | |
315 | |
316 base::DictionaryValue toplevel; | |
317 | |
318 // TODO(davidben): Fix the serialization format by splitting the on-disk | |
319 // representation of the STS and PKP states. https://crbug.com/470295. | |
320 SerializeSTSData(transport_security_state_, &toplevel); | |
321 SerializePKPData(transport_security_state_, &toplevel); | |
322 SerializeExpectCTData(transport_security_state_, &toplevel); | |
208 | 323 |
209 base::JSONWriter::WriteWithOptions( | 324 base::JSONWriter::WriteWithOptions( |
210 toplevel, base::JSONWriter::OPTIONS_PRETTY_PRINT, output); | 325 toplevel, base::JSONWriter::OPTIONS_PRETTY_PRINT, output); |
211 return true; | 326 return true; |
212 } | 327 } |
213 | 328 |
214 bool TransportSecurityPersister::LoadEntries(const std::string& serialized, | 329 bool TransportSecurityPersister::LoadEntries(const std::string& serialized, |
215 bool* dirty) { | 330 bool* dirty) { |
216 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | 331 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); |
217 | 332 |
(...skipping 16 matching lines...) Expand all Loading... | |
234 for (base::DictionaryValue::Iterator i(*dict_value); | 349 for (base::DictionaryValue::Iterator i(*dict_value); |
235 !i.IsAtEnd(); i.Advance()) { | 350 !i.IsAtEnd(); i.Advance()) { |
236 const base::DictionaryValue* parsed = NULL; | 351 const base::DictionaryValue* parsed = NULL; |
237 if (!i.value().GetAsDictionary(&parsed)) { | 352 if (!i.value().GetAsDictionary(&parsed)) { |
238 LOG(WARNING) << "Could not parse entry " << i.key() << "; skipping entry"; | 353 LOG(WARNING) << "Could not parse entry " << i.key() << "; skipping entry"; |
239 continue; | 354 continue; |
240 } | 355 } |
241 | 356 |
242 TransportSecurityState::STSState sts_state; | 357 TransportSecurityState::STSState sts_state; |
243 TransportSecurityState::PKPState pkp_state; | 358 TransportSecurityState::PKPState pkp_state; |
359 TransportSecurityState::ExpectCTState expect_ct_state; | |
244 | 360 |
245 // kIncludeSubdomains is a legacy synonym for kStsIncludeSubdomains and | 361 // kIncludeSubdomains is a legacy synonym for kStsIncludeSubdomains and |
246 // kPkpIncludeSubdomains. Parse at least one of these properties, | 362 // kPkpIncludeSubdomains. Parse at least one of these properties, |
247 // preferably the new ones. | 363 // preferably the new ones. |
248 bool include_subdomains = false; | 364 bool include_subdomains = false; |
249 bool parsed_include_subdomains = parsed->GetBoolean(kIncludeSubdomains, | 365 bool parsed_include_subdomains = parsed->GetBoolean(kIncludeSubdomains, |
250 &include_subdomains); | 366 &include_subdomains); |
251 sts_state.include_subdomains = include_subdomains; | 367 sts_state.include_subdomains = include_subdomains; |
252 pkp_state.include_subdomains = include_subdomains; | 368 pkp_state.include_subdomains = include_subdomains; |
253 if (parsed->GetBoolean(kStsIncludeSubdomains, &include_subdomains)) { | 369 if (parsed->GetBoolean(kStsIncludeSubdomains, &include_subdomains)) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 } | 432 } |
317 if (parsed->GetDouble(kPkpObserved, &pkp_observed)) { | 433 if (parsed->GetDouble(kPkpObserved, &pkp_observed)) { |
318 pkp_state.last_observed = base::Time::FromDoubleT(pkp_observed); | 434 pkp_state.last_observed = base::Time::FromDoubleT(pkp_observed); |
319 } else if (parsed->GetDouble(kCreated, &pkp_observed)) { | 435 } else if (parsed->GetDouble(kCreated, &pkp_observed)) { |
320 pkp_state.last_observed = base::Time::FromDoubleT(pkp_observed); | 436 pkp_state.last_observed = base::Time::FromDoubleT(pkp_observed); |
321 } else { | 437 } else { |
322 dirtied = true; | 438 dirtied = true; |
323 pkp_state.last_observed = base::Time::Now(); | 439 pkp_state.last_observed = base::Time::Now(); |
324 } | 440 } |
325 | 441 |
442 if (!DeserializeExpectCTState(parsed, &expect_ct_state)) { | |
443 continue; | |
444 } | |
445 | |
326 bool has_sts = | 446 bool has_sts = |
327 sts_state.expiry > current_time && sts_state.ShouldUpgradeToSSL(); | 447 sts_state.expiry > current_time && sts_state.ShouldUpgradeToSSL(); |
328 bool has_pkp = | 448 bool has_pkp = |
329 pkp_state.expiry > current_time && pkp_state.HasPublicKeyPins(); | 449 pkp_state.expiry > current_time && pkp_state.HasPublicKeyPins(); |
330 if (!has_sts && !has_pkp) { | 450 bool has_expect_ct = |
451 expect_ct_state.expiry > current_time && | |
452 (expect_ct_state.enforce || !expect_ct_state.report_uri.is_empty()); | |
453 if (!has_sts && !has_pkp && !has_expect_ct) { | |
331 // Make sure we dirty the state if we drop an entry. The entries can only | 454 // Make sure we dirty the state if we drop an entry. The entries can only |
332 // be dropped when both the STS and PKP states are expired or invalid. | 455 // be dropped when all the STS, PKP, and Expect-CT states are expired or |
456 // invalid. | |
333 dirtied = true; | 457 dirtied = true; |
334 continue; | 458 continue; |
335 } | 459 } |
336 | 460 |
337 std::string hashed = ExternalStringToHashedDomain(i.key()); | 461 std::string hashed = ExternalStringToHashedDomain(i.key()); |
338 if (hashed.empty()) { | 462 if (hashed.empty()) { |
339 dirtied = true; | 463 dirtied = true; |
340 continue; | 464 continue; |
341 } | 465 } |
342 | 466 |
343 // Until the on-disk storage is split, there will always be 'null' entries. | 467 // Until the on-disk storage is split, there will always be 'null' entries. |
344 // We only register entries that have actual state. | 468 // We only register entries that have actual state. |
345 if (has_sts) | 469 if (has_sts) |
346 state->AddOrUpdateEnabledSTSHosts(hashed, sts_state); | 470 state->AddOrUpdateEnabledSTSHosts(hashed, sts_state); |
347 if (has_pkp) | 471 if (has_pkp) |
348 state->AddOrUpdateEnabledPKPHosts(hashed, pkp_state); | 472 state->AddOrUpdateEnabledPKPHosts(hashed, pkp_state); |
473 if (has_expect_ct) | |
474 state->AddOrUpdateEnabledExpectCTHosts(hashed, expect_ct_state); | |
349 } | 475 } |
350 | 476 |
351 *dirty = dirtied; | 477 *dirty = dirtied; |
352 return true; | 478 return true; |
353 } | 479 } |
354 | 480 |
355 void TransportSecurityPersister::PopulateEntryWithDefaults( | |
356 base::DictionaryValue* host) { | |
357 host->Clear(); | |
358 | |
359 // STS default values. | |
360 host->SetBoolean(kStsIncludeSubdomains, false); | |
361 host->SetDouble(kStsObserved, 0.0); | |
362 host->SetDouble(kExpiry, 0.0); | |
363 host->SetString(kMode, kDefault); | |
364 | |
365 // PKP default values. | |
366 host->SetBoolean(kPkpIncludeSubdomains, false); | |
367 host->SetDouble(kPkpObserved, 0.0); | |
368 host->SetDouble(kDynamicSPKIHashesExpiry, 0.0); | |
369 } | |
370 | |
371 void TransportSecurityPersister::CompleteLoad(const std::string& state) { | 481 void TransportSecurityPersister::CompleteLoad(const std::string& state) { |
372 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); | 482 DCHECK(foreground_runner_->RunsTasksOnCurrentThread()); |
373 | 483 |
374 if (state.empty()) | 484 if (state.empty()) |
375 return; | 485 return; |
376 | 486 |
377 bool dirty = false; | 487 bool dirty = false; |
378 if (!LoadEntries(state, &dirty)) { | 488 if (!LoadEntries(state, &dirty)) { |
379 LOG(ERROR) << "Failed to deserialize state: " << state; | 489 LOG(ERROR) << "Failed to deserialize state: " << state; |
380 return; | 490 return; |
381 } | 491 } |
382 if (dirty) | 492 if (dirty) |
383 StateIsDirty(transport_security_state_); | 493 StateIsDirty(transport_security_state_); |
384 } | 494 } |
385 | 495 |
386 } // namespace net | 496 } // namespace net |
OLD | NEW |