Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "net/extras/sqlite/sqlite_channel_id_store.h" | 5 #include "net/extras/sqlite/sqlite_channel_id_store.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 #include "net/ssl/ssl_client_cert_type.h" | 26 #include "net/ssl/ssl_client_cert_type.h" |
| 27 #include "sql/error_delegate_util.h" | 27 #include "sql/error_delegate_util.h" |
| 28 #include "sql/meta_table.h" | 28 #include "sql/meta_table.h" |
| 29 #include "sql/statement.h" | 29 #include "sql/statement.h" |
| 30 #include "sql/transaction.h" | 30 #include "sql/transaction.h" |
| 31 #include "url/gurl.h" | 31 #include "url/gurl.h" |
| 32 | 32 |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 // Version number of the database. | 35 // Version number of the database. |
| 36 const int kCurrentVersionNumber = 5; | 36 const int kCurrentVersionNumber = 6; |
| 37 const int kCompatibleVersionNumber = 5; | 37 const int kCompatibleVersionNumber = 6; |
| 38 | 38 |
| 39 } // namespace | 39 } // namespace |
| 40 | 40 |
| 41 namespace net { | 41 namespace net { |
| 42 | 42 |
| 43 // This class is designed to be shared between any calling threads and the | 43 // This class is designed to be shared between any calling threads and the |
| 44 // background task runner. It batches operations and commits them on a timer. | 44 // background task runner. It batches operations and commits them on a timer. |
| 45 class SQLiteChannelIDStore::Backend | 45 class SQLiteChannelIDStore::Backend |
| 46 : public base::RefCountedThreadSafe<SQLiteChannelIDStore::Backend> { | 46 : public base::RefCountedThreadSafe<SQLiteChannelIDStore::Backend> { |
| 47 public: | 47 public: |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 KillDatabase(); | 205 KillDatabase(); |
| 206 meta_table_.Reset(); | 206 meta_table_.Reset(); |
| 207 db_.reset(); | 207 db_.reset(); |
| 208 return; | 208 return; |
| 209 } | 209 } |
| 210 | 210 |
| 211 db_->Preload(); | 211 db_->Preload(); |
| 212 | 212 |
| 213 // Slurp all the certs into the out-vector. | 213 // Slurp all the certs into the out-vector. |
| 214 sql::Statement smt(db_->GetUniqueStatement( | 214 sql::Statement smt(db_->GetUniqueStatement( |
| 215 "SELECT host, private_key, public_key, creation_time FROM channel_id")); | 215 "SELECT host, private_key, creation_time FROM channel_id")); |
| 216 if (!smt.is_valid()) { | 216 if (!smt.is_valid()) { |
| 217 if (corruption_detected_) | 217 if (corruption_detected_) |
| 218 KillDatabase(); | 218 KillDatabase(); |
| 219 meta_table_.Reset(); | 219 meta_table_.Reset(); |
| 220 db_.reset(); | 220 db_.reset(); |
| 221 return; | 221 return; |
| 222 } | 222 } |
| 223 | 223 |
| 224 while (smt.Step()) { | 224 while (smt.Step()) { |
| 225 std::vector<uint8_t> private_key_from_db, public_key_from_db; | 225 std::vector<uint8_t> private_key_from_db; |
| 226 smt.ColumnBlobAsVector(1, &private_key_from_db); | 226 smt.ColumnBlobAsVector(1, &private_key_from_db); |
| 227 smt.ColumnBlobAsVector(2, &public_key_from_db); | |
| 228 std::unique_ptr<crypto::ECPrivateKey> key( | 227 std::unique_ptr<crypto::ECPrivateKey> key( |
| 229 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | 228 crypto::ECPrivateKey::CreateFromPrivateKeyInfo(private_key_from_db)); |
| 230 private_key_from_db, public_key_from_db)); | |
| 231 if (!key) | 229 if (!key) |
| 232 continue; | 230 continue; |
| 233 std::unique_ptr<DefaultChannelIDStore::ChannelID> channel_id( | 231 std::unique_ptr<DefaultChannelIDStore::ChannelID> channel_id( |
| 234 new DefaultChannelIDStore::ChannelID( | 232 new DefaultChannelIDStore::ChannelID( |
| 235 smt.ColumnString(0), // host | 233 smt.ColumnString(0), // host |
| 236 base::Time::FromInternalValue(smt.ColumnInt64(3)), std::move(key))); | 234 base::Time::FromInternalValue(smt.ColumnInt64(2)), std::move(key))); |
| 237 channel_ids->push_back(std::move(channel_id)); | 235 channel_ids->push_back(std::move(channel_id)); |
| 238 } | 236 } |
| 239 | 237 |
| 240 UMA_HISTOGRAM_COUNTS_10000( | 238 UMA_HISTOGRAM_COUNTS_10000( |
| 241 "DomainBoundCerts.DBLoadedCount", | 239 "DomainBoundCerts.DBLoadedCount", |
| 242 static_cast<base::HistogramBase::Sample>(channel_ids->size())); | 240 static_cast<base::HistogramBase::Sample>(channel_ids->size())); |
| 243 base::TimeDelta load_time = base::TimeTicks::Now() - start; | 241 base::TimeDelta load_time = base::TimeTicks::Now() - start; |
| 244 UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.DBLoadTime", | 242 UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.DBLoadTime", |
| 245 load_time, | 243 load_time, |
| 246 base::TimeDelta::FromMilliseconds(1), | 244 base::TimeDelta::FromMilliseconds(1), |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 return false; | 277 return false; |
| 280 } | 278 } |
| 281 } | 279 } |
| 282 | 280 |
| 283 // Migrate from previous versions to new version if possible | 281 // Migrate from previous versions to new version if possible |
| 284 if (cur_version >= 2 && cur_version <= 4) { | 282 if (cur_version >= 2 && cur_version <= 4) { |
| 285 sql::Statement statement(db_->GetUniqueStatement( | 283 sql::Statement statement(db_->GetUniqueStatement( |
| 286 "SELECT origin, cert, private_key, cert_type FROM origin_bound_certs")); | 284 "SELECT origin, cert, private_key, cert_type FROM origin_bound_certs")); |
| 287 sql::Statement insert_statement(db_->GetUniqueStatement( | 285 sql::Statement insert_statement(db_->GetUniqueStatement( |
| 288 "INSERT INTO channel_id (host, private_key, public_key, creation_time) " | 286 "INSERT INTO channel_id (host, private_key, public_key, creation_time) " |
| 289 "VALUES (?, ?, ?, ?)")); | 287 "VALUES (?, ?, \"\", ?)")); |
| 290 if (!statement.is_valid() || !insert_statement.is_valid()) { | 288 if (!statement.is_valid() || !insert_statement.is_valid()) { |
| 291 LOG(WARNING) << "Unable to update server bound cert database to " | 289 LOG(WARNING) << "Unable to update server bound cert database to " |
| 292 << "version 5."; | 290 << "version 6."; |
| 293 return false; | 291 return false; |
| 294 } | 292 } |
| 295 | 293 |
| 296 while (statement.Step()) { | 294 while (statement.Step()) { |
| 297 if (statement.ColumnInt64(3) != CLIENT_CERT_ECDSA_SIGN) | 295 if (statement.ColumnInt64(3) != CLIENT_CERT_ECDSA_SIGN) |
| 298 continue; | 296 continue; |
| 299 std::string origin = statement.ColumnString(0); | 297 std::string origin = statement.ColumnString(0); |
| 300 std::string cert_from_db; | 298 std::string cert_from_db; |
| 301 statement.ColumnBlobAsString(1, &cert_from_db); | 299 statement.ColumnBlobAsString(1, &cert_from_db); |
| 302 std::string private_key; | 300 std::vector<uint8_t> encrypted_private_key, private_key; |
| 303 statement.ColumnBlobAsString(2, &private_key); | 301 statement.ColumnBlobAsVector(2, &encrypted_private_key); |
| 302 std::unique_ptr<crypto::ECPrivateKey> key( | |
| 303 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | |
| 304 encrypted_private_key, std::vector<uint8_t>())); | |
| 305 if (!key || !key->ExportPrivateKey(&private_key)) { | |
| 306 LOG(WARNING) << "Unable to parse encrypted private key when migrating " | |
| 307 "Channel ID database to version 6."; | |
| 308 continue; | |
| 309 } | |
| 304 // Parse the cert and extract the real value and then update the DB. | 310 // Parse the cert and extract the real value and then update the DB. |
| 305 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromBytes( | 311 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromBytes( |
| 306 cert_from_db.data(), static_cast<int>(cert_from_db.size()))); | 312 cert_from_db.data(), static_cast<int>(cert_from_db.size()))); |
| 307 if (cert.get()) { | 313 if (cert.get()) { |
| 308 insert_statement.Reset(true); | 314 insert_statement.Reset(true); |
| 309 insert_statement.BindString(0, origin); | 315 insert_statement.BindString(0, origin); |
| 310 insert_statement.BindBlob(1, private_key.data(), | 316 insert_statement.BindBlob(1, private_key.data(), |
| 311 static_cast<int>(private_key.size())); | 317 static_cast<int>(private_key.size())); |
| 312 base::StringPiece spki; | 318 insert_statement.BindInt64(2, cert->valid_start().ToInternalValue()); |
| 313 if (!asn1::ExtractSPKIFromDERCert(cert_from_db, &spki)) { | |
| 314 LOG(WARNING) << "Unable to extract SPKI from cert when migrating " | |
| 315 "channel id database to version 5."; | |
| 316 return false; | |
| 317 } | |
| 318 insert_statement.BindBlob(2, spki.data(), | |
| 319 static_cast<int>(spki.size())); | |
| 320 insert_statement.BindInt64(3, cert->valid_start().ToInternalValue()); | |
| 321 if (!insert_statement.Run()) { | 319 if (!insert_statement.Run()) { |
| 322 LOG(WARNING) << "Unable to update channel id database to " | 320 LOG(WARNING) << "Unable to update channel id database to " |
| 323 << "version 5."; | 321 << "version 6."; |
| 324 return false; | 322 return false; |
| 325 } | 323 } |
| 326 } else { | 324 } else { |
| 327 // If there's a cert we can't parse, just leave it. It'll get replaced | 325 // If there's a cert we can't parse, just leave it. It'll get replaced |
| 328 // with a new one if we ever try to use it. | 326 // with a new one if we ever try to use it. |
| 329 LOG(WARNING) << "Error parsing cert for database upgrade for origin " | 327 LOG(WARNING) << "Error parsing cert for database upgrade for origin " |
| 330 << statement.ColumnString(0); | 328 << statement.ColumnString(0); |
| 331 } | 329 } |
| 332 } | 330 } |
| 331 } else if (cur_version >= 2 && cur_version <= 5) { | |
|
mattm
2017/04/04 22:44:24
Should be cur_version == 5? or maybe (cur_version
nharper
2017/04/04 23:01:31
Done.
| |
| 332 sql::Statement select( | |
| 333 db_->GetUniqueStatement("SELECT host, private_key FROM channel_id")); | |
| 334 sql::Statement update(db_->GetUniqueStatement( | |
| 335 "UPDATE channel_id SET private_key = ? WHERE host = ?")); | |
|
mattm
2017/04/04 22:44:24
Also set public_key to "" here?
nharper
2017/04/04 23:01:31
Done.
| |
| 336 if (!select.is_valid() || !update.is_valid()) { | |
| 337 LOG(WARNING) << "Invalid SQL statements to update Channel ID database to " | |
| 338 "version 6."; | |
| 339 return false; | |
| 340 } | |
| 341 | |
| 342 while (select.Step()) { | |
| 343 std::string host = select.ColumnString(0); | |
| 344 std::vector<uint8_t> encrypted_private_key, private_key; | |
| 345 select.ColumnBlobAsVector(1, &encrypted_private_key); | |
| 346 std::unique_ptr<crypto::ECPrivateKey> key( | |
| 347 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | |
| 348 encrypted_private_key, std::vector<uint8_t>())); | |
| 349 if (!key || !key->ExportPrivateKey(&private_key)) { | |
| 350 LOG(WARNING) << "Unable to parse encrypted private key when migrating " | |
| 351 "Channel ID database to version 6."; | |
| 352 continue; | |
| 353 } | |
| 354 update.Reset(true); | |
| 355 update.BindBlob(0, private_key.data(), | |
| 356 static_cast<int>(private_key.size())); | |
| 357 update.BindString(1, host); | |
| 358 if (!update.Run()) { | |
| 359 LOG(WARNING) << "UPDATE statement failed when updating Channel ID " | |
| 360 "database to version 6."; | |
| 361 return false; | |
| 362 } | |
| 363 } | |
| 333 } | 364 } |
| 334 | 365 |
| 335 if (cur_version < kCurrentVersionNumber) { | 366 if (cur_version < kCurrentVersionNumber) { |
| 336 sql::Statement statement( | 367 if (cur_version <= 4) { |
| 337 db_->GetUniqueStatement("DROP TABLE origin_bound_certs")); | 368 sql::Statement statement( |
| 338 if (!statement.Run()) { | 369 db_->GetUniqueStatement("DROP TABLE origin_bound_certs")); |
| 339 LOG(WARNING) << "Error dropping old origin_bound_certs table"; | 370 if (!statement.Run()) { |
| 340 return false; | 371 LOG(WARNING) << "Error dropping old origin_bound_certs table"; |
| 372 return false; | |
| 373 } | |
| 341 } | 374 } |
| 342 meta_table_.SetVersionNumber(kCurrentVersionNumber); | 375 meta_table_.SetVersionNumber(kCurrentVersionNumber); |
| 343 meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber); | 376 meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber); |
| 344 } | 377 } |
| 345 transaction.Commit(); | 378 transaction.Commit(); |
| 346 | 379 |
| 347 // Put future migration cases here. | 380 // Put future migration cases here. |
| 348 | 381 |
| 349 return true; | 382 return true; |
| 350 } | 383 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 pending_.swap(ops); | 500 pending_.swap(ops); |
| 468 num_pending_ = 0; | 501 num_pending_ = 0; |
| 469 } | 502 } |
| 470 | 503 |
| 471 // Maybe an old timer fired or we are already Close()'ed. | 504 // Maybe an old timer fired or we are already Close()'ed. |
| 472 if (!db_.get() || ops.empty()) | 505 if (!db_.get() || ops.empty()) |
| 473 return; | 506 return; |
| 474 | 507 |
| 475 sql::Statement add_statement(db_->GetCachedStatement( | 508 sql::Statement add_statement(db_->GetCachedStatement( |
| 476 SQL_FROM_HERE, | 509 SQL_FROM_HERE, |
| 477 "INSERT INTO channel_id (host, private_key, public_key, " | 510 "INSERT INTO channel_id (host, private_key, public_key, creation_time) " |
| 478 "creation_time) VALUES (?,?,?,?)")); | 511 "VALUES (?,?,\"\",?)")); |
| 479 if (!add_statement.is_valid()) | 512 if (!add_statement.is_valid()) |
| 480 return; | 513 return; |
| 481 | 514 |
| 482 sql::Statement del_statement(db_->GetCachedStatement( | 515 sql::Statement del_statement(db_->GetCachedStatement( |
| 483 SQL_FROM_HERE, "DELETE FROM channel_id WHERE host=?")); | 516 SQL_FROM_HERE, "DELETE FROM channel_id WHERE host=?")); |
| 484 if (!del_statement.is_valid()) | 517 if (!del_statement.is_valid()) |
| 485 return; | 518 return; |
| 486 | 519 |
| 487 sql::Transaction transaction(db_.get()); | 520 sql::Transaction transaction(db_.get()); |
| 488 if (!transaction.Begin()) | 521 if (!transaction.Begin()) |
| 489 return; | 522 return; |
| 490 | 523 |
| 491 for (PendingOperationsList::iterator it = ops.begin(); it != ops.end(); | 524 for (PendingOperationsList::iterator it = ops.begin(); it != ops.end(); |
| 492 ++it) { | 525 ++it) { |
| 493 // Free the certs as we commit them to the database. | 526 // Free the certs as we commit them to the database. |
| 494 std::unique_ptr<PendingOperation> po(*it); | 527 std::unique_ptr<PendingOperation> po(*it); |
| 495 switch (po->op()) { | 528 switch (po->op()) { |
| 496 case PendingOperation::CHANNEL_ID_ADD: { | 529 case PendingOperation::CHANNEL_ID_ADD: { |
| 497 add_statement.Reset(true); | 530 add_statement.Reset(true); |
| 498 add_statement.BindString(0, po->channel_id().server_identifier()); | 531 add_statement.BindString(0, po->channel_id().server_identifier()); |
| 499 std::vector<uint8_t> private_key, public_key; | 532 std::vector<uint8_t> private_key; |
| 500 if (!po->channel_id().key()->ExportEncryptedPrivateKey(&private_key)) | 533 if (!po->channel_id().key()->ExportPrivateKey(&private_key)) |
| 501 continue; | |
| 502 if (!po->channel_id().key()->ExportPublicKey(&public_key)) | |
| 503 continue; | 534 continue; |
| 504 add_statement.BindBlob( | 535 add_statement.BindBlob( |
| 505 1, private_key.data(), static_cast<int>(private_key.size())); | 536 1, private_key.data(), static_cast<int>(private_key.size())); |
| 506 add_statement.BindBlob(2, public_key.data(), | |
| 507 static_cast<int>(public_key.size())); | |
| 508 add_statement.BindInt64( | 537 add_statement.BindInt64( |
| 509 3, po->channel_id().creation_time().ToInternalValue()); | 538 2, po->channel_id().creation_time().ToInternalValue()); |
| 510 if (!add_statement.Run()) | 539 if (!add_statement.Run()) |
| 511 NOTREACHED() << "Could not add a server bound cert to the DB."; | 540 NOTREACHED() << "Could not add a server bound cert to the DB."; |
| 512 break; | 541 break; |
| 513 } | 542 } |
| 514 case PendingOperation::CHANNEL_ID_DELETE: | 543 case PendingOperation::CHANNEL_ID_DELETE: |
| 515 del_statement.Reset(true); | 544 del_statement.Reset(true); |
| 516 del_statement.BindString(0, po->channel_id().server_identifier()); | 545 del_statement.BindString(0, po->channel_id().server_identifier()); |
| 517 if (!del_statement.Run()) | 546 if (!del_statement.Run()) |
| 518 NOTREACHED() << "Could not delete a server bound cert from the DB."; | 547 NOTREACHED() << "Could not delete a server bound cert from the DB."; |
| 519 break; | 548 break; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 611 backend_->SetForceKeepSessionState(); | 640 backend_->SetForceKeepSessionState(); |
| 612 } | 641 } |
| 613 | 642 |
| 614 SQLiteChannelIDStore::~SQLiteChannelIDStore() { | 643 SQLiteChannelIDStore::~SQLiteChannelIDStore() { |
| 615 backend_->Close(); | 644 backend_->Close(); |
| 616 // We release our reference to the Backend, though it will probably still have | 645 // We release our reference to the Backend, though it will probably still have |
| 617 // a reference if the background task runner has not run Close() yet. | 646 // a reference if the background task runner has not run Close() yet. |
| 618 } | 647 } |
| 619 | 648 |
| 620 } // namespace net | 649 } // namespace net |
| OLD | NEW |