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