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

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, 9 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::DynamicEntry>::const_iterator
163 TransportSecurityState::Iterator state(*transport_security_state_); 163 iter = transport_security_state_->GetHSTSEntries().begin();
palmer 2013/03/25 23:54:34 This variable should be scoped to be inside the fo
unsafe 2013/03/26 01:42:22 yeah, line's too long. I could add a typedef just
164 for (; state.HasNext(); state.Advance()) { 164 for (; iter != transport_security_state_->GetHSTSEntries().end(); iter++) {
palmer 2013/03/25 23:54:34 Chromium style is ++iter.
unsafe 2013/03/26 01:42:22 Done.
165 const std::string& hostname = state.hostname(); 165 const std::string& hashed_host = iter->first;
166 const TransportSecurityState::DomainState& domain_state = 166 const TransportSecurityState::DynamicEntry& 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());
234 bool dirtied = false; 202 bool dirtied = false;
235 203
236 for (DictionaryValue::key_iterator i = dict_value->begin_keys(); 204 for (DictionaryValue::key_iterator i = dict_value->begin_keys();
237 i != dict_value->end_keys(); ++i) { 205 i != dict_value->end_keys(); ++i) {
238 DictionaryValue* parsed; 206 DictionaryValue* parsed;
239 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &parsed)) { 207 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &parsed)) {
240 LOG(WARNING) << "Could not parse entry " << *i << "; skipping entry"; 208 LOG(WARNING) << "Could not parse entry " << *i << "; skipping entry";
241 continue; 209 continue;
242 } 210 }
243 211
212 bool include_subdomains = false;
213 double created_double = 0, expiry_double = 0;
214 base::Time created, expiry;
244 std::string mode_string; 215 std::string mode_string;
245 double created;
246 double expiry;
247 double dynamic_spki_hashes_expiry = 0.0;
248 TransportSecurityState::DomainState domain_state;
249 216
250 if (!parsed->GetBoolean(kIncludeSubdomains, 217 if (!parsed->GetBoolean(kIncludeSubdomains,
251 &domain_state.include_subdomains) || 218 &include_subdomains) ||
252 !parsed->GetString(kMode, &mode_string) || 219 !parsed->GetString(kMode, &mode_string) ||
253 !parsed->GetDouble(kExpiry, &expiry)) { 220 !parsed->GetDouble(kExpiry, &expiry_double)) {
254 LOG(WARNING) << "Could not parse some elements of entry " << *i 221 LOG(WARNING) << "Could not parse some elements of entry " << *i
255 << "; skipping entry"; 222 << "; skipping entry";
256 continue; 223 continue;
257 } 224 }
258 225
259 // Don't fail if this key is not present. 226 if (parsed->GetDouble(kCreated, &created_double)) {
260 parsed->GetDouble(kDynamicSPKIHashesExpiry, 227 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 { 228 } else {
292 // We're migrating an old entry with no creation date. Make sure we 229 // We're migrating an old entry with no creation date. Make sure we
293 // write the new date back in a reasonable time frame. 230 // write the new date back in a reasonable time frame.
294 dirtied = true; 231 dirtied = true;
295 domain_state.created = base::Time::Now(); 232 created = base::Time::Now();
296 } 233 }
297 234
298 if (domain_state.upgrade_expiry <= current_time && 235 if (mode_string == kForceHTTPS || mode_string == kStrict) {
299 domain_state.dynamic_spki_hashes_expiry <= current_time) { 236 std::string hashed_host = ExternalStringToHashedDomain(*i);
300 // Make sure we dirty the state if we drop an entry. 237 base::Time expiry = base::Time::FromDoubleT(expiry_double);
301 dirtied = true; 238 if (expiry > current_time)
302 continue; 239 state->AddHSTSHashedHost(hashed_host, created, expiry,
240 include_subdomains);
241 else
242 dirtied = true;
303 } 243 }
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 } 244 }
316 245
317 *dirty = dirtied; 246 *dirty = dirtied;
318 return true; 247 return true;
319 } 248 }
320 249
321 void TransportSecurityPersister::CompleteLoad(const std::string& state) { 250 void TransportSecurityPersister::CompleteLoad(const std::string& state) {
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323 252
324 bool dirty = false; 253 bool dirty = false;
325 if (!LoadEntries(state, &dirty)) { 254 if (!LoadEntries(state, &dirty)) {
326 LOG(ERROR) << "Failed to deserialize state: " << state; 255 LOG(ERROR) << "Failed to deserialize state: " << state;
327 return; 256 return;
328 } 257 }
329 if (dirty) 258 if (dirty)
330 StateIsDirty(transport_security_state_); 259 StateIsDirty(transport_security_state_);
331 } 260 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698