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