summaryrefslogtreecommitdiffstats
path: root/content/browser/net
diff options
context:
space:
mode:
authorbcwhite@chromium.org <bcwhite@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-13 18:40:56 +0000
committerbcwhite@chromium.org <bcwhite@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-13 18:40:56 +0000
commit582fce2bafb46d8114ed412675171178052e343c (patch)
tree205708ee4ac532c3e685f8a8dd5ec8c8b87913af /content/browser/net
parentf431d3cfe81a97b45803d6258f9a66ab3a7186dc (diff)
downloadchromium_src-582fce2bafb46d8114ed412675171178052e343c.zip
chromium_src-582fce2bafb46d8114ed412675171178052e343c.tar.gz
chromium_src-582fce2bafb46d8114ed412675171178052e343c.tar.bz2
Encrypt all stored cookies on selected operating systems.
As part of the goal of protecting private user information, this encrypts the cookie values on operating systems with user-specific crypto APIs and that do not otherwise protect this data. Performance tests indicate a penalty of about 1ms per cookie (regardless of size) on a Mac and 0.1ms to 0.7ms (depending on the size) under Windows. This will be higher on older hardware but still insignificant. Encrypted data is binary (with an overhead of 128 bytes on Windows) and binary data must be stored in a BLOB so only one of two fields ("value" or "encrypted_value") will have data with the other being empty. Both values, however, need to be read & written when accessing a cookie because they are marked "non null"). BUG=313323 Review URL: https://codereview.chromium.org/24734007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234855 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/net')
-rw-r--r--content/browser/net/sqlite_persistent_cookie_store.cc129
-rw-r--r--content/browser/net/sqlite_persistent_cookie_store.h4
-rw-r--r--content/browser/net/sqlite_persistent_cookie_store_perftest.cc7
-rw-r--r--content/browser/net/sqlite_persistent_cookie_store_unittest.cc164
4 files changed, 243 insertions, 61 deletions
diff --git a/content/browser/net/sqlite_persistent_cookie_store.cc b/content/browser/net/sqlite_persistent_cookie_store.cc
index 1c0a8e7..dd77f85 100644
--- a/content/browser/net/sqlite_persistent_cookie_store.cc
+++ b/content/browser/net/sqlite_persistent_cookie_store.cc
@@ -26,6 +26,7 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/cookie_crypto_delegate.h"
#include "content/public/browser/cookie_store_factory.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
@@ -73,7 +74,8 @@ class SQLitePersistentCookieStore::Backend
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy)
+ quota::SpecialStoragePolicy* special_storage_policy,
+ scoped_ptr<CookieCryptoDelegate> crypto_delegate)
: path_(path),
num_pending_(0),
force_keep_session_state_(false),
@@ -85,7 +87,8 @@ class SQLitePersistentCookieStore::Backend
client_task_runner_(client_task_runner),
background_task_runner_(background_task_runner),
num_priority_waiting_(0),
- total_priority_requests_(0) {}
+ total_priority_requests_(0),
+ crypto_(crypto_delegate.Pass()) {}
// Creates or loads the SQLite database.
void Load(const LoadedCallback& loaded_callback);
@@ -268,6 +271,9 @@ class SQLitePersistentCookieStore::Backend
// The cumulative duration of time when |num_priority_waiting_| was greater
// than 1.
base::TimeDelta priority_wait_duration_;
+ // Class with functions that do cryptographic operations (for protecting
+ // cookies stored persistently).
+ scoped_ptr<CookieCryptoDelegate> crypto_;
DISALLOW_COPY_AND_ASSIGN(Backend);
};
@@ -276,6 +282,13 @@ namespace {
// Version number of the database.
//
+// Version 7 adds encrypted values. Old values will continue to be used but
+// all new values written will be encrypted on selected operating systems. New
+// records read by old clients will simply get an empty cookie value while old
+// records read by new clients will continue to operate with the unencrypted
+// version. New and old clients alike will always write/update records with
+// what they support.
+//
// Version 6 adds cookie priorities. This allows developers to influence the
// order in which cookies are evicted in order to meet domain cookie limits.
//
@@ -292,7 +305,7 @@ namespace {
// Version 3 updated the database to include the last access time, so we can
// expire them in decreasing order of use when we've reached the maximum
// number of cookies.
-const int kCurrentVersionNumber = 6;
+const int kCurrentVersionNumber = 7;
const int kCompatibleVersionNumber = 5;
// Possible values for the 'priority' column.
@@ -369,7 +382,8 @@ bool InitTable(sql::Connection* db) {
"last_access_utc INTEGER NOT NULL, "
"has_expires INTEGER NOT NULL DEFAULT 1, "
"persistent INTEGER NOT NULL DEFAULT 1,"
- "priority INTEGER NOT NULL DEFAULT %d)",
+ "priority INTEGER NOT NULL DEFAULT %d,"
+ "encrypted_value BLOB DEFAULT '')",
CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT)));
if (!db->Execute(stmt.c_str()))
return false;
@@ -678,15 +692,16 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
if (restore_old_session_cookies_) {
smt.Assign(db_->GetCachedStatement(
SQL_FROM_HERE,
- "SELECT creation_utc, host_key, name, value, path, expires_utc, "
- "secure, httponly, last_access_utc, has_expires, persistent, priority "
- "FROM cookies WHERE host_key = ?"));
+ "SELECT creation_utc, host_key, name, value, encrypted_value, path, "
+ "expires_utc, secure, httponly, last_access_utc, has_expires, "
+ "persistent, priority FROM cookies WHERE host_key = ?"));
} else {
smt.Assign(db_->GetCachedStatement(
SQL_FROM_HERE,
- "SELECT creation_utc, host_key, name, value, path, expires_utc, "
- "secure, httponly, last_access_utc, has_expires, persistent, priority "
- "FROM cookies WHERE host_key = ? AND persistent = 1"));
+ "SELECT creation_utc, host_key, name, value, encrypted_value, path, "
+ "expires_utc, secure, httponly, last_access_utc, has_expires, "
+ "persistent, priority FROM cookies WHERE host_key = ? "
+ "AND persistent = 1"));
}
if (!smt.is_valid()) {
smt.Clear(); // Disconnect smt_ref from db_.
@@ -700,20 +715,28 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
for (; it != domains.end(); ++it) {
smt.BindString(0, *it);
while (smt.Step()) {
+ std::string value;
+ std::string encrypted_value = smt.ColumnString(4);
+ if (!encrypted_value.empty() && crypto_.get()) {
+ crypto_->DecryptString(encrypted_value, &value);
+ } else {
+ DCHECK(encrypted_value.empty());
+ value = smt.ColumnString(3);
+ }
scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie(
// The "source" URL is not used with persisted cookies.
GURL(), // Source
smt.ColumnString(2), // name
- smt.ColumnString(3), // value
+ value, // value
smt.ColumnString(1), // domain
- smt.ColumnString(4), // path
+ smt.ColumnString(5), // path
Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
- Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc
- Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc
- smt.ColumnInt(6) != 0, // secure
- smt.ColumnInt(7) != 0, // httponly
+ Time::FromInternalValue(smt.ColumnInt64(6)), // expires_utc
+ Time::FromInternalValue(smt.ColumnInt64(9)), // last_access_utc
+ smt.ColumnInt(7) != 0, // secure
+ smt.ColumnInt(8) != 0, // httponly
DBCookiePriorityToCookiePriority(
- static_cast<DBCookiePriority>(smt.ColumnInt(11))))); // priority
+ static_cast<DBCookiePriority>(smt.ColumnInt(12))))); // priority
DLOG_IF(WARNING,
cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++;
@@ -836,6 +859,26 @@ bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() {
base::TimeTicks::Now() - start_time);
}
+ if (cur_version == 6) {
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ // Alter the table to add empty "encrypted value" column.
+ if (!db_->Execute("ALTER TABLE cookies "
+ "ADD COLUMN encrypted_value BLOB DEFAULT ''")) {
+ LOG(WARNING) << "Unable to update cookie database to version 7.";
+ return false;
+ }
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber));
+ transaction.Commit();
+ UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV7",
+ base::TimeTicks::Now() - start_time);
+ }
+
// Put future migration cases here.
if (cur_version < kCurrentVersionNumber) {
@@ -920,10 +963,10 @@ void SQLitePersistentCookieStore::Backend::Commit() {
return;
sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO cookies (creation_utc, host_key, name, value, path, "
- "expires_utc, secure, httponly, last_access_utc, has_expires, "
- "persistent, priority) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "INSERT INTO cookies (creation_utc, host_key, name, value, "
+ "encrypted_value, path, expires_utc, secure, httponly, last_access_utc, "
+ "has_expires, persistent, priority) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
if (!add_smt.is_valid())
return;
@@ -953,16 +996,26 @@ void SQLitePersistentCookieStore::Backend::Commit() {
add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue());
add_smt.BindString(1, po->cc().Domain());
add_smt.BindString(2, po->cc().Name());
- add_smt.BindString(3, po->cc().Value());
- add_smt.BindString(4, po->cc().Path());
- add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue());
- add_smt.BindInt(6, po->cc().IsSecure());
- add_smt.BindInt(7, po->cc().IsHttpOnly());
- add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue());
- add_smt.BindInt(9, po->cc().IsPersistent());
+ if (crypto_.get()) {
+ std::string encrypted_value;
+ add_smt.BindCString(3, ""); // value
+ crypto_->EncryptString(po->cc().Value(), &encrypted_value);
+ // BindBlob() immediately makes an internal copy of the data.
+ add_smt.BindBlob(4, encrypted_value.data(),
+ static_cast<int>(encrypted_value.length()));
+ } else {
+ add_smt.BindString(3, po->cc().Value());
+ add_smt.BindBlob(4, "", 0); // encrypted_value
+ }
+ add_smt.BindString(5, po->cc().Path());
+ add_smt.BindInt64(6, po->cc().ExpiryDate().ToInternalValue());
+ add_smt.BindInt(7, po->cc().IsSecure());
+ add_smt.BindInt(8, po->cc().IsHttpOnly());
+ add_smt.BindInt64(9, po->cc().LastAccessDate().ToInternalValue());
add_smt.BindInt(10, po->cc().IsPersistent());
+ add_smt.BindInt(11, po->cc().IsPersistent());
add_smt.BindInt(
- 11, CookiePriorityToDBCookiePriority(po->cc().Priority()));
+ 12, CookiePriorityToDBCookiePriority(po->cc().Priority()));
if (!add_smt.Run())
NOTREACHED() << "Could not add a cookie to the DB.";
break;
@@ -1148,12 +1201,14 @@ SQLitePersistentCookieStore::SQLitePersistentCookieStore(
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy)
+ quota::SpecialStoragePolicy* special_storage_policy,
+ scoped_ptr<CookieCryptoDelegate> crypto_delegate)
: backend_(new Backend(path,
client_task_runner,
background_task_runner,
restore_old_session_cookies,
- special_storage_policy)) {
+ special_storage_policy,
+ crypto_delegate.Pass())) {
}
void SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
@@ -1199,14 +1254,16 @@ net::CookieStore* CreatePersistentCookieStore(
quota::SpecialStoragePolicy* storage_policy,
net::CookieMonster::Delegate* cookie_monster_delegate,
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
+ const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
+ scoped_ptr<CookieCryptoDelegate> crypto_delegate) {
SQLitePersistentCookieStore* persistent_store =
new SQLitePersistentCookieStore(
path,
client_task_runner,
background_task_runner,
restore_old_session_cookies,
- storage_policy);
+ storage_policy,
+ crypto_delegate.Pass());
return new net::CookieMonster(persistent_store, cookie_monster_delegate);
}
@@ -1214,7 +1271,8 @@ net::CookieStore* CreatePersistentCookieStore(
const base::FilePath& path,
bool restore_old_session_cookies,
quota::SpecialStoragePolicy* storage_policy,
- net::CookieMonster::Delegate* cookie_monster_delegate) {
+ net::CookieMonster::Delegate* cookie_monster_delegate,
+ scoped_ptr<CookieCryptoDelegate> crypto_delegate) {
return CreatePersistentCookieStore(
path,
restore_old_session_cookies,
@@ -1222,7 +1280,8 @@ net::CookieStore* CreatePersistentCookieStore(
cookie_monster_delegate,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
- BrowserThread::GetBlockingPool()->GetSequenceToken()));
+ BrowserThread::GetBlockingPool()->GetSequenceToken()),
+ crypto_delegate.Pass());
}
} // namespace content
diff --git a/content/browser/net/sqlite_persistent_cookie_store.h b/content/browser/net/sqlite_persistent_cookie_store.h
index 65e3982..e94327e 100644
--- a/content/browser/net/sqlite_persistent_cookie_store.h
+++ b/content/browser/net/sqlite_persistent_cookie_store.h
@@ -32,6 +32,7 @@ class SpecialStoragePolicy;
}
namespace content {
+class CookieCryptoDelegate;
// Implements the PersistentCookieStore interface in terms of a SQLite database.
// For documentation about the actual member functions consult the documentation
@@ -49,7 +50,8 @@ class CONTENT_EXPORT SQLitePersistentCookieStore
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy);
+ quota::SpecialStoragePolicy* special_storage_policy,
+ scoped_ptr<CookieCryptoDelegate> crypto_delegate);
// net::CookieMonster::PersistentCookieStore:
virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
diff --git a/content/browser/net/sqlite_persistent_cookie_store_perftest.cc b/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
index e71b56b..980a0c1 100644
--- a/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
+++ b/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
@@ -13,6 +13,7 @@
#include "base/test/perf_time_logger.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "content/public/browser/cookie_crypto_delegate.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -66,7 +67,8 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
temp_dir_.path().Append(cookie_filename),
client_task_runner(),
background_task_runner(),
- false, NULL);
+ false, NULL,
+ scoped_ptr<content::CookieCryptoDelegate>());
std::vector<net::CanonicalCookie*> cookies;
Load();
ASSERT_EQ(0u, cookies_.size());
@@ -97,7 +99,8 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
temp_dir_.path().Append(cookie_filename),
client_task_runner(),
background_task_runner(),
- false, NULL);
+ false, NULL,
+ scoped_ptr<content::CookieCryptoDelegate>());
}
virtual void TearDown() OVERRIDE {
diff --git a/content/browser/net/sqlite_persistent_cookie_store_unittest.cc b/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
index 4adb790..3869896 100644
--- a/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
+++ b/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
@@ -19,10 +19,15 @@
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
+#include "content/public/browser/cookie_crypto_delegate.h"
+#include "content/public/browser/cookie_store_factory.h"
+#include "crypto/encryptor.h"
+#include "crypto/symmetric_key.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "sql/connection.h"
#include "sql/meta_table.h"
+#include "sql/statement.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -32,6 +37,36 @@ namespace {
const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies");
+class CookieCryptor : public content::CookieCryptoDelegate {
+ public:
+ CookieCryptor();
+ virtual bool EncryptString(const std::string& plaintext,
+ std::string* ciphertext) OVERRIDE;
+ virtual bool DecryptString(const std::string& ciphertext,
+ std::string* plaintext) OVERRIDE;
+
+ private:
+ scoped_ptr<crypto::SymmetricKey> key_;
+ crypto::Encryptor encryptor_;
+};
+
+CookieCryptor::CookieCryptor() : key_(
+ crypto::SymmetricKey::DeriveKeyFromPassword(
+ crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)) {
+ std::string iv("the iv: 16 bytes");
+ encryptor_.Init(key_.get(), crypto::Encryptor::CBC, iv);
+}
+
+bool CookieCryptor::EncryptString(const std::string& plaintext,
+ std::string* ciphertext) {
+ return encryptor_.Encrypt(plaintext, ciphertext);
+}
+
+bool CookieCryptor::DecryptString(const std::string& ciphertext,
+ std::string* plaintext) {
+ return encryptor_.Decrypt(ciphertext, plaintext);
+}
+
} // namespace
typedef std::vector<net::CanonicalCookie*> CanonicalCookieVector;
@@ -90,20 +125,24 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
pool_owner_.reset(new base::SequencedWorkerPoolOwner(3, "Background Pool"));
}
- void CreateAndLoad(bool restore_old_session_cookies,
+ void CreateAndLoad(bool crypt_cookies,
+ bool restore_old_session_cookies,
CanonicalCookieVector* cookies) {
store_ = new SQLitePersistentCookieStore(
temp_dir_.path().Append(kCookieFilename),
client_task_runner(),
background_task_runner(),
restore_old_session_cookies,
- NULL);
+ NULL,
+ crypt_cookies ?
+ scoped_ptr<content::CookieCryptoDelegate>(new CookieCryptor) :
+ scoped_ptr<content::CookieCryptoDelegate>());
Load(cookies);
}
- void InitializeStore(bool restore_old_session_cookies) {
+ void InitializeStore(bool crypt, bool restore_old_session_cookies) {
CanonicalCookieVector cookies;
- CreateAndLoad(restore_old_session_cookies, &cookies);
+ CreateAndLoad(crypt, restore_old_session_cookies, &cookies);
EXPECT_EQ(0U, cookies.size());
}
@@ -125,6 +164,14 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
net::COOKIE_PRIORITY_DEFAULT));
}
+ std::string ReadRawDBContents() {
+ std::string contents;
+ if (!base::ReadFileToString(temp_dir_.path().Append(kCookieFilename),
+ &contents))
+ return std::string();
+ return contents;
+ }
+
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
@@ -146,13 +193,13 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
};
TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
- InitializeStore(false);
+ InitializeStore(false, false);
AddCookie("A", "B", "foo.bar", "/", base::Time::Now());
DestroyStore();
// Load up the store and verify that it has good data in it.
CanonicalCookieVector cookies;
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(1U, cookies.size());
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
ASSERT_STREQ("A", cookies[0]->Name().c_str());
@@ -171,13 +218,13 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
}
// Upon loading, the database should be reset to a good, blank state.
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(0U, cookies.size());
// Verify that, after, recovery, the database persists properly.
AddCookie("X", "Y", "foo.bar", "/", base::Time::Now());
DestroyStore();
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(1U, cookies.size());
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
ASSERT_STREQ("X", cookies[0]->Name().c_str());
@@ -187,7 +234,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
// Test if data is stored as expected in the SQLite database.
TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
- InitializeStore(false);
+ InitializeStore(false, false);
AddCookie("A", "B", "foo.bar", "/", base::Time::Now());
// Replace the store effectively destroying the current one and forcing it
// to write its data to disk. Then we can see if after loading it again it
@@ -195,7 +242,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
DestroyStore();
// Reload and test for persistence
CanonicalCookieVector cookies;
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(1U, cookies.size());
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
ASSERT_STREQ("A", cookies[0]->Name().c_str());
@@ -207,14 +254,14 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
STLDeleteElements(&cookies);
// Reload and check if the cookie has been removed.
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(0U, cookies.size());
}
// Test that priority load of cookies for a specfic domain key could be
// completed before the entire store is loaded
TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
- InitializeStore(false);
+ InitializeStore(false, false);
base::Time t = base::Time::Now();
AddCookie("A", "B", "foo.bar", "/", t);
t += base::TimeDelta::FromInternalValue(10);
@@ -229,7 +276,9 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
temp_dir_.path().Append(kCookieFilename),
client_task_runner(),
background_task_runner(),
- false, NULL);
+ false, NULL,
+ scoped_ptr<content::CookieCryptoDelegate>());
+
// Posting a blocking task to db_thread_ makes sure that the DB thread waits
// until both Load and LoadCookiesForKey have been posted to its task queue.
background_task_runner()->PostTask(
@@ -284,7 +333,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
// Test that we can force the database to be written by calling Flush().
TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
- InitializeStore(false);
+ InitializeStore(false, false);
// File timestamps don't work well on all platforms, so we'll determine
// whether the DB file has been modified by checking its size.
base::FilePath path = temp_dir_.path().Append(kCookieFilename);
@@ -310,7 +359,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
// Test loading old session cookies from the disk.
TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
- InitializeStore(true);
+ InitializeStore(false, true);
// Add a session cookie.
store_->AddCookie(
@@ -325,7 +374,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
// Create a store that loads session cookies and test that the session cookie
// was loaded.
CanonicalCookieVector cookies;
- CreateAndLoad(true, &cookies);
+ CreateAndLoad(false, true, &cookies);
ASSERT_EQ(1U, cookies.size());
ASSERT_STREQ("sessioncookie.com", cookies[0]->Domain().c_str());
@@ -338,7 +387,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
// Test loading old session cookies from the disk.
TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) {
- InitializeStore(true);
+ InitializeStore(false, true);
// Add a session cookie.
store_->AddCookie(
@@ -353,7 +402,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) {
// Create a store that doesn't load old session cookies and test that the
// session cookie was not loaded.
CanonicalCookieVector cookies;
- CreateAndLoad(false, &cookies);
+ CreateAndLoad(false, false, &cookies);
ASSERT_EQ(0U, cookies.size());
// The store should also delete the session cookie. Wait until that has been
@@ -362,12 +411,12 @@ TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) {
// Create a store that loads old session cookies and test that the session
// cookie is gone.
- CreateAndLoad(true, &cookies);
+ CreateAndLoad(false, true, &cookies);
ASSERT_EQ(0U, cookies.size());
}
TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) {
- InitializeStore(true);
+ InitializeStore(false, true);
static const char kSessionName[] = "session";
static const char kPersistentName[] = "persistent";
@@ -392,7 +441,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) {
// Create a store that loads session cookie and test that the IsPersistent
// attribute is restored.
CanonicalCookieVector cookies;
- CreateAndLoad(true, &cookies);
+ CreateAndLoad(false, true, &cookies);
ASSERT_EQ(2U, cookies.size());
std::map<std::string, net::CanonicalCookie*> cookie_map;
@@ -422,7 +471,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
static const char kCookieValue[] = "value";
static const char kCookiePath[] = "/";
- InitializeStore(true);
+ InitializeStore(false, true);
// Add a low-priority persistent cookie.
store_->AddCookie(
@@ -457,7 +506,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
// Create a store that loads session cookie and test that the priority
// attribute values are restored.
CanonicalCookieVector cookies;
- CreateAndLoad(true, &cookies);
+ CreateAndLoad(false, true, &cookies);
ASSERT_EQ(3U, cookies.size());
// Put the cookies into a map, by name, so we can easily find them.
@@ -485,4 +534,73 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
STLDeleteElements(&cookies);
}
+TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
+ CanonicalCookieVector cookies;
+
+ // Create unencrypted cookie store and write something to it.
+ InitializeStore(false, false);
+ AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now());
+ DestroyStore();
+
+ // Verify that "value" is visible in the file. This is necessary in order to
+ // have confidence in a later test that "encrypted_value" is not visible.
+ std::string contents = ReadRawDBContents();
+ EXPECT_NE(0U, contents.length());
+ EXPECT_NE(contents.find("value123XYZ"), std::string::npos);
+
+ // Create encrypted cookie store and ensure old cookie still reads.
+ STLDeleteElements(&cookies_);
+ EXPECT_EQ(0U, cookies_.size());
+ CreateAndLoad(true, false, &cookies);
+ EXPECT_EQ(1U, cookies_.size());
+ EXPECT_EQ("name", cookies_[0]->Name());
+ EXPECT_EQ("value123XYZ", cookies_[0]->Value());
+
+ // Make sure we can update existing cookie and add new cookie as encrypted.
+ store_->DeleteCookie(*(cookies_[0]));
+ AddCookie("name", "encrypted_value123XYZ", "foo.bar", "/", base::Time::Now());
+ AddCookie("other", "something456ABC", "foo.bar", "/",
+ base::Time::Now() + base::TimeDelta::FromInternalValue(10));
+ DestroyStore();
+ STLDeleteElements(&cookies_);
+ CreateAndLoad(true, false, &cookies);
+ EXPECT_EQ(2U, cookies_.size());
+ net::CanonicalCookie* cookie_name = NULL;
+ net::CanonicalCookie* cookie_other = NULL;
+ if (cookies_[0]->Name() == "name") {
+ cookie_name = cookies_[0];
+ cookie_other = cookies_[1];
+ } else {
+ cookie_name = cookies_[1];
+ cookie_other = cookies_[0];
+ }
+ EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value());
+ EXPECT_EQ("something456ABC", cookie_other->Value());
+ DestroyStore();
+
+ // Examine the real record to make sure plaintext version doesn't exist.
+ sql::Connection db;
+ sql::Statement smt;
+ int resultcount = 0;
+ ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename)));
+ smt.Assign(db.GetCachedStatement(SQL_FROM_HERE,
+ "SELECT * "
+ "FROM cookies "
+ "WHERE host_key = 'foo.bar'"));
+ while (smt.Step()) {
+ resultcount++;
+ for (int i=0; i < smt.ColumnCount(); i++) {
+ EXPECT_EQ(smt.ColumnString(i).find("value"), std::string::npos);
+ EXPECT_EQ(smt.ColumnString(i).find("something"), std::string::npos);
+ }
+ }
+ EXPECT_EQ(2, resultcount);
+
+ // Verify that "encrypted_value" is NOT visible in the file.
+ contents = ReadRawDBContents();
+ EXPECT_NE(0U, contents.length());
+ EXPECT_EQ(contents.find("encrypted_value123XYZ"), std::string::npos);
+ EXPECT_EQ(contents.find("something456ABC"), std::string::npos);
+}
+
} // namespace content