Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / sqlite_channel_id_store_unittest.cc
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.
4
5 #include "base/bind.h"
6 #include "base/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/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "chrome/browser/net/sqlite_channel_id_store.h"
14 #include "chrome/common/chrome_constants.h"
15 #include "content/public/test/mock_special_storage_policy.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "net/base/test_data_directory.h"
18 #include "net/ssl/ssl_client_cert_type.h"
19 #include "net/test/cert_test_util.h"
20 #include "sql/statement.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 class SQLiteChannelIDStoreTest : public testing::Test {
24  public:
25   void Load(
26       ScopedVector<net::DefaultChannelIDStore::ChannelID>* channel_ids) {
27     base::RunLoop run_loop;
28     store_->Load(base::Bind(&SQLiteChannelIDStoreTest::OnLoaded,
29                             base::Unretained(this),
30                             &run_loop));
31     run_loop.Run();
32     channel_ids->swap(channel_ids_);
33     channel_ids_.clear();
34   }
35
36   void OnLoaded(
37       base::RunLoop* run_loop,
38       scoped_ptr<ScopedVector<
39           net::DefaultChannelIDStore::ChannelID> > channel_ids) {
40     channel_ids_.swap(*channel_ids);
41     run_loop->Quit();
42   }
43
44  protected:
45   static void ReadTestKeyAndCert(std::string* key, std::string* cert) {
46     base::FilePath key_path = net::GetTestCertsDirectory().AppendASCII(
47         "unittest.originbound.key.der");
48     base::FilePath cert_path = net::GetTestCertsDirectory().AppendASCII(
49         "unittest.originbound.der");
50     ASSERT_TRUE(base::ReadFileToString(key_path, key));
51     ASSERT_TRUE(base::ReadFileToString(cert_path, cert));
52   }
53
54   static base::Time GetTestCertExpirationTime() {
55     // Cert expiration time from 'dumpasn1 unittest.originbound.der':
56     // GeneralizedTime 19/11/2111 02:23:45 GMT
57     // base::Time::FromUTCExploded can't generate values past 2038 on 32-bit
58     // linux, so we use the raw value here.
59     return base::Time::FromInternalValue(GG_INT64_C(16121816625000000));
60   }
61
62   static base::Time GetTestCertCreationTime() {
63     // UTCTime 13/12/2011 02:23:45 GMT
64     base::Time::Exploded exploded_time;
65     exploded_time.year = 2011;
66     exploded_time.month = 12;
67     exploded_time.day_of_week = 0;  // Unused.
68     exploded_time.day_of_month = 13;
69     exploded_time.hour = 2;
70     exploded_time.minute = 23;
71     exploded_time.second = 45;
72     exploded_time.millisecond = 0;
73     return base::Time::FromUTCExploded(exploded_time);
74   }
75
76   virtual void SetUp() {
77     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
78     store_ = new SQLiteChannelIDStore(
79         temp_dir_.path().Append(chrome::kChannelIDFilename),
80         base::MessageLoopProxy::current(),
81         NULL);
82     ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
83     Load(&channel_ids);
84     ASSERT_EQ(0u, channel_ids.size());
85     // Make sure the store gets written at least once.
86     store_->AddChannelID(
87         net::DefaultChannelIDStore::ChannelID(
88             "google.com",
89             base::Time::FromInternalValue(1),
90             base::Time::FromInternalValue(2),
91             "a", "b"));
92   }
93
94   content::TestBrowserThreadBundle thread_bundle_;
95   base::ScopedTempDir temp_dir_;
96   scoped_refptr<SQLiteChannelIDStore> store_;
97   ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids_;
98 };
99
100 // Test if data is stored as expected in the SQLite database.
101 TEST_F(SQLiteChannelIDStoreTest, TestPersistence) {
102   store_->AddChannelID(
103       net::DefaultChannelIDStore::ChannelID(
104           "foo.com",
105           base::Time::FromInternalValue(3),
106           base::Time::FromInternalValue(4),
107           "c", "d"));
108
109   ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
110   // Replace the store effectively destroying the current one and forcing it
111   // to write its data to disk. Then we can see if after loading it again it
112   // is still there.
113   store_ = NULL;
114   // Make sure we wait until the destructor has run.
115   base::RunLoop().RunUntilIdle();
116   store_ = new SQLiteChannelIDStore(
117       temp_dir_.path().Append(chrome::kChannelIDFilename),
118       base::MessageLoopProxy::current(),
119       NULL);
120
121   // Reload and test for persistence
122   Load(&channel_ids);
123   ASSERT_EQ(2U, channel_ids.size());
124   net::DefaultChannelIDStore::ChannelID* goog_channel_id;
125   net::DefaultChannelIDStore::ChannelID* foo_channel_id;
126   if (channel_ids[0]->server_identifier() == "google.com") {
127     goog_channel_id = channel_ids[0];
128     foo_channel_id = channel_ids[1];
129   } else {
130     goog_channel_id = channel_ids[1];
131     foo_channel_id = channel_ids[0];
132   }
133   ASSERT_EQ("google.com", goog_channel_id->server_identifier());
134   ASSERT_STREQ("a", goog_channel_id->private_key().c_str());
135   ASSERT_STREQ("b", goog_channel_id->cert().c_str());
136   ASSERT_EQ(1, goog_channel_id->creation_time().ToInternalValue());
137   ASSERT_EQ(2, goog_channel_id->expiration_time().ToInternalValue());
138   ASSERT_EQ("foo.com", foo_channel_id->server_identifier());
139   ASSERT_STREQ("c", foo_channel_id->private_key().c_str());
140   ASSERT_STREQ("d", foo_channel_id->cert().c_str());
141   ASSERT_EQ(3, foo_channel_id->creation_time().ToInternalValue());
142   ASSERT_EQ(4, foo_channel_id->expiration_time().ToInternalValue());
143
144   // Now delete the cert and check persistence again.
145   store_->DeleteChannelID(*channel_ids[0]);
146   store_->DeleteChannelID(*channel_ids[1]);
147   store_ = NULL;
148   // Make sure we wait until the destructor has run.
149   base::RunLoop().RunUntilIdle();
150   channel_ids.clear();
151   store_ = new SQLiteChannelIDStore(
152       temp_dir_.path().Append(chrome::kChannelIDFilename),
153       base::MessageLoopProxy::current(),
154       NULL);
155
156   // Reload and check if the cert has been removed.
157   Load(&channel_ids);
158   ASSERT_EQ(0U, channel_ids.size());
159 }
160
161 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV1) {
162   // Reset the store.  We'll be using a different database for this test.
163   store_ = NULL;
164
165   base::FilePath v1_db_path(temp_dir_.path().AppendASCII("v1db"));
166
167   std::string key_data;
168   std::string cert_data;
169   ReadTestKeyAndCert(&key_data, &cert_data);
170
171   // Create a version 1 database.
172   {
173     sql::Connection db;
174     ASSERT_TRUE(db.Open(v1_db_path));
175     ASSERT_TRUE(db.Execute(
176         "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
177             "value LONGVARCHAR);"
178         "INSERT INTO \"meta\" VALUES('version','1');"
179         "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
180         "CREATE TABLE origin_bound_certs ("
181             "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
182             "private_key BLOB NOT NULL,cert BLOB NOT NULL);"));
183
184     sql::Statement add_smt(db.GetUniqueStatement(
185         "INSERT INTO origin_bound_certs (origin, private_key, cert) "
186         "VALUES (?,?,?)"));
187     add_smt.BindString(0, "google.com");
188     add_smt.BindBlob(1, key_data.data(), key_data.size());
189     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
190     ASSERT_TRUE(add_smt.Run());
191
192     ASSERT_TRUE(db.Execute(
193         "INSERT INTO \"origin_bound_certs\" VALUES("
194             "'foo.com',X'AA',X'BB');"
195         ));
196   }
197
198   // Load and test the DB contents twice.  First time ensures that we can use
199   // the updated values immediately.  Second time ensures that the updated
200   // values are stored and read correctly on next load.
201   for (int i = 0; i < 2; ++i) {
202     SCOPED_TRACE(i);
203
204     ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
205     store_ = new SQLiteChannelIDStore(
206         v1_db_path, base::MessageLoopProxy::current(), NULL);
207
208     // Load the database. Because the existing v1 certs are implicitly of type
209     // RSA, which is unsupported, they're discarded.
210     Load(&channel_ids);
211     ASSERT_EQ(0U, channel_ids.size());
212
213     store_ = NULL;
214     base::RunLoop().RunUntilIdle();
215
216     // Verify the database version is updated.
217     {
218       sql::Connection db;
219       ASSERT_TRUE(db.Open(v1_db_path));
220       sql::Statement smt(db.GetUniqueStatement(
221           "SELECT value FROM meta WHERE key = \"version\""));
222       ASSERT_TRUE(smt.Step());
223       EXPECT_EQ(4, smt.ColumnInt(0));
224       EXPECT_FALSE(smt.Step());
225     }
226   }
227 }
228
229 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV2) {
230   // Reset the store.  We'll be using a different database for this test.
231   store_ = NULL;
232
233   base::FilePath v2_db_path(temp_dir_.path().AppendASCII("v2db"));
234
235   std::string key_data;
236   std::string cert_data;
237   ReadTestKeyAndCert(&key_data, &cert_data);
238
239   // Create a version 2 database.
240   {
241     sql::Connection db;
242     ASSERT_TRUE(db.Open(v2_db_path));
243     ASSERT_TRUE(db.Execute(
244         "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
245             "value LONGVARCHAR);"
246         "INSERT INTO \"meta\" VALUES('version','2');"
247         "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
248         "CREATE TABLE origin_bound_certs ("
249             "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
250             "private_key BLOB NOT NULL,"
251             "cert BLOB NOT NULL,"
252             "cert_type INTEGER);"
253         ));
254
255     sql::Statement add_smt(db.GetUniqueStatement(
256         "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type) "
257         "VALUES (?,?,?,?)"));
258     add_smt.BindString(0, "google.com");
259     add_smt.BindBlob(1, key_data.data(), key_data.size());
260     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
261     add_smt.BindInt64(3, 64);
262     ASSERT_TRUE(add_smt.Run());
263
264     ASSERT_TRUE(db.Execute(
265         "INSERT INTO \"origin_bound_certs\" VALUES("
266             "'foo.com',X'AA',X'BB',64);"
267         ));
268   }
269
270   // Load and test the DB contents twice.  First time ensures that we can use
271   // the updated values immediately.  Second time ensures that the updated
272   // values are saved and read correctly on next load.
273   for (int i = 0; i < 2; ++i) {
274     SCOPED_TRACE(i);
275
276     ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
277     store_ = new SQLiteChannelIDStore(
278         v2_db_path, base::MessageLoopProxy::current(), NULL);
279
280     // Load the database and ensure the certs can be read.
281     Load(&channel_ids);
282     ASSERT_EQ(2U, channel_ids.size());
283
284     ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
285     ASSERT_EQ(GetTestCertExpirationTime(),
286               channel_ids[0]->expiration_time());
287     ASSERT_EQ(key_data, channel_ids[0]->private_key());
288     ASSERT_EQ(cert_data, channel_ids[0]->cert());
289
290     ASSERT_EQ("foo.com", channel_ids[1]->server_identifier());
291     // Undecodable cert, expiration time will be uninitialized.
292     ASSERT_EQ(base::Time(), channel_ids[1]->expiration_time());
293     ASSERT_STREQ("\xaa", channel_ids[1]->private_key().c_str());
294     ASSERT_STREQ("\xbb", channel_ids[1]->cert().c_str());
295
296     store_ = NULL;
297     // Make sure we wait until the destructor has run.
298     base::RunLoop().RunUntilIdle();
299
300     // Verify the database version is updated.
301     {
302       sql::Connection db;
303       ASSERT_TRUE(db.Open(v2_db_path));
304       sql::Statement smt(db.GetUniqueStatement(
305           "SELECT value FROM meta WHERE key = \"version\""));
306       ASSERT_TRUE(smt.Step());
307       EXPECT_EQ(4, smt.ColumnInt(0));
308       EXPECT_FALSE(smt.Step());
309     }
310   }
311 }
312
313 TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV3) {
314   // Reset the store.  We'll be using a different database for this test.
315   store_ = NULL;
316
317   base::FilePath v3_db_path(temp_dir_.path().AppendASCII("v3db"));
318
319   std::string key_data;
320   std::string cert_data;
321   ReadTestKeyAndCert(&key_data, &cert_data);
322
323   // Create a version 3 database.
324   {
325     sql::Connection db;
326     ASSERT_TRUE(db.Open(v3_db_path));
327     ASSERT_TRUE(db.Execute(
328         "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
329             "value LONGVARCHAR);"
330         "INSERT INTO \"meta\" VALUES('version','3');"
331         "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
332         "CREATE TABLE origin_bound_certs ("
333             "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
334             "private_key BLOB NOT NULL,"
335             "cert BLOB NOT NULL,"
336             "cert_type INTEGER,"
337             "expiration_time INTEGER);"
338         ));
339
340     sql::Statement add_smt(db.GetUniqueStatement(
341         "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type, "
342         "expiration_time) VALUES (?,?,?,?,?)"));
343     add_smt.BindString(0, "google.com");
344     add_smt.BindBlob(1, key_data.data(), key_data.size());
345     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
346     add_smt.BindInt64(3, 64);
347     add_smt.BindInt64(4, 1000);
348     ASSERT_TRUE(add_smt.Run());
349
350     ASSERT_TRUE(db.Execute(
351         "INSERT INTO \"origin_bound_certs\" VALUES("
352             "'foo.com',X'AA',X'BB',64,2000);"
353         ));
354   }
355
356   // Load and test the DB contents twice.  First time ensures that we can use
357   // the updated values immediately.  Second time ensures that the updated
358   // values are saved and read correctly on next load.
359   for (int i = 0; i < 2; ++i) {
360     SCOPED_TRACE(i);
361
362     ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
363     store_ = new SQLiteChannelIDStore(
364         v3_db_path, base::MessageLoopProxy::current(), NULL);
365
366     // Load the database and ensure the certs can be read.
367     Load(&channel_ids);
368     ASSERT_EQ(2U, channel_ids.size());
369
370     ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
371     ASSERT_EQ(1000, channel_ids[0]->expiration_time().ToInternalValue());
372     ASSERT_EQ(GetTestCertCreationTime(),
373               channel_ids[0]->creation_time());
374     ASSERT_EQ(key_data, channel_ids[0]->private_key());
375     ASSERT_EQ(cert_data, channel_ids[0]->cert());
376
377     ASSERT_EQ("foo.com", channel_ids[1]->server_identifier());
378     ASSERT_EQ(2000, channel_ids[1]->expiration_time().ToInternalValue());
379     // Undecodable cert, creation time will be uninitialized.
380     ASSERT_EQ(base::Time(), channel_ids[1]->creation_time());
381     ASSERT_STREQ("\xaa", channel_ids[1]->private_key().c_str());
382     ASSERT_STREQ("\xbb", channel_ids[1]->cert().c_str());
383
384     store_ = NULL;
385     // Make sure we wait until the destructor has run.
386     base::RunLoop().RunUntilIdle();
387
388     // Verify the database version is updated.
389     {
390       sql::Connection db;
391       ASSERT_TRUE(db.Open(v3_db_path));
392       sql::Statement smt(db.GetUniqueStatement(
393           "SELECT value FROM meta WHERE key = \"version\""));
394       ASSERT_TRUE(smt.Step());
395       EXPECT_EQ(4, smt.ColumnInt(0));
396       EXPECT_FALSE(smt.Step());
397     }
398   }
399 }
400
401 TEST_F(SQLiteChannelIDStoreTest, TestRSADiscarded) {
402   // Reset the store.  We'll be using a different database for this test.
403   store_ = NULL;
404
405   base::FilePath v4_db_path(temp_dir_.path().AppendASCII("v4dbrsa"));
406
407   std::string key_data;
408   std::string cert_data;
409   ReadTestKeyAndCert(&key_data, &cert_data);
410
411   // Create a version 4 database with a mix of RSA and ECDSA certs.
412   {
413     sql::Connection db;
414     ASSERT_TRUE(db.Open(v4_db_path));
415     ASSERT_TRUE(db.Execute(
416         "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
417             "value LONGVARCHAR);"
418         "INSERT INTO \"meta\" VALUES('version','4');"
419         "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
420         "CREATE TABLE origin_bound_certs ("
421             "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
422             "private_key BLOB NOT NULL,"
423             "cert BLOB NOT NULL,"
424             "cert_type INTEGER,"
425             "expiration_time INTEGER,"
426             "creation_time INTEGER);"
427         ));
428
429     sql::Statement add_smt(db.GetUniqueStatement(
430         "INSERT INTO origin_bound_certs "
431         "(origin, private_key, cert, cert_type, expiration_time, creation_time)"
432         " VALUES (?,?,?,?,?,?)"));
433     add_smt.BindString(0, "google.com");
434     add_smt.BindBlob(1, key_data.data(), key_data.size());
435     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
436     add_smt.BindInt64(3, 64);
437     add_smt.BindInt64(4, GetTestCertExpirationTime().ToInternalValue());
438     add_smt.BindInt64(5, base::Time::Now().ToInternalValue());
439     ASSERT_TRUE(add_smt.Run());
440
441     add_smt.Clear();
442     add_smt.Assign(db.GetUniqueStatement(
443         "INSERT INTO origin_bound_certs "
444         "(origin, private_key, cert, cert_type, expiration_time, creation_time)"
445         " VALUES (?,?,?,?,?,?)"));
446     add_smt.BindString(0, "foo.com");
447     add_smt.BindBlob(1, key_data.data(), key_data.size());
448     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
449     add_smt.BindInt64(3, 1);
450     add_smt.BindInt64(4, GetTestCertExpirationTime().ToInternalValue());
451     add_smt.BindInt64(5, base::Time::Now().ToInternalValue());
452     ASSERT_TRUE(add_smt.Run());
453   }
454
455   ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids;
456   store_ = new SQLiteChannelIDStore(
457       v4_db_path, base::MessageLoopProxy::current(), NULL);
458
459   // Load the database and ensure the certs can be read.
460   Load(&channel_ids);
461   // Only the ECDSA cert (for google.com) is read, the RSA one is discarded.
462   ASSERT_EQ(1U, channel_ids.size());
463
464   ASSERT_EQ("google.com", channel_ids[0]->server_identifier());
465   ASSERT_EQ(GetTestCertExpirationTime(),
466             channel_ids[0]->expiration_time());
467   ASSERT_EQ(key_data, channel_ids[0]->private_key());
468   ASSERT_EQ(cert_data, channel_ids[0]->cert());
469
470   store_ = NULL;
471   // Make sure we wait until the destructor has run.
472   base::RunLoop().RunUntilIdle();
473 }