| 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 "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
| 7 #include "base/memory/ref_counted.h" | 7 #include "base/memory/ref_counted.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/scoped_temp_dir.h" | 9 #include "base/scoped_temp_dir.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "base/test/thread_test_helper.h" | 11 #include "base/test/thread_test_helper.h" |
| 12 #include "chrome/browser/net/sqlite_origin_bound_cert_store.h" | 12 #include "chrome/browser/net/sqlite_origin_bound_cert_store.h" |
| 13 #include "chrome/common/chrome_constants.h" | 13 #include "chrome/common/chrome_constants.h" |
| 14 #include "content/test/test_browser_thread.h" | 14 #include "content/test/test_browser_thread.h" |
| 15 #include "sql/statement.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 17 |
| 17 using content::BrowserThread; | 18 using content::BrowserThread; |
| 18 | 19 |
| 19 class SQLiteOriginBoundCertStoreTest : public testing::Test { | 20 class SQLiteOriginBoundCertStoreTest : public testing::Test { |
| 20 public: | 21 public: |
| 21 SQLiteOriginBoundCertStoreTest() | 22 SQLiteOriginBoundCertStoreTest() |
| 22 : db_thread_(BrowserThread::DB) { | 23 : db_thread_(BrowserThread::DB) { |
| 23 } | 24 } |
| 24 | 25 |
| 25 protected: | 26 protected: |
| 26 virtual void SetUp() { | 27 virtual void SetUp() { |
| 27 db_thread_.Start(); | 28 db_thread_.Start(); |
| 28 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 29 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 29 store_ = new SQLiteOriginBoundCertStore( | 30 store_ = new SQLiteOriginBoundCertStore( |
| 30 temp_dir_.path().Append(chrome::kOBCertFilename)); | 31 temp_dir_.path().Append(chrome::kOBCertFilename)); |
| 31 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs; | 32 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs; |
| 32 ASSERT_TRUE(store_->Load(&certs)); | 33 ASSERT_TRUE(store_->Load(&certs)); |
| 33 ASSERT_EQ(0u, certs.size()); | 34 ASSERT_EQ(0u, certs.size()); |
| 34 // Make sure the store gets written at least once. | 35 // Make sure the store gets written at least once. |
| 35 store_->AddOriginBoundCert( | 36 store_->AddOriginBoundCert( |
| 36 net::DefaultOriginBoundCertStore::OriginBoundCert( | 37 net::DefaultOriginBoundCertStore::OriginBoundCert( |
| 37 "https://encrypted.google.com:8443", "a", "b")); | 38 "https://encrypted.google.com:8443", |
| 39 net::CLIENT_CERT_RSA_SIGN, "a", "b")); |
| 38 } | 40 } |
| 39 | 41 |
| 40 content::TestBrowserThread db_thread_; | 42 content::TestBrowserThread db_thread_; |
| 41 ScopedTempDir temp_dir_; | 43 ScopedTempDir temp_dir_; |
| 42 scoped_refptr<SQLiteOriginBoundCertStore> store_; | 44 scoped_refptr<SQLiteOriginBoundCertStore> store_; |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 TEST_F(SQLiteOriginBoundCertStoreTest, KeepOnDestruction) { | 47 TEST_F(SQLiteOriginBoundCertStoreTest, KeepOnDestruction) { |
| 46 store_->SetClearLocalStateOnExit(false); | 48 store_->SetClearLocalStateOnExit(false); |
| 47 store_ = NULL; | 49 store_ = NULL; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 68 new base::ThreadTestHelper( | 70 new base::ThreadTestHelper( |
| 69 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); | 71 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); |
| 70 ASSERT_TRUE(helper->Run()); | 72 ASSERT_TRUE(helper->Run()); |
| 71 | 73 |
| 72 ASSERT_FALSE(file_util::PathExists( | 74 ASSERT_FALSE(file_util::PathExists( |
| 73 temp_dir_.path().Append(chrome::kOBCertFilename))); | 75 temp_dir_.path().Append(chrome::kOBCertFilename))); |
| 74 } | 76 } |
| 75 | 77 |
| 76 // Test if data is stored as expected in the SQLite database. | 78 // Test if data is stored as expected in the SQLite database. |
| 77 TEST_F(SQLiteOriginBoundCertStoreTest, TestPersistence) { | 79 TEST_F(SQLiteOriginBoundCertStoreTest, TestPersistence) { |
| 80 store_->AddOriginBoundCert( |
| 81 net::DefaultOriginBoundCertStore::OriginBoundCert( |
| 82 "https://www.google.com/", net::CLIENT_CERT_ECDSA_SIGN, "c", "d")); |
| 83 |
| 78 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs; | 84 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs; |
| 79 // Replace the store effectively destroying the current one and forcing it | 85 // Replace the store effectively destroying the current one and forcing it |
| 80 // to write it's data to disk. Then we can see if after loading it again it | 86 // to write it's data to disk. Then we can see if after loading it again it |
| 81 // is still there. | 87 // is still there. |
| 82 store_ = NULL; | 88 store_ = NULL; |
| 83 scoped_refptr<base::ThreadTestHelper> helper( | 89 scoped_refptr<base::ThreadTestHelper> helper( |
| 84 new base::ThreadTestHelper( | 90 new base::ThreadTestHelper( |
| 85 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); | 91 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); |
| 86 // Make sure we wait until the destructor has run. | 92 // Make sure we wait until the destructor has run. |
| 87 ASSERT_TRUE(helper->Run()); | 93 ASSERT_TRUE(helper->Run()); |
| 88 store_ = new SQLiteOriginBoundCertStore( | 94 store_ = new SQLiteOriginBoundCertStore( |
| 89 temp_dir_.path().Append(chrome::kOBCertFilename)); | 95 temp_dir_.path().Append(chrome::kOBCertFilename)); |
| 90 | 96 |
| 91 // Reload and test for persistence | 97 // Reload and test for persistence |
| 92 ASSERT_TRUE(store_->Load(&certs)); | 98 ASSERT_TRUE(store_->Load(&certs)); |
| 93 ASSERT_EQ(1U, certs.size()); | 99 ASSERT_EQ(2U, certs.size()); |
| 94 ASSERT_STREQ("https://encrypted.google.com:8443", certs[0]->origin().c_str()); | 100 net::DefaultOriginBoundCertStore::OriginBoundCert* ec_cert; |
| 95 ASSERT_STREQ("a", certs[0]->private_key().c_str()); | 101 net::DefaultOriginBoundCertStore::OriginBoundCert* rsa_cert; |
| 96 ASSERT_STREQ("b", certs[0]->cert().c_str()); | 102 if (net::CLIENT_CERT_RSA_SIGN == certs[0]->type()) { |
| 103 rsa_cert = certs[0]; |
| 104 ec_cert = certs[1]; |
| 105 } else { |
| 106 rsa_cert = certs[1]; |
| 107 ec_cert = certs[0]; |
| 108 } |
| 109 ASSERT_STREQ("https://encrypted.google.com:8443", rsa_cert->origin().c_str()); |
| 110 ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, rsa_cert->type()); |
| 111 ASSERT_STREQ("a", rsa_cert->private_key().c_str()); |
| 112 ASSERT_STREQ("b", rsa_cert->cert().c_str()); |
| 113 ASSERT_STREQ("https://www.google.com/", ec_cert->origin().c_str()); |
| 114 ASSERT_EQ(net::CLIENT_CERT_ECDSA_SIGN, ec_cert->type()); |
| 115 ASSERT_STREQ("c", ec_cert->private_key().c_str()); |
| 116 ASSERT_STREQ("d", ec_cert->cert().c_str()); |
| 97 | 117 |
| 98 // Now delete the cert and check persistence again. | 118 // Now delete the cert and check persistence again. |
| 99 store_->DeleteOriginBoundCert(*certs[0]); | 119 store_->DeleteOriginBoundCert(*certs[0]); |
| 120 store_->DeleteOriginBoundCert(*certs[1]); |
| 100 store_ = NULL; | 121 store_ = NULL; |
| 101 // Make sure we wait until the destructor has run. | 122 // Make sure we wait until the destructor has run. |
| 102 ASSERT_TRUE(helper->Run()); | 123 ASSERT_TRUE(helper->Run()); |
| 103 STLDeleteContainerPointers(certs.begin(), certs.end()); | 124 STLDeleteContainerPointers(certs.begin(), certs.end()); |
| 104 certs.clear(); | 125 certs.clear(); |
| 105 store_ = new SQLiteOriginBoundCertStore( | 126 store_ = new SQLiteOriginBoundCertStore( |
| 106 temp_dir_.path().Append(chrome::kOBCertFilename)); | 127 temp_dir_.path().Append(chrome::kOBCertFilename)); |
| 107 | 128 |
| 108 // Reload and check if the cert has been removed. | 129 // Reload and check if the cert has been removed. |
| 109 ASSERT_TRUE(store_->Load(&certs)); | 130 ASSERT_TRUE(store_->Load(&certs)); |
| 110 ASSERT_EQ(0U, certs.size()); | 131 ASSERT_EQ(0U, certs.size()); |
| 111 } | 132 } |
| 112 | 133 |
| 134 TEST_F(SQLiteOriginBoundCertStoreTest, TestUpgrade) { |
| 135 // Reset the store. We'll be using a different database for this test. |
| 136 store_ = NULL; |
| 137 |
| 138 FilePath v1_db_path(temp_dir_.path().AppendASCII("v1db")); |
| 139 |
| 140 // Create a version 1 database. |
| 141 { |
| 142 sql::Connection db; |
| 143 ASSERT_TRUE(db.Open(v1_db_path)); |
| 144 ASSERT_TRUE(db.Execute( |
| 145 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY," |
| 146 "value LONGVARCHAR);" |
| 147 "INSERT INTO \"meta\" VALUES('version','1');" |
| 148 "INSERT INTO \"meta\" VALUES('last_compatible_version','1');" |
| 149 "CREATE TABLE origin_bound_certs (" |
| 150 "origin TEXT NOT NULL UNIQUE PRIMARY KEY," |
| 151 "private_key BLOB NOT NULL,cert BLOB NOT NULL);" |
| 152 "INSERT INTO \"origin_bound_certs\" VALUES(" |
| 153 "'https://google.com',X'AA',X'BB');" |
| 154 "INSERT INTO \"origin_bound_certs\" VALUES(" |
| 155 "'https://foo.com',X'CC',X'DD');" |
| 156 )); |
| 157 } |
| 158 |
| 159 std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs; |
| 160 store_ = new SQLiteOriginBoundCertStore(v1_db_path); |
| 161 |
| 162 // Load the database and ensure the certs can be read and are marked as RSA. |
| 163 ASSERT_TRUE(store_->Load(&certs)); |
| 164 ASSERT_EQ(2U, certs.size()); |
| 165 ASSERT_STREQ("https://google.com", certs[0]->origin().c_str()); |
| 166 ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type()); |
| 167 ASSERT_STREQ("\xaa", certs[0]->private_key().c_str()); |
| 168 ASSERT_STREQ("\xbb", certs[0]->cert().c_str()); |
| 169 ASSERT_STREQ("https://foo.com", certs[1]->origin().c_str()); |
| 170 ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[1]->type()); |
| 171 ASSERT_STREQ("\xcc", certs[1]->private_key().c_str()); |
| 172 ASSERT_STREQ("\xdd", certs[1]->cert().c_str()); |
| 173 |
| 174 STLDeleteContainerPointers(certs.begin(), certs.end()); |
| 175 certs.clear(); |
| 176 |
| 177 store_ = NULL; |
| 178 // Make sure we wait until the destructor has run. |
| 179 scoped_refptr<base::ThreadTestHelper> helper( |
| 180 new base::ThreadTestHelper( |
| 181 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); |
| 182 ASSERT_TRUE(helper->Run()); |
| 183 |
| 184 // Verify the database version is updated. |
| 185 { |
| 186 sql::Connection db; |
| 187 ASSERT_TRUE(db.Open(v1_db_path)); |
| 188 sql::Statement smt(db.GetUniqueStatement( |
| 189 "SELECT value FROM meta WHERE key = \"version\"")); |
| 190 ASSERT_TRUE(smt); |
| 191 ASSERT_TRUE(smt.Step()); |
| 192 EXPECT_EQ(2, smt.ColumnInt(0)); |
| 193 EXPECT_FALSE(smt.Step()); |
| 194 } |
| 195 } |
| 196 |
| 113 // Test that we can force the database to be written by calling Flush(). | 197 // Test that we can force the database to be written by calling Flush(). |
| 114 TEST_F(SQLiteOriginBoundCertStoreTest, TestFlush) { | 198 TEST_F(SQLiteOriginBoundCertStoreTest, TestFlush) { |
| 115 // File timestamps don't work well on all platforms, so we'll determine | 199 // File timestamps don't work well on all platforms, so we'll determine |
| 116 // whether the DB file has been modified by checking its size. | 200 // whether the DB file has been modified by checking its size. |
| 117 FilePath path = temp_dir_.path().Append(chrome::kOBCertFilename); | 201 FilePath path = temp_dir_.path().Append(chrome::kOBCertFilename); |
| 118 base::PlatformFileInfo info; | 202 base::PlatformFileInfo info; |
| 119 ASSERT_TRUE(file_util::GetFileInfo(path, &info)); | 203 ASSERT_TRUE(file_util::GetFileInfo(path, &info)); |
| 120 int64 base_size = info.size; | 204 int64 base_size = info.size; |
| 121 | 205 |
| 122 // Write some certs, so the DB will have to expand by several KB. | 206 // Write some certs, so the DB will have to expand by several KB. |
| 123 for (char c = 'a'; c < 'z'; ++c) { | 207 for (char c = 'a'; c < 'z'; ++c) { |
| 124 std::string origin(1, c); | 208 std::string origin(1, c); |
| 125 std::string private_key(1000, c); | 209 std::string private_key(1000, c); |
| 126 std::string cert(1000, c); | 210 std::string cert(1000, c); |
| 127 store_->AddOriginBoundCert( | 211 store_->AddOriginBoundCert( |
| 128 net::DefaultOriginBoundCertStore::OriginBoundCert(origin, | 212 net::DefaultOriginBoundCertStore::OriginBoundCert( |
| 129 private_key, | 213 origin, |
| 130 cert)); | 214 net::CLIENT_CERT_RSA_SIGN, |
| 215 private_key, |
| 216 cert)); |
| 131 } | 217 } |
| 132 | 218 |
| 133 // Call Flush() and wait until the DB thread is idle. | 219 // Call Flush() and wait until the DB thread is idle. |
| 134 store_->Flush(base::Closure()); | 220 store_->Flush(base::Closure()); |
| 135 scoped_refptr<base::ThreadTestHelper> helper( | 221 scoped_refptr<base::ThreadTestHelper> helper( |
| 136 new base::ThreadTestHelper( | 222 new base::ThreadTestHelper( |
| 137 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); | 223 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); |
| 138 ASSERT_TRUE(helper->Run()); | 224 ASSERT_TRUE(helper->Run()); |
| 139 | 225 |
| 140 // We forced a write, so now the file will be bigger. | 226 // We forced a write, so now the file will be bigger. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 169 | 255 |
| 170 store_->Flush(base::Bind(&CallbackCounter::Callback, counter.get())); | 256 store_->Flush(base::Bind(&CallbackCounter::Callback, counter.get())); |
| 171 | 257 |
| 172 scoped_refptr<base::ThreadTestHelper> helper( | 258 scoped_refptr<base::ThreadTestHelper> helper( |
| 173 new base::ThreadTestHelper( | 259 new base::ThreadTestHelper( |
| 174 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); | 260 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))); |
| 175 ASSERT_TRUE(helper->Run()); | 261 ASSERT_TRUE(helper->Run()); |
| 176 | 262 |
| 177 ASSERT_EQ(1, counter->callback_count()); | 263 ASSERT_EQ(1, counter->callback_count()); |
| 178 } | 264 } |
| OLD | NEW |