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

Side by Side Diff: chrome/browser/net/transport_security_persister.cc

Issue 12974003: Improve TransportSecurityState data storage. (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 7 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) 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 "chrome/browser/net/transport_security_persister.h" 5 #include "chrome/browser/net/transport_security_persister.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 DCHECK_EQ(transport_security_state_, state); 152 DCHECK_EQ(transport_security_state_, state);
153 153
154 if (!readonly_) 154 if (!readonly_)
155 writer_.ScheduleWrite(this); 155 writer_.ScheduleWrite(this);
156 } 156 }
157 157
158 bool TransportSecurityPersister::SerializeData(std::string* output) { 158 bool TransportSecurityPersister::SerializeData(std::string* output) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
160 160
161 DictionaryValue toplevel; 161 DictionaryValue toplevel;
162 base::Time now = base::Time::Now(); 162 std::map<std::string, TransportSecurityState::HSTSEntry>::const_iterator
163 TransportSecurityState::Iterator state(*transport_security_state_); 163 iter = transport_security_state_->GetHSTSEntries().begin();
164 for (; state.HasNext(); state.Advance()) { 164 for (; iter != transport_security_state_->GetHSTSEntries().end(); ++iter) {
165 const std::string& hostname = state.hostname(); 165 const std::string& hashed_host = iter->first;
166 const TransportSecurityState::DomainState& domain_state = 166 const TransportSecurityState::HSTSEntry& entry = iter->second;
167 state.domain_state();
168 167
169 DictionaryValue* serialized = new DictionaryValue; 168 DictionaryValue* serialized = new DictionaryValue;
170 serialized->SetBoolean(kIncludeSubdomains, 169 serialized->SetBoolean(kIncludeSubdomains,
171 domain_state.include_subdomains); 170 entry.include_subdomains_);
172 serialized->SetDouble(kCreated, domain_state.created.ToDoubleT()); 171 serialized->SetDouble(kCreated, entry.created_.ToDoubleT());
173 serialized->SetDouble(kExpiry, domain_state.upgrade_expiry.ToDoubleT()); 172 serialized->SetDouble(kExpiry, entry.expiry_.ToDoubleT());
174 serialized->SetDouble(kDynamicSPKIHashesExpiry, 173 serialized->SetString(kMode, kForceHTTPS);
175 domain_state.dynamic_spki_hashes_expiry.ToDoubleT()); 174 toplevel.Set(HashedDomainToExternalString(hashed_host), serialized);
176
177 switch (domain_state.upgrade_mode) {
178 case TransportSecurityState::DomainState::MODE_FORCE_HTTPS:
179 serialized->SetString(kMode, kForceHTTPS);
180 break;
181 case TransportSecurityState::DomainState::MODE_DEFAULT:
182 serialized->SetString(kMode, kDefault);
183 break;
184 default:
185 NOTREACHED() << "DomainState with unknown mode";
186 delete serialized;
187 continue;
188 }
189
190 serialized->Set(kStaticSPKIHashes,
191 SPKIHashesToListValue(domain_state.static_spki_hashes));
192
193 if (now < domain_state.dynamic_spki_hashes_expiry) {
194 serialized->Set(kDynamicSPKIHashes,
195 SPKIHashesToListValue(domain_state.dynamic_spki_hashes));
196 }
197
198 toplevel.Set(HashedDomainToExternalString(hostname), serialized);
199 } 175 }
200 176
201 base::JSONWriter::WriteWithOptions(&toplevel, 177 base::JSONWriter::WriteWithOptions(&toplevel,
202 base::JSONWriter::OPTIONS_PRETTY_PRINT, 178 base::JSONWriter::OPTIONS_PRETTY_PRINT,
203 output); 179 output);
204 return true; 180 return true;
205 } 181 }
206 182
207 bool TransportSecurityPersister::DeserializeFromCommandLine(
208 const std::string& serialized) {
209 // Purposefully ignore |dirty| because we do not want to persist entries
210 // deserialized in this way.
211 bool dirty;
212 return Deserialize(serialized, true, &dirty, transport_security_state_);
213 }
214
215 bool TransportSecurityPersister::LoadEntries(const std::string& serialized, 183 bool TransportSecurityPersister::LoadEntries(const std::string& serialized,
216 bool* dirty) { 184 bool* dirty) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
218 186
219 transport_security_state_->ClearDynamicData(); 187 transport_security_state_->ClearDynamicData();
220 return Deserialize(serialized, false, dirty, transport_security_state_); 188 return Deserialize(serialized, false, dirty, transport_security_state_);
221 } 189 }
222 190
223 // static 191 // static
224 bool TransportSecurityPersister::Deserialize(const std::string& serialized, 192 bool TransportSecurityPersister::Deserialize(const std::string& serialized,
225 bool forced, 193 bool forced,
226 bool* dirty, 194 bool* dirty,
227 TransportSecurityState* state) { 195 TransportSecurityState* state) {
228 scoped_ptr<Value> value(base::JSONReader::Read(serialized)); 196 scoped_ptr<Value> value(base::JSONReader::Read(serialized));
229 DictionaryValue* dict_value; 197 DictionaryValue* dict_value;
230 if (!value.get() || !value->GetAsDictionary(&dict_value)) 198 if (!value.get() || !value->GetAsDictionary(&dict_value))
231 return false; 199 return false;
232 200
233 const base::Time current_time(base::Time::Now()); 201 const base::Time current_time(base::Time::Now());
202
203 // dirtied is set to false only if every JSON entry is succesfully loaded
204 // and has a creation date. Otherwise, dirtied is set to true, so that
205 // the JSON will be re-serialized in canonical form.
234 bool dirtied = false; 206 bool dirtied = false;
235 207
236 for (DictionaryValue::key_iterator i = dict_value->begin_keys(); 208 for (DictionaryValue::key_iterator i = dict_value->begin_keys();
237 i != dict_value->end_keys(); ++i) { 209 i != dict_value->end_keys(); ++i) {
238 DictionaryValue* parsed; 210 DictionaryValue* parsed;
239 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &parsed)) { 211 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &parsed)) {
240 LOG(WARNING) << "Could not parse entry " << *i << "; skipping entry"; 212 LOG(WARNING) << "Could not parse entry " << *i << "; skipping entry";
213 dirtied = true;
241 continue; 214 continue;
242 } 215 }
243 216
217 bool include_subdomains;
218 double created_double, expiry_double;
219 base::Time created, expiry;
244 std::string mode_string; 220 std::string mode_string;
245 double created;
246 double expiry;
247 double dynamic_spki_hashes_expiry = 0.0;
248 TransportSecurityState::DomainState domain_state;
249 221
250 if (!parsed->GetBoolean(kIncludeSubdomains, 222 if (!parsed->GetBoolean(kIncludeSubdomains,
251 &domain_state.include_subdomains) || 223 &include_subdomains) ||
252 !parsed->GetString(kMode, &mode_string) || 224 !parsed->GetString(kMode, &mode_string) ||
253 !parsed->GetDouble(kExpiry, &expiry)) { 225 !parsed->GetDouble(kExpiry, &expiry_double)) {
254 LOG(WARNING) << "Could not parse some elements of entry " << *i 226 LOG(WARNING) << "Could not parse some elements of entry " << *i
255 << "; skipping entry"; 227 << "; skipping entry";
228 dirtied = true;
256 continue; 229 continue;
257 } 230 }
258 231
259 // Don't fail if this key is not present. 232 if (parsed->GetDouble(kCreated, &created_double)) {
260 parsed->GetDouble(kDynamicSPKIHashesExpiry, 233 created = base::Time::FromDoubleT(created_double);
261 &dynamic_spki_hashes_expiry);
262
263 ListValue* pins_list = NULL;
264 // preloaded_spki_hashes is a legacy synonym for static_spki_hashes.
265 if (parsed->GetList(kStaticSPKIHashes, &pins_list))
266 SPKIHashesFromListValue(*pins_list, &domain_state.static_spki_hashes);
267 else if (parsed->GetList(kPreloadedSPKIHashes, &pins_list))
268 SPKIHashesFromListValue(*pins_list, &domain_state.static_spki_hashes);
269
270 if (parsed->GetList(kDynamicSPKIHashes, &pins_list))
271 SPKIHashesFromListValue(*pins_list, &domain_state.dynamic_spki_hashes);
272
273 if (mode_string == kForceHTTPS || mode_string == kStrict) {
274 domain_state.upgrade_mode =
275 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
276 } else if (mode_string == kDefault || mode_string == kPinningOnly) {
277 domain_state.upgrade_mode =
278 TransportSecurityState::DomainState::MODE_DEFAULT;
279 } else {
280 LOG(WARNING) << "Unknown TransportSecurityState mode string "
281 << mode_string << " found for entry " << *i
282 << "; skipping entry";
283 continue;
284 }
285
286 domain_state.upgrade_expiry = base::Time::FromDoubleT(expiry);
287 domain_state.dynamic_spki_hashes_expiry =
288 base::Time::FromDoubleT(dynamic_spki_hashes_expiry);
289 if (parsed->GetDouble(kCreated, &created)) {
290 domain_state.created = base::Time::FromDoubleT(created);
291 } else { 234 } else {
292 // We're migrating an old entry with no creation date. Make sure we 235 // We're migrating an old entry with no creation date. Make sure we
293 // write the new date back in a reasonable time frame. 236 // write the new date back in a reasonable time frame.
294 dirtied = true; 237 dirtied = true;
295 domain_state.created = base::Time::Now(); 238 created = base::Time::Now();
296 } 239 }
297 240
298 if (domain_state.upgrade_expiry <= current_time && 241 if (mode_string == kForceHTTPS || mode_string == kStrict) {
299 domain_state.dynamic_spki_hashes_expiry <= current_time) { 242 std::string hashed_host = ExternalStringToHashedDomain(*i);
300 // Make sure we dirty the state if we drop an entry. 243 base::Time expiry = base::Time::FromDoubleT(expiry_double);
301 dirtied = true; 244 if (expiry > current_time) {
302 continue; 245 state->AddHSTSHashedHost(hashed_host, created, expiry,
246 include_subdomains);
247 } else {
248 dirtied = true;
249 }
303 } 250 }
304
305 std::string hashed = ExternalStringToHashedDomain(*i);
306 if (hashed.empty()) {
307 dirtied = true;
308 continue;
309 }
310
311 if (forced)
312 state->AddOrUpdateForcedHosts(hashed, domain_state);
313 else
314 state->AddOrUpdateEnabledHosts(hashed, domain_state);
315 } 251 }
316 252
317 *dirty = dirtied; 253 *dirty = dirtied;
318 return true; 254 return true;
319 } 255 }
320 256
321 void TransportSecurityPersister::CompleteLoad(const std::string& state) { 257 void TransportSecurityPersister::CompleteLoad(const std::string& state) {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323 259
324 bool dirty = false; 260 bool dirty = false;
325 if (!LoadEntries(state, &dirty)) { 261 if (!LoadEntries(state, &dirty)) {
326 LOG(ERROR) << "Failed to deserialize state: " << state; 262 LOG(ERROR) << "Failed to deserialize state: " << state;
327 return; 263 return;
328 } 264 }
329 if (dirty) 265 if (dirty)
330 StateIsDirty(transport_security_state_); 266 StateIsDirty(transport_security_state_);
331 } 267 }
OLDNEW
« no previous file with comments | « chrome/browser/net/transport_security_persister.h ('k') | chrome/browser/profiles/profile_io_data.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698