1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include <memory>
#include <optional>
#include <vector>
#include "base/functional/bind.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_future.h"
#include "chrome/browser/browser_process.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/os_crypt/async/browser/test_utils.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/os_crypt/sync/os_crypt.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/test/browser_test.h"
#include "services/test/echo/public/mojom/echo.mojom.h"
namespace os_crypt_async {
namespace {
Encryptor GetInstanceSync(OSCryptAsync& factory,
Encryptor::Option option = Encryptor::Option::kNone) {
base::RunLoop run_loop;
std::optional<Encryptor> encryptor;
auto sub = factory.GetInstance(
base::BindLambdaForTesting([&](Encryptor instance, bool result) {
EXPECT_TRUE(result);
encryptor.emplace(std::move(instance));
run_loop.Quit();
}),
option);
run_loop.Run();
return std::move(*encryptor);
}
} // namespace
class OSCryptAsyncBrowserTest : public InProcessBrowserTest {
protected:
base::HistogramTester histogram_tester_;
};
// Test the basic browser interface to Encrypt and Decrypt data.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, EncryptDecrypt) {
auto encryptor = GetInstanceSync(*g_browser_process->os_crypt_async());
// These histograms should always have been recorded by the time the
// GetInstance callback above has happened, since the browser registers its
// metrics callback before anything else gets a chance to.
histogram_tester_.ExpectTotalCount("OSCrypt.AsyncInitialization.Time", 1u);
histogram_tester_.ExpectUniqueSample("OSCrypt.AsyncInitialization.Result",
true, 1u);
auto ciphertext = encryptor.EncryptString("plaintext");
ASSERT_TRUE(ciphertext);
auto decrypted = encryptor.DecryptData(*ciphertext);
ASSERT_TRUE(decrypted);
EXPECT_EQ(*decrypted, "plaintext");
}
// This test verifies that an Encryptor works inside a fully sandboxed process.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, SandboxedEncryptionTest) {
// Use a testing instance, otherwise fallback to os_crypt sync does not work
// on all platforms when inside a sandbox without transferring the key over
// manually.
auto os_crypt_async = GetTestOSCryptAsyncForTesting();
Encryptor encryptor = GetInstanceSync(*os_crypt_async);
constexpr char kTestData[] = "testdatatest";
// First, encrypt the data.
const auto encrypted_data = encryptor.EncryptString(kTestData);
ASSERT_TRUE(encrypted_data.has_value());
// Launch sandboxed echo service.
auto echo_service =
content::ServiceProcessHost::Launch<echo::mojom::EchoService>();
base::test::TestFuture<std::optional<std::vector<uint8_t>>> future;
// This performs a decrypt, then an encrypt.
echo_service->DecryptEncrypt(
std::move(encryptor), *encrypted_data,
future.GetCallback<const std::optional<std::vector<uint8_t>>&>());
auto& result = future.Get();
ASSERT_TRUE(result.has_value());
// Obtain a second encryptor, since the first one was consumed in the mojo
// call above.
Encryptor encryptor2 = GetInstanceSync(*os_crypt_async);
// Finally, decrypt the data again.
const auto plaintext = encryptor2.DecryptData(*result);
ASSERT_TRUE(plaintext.has_value());
EXPECT_EQ(*plaintext, kTestData);
}
// This test verifies that an Encryptor obtained with the kEncryptSyncCompat
// option encrypts data that can be decrypted by OSCrypt, as well as ensuring
// that kEncryptSyncCompat and kNone options are interoperable with each other.
IN_PROC_BROWSER_TEST_F(OSCryptAsyncBrowserTest, OSCryptBackwardsCompatTest) {
auto encryptor = GetInstanceSync(*g_browser_process->os_crypt_async(),
Encryptor::Option::kEncryptSyncCompat);
auto ciphertext = encryptor.EncryptString("plaintext");
ASSERT_TRUE(ciphertext);
{
const auto decrypted = encryptor.DecryptData(*ciphertext);
ASSERT_TRUE(decrypted);
EXPECT_EQ(*decrypted, "plaintext");
}
{
std::string decrypted;
ASSERT_TRUE(OSCrypt::DecryptString(
std::string(ciphertext->begin(), ciphertext->end()), &decrypted));
EXPECT_EQ(decrypted, "plaintext");
}
{
// Verify that data encrypted from a kEncryptSyncCompat encryptor can be
// decrypted with a kNone encryptor.
auto full_encryptor = GetInstanceSync(*g_browser_process->os_crypt_async(),
Encryptor::Option::kNone);
const auto decrypted = full_encryptor.DecryptData(*ciphertext);
ASSERT_TRUE(decrypted);
EXPECT_EQ(decrypted, "plaintext");
// Verify that data encrypted from a kNone encryptor can be decrypted with a
// kEncryptSyncCompat encryptor.
const auto ciphertext2 = full_encryptor.EncryptString("more_plaintext");
ASSERT_TRUE(ciphertext2);
const auto decrypted2 = encryptor.DecryptData(*ciphertext2);
ASSERT_TRUE(decrypted2);
EXPECT_EQ(*decrypted2, "more_plaintext");
}
}
} // namespace os_crypt_async
|