OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/sqlite_origin_bound_cert_store.h" | 5 #include "chrome/browser/net/sqlite_origin_bound_cert_store.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "base/threading/thread.h" | 15 #include "base/threading/thread.h" |
16 #include "base/threading/thread_restrictions.h" | 16 #include "base/threading/thread_restrictions.h" |
17 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" | 17 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" |
18 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
19 #include "net/base/origin_bound_cert_type.h" | |
19 #include "sql/meta_table.h" | 20 #include "sql/meta_table.h" |
20 #include "sql/statement.h" | 21 #include "sql/statement.h" |
21 #include "sql/transaction.h" | 22 #include "sql/transaction.h" |
22 | 23 |
23 using content::BrowserThread; | 24 using content::BrowserThread; |
24 | 25 |
25 // This class is designed to be shared between any calling threads and the | 26 // This class is designed to be shared between any calling threads and the |
26 // database thread. It batches operations and commits them on a timer. | 27 // database thread. It batches operations and commits them on a timer. |
27 class SQLiteOriginBoundCertStore::Backend | 28 class SQLiteOriginBoundCertStore::Backend |
28 : public base::RefCountedThreadSafe<SQLiteOriginBoundCertStore::Backend> { | 29 : public base::RefCountedThreadSafe<SQLiteOriginBoundCertStore::Backend> { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 PendingOperationsList::size_type num_pending_; | 109 PendingOperationsList::size_type num_pending_; |
109 // True if the persistent store should be deleted upon destruction. | 110 // True if the persistent store should be deleted upon destruction. |
110 bool clear_local_state_on_exit_; | 111 bool clear_local_state_on_exit_; |
111 // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|. | 112 // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|. |
112 base::Lock lock_; | 113 base::Lock lock_; |
113 | 114 |
114 DISALLOW_COPY_AND_ASSIGN(Backend); | 115 DISALLOW_COPY_AND_ASSIGN(Backend); |
115 }; | 116 }; |
116 | 117 |
117 // Version number of the database. | 118 // Version number of the database. |
118 static const int kCurrentVersionNumber = 1; | 119 static const int kCurrentVersionNumber = 2; |
119 static const int kCompatibleVersionNumber = 1; | 120 static const int kCompatibleVersionNumber = 1; |
120 | 121 |
121 namespace { | 122 namespace { |
122 | 123 |
123 // Initializes the certs table, returning true on success. | 124 // Initializes the certs table, returning true on success. |
124 bool InitTable(sql::Connection* db) { | 125 bool InitTable(sql::Connection* db) { |
125 if (!db->DoesTableExist("origin_bound_certs")) { | 126 if (!db->DoesTableExist("origin_bound_certs")) { |
126 if (!db->Execute("CREATE TABLE origin_bound_certs (" | 127 if (!db->Execute("CREATE TABLE origin_bound_certs (" |
127 "origin TEXT NOT NULL UNIQUE PRIMARY KEY," | 128 "origin TEXT NOT NULL UNIQUE PRIMARY KEY," |
128 "private_key BLOB NOT NULL," | 129 "private_key BLOB NOT NULL," |
129 "cert BLOB NOT NULL)")) | 130 "cert BLOB NOT NULL," |
131 "cert_type INTEGER DEFAULT 1)")) | |
wtc
2011/11/30 23:23:40
Nit: it seems better to put cert_type before priva
mattm
2011/12/02 01:55:59
Could probably do that since the selects and such
wtc
2011/12/02 22:06:59
I didn't realize an upgraded db has to add a new c
| |
130 return false; | 132 return false; |
131 } | 133 } |
132 | 134 |
133 return true; | 135 return true; |
134 } | 136 } |
135 | 137 |
136 } // namespace | 138 } // namespace |
137 | 139 |
138 bool SQLiteOriginBoundCertStore::Backend::Load( | 140 bool SQLiteOriginBoundCertStore::Backend::Load( |
139 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*>* certs) { | 141 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*>* certs) { |
(...skipping 21 matching lines...) Expand all Loading... | |
161 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { | 163 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { |
162 NOTREACHED() << "Unable to open cert DB."; | 164 NOTREACHED() << "Unable to open cert DB."; |
163 db_.reset(); | 165 db_.reset(); |
164 return false; | 166 return false; |
165 } | 167 } |
166 | 168 |
167 db_->Preload(); | 169 db_->Preload(); |
168 | 170 |
169 // Slurp all the certs into the out-vector. | 171 // Slurp all the certs into the out-vector. |
170 sql::Statement smt(db_->GetUniqueStatement( | 172 sql::Statement smt(db_->GetUniqueStatement( |
171 "SELECT origin, private_key, cert FROM origin_bound_certs")); | 173 "SELECT origin, private_key, cert, cert_type FROM origin_bound_certs")); |
172 if (!smt) { | 174 if (!smt) { |
173 NOTREACHED() << "select statement prep failed"; | 175 NOTREACHED() << "select statement prep failed"; |
174 db_.reset(); | 176 db_.reset(); |
175 return false; | 177 return false; |
176 } | 178 } |
177 | 179 |
178 while (smt.Step()) { | 180 while (smt.Step()) { |
179 std::string private_key_from_db, cert_from_db; | 181 std::string private_key_from_db, cert_from_db; |
180 smt.ColumnBlobAsString(1, &private_key_from_db); | 182 smt.ColumnBlobAsString(1, &private_key_from_db); |
181 smt.ColumnBlobAsString(2, &cert_from_db); | 183 smt.ColumnBlobAsString(2, &cert_from_db); |
182 scoped_ptr<net::DefaultOriginBoundCertStore::OriginBoundCert> cert( | 184 scoped_ptr<net::DefaultOriginBoundCertStore::OriginBoundCert> cert( |
183 new net::DefaultOriginBoundCertStore::OriginBoundCert( | 185 new net::DefaultOriginBoundCertStore::OriginBoundCert( |
184 smt.ColumnString(0), // origin | 186 smt.ColumnString(0), // origin |
187 static_cast<net::OriginBoundCertType>(smt.ColumnInt(3)), | |
185 private_key_from_db, | 188 private_key_from_db, |
186 cert_from_db)); | 189 cert_from_db)); |
187 certs->push_back(cert.release()); | 190 certs->push_back(cert.release()); |
188 } | 191 } |
189 | 192 |
190 return true; | 193 return true; |
191 } | 194 } |
192 | 195 |
193 bool SQLiteOriginBoundCertStore::Backend::EnsureDatabaseVersion() { | 196 bool SQLiteOriginBoundCertStore::Backend::EnsureDatabaseVersion() { |
194 // Version check. | 197 // Version check. |
195 if (!meta_table_.Init( | 198 if (!meta_table_.Init( |
196 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { | 199 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { |
197 return false; | 200 return false; |
198 } | 201 } |
199 | 202 |
200 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { | 203 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { |
201 LOG(WARNING) << "Origin bound cert database is too new."; | 204 LOG(WARNING) << "Origin bound cert database is too new."; |
202 return false; | 205 return false; |
203 } | 206 } |
204 | 207 |
205 int cur_version = meta_table_.GetVersionNumber(); | 208 int cur_version = meta_table_.GetVersionNumber(); |
209 if (cur_version == 1) { | |
210 sql::Transaction transaction(db_.get()); | |
211 if (!transaction.Begin()) | |
212 return false; | |
213 if (!db_->Execute("ALTER TABLE origin_bound_certs ADD COLUMN cert_type " | |
214 "INTEGER DEFAULT 1")) { | |
215 LOG(WARNING) << "Unable to update origin bound cert database to " | |
216 << "version 2."; | |
217 return false; | |
218 } | |
219 ++cur_version; | |
220 meta_table_.SetVersionNumber(cur_version); | |
221 meta_table_.SetCompatibleVersionNumber( | |
222 std::min(cur_version, kCompatibleVersionNumber)); | |
223 transaction.Commit(); | |
224 } | |
206 | 225 |
207 // Put future migration cases here. | 226 // Put future migration cases here. |
208 | 227 |
209 // When the version is too old, we just try to continue anyway, there should | 228 // When the version is too old, we just try to continue anyway, there should |
210 // not be a released product that makes a database too old for us to handle. | 229 // not be a released product that makes a database too old for us to handle. |
211 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << | 230 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << |
212 "Origin bound cert database version " << cur_version << | 231 "Origin bound cert database version " << cur_version << |
213 " is too old to handle."; | 232 " is too old to handle."; |
214 | 233 |
215 return true; | 234 return true; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 base::AutoLock locked(lock_); | 284 base::AutoLock locked(lock_); |
266 pending_.swap(ops); | 285 pending_.swap(ops); |
267 num_pending_ = 0; | 286 num_pending_ = 0; |
268 } | 287 } |
269 | 288 |
270 // Maybe an old timer fired or we are already Close()'ed. | 289 // Maybe an old timer fired or we are already Close()'ed. |
271 if (!db_.get() || ops.empty()) | 290 if (!db_.get() || ops.empty()) |
272 return; | 291 return; |
273 | 292 |
274 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, | 293 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, |
275 "INSERT INTO origin_bound_certs (origin, private_key, cert) " | 294 "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type) " |
276 "VALUES (?,?,?)")); | 295 "VALUES (?,?,?,?)")); |
277 if (!add_smt) { | 296 if (!add_smt) { |
278 NOTREACHED(); | 297 NOTREACHED(); |
279 return; | 298 return; |
280 } | 299 } |
281 | 300 |
282 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, | 301 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, |
283 "DELETE FROM origin_bound_certs WHERE origin=?")); | 302 "DELETE FROM origin_bound_certs WHERE origin=?")); |
284 if (!del_smt) { | 303 if (!del_smt) { |
285 NOTREACHED(); | 304 NOTREACHED(); |
286 return; | 305 return; |
287 } | 306 } |
288 | 307 |
289 sql::Transaction transaction(db_.get()); | 308 sql::Transaction transaction(db_.get()); |
290 if (!transaction.Begin()) { | 309 if (!transaction.Begin()) { |
291 NOTREACHED(); | 310 NOTREACHED(); |
292 return; | 311 return; |
293 } | 312 } |
294 for (PendingOperationsList::iterator it = ops.begin(); | 313 for (PendingOperationsList::iterator it = ops.begin(); |
295 it != ops.end(); ++it) { | 314 it != ops.end(); ++it) { |
296 // Free the certs as we commit them to the database. | 315 // Free the certs as we commit them to the database. |
297 scoped_ptr<PendingOperation> po(*it); | 316 scoped_ptr<PendingOperation> po(*it); |
298 switch (po->op()) { | 317 switch (po->op()) { |
299 case PendingOperation::CERT_ADD: { | 318 case PendingOperation::CERT_ADD: { |
300 add_smt.Reset(); | 319 add_smt.Reset(); |
301 add_smt.BindString(0, po->cert().origin()); | 320 add_smt.BindString(0, po->cert().origin()); |
302 const std::string& private_key = po->cert().private_key(); | 321 const std::string& private_key = po->cert().private_key(); |
303 add_smt.BindBlob(1, private_key.data(), private_key.size()); | 322 add_smt.BindBlob(1, private_key.data(), private_key.size()); |
304 const std::string& cert = po->cert().cert(); | 323 const std::string& cert = po->cert().cert(); |
305 add_smt.BindBlob(2, cert.data(), cert.size()); | 324 add_smt.BindBlob(2, cert.data(), cert.size()); |
325 add_smt.BindInt(3, po->cert().type()); | |
306 if (!add_smt.Run()) | 326 if (!add_smt.Run()) |
307 NOTREACHED() << "Could not add an origin bound cert to the DB."; | 327 NOTREACHED() << "Could not add an origin bound cert to the DB."; |
308 break; | 328 break; |
309 } | 329 } |
310 case PendingOperation::CERT_DELETE: | 330 case PendingOperation::CERT_DELETE: |
311 del_smt.Reset(); | 331 del_smt.Reset(); |
312 del_smt.BindString(0, po->cert().origin()); | 332 del_smt.BindString(0, po->cert().origin()); |
313 if (!del_smt.Run()) | 333 if (!del_smt.Run()) |
314 NOTREACHED() << "Could not delete an origin bound cert from the DB."; | 334 NOTREACHED() << "Could not delete an origin bound cert from the DB."; |
315 break; | 335 break; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 if (backend_.get()) | 417 if (backend_.get()) |
398 backend_->SetClearLocalStateOnExit(clear_local_state); | 418 backend_->SetClearLocalStateOnExit(clear_local_state); |
399 } | 419 } |
400 | 420 |
401 void SQLiteOriginBoundCertStore::Flush(Task* completion_task) { | 421 void SQLiteOriginBoundCertStore::Flush(Task* completion_task) { |
402 if (backend_.get()) | 422 if (backend_.get()) |
403 backend_->Flush(completion_task); | 423 backend_->Flush(completion_task); |
404 else if (completion_task) | 424 else if (completion_task) |
405 MessageLoop::current()->PostTask(FROM_HERE, completion_task); | 425 MessageLoop::current()->PostTask(FROM_HERE, completion_task); |
406 } | 426 } |
OLD | NEW |