Cleanup OSCrypt after initialisation
OSCrypt only needs to read from the backend during its initialisation.
Instances created for this initialisation can be cleaned up afterwards.
To support this change, the mocking of OSCrypt can no longer be based
on a singleton. Tests using the mocking mechanism are updated.
Bug: 709096
Change-Id: Iba5b37ad45ada11b9a217dc2c388313f2371f647
Reviewed-on: https://chromium-review.googlesource.com/571221
Reviewed-by: Roger Tawa <[email protected]>
Reviewed-by: Mathieu Perreault <[email protected]>
Reviewed-by: Martin Šrámek <[email protected]>
Reviewed-by: Pavel Yatsuk <[email protected]>
Reviewed-by: Scott Violet <[email protected]>
Reviewed-by: Vasilii Sukhanov <[email protected]>
Commit-Queue: Christos Froussios <[email protected]>
Cr-Commit-Position: refs/heads/master@{#488675}
diff --git a/components/os_crypt/os_crypt.h b/components/os_crypt/os_crypt.h
index bd07981..d5898bf 100644
--- a/components/os_crypt/os_crypt.h
+++ b/components/os_crypt/os_crypt.h
@@ -74,8 +74,9 @@
// |get_password_v11_mock| provides a password to derive the encryption key from
// If one parameter is |nullptr|, the function will be not be replaced.
// If all parameters are |nullptr|, the real implementation is restored.
-void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)());
+void UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
+ std::string* (*get_password_v11_mock)());
// Clears any caching and most lazy initialisations performed by the production
// code. Should be used after any test which required a password.
diff --git a/components/os_crypt/os_crypt_linux.cc b/components/os_crypt/os_crypt_linux.cc
index 1a14183..b39bb091 100644
--- a/components/os_crypt/os_crypt_linux.cc
+++ b/components/os_crypt/os_crypt_linux.cc
@@ -50,12 +50,14 @@
"v10", "v11",
};
+// Everything in Cache may be leaked on shutdown.
struct Cache {
- std::unique_ptr<KeyStorageLinux> key_storage_cache;
+ // For password_v10, null means uninitialised.
std::unique_ptr<std::string> password_v10_cache;
+ // For password_v11, null means no backend.
std::unique_ptr<std::string> password_v11_cache;
- bool is_key_storage_cached;
bool is_password_v11_cached;
+ // |config| is used to initialise |password_v11_cache| and then cleared.
std::unique_ptr<os_crypt::Config> config;
// Guards access to |g_cache|, making lazy initialization of individual parts
// thread safe.
@@ -64,21 +66,20 @@
base::LazyInstance<Cache>::Leaky g_cache = LAZY_INSTANCE_INITIALIZER;
-// Lazy acquisition and caching of a KeyStorage. Will be null if no service is
-// found.
-KeyStorageLinux* GetKeyStorage() {
- if (!g_cache.Get().is_key_storage_cached) {
- DCHECK(g_cache.Get().config);
- g_cache.Get().is_key_storage_cached = true;
- g_cache.Get().key_storage_cache =
- KeyStorageLinux::CreateService(*g_cache.Get().config);
- }
- return g_cache.Get().key_storage_cache.get();
+// Create the KeyStorage. Will be null if no service is found. A Config must be
+// set before every call to this function.
+std::unique_ptr<KeyStorageLinux> CreateKeyStorage() {
+ DCHECK(g_cache.Get().config);
+ std::unique_ptr<KeyStorageLinux> key_storage =
+ KeyStorageLinux::CreateService(*g_cache.Get().config);
+ g_cache.Get().config.reset();
+ return key_storage;
}
// Pointer to a function that creates and returns the |KeyStorage| instance to
// be used. The function maintains ownership of the pointer.
-KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
+std::unique_ptr<KeyStorageLinux> (*g_key_storage_provider)() =
+ &CreateKeyStorage;
// Returns a cached string of "peanuts". Is thread-safe.
std::string* GetPasswordV10() {
@@ -94,10 +95,9 @@
std::string* GetPasswordV11() {
base::AutoLock auto_lock(g_cache.Get().lock);
if (!g_cache.Get().is_password_v11_cached) {
+ std::unique_ptr<KeyStorageLinux> key_storage = g_key_storage_provider();
g_cache.Get().password_v11_cache.reset(
- g_key_storage_provider()
- ? new std::string(g_key_storage_provider()->GetKey())
- : nullptr);
+ key_storage ? new std::string(key_storage->GetKey()) : nullptr);
g_cache.Get().is_password_v11_cached = true;
}
return g_cache.Get().password_v11_cache.get();
@@ -230,7 +230,7 @@
// static
void OSCrypt::SetConfig(std::unique_ptr<os_crypt::Config> config) {
// Setting initialisation parameters makes no sense after initializing.
- DCHECK(!g_cache.Get().is_key_storage_cached);
+ DCHECK(!g_cache.Get().is_password_v11_cached);
g_cache.Get().config = std::move(config);
}
@@ -240,15 +240,15 @@
}
void ClearCacheForTesting() {
- g_cache.Get().key_storage_cache.reset();
g_cache.Get().password_v10_cache.reset();
g_cache.Get().password_v11_cache.reset();
- g_cache.Get().is_key_storage_cached = false;
g_cache.Get().is_password_v11_cached = false;
+ g_cache.Get().config.reset();
}
-void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)()) {
+void UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
+ std::string* (*get_password_v11_mock)()) {
// Save the real implementation to restore it later.
static bool is_get_password_saved = false;
static std::string* (*get_password_save[arraysize(g_get_password)])();
@@ -270,6 +270,6 @@
// Restore real implementation
std::copy(std::begin(get_password_save), std::end(get_password_save),
std::begin(g_get_password));
- g_key_storage_provider = &GetKeyStorage;
+ g_key_storage_provider = &CreateKeyStorage;
}
}
diff --git a/components/os_crypt/os_crypt_linux_unittest.cc b/components/os_crypt/os_crypt_linux_unittest.cc
index dce4c4a2..58d6da38 100644
--- a/components/os_crypt/os_crypt_linux_unittest.cc
+++ b/components/os_crypt/os_crypt_linux_unittest.cc
@@ -12,35 +12,45 @@
namespace {
-KeyStorageLinux* GetNullKeyStorage() {
+std::unique_ptr<KeyStorageLinux> GetNullKeyStorage() {
return nullptr;
}
class OSCryptLinuxTest : public testing::Test {
public:
- OSCryptLinuxTest() = default;
- ~OSCryptLinuxTest() override = default;
+ OSCryptLinuxTest() : key_("something") { key_ptr_ = &key_; }
+
+ ~OSCryptLinuxTest() override { key_ptr_ = nullptr; };
void SetUp() override {
- OSCryptMockerLinux::SetUpWithSingleton();
- key_storage_ = OSCryptMockerLinux::GetInstance();
+ OSCryptMockerLinux::SetUp();
+ UseMockKeyStorageForTesting(nullptr, OSCryptLinuxTest::GetKey);
}
void TearDown() override { OSCryptMockerLinux::TearDown(); }
protected:
- OSCryptMockerLinux* key_storage_ = nullptr;
+ void SetEncryptionKey(const std::string& key) { key_ = key; }
+
+ // Get the key of the currently running test.
+ static std::string* GetKey() { return key_ptr_; }
private:
+ std::string key_;
+ // Points to the |key_| of the currently running test.
+ static std::string* key_ptr_;
+
DISALLOW_COPY_AND_ASSIGN(OSCryptLinuxTest);
};
+std::string* OSCryptLinuxTest::key_ptr_;
+
TEST_F(OSCryptLinuxTest, VerifyV0) {
const std::string originaltext = "hello";
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("");
+ SetEncryptionKey(std::string());
ciphertext = originaltext; // No encryption
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -51,9 +61,9 @@
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("peanuts");
+ SetEncryptionKey("peanuts");
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
- key_storage_->ResetTo("not_peanuts");
+ SetEncryptionKey("not_peanuts");
ciphertext = ciphertext.substr(3).insert(0, "v10");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -64,7 +74,7 @@
std::string ciphertext;
std::string decipheredtext;
- key_storage_->ResetTo("");
+ SetEncryptionKey(std::string());
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
ASSERT_EQ(ciphertext.substr(0, 3), "v11");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
diff --git a/components/os_crypt/os_crypt_mocker.cc b/components/os_crypt/os_crypt_mocker.cc
index 7f3afb3..5e8745b 100644
--- a/components/os_crypt/os_crypt_mocker.cc
+++ b/components/os_crypt/os_crypt_mocker.cc
@@ -11,11 +11,11 @@
#endif
// static
-void OSCryptMocker::SetUpWithSingleton() {
+void OSCryptMocker::SetUp() {
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(true);
#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
- OSCryptMockerLinux::SetUpWithSingleton();
+ OSCryptMockerLinux::SetUp();
#endif
}
diff --git a/components/os_crypt/os_crypt_mocker.h b/components/os_crypt/os_crypt_mocker.h
index a2992ef..6f394f8 100644
--- a/components/os_crypt/os_crypt_mocker.h
+++ b/components/os_crypt/os_crypt_mocker.h
@@ -12,7 +12,7 @@
class OSCryptMocker {
public:
// Inject mocking into OSCrypt.
- static void SetUpWithSingleton();
+ static void SetUp();
// Restore OSCrypt to its real behaviour.
static void TearDown();
diff --git a/components/os_crypt/os_crypt_mocker_linux.cc b/components/os_crypt/os_crypt_mocker_linux.cc
index 899616c..f8f0504 100644
--- a/components/os_crypt/os_crypt_mocker_linux.cc
+++ b/components/os_crypt/os_crypt_mocker_linux.cc
@@ -15,45 +15,24 @@
namespace {
-static base::LazyInstance<OSCryptMockerLinux>::Leaky g_mocker =
- LAZY_INSTANCE_INITIALIZER;
-
-KeyStorageLinux* GetKeyStorage() {
- return OSCryptMockerLinux::GetInstance();
+std::unique_ptr<KeyStorageLinux> CreateNewMock() {
+ return base::MakeUnique<OSCryptMockerLinux>();
}
-std::string* GetPassword() {
- return OSCryptMockerLinux::GetInstance()->GetKeyPtr();
}
-} // namespace
-
std::string OSCryptMockerLinux::GetKey() {
- if (key_.empty())
- base::Base64Encode(base::RandBytesAsString(16), &key_);
return key_;
}
-bool OSCryptMockerLinux::Init() {
- return true;
-}
-
-void OSCryptMockerLinux::ResetTo(base::StringPiece new_key) {
- key_ = new_key.as_string();
-}
-
std::string* OSCryptMockerLinux::GetKeyPtr() {
return &key_;
}
// static
-OSCryptMockerLinux* OSCryptMockerLinux::GetInstance() {
- return g_mocker.Pointer();
-}
-
-// static
-void OSCryptMockerLinux::SetUpWithSingleton() {
- UseMockKeyStorageForTesting(&GetKeyStorage, &GetPassword);
+void OSCryptMockerLinux::SetUp() {
+ UseMockKeyStorageForTesting(
+ &CreateNewMock, nullptr /* get the key from the provider above */);
OSCrypt::SetConfig(base::MakeUnique<os_crypt::Config>());
}
@@ -62,3 +41,8 @@
UseMockKeyStorageForTesting(nullptr, nullptr);
ClearCacheForTesting();
}
+
+bool OSCryptMockerLinux::Init() {
+ key_ = "the_encryption_key";
+ return true;
+}
diff --git a/components/os_crypt/os_crypt_mocker_linux.h b/components/os_crypt/os_crypt_mocker_linux.h
index b9a6507..4a4c1cd2 100644
--- a/components/os_crypt/os_crypt_mocker_linux.h
+++ b/components/os_crypt/os_crypt_mocker_linux.h
@@ -20,17 +20,11 @@
// KeyStorageLinux
std::string GetKey() override;
- // Set the password that OSCryptMockerLinux holds.
- void ResetTo(base::StringPiece new_key);
-
// Get a pointer to the stored password. OSCryptMockerLinux owns the pointer.
std::string* GetKeyPtr();
- // Getter for the singleton.
- static OSCryptMockerLinux* GetInstance();
-
- // Inject the singleton mock into OSCrypt.
- static void SetUpWithSingleton();
+ // Inject the mocking scheme into OSCrypt.
+ static void SetUp();
// Restore OSCrypt to its real behaviour.
static void TearDown();
diff --git a/components/os_crypt/os_crypt_unittest.cc b/components/os_crypt/os_crypt_unittest.cc
index b5abfc9..f3ef01fe 100644
--- a/components/os_crypt/os_crypt_unittest.cc
+++ b/components/os_crypt/os_crypt_unittest.cc
@@ -26,7 +26,7 @@
class OSCryptTest : public testing::Test {
public:
- OSCryptTest() { OSCryptMocker::SetUpWithSingleton(); }
+ OSCryptTest() { OSCryptMocker::SetUp(); }
~OSCryptTest() override { OSCryptMocker::TearDown(); }
@@ -150,16 +150,7 @@
class OSCryptConcurrencyTest : public testing::Test {
public:
- OSCryptConcurrencyTest() {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- // Mock the key storage, but not the process of getting the passwords.
- UseMockKeyStorageForTesting(
- []() -> KeyStorageLinux* { return OSCryptMockerLinux::GetInstance(); },
- nullptr);
-#else
- OSCryptMocker::SetUpWithSingleton();
-#endif
- }
+ OSCryptConcurrencyTest() { OSCryptMocker::SetUp(); }
~OSCryptConcurrencyTest() override { OSCryptMocker::TearDown(); };