Chromium Code Reviews| 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 |