Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / extras / sqlite / sqlite_channel_id_store_unittest.cc
blobc06a42fa0f82c748bd3da8c857313326829ccfee
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
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "crypto/ec_private_key.h"
14 #include "net/base/test_data_directory.h"
15 #include "net/cert/asn1_util.h"
16 #include "net/extras/sqlite/sqlite_channel_id_store.h"
17 #include "net/ssl/channel_id_service.h"
18 #include "net/ssl/ssl_client_cert_type.h"
19 #include "net/test/cert_test_util.h"
20 #include "net/test/channel_id_test_util.h"
21 #include "sql/statement.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace net {
26 const base::FilePath::CharType kTestChannelIDFilename[] =
27 FILE_PATH_LITERAL("ChannelID");
29 class SQLiteChannelIDStoreTest : public testing::Test {
30 public:
31 void Load(ScopedVector<DefaultChannelIDStore::ChannelID>* channel_ids) {
32 base::RunLoop run_loop;
33 store_->Load(base::Bind(&SQLiteChannelIDStoreTest::OnLoaded,
34 base::Unretained(this),
35 &run_loop));
36 run_loop.Run();
37 channel_ids->swap(channel_ids_);
38 channel_ids_.clear();
41 void OnLoaded(
42 base::RunLoop* run_loop,
43 scoped_ptr<ScopedVector<DefaultChannelIDStore::ChannelID> > channel_ids) {
44 channel_ids_.swap(*channel_ids);
45 run_loop->Quit();
48 protected:
49 static void ReadTestKeyAndCert(std::string* key_data,
50 std::string* cert_data,
51 scoped_ptr<crypto::ECPrivateKey>* key) {
52 base::FilePath key_path =
53 GetTestCertsDirectory().AppendASCII("unittest.originbound.key.der");
54 base::FilePath cert_path =
55 GetTestCertsDirectory().AppendASCII("unittest.originbound.der");
56 ASSERT_TRUE(base::ReadFileToString(key_path, key_data));
57 ASSERT_TRUE(base::ReadFileToString(cert_path, cert_data));
58 std::vector<uint8> private_key(key_data->size());
59 memcpy(vector_as_array(&private_key), key_data->data(), key_data->size());
60 base::StringPiece spki;
61 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(*cert_data, &spki));
62 std::vector<uint8> public_key(spki.size());
63 memcpy(vector_as_array(&public_key), spki.data(), spki.size());
64 key->reset(crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
65 ChannelIDService::kEPKIPassword, private_key, public_key));
68 static base::Time GetTestCertExpirationTime() {
69 // Cert expiration time from 'openssl asn1parse -inform der -in
70 // unittest.originbound.der':
71 // UTCTIME :160507022239Z
72 // base::Time::FromUTCExploded can't generate values past 2038 on 32-bit
73 // linux, so we use the raw value here.
74 base::Time::Exploded exploded_time;
75 exploded_time.year = 2016;
76 exploded_time.month = 5;
77 exploded_time.day_of_week = 0; // Unused.
78 exploded_time.day_of_month = 7;
79 exploded_time.hour = 2;
80 exploded_time.minute = 22;
81 exploded_time.second = 39;
82 exploded_time.millisecond = 0;
83 return base::Time::FromUTCExploded(exploded_time);
86 static base::Time GetTestCertCreationTime() {
87 // UTCTIME :150508022239Z
88 base::Time::Exploded exploded_time;
89 exploded_time.year = 2015;
90 exploded_time.month = 5;
91 exploded_time.day_of_week = 0; // Unused.
92 exploded_time.day_of_month = 8;
93 exploded_time.hour = 2;
94 exploded_time.minute = 22;
95 exploded_time.second = 39;
96 exploded_time.millisecond = 0;
97 return base::Time::FromUTCExploded(exploded_time);
100 void SetUp() override {
101 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
102 store_ = new SQLiteChannelIDStore(
103 temp_dir_.path().Append(kTestChannelIDFilename),
104 base::ThreadTaskRunnerHandle::Get());
105 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
106 Load(&channel_ids);
107 ASSERT_EQ(0u, channel_ids.size());
108 // Make sure the store gets written at least once.
109 google_key_.reset(crypto::ECPrivateKey::Create());
110 store_->AddChannelID(DefaultChannelIDStore::ChannelID(
111 "google.com", base::Time::FromInternalValue(1),
112 make_scoped_ptr(google_key_->Copy())));
115 base::ScopedTempDir temp_dir_;
116 scoped_refptr<SQLiteChannelIDStore> store_;
117 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids_;
118 scoped_ptr<crypto::ECPrivateKey> google_key_;
121 // Test if data is stored as expected in the SQLite database.
122 TEST_F(SQLiteChannelIDStoreTest, TestPersistence) {
123 scoped_ptr<crypto::ECPrivateKey> foo_key(crypto::ECPrivateKey::Create());
124 store_->AddChannelID(DefaultChannelIDStore::ChannelID(
125 "foo.com", base::Time::FromInternalValue(3),
126 make_scoped_ptr(foo_key->Copy())));
128 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
129 // Replace the store effectively destroying the current one and forcing it
130 // to write its data to disk. Then we can see if after loading it again it
131 // is still there.
132 store_ = NULL;
133 // Make sure we wait until the destructor has run.
134 base::RunLoop().RunUntilIdle();
135 store_ =
136 new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
137 base::ThreadTaskRunnerHandle::Get());
139 // Reload and test for persistence
140 Load(&channel_ids);
141 ASSERT_EQ(2U, channel_ids.size());
142 DefaultChannelIDStore::ChannelID* goog_channel_id;
143 DefaultChannelIDStore::ChannelID* foo_channel_id;
144 if (channel_ids[0]->server_identifier() == "google.com") {
145 goog_channel_id = channel_ids[0];
146 foo_channel_id = channel_ids[1];
147 } else {
148 goog_channel_id = channel_ids[1];
149 foo_channel_id = channel_ids[0];
151 ASSERT_EQ("google.com", goog_channel_id->server_identifier());
152 EXPECT_TRUE(KeysEqual(google_key_.get(), goog_channel_id->key()));
153 ASSERT_EQ(1, goog_channel_id->creation_time().ToInternalValue());
154 ASSERT_EQ("foo.com", foo_channel_id->server_identifier());
155 EXPECT_TRUE(KeysEqual(foo_key.get(), foo_channel_id->key()));
156 ASSERT_EQ(3, foo_channel_id->creation_time().ToInternalValue());
158 // Now delete the keypair and check persistence again.
159 store_->DeleteChannelID(*channel_ids[0]);
160 store_->DeleteChannelID(*channel_ids[1]);
161 store_ = NULL;
162 // Make sure we wait until the destructor has run.
163 base::RunLoop().RunUntilIdle();
164 channel_ids.clear();
165 store_ =
166 new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
167 base::ThreadTaskRunnerHandle::Get());
169 // Reload and check if the keypair has been removed.
170 Load(&channel_ids);
171 ASSERT_EQ(0U, channel_ids.size());
172 // Close the store.
173 store_ = NULL;
174 // Make sure we wait until the destructor has run.
175 base::RunLoop().RunUntilIdle();
178 // Test if data is stored as expected in the SQLite database.
179 TEST_F(SQLiteChannelIDStoreTest, TestDeleteAll) {
180 store_->AddChannelID(DefaultChannelIDStore::ChannelID(
181 "foo.com", base::Time::FromInternalValue(3),
182 make_scoped_ptr(crypto::ECPrivateKey::Create())));
184 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
185 // Replace the store effectively destroying the current one and forcing it
186 // to write its data to disk. Then we can see if after loading it again it
187 // is still there.
188 store_ = NULL;
189 // Make sure we wait until the destructor has run.
190 base::RunLoop().RunUntilIdle();
191 store_ =
192 new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
193 base::ThreadTaskRunnerHandle::Get());
195 // Reload and test for persistence
196 Load(&channel_ids);
197 ASSERT_EQ(2U, channel_ids.size());
198 // DeleteAll except foo.com (shouldn't fail if one is missing either).
199 std::list<std::string> delete_server_identifiers;
200 delete_server_identifiers.push_back("google.com");
201 delete_server_identifiers.push_back("missing.com");
202 store_->DeleteAllInList(delete_server_identifiers);
204 // Now check persistence again.
205 store_ = NULL;
206 // Make sure we wait until the destructor has run.
207 base::RunLoop().RunUntilIdle();
208 channel_ids.clear();
209 store_ =
210 new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
211 base::ThreadTaskRunnerHandle::Get());
213 // Reload and check that only foo.com persisted in store.
214 Load(&channel_ids);
215 ASSERT_EQ(1U, channel_ids.size());
216 ASSERT_EQ("foo.com", channel_ids[0]->server_identifier());
217 // Close the store.
218 store_ = NULL;
219 // Make sure we wait until the destructor has run.
220 base::RunLoop().RunUntilIdle();
223 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV1) {
224 // Reset the store. We'll be using a different database for this test.
225 store_ = NULL;
227 base::FilePath v1_db_path(temp_dir_.path().AppendASCII("v1db"));
229 std::string key_data;
230 std::string cert_data;
231 scoped_ptr<crypto::ECPrivateKey> key;
232 ASSERT_NO_FATAL_FAILURE(ReadTestKeyAndCert(&key_data, &cert_data, &key));
234 // Create a version 1 database.
236 sql::Connection db;
237 ASSERT_TRUE(db.Open(v1_db_path));
238 ASSERT_TRUE(db.Execute(
239 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
240 "value LONGVARCHAR);"
241 "INSERT INTO \"meta\" VALUES('version','1');"
242 "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
243 "CREATE TABLE origin_bound_certs ("
244 "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
245 "private_key BLOB NOT NULL,cert BLOB NOT NULL);"));
247 sql::Statement add_smt(db.GetUniqueStatement(
248 "INSERT INTO origin_bound_certs (origin, private_key, cert) "
249 "VALUES (?,?,?)"));
250 add_smt.BindString(0, "google.com");
251 add_smt.BindBlob(1, key_data.data(), key_data.size());
252 add_smt.BindBlob(2, cert_data.data(), cert_data.size());
253 ASSERT_TRUE(add_smt.Run());
255 ASSERT_TRUE(db.Execute(
256 "INSERT INTO \"origin_bound_certs\" VALUES("
257 "'foo.com',X'AA',X'BB');"));
260 // Load and test the DB contents twice. First time ensures that we can use
261 // the updated values immediately. Second time ensures that the updated
262 // values are stored and read correctly on next load.
263 for (int i = 0; i < 2; ++i) {
264 SCOPED_TRACE(i);
266 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
267 store_ = new SQLiteChannelIDStore(v1_db_path,
268 base::ThreadTaskRunnerHandle::Get());
270 // Load the database. Because the existing v1 certs are implicitly of type
271 // RSA, which is unsupported, they're discarded.
272 Load(&channel_ids);
273 ASSERT_EQ(0U, channel_ids.size());
275 store_ = NULL;
276 base::RunLoop().RunUntilIdle();
278 // Verify the database version is updated.
280 sql::Connection db;
281 ASSERT_TRUE(db.Open(v1_db_path));
282 sql::Statement smt(db.GetUniqueStatement(
283 "SELECT value FROM meta WHERE key = \"version\""));
284 ASSERT_TRUE(smt.Step());
285 EXPECT_EQ(5, smt.ColumnInt(0));
286 EXPECT_FALSE(smt.Step());
291 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV2) {
292 // Reset the store. We'll be using a different database for this test.
293 store_ = NULL;
295 base::FilePath v2_db_path(temp_dir_.path().AppendASCII("v2db"));
297 std::string key_data;
298 std::string cert_data;
299 scoped_ptr<crypto::ECPrivateKey> key;
300 ASSERT_NO_FATAL_FAILURE(ReadTestKeyAndCert(&key_data, &cert_data, &key));
302 // Create a version 2 database.
304 sql::Connection db;
305 ASSERT_TRUE(db.Open(v2_db_path));
306 ASSERT_TRUE(db.Execute(
307 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
308 "value LONGVARCHAR);"
309 "INSERT INTO \"meta\" VALUES('version','2');"
310 "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
311 "CREATE TABLE origin_bound_certs ("
312 "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
313 "private_key BLOB NOT NULL,"
314 "cert BLOB NOT NULL,"
315 "cert_type INTEGER);"));
317 sql::Statement add_smt(db.GetUniqueStatement(
318 "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type) "
319 "VALUES (?,?,?,?)"));
320 add_smt.BindString(0, "google.com");
321 add_smt.BindBlob(1, key_data.data(), key_data.size());
322 add_smt.BindBlob(2, cert_data.data(), cert_data.size());
323 add_smt.BindInt64(3, 64);
324 ASSERT_TRUE(add_smt.Run());
326 // Malformed certs will be ignored and not migrated.
327 ASSERT_TRUE(db.Execute(
328 "INSERT INTO \"origin_bound_certs\" VALUES("
329 "'foo.com',X'AA',X'BB',64);"));
332 // Load and test the DB contents twice. First time ensures that we can use
333 // the updated values immediately. Second time ensures that the updated
334 // values are saved and read correctly on next load.
335 for (int i = 0; i < 2; ++i) {
336 SCOPED_TRACE(i);
338 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
339 store_ = new SQLiteChannelIDStore(v2_db_path,
340 base::ThreadTaskRunnerHandle::Get());
342 // Load the database and ensure the certs can be read.
343 Load(&channel_ids);
344 ASSERT_EQ(1U, channel_ids.size());
346 ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
347 ASSERT_EQ(GetTestCertCreationTime(), channel_ids[0]->creation_time());
348 EXPECT_TRUE(KeysEqual(key.get(), channel_ids[0]->key()));
350 store_ = NULL;
351 // Make sure we wait until the destructor has run.
352 base::RunLoop().RunUntilIdle();
354 // Verify the database version is updated.
356 sql::Connection db;
357 ASSERT_TRUE(db.Open(v2_db_path));
358 sql::Statement smt(db.GetUniqueStatement(
359 "SELECT value FROM meta WHERE key = \"version\""));
360 ASSERT_TRUE(smt.Step());
361 EXPECT_EQ(5, smt.ColumnInt(0));
362 EXPECT_FALSE(smt.Step());
367 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV3) {
368 // Reset the store. We'll be using a different database for this test.
369 store_ = NULL;
371 base::FilePath v3_db_path(temp_dir_.path().AppendASCII("v3db"));
373 std::string key_data;
374 std::string cert_data;
375 scoped_ptr<crypto::ECPrivateKey> key;
376 ASSERT_NO_FATAL_FAILURE(ReadTestKeyAndCert(&key_data, &cert_data, &key));
378 // Create a version 3 database.
380 sql::Connection db;
381 ASSERT_TRUE(db.Open(v3_db_path));
382 ASSERT_TRUE(db.Execute(
383 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
384 "value LONGVARCHAR);"
385 "INSERT INTO \"meta\" VALUES('version','3');"
386 "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
387 "CREATE TABLE origin_bound_certs ("
388 "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
389 "private_key BLOB NOT NULL,"
390 "cert BLOB NOT NULL,"
391 "cert_type INTEGER,"
392 "expiration_time INTEGER);"));
394 sql::Statement add_smt(db.GetUniqueStatement(
395 "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type, "
396 "expiration_time) VALUES (?,?,?,?,?)"));
397 add_smt.BindString(0, "google.com");
398 add_smt.BindBlob(1, key_data.data(), key_data.size());
399 add_smt.BindBlob(2, cert_data.data(), cert_data.size());
400 add_smt.BindInt64(3, 64);
401 add_smt.BindInt64(4, 1000);
402 ASSERT_TRUE(add_smt.Run());
404 // Malformed certs will be ignored and not migrated.
405 ASSERT_TRUE(db.Execute(
406 "INSERT INTO \"origin_bound_certs\" VALUES("
407 "'foo.com',X'AA',X'BB',64,2000);"));
410 // Load and test the DB contents twice. First time ensures that we can use
411 // the updated values immediately. Second time ensures that the updated
412 // values are saved and read correctly on next load.
413 for (int i = 0; i < 2; ++i) {
414 SCOPED_TRACE(i);
416 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
417 store_ = new SQLiteChannelIDStore(v3_db_path,
418 base::ThreadTaskRunnerHandle::Get());
420 // Load the database and ensure the certs can be read.
421 Load(&channel_ids);
422 ASSERT_EQ(1U, channel_ids.size());
424 ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
425 ASSERT_EQ(GetTestCertCreationTime(), channel_ids[0]->creation_time());
426 EXPECT_TRUE(KeysEqual(key.get(), channel_ids[0]->key()));
428 store_ = NULL;
429 // Make sure we wait until the destructor has run.
430 base::RunLoop().RunUntilIdle();
432 // Verify the database version is updated.
434 sql::Connection db;
435 ASSERT_TRUE(db.Open(v3_db_path));
436 sql::Statement smt(db.GetUniqueStatement(
437 "SELECT value FROM meta WHERE key = \"version\""));
438 ASSERT_TRUE(smt.Step());
439 EXPECT_EQ(5, smt.ColumnInt(0));
440 EXPECT_FALSE(smt.Step());
445 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV4) {
446 // Reset the store. We'll be using a different database for this test.
447 store_ = NULL;
449 base::FilePath v4_db_path(temp_dir_.path().AppendASCII("v4db"));
451 std::string key_data;
452 std::string cert_data;
453 scoped_ptr<crypto::ECPrivateKey> key;
454 ASSERT_NO_FATAL_FAILURE(ReadTestKeyAndCert(&key_data, &cert_data, &key));
456 // Create a version 4 database.
458 sql::Connection db;
459 ASSERT_TRUE(db.Open(v4_db_path));
460 ASSERT_TRUE(db.Execute(
461 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
462 "value LONGVARCHAR);"
463 "INSERT INTO \"meta\" VALUES('version','4');"
464 "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
465 "CREATE TABLE origin_bound_certs ("
466 "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
467 "private_key BLOB NOT NULL,"
468 "cert BLOB NOT NULL,"
469 "cert_type INTEGER,"
470 "expiration_time INTEGER,"
471 "creation_time INTEGER);"));
473 sql::Statement add_smt(db.GetUniqueStatement(
474 "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type, "
475 "expiration_time, creation_time) VALUES (?,?,?,?,?,?)"));
476 add_smt.BindString(0, "google.com");
477 add_smt.BindBlob(1, key_data.data(), key_data.size());
478 add_smt.BindBlob(2, cert_data.data(), cert_data.size());
479 add_smt.BindInt64(3, 64);
480 add_smt.BindInt64(4, 1000);
481 add_smt.BindInt64(5, GetTestCertCreationTime().ToInternalValue());
482 ASSERT_TRUE(add_smt.Run());
484 // Add an RSA cert to the db. This cert should be ignored in the migration.
485 add_smt.Clear();
486 add_smt.Assign(db.GetUniqueStatement(
487 "INSERT INTO origin_bound_certs "
488 "(origin, private_key, cert, cert_type, expiration_time, creation_time)"
489 " VALUES (?,?,?,?,?,?)"));
490 add_smt.BindString(0, "foo.com");
491 add_smt.BindBlob(1, key_data.data(), key_data.size());
492 add_smt.BindBlob(2, cert_data.data(), cert_data.size());
493 add_smt.BindInt64(3, 1);
494 add_smt.BindInt64(4, GetTestCertExpirationTime().ToInternalValue());
495 add_smt.BindInt64(5, base::Time::Now().ToInternalValue());
496 ASSERT_TRUE(add_smt.Run());
498 // Malformed certs will be ignored and not migrated.
499 ASSERT_TRUE(db.Execute(
500 "INSERT INTO \"origin_bound_certs\" VALUES("
501 "'bar.com',X'AA',X'BB',64,2000,3000);"));
504 // Load and test the DB contents twice. First time ensures that we can use
505 // the updated values immediately. Second time ensures that the updated
506 // values are saved and read correctly on next load.
507 for (int i = 0; i < 2; ++i) {
508 SCOPED_TRACE(i);
510 ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
511 store_ = new SQLiteChannelIDStore(v4_db_path,
512 base::ThreadTaskRunnerHandle::Get());
514 // Load the database and ensure the certs can be read.
515 Load(&channel_ids);
516 ASSERT_EQ(1U, channel_ids.size());
518 ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
519 ASSERT_EQ(GetTestCertCreationTime(), channel_ids[0]->creation_time());
520 EXPECT_TRUE(KeysEqual(key.get(), channel_ids[0]->key()));
522 store_ = NULL;
523 // Make sure we wait until the destructor has run.
524 base::RunLoop().RunUntilIdle();
526 // Verify the database version is updated.
528 sql::Connection db;
529 ASSERT_TRUE(db.Open(v4_db_path));
530 sql::Statement smt(db.GetUniqueStatement(
531 "SELECT value FROM meta WHERE key = \"version\""));
532 ASSERT_TRUE(smt.Step());
533 EXPECT_EQ(5, smt.ColumnInt(0));
534 EXPECT_FALSE(smt.Step());
539 } // namespace net