1 // Copyright 2024 The Chromium Authors
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 "crypto/process_bound_string.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/test/scoped_feature_list.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace crypto {
15
16 namespace {
17
18 MATCHER_P(ContainsSubsequence, subsequence, "contains subsequence") {
19 return std::search(arg.begin(), arg.end(), subsequence.begin(),
20 subsequence.end()) != arg.end();
21 }
22
23 } // namespace
24
25 // Test fixture template
26 template <typename T>
27 class ProcessBoundTest : public ::testing::Test {};
28
29 // Define the types you want to test
30 typedef ::testing::Types<std::string, std::wstring, std::u16string> TestTypes;
31
32 // Register the test fixture for these types
33 TYPED_TEST_SUITE(ProcessBoundTest, TestTypes);
34
TYPED_TEST(ProcessBoundTest,TestCases)35 TYPED_TEST(ProcessBoundTest, TestCases) {
36 const size_t test_cases[] = {0, 1, 15, 16, 17};
37
38 for (const auto test_length : test_cases) {
39 TypeParam test_value;
40 for (size_t i = 0; i < test_length; i++) {
41 test_value.append(
42 1, static_cast<typename TypeParam::value_type>('0' + (i % 10)));
43 }
44 crypto::ProcessBound<TypeParam> str(test_value);
45 EXPECT_EQ(test_value, str.value());
46 }
47 }
48
TEST(ProcessBound,Copy)49 TEST(ProcessBound, Copy) {
50 crypto::ProcessBound<std::string> str(std::string("hello"));
51
52 auto str2 = str;
53
54 EXPECT_EQ(str2.value(), str.value());
55 EXPECT_EQ(str.value(), "hello");
56 }
57
TEST(ProcessBound,Move)58 TEST(ProcessBound, Move) {
59 crypto::ProcessBound<std::string> str(std::string("hello"));
60
61 auto str2 = std::move(str);
62
63 EXPECT_EQ(str2.value(), "hello");
64 }
65
66 class ProcessBoundFeatureTest : public ::testing::Test,
67 public ::testing::WithParamInterface<
68 /*kProcessBoundStringEncryption*/ bool> {
69 public:
ProcessBoundFeatureTest()70 ProcessBoundFeatureTest() {
71 scoped_feature_list_.InitWithFeatureState(
72 crypto::features::kProcessBoundStringEncryption, GetParam());
73 }
74
75 private:
76 base::test::ScopedFeatureList scoped_feature_list_;
77 };
78
79 // Only Windows supports real encryption at the moment. On other platforms, the
80 // underlying decrypted buffer is returned and since it was never decrypted,
81 // Short String Optimization means that the custom allocator is never used for
82 // the test string, meaning it never gets cleared. Which is fine, since it was
83 // never encrypted anyway.
84 #if BUILDFLAG(IS_WIN)
85 // Reading into freed memory upsets sanitizers.
86 #if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \
87 !defined(MEMORY_SANITIZER)
TEST_P(ProcessBoundFeatureTest,Encryption)88 TEST_P(ProcessBoundFeatureTest, Encryption) {
89 [[maybe_unused]] const char* data;
90 {
91 crypto::ProcessBound<std::string> process_bound(std::string("hello"));
92 crypto::SecureString secure = process_bound.secure_value();
93 constexpr std::array<uint8_t, 5> kPlainText = {'h', 'e', 'l', 'l', 'o'};
94 if (GetParam()) {
95 EXPECT_THAT(process_bound.maybe_encrypted_data_,
96 ::testing::Not(ContainsSubsequence(kPlainText)));
97 } else {
98 EXPECT_THAT(process_bound.maybe_encrypted_data_,
99 ContainsSubsequence(kPlainText));
100 }
101 EXPECT_STREQ(secure.c_str(), "hello");
102 data = secure.data();
103 }
104 // In debug builds, frees are poisoned after the SecureString allocator has
105 // zeroed it, so this check can only take place for release builds.
106 #if defined(NDEBUG)
107 if (GetParam()) {
108 EXPECT_EQ(data[0], '\x00');
109 }
110 #endif // defined(NDEBUG)
111 }
112 #endif // !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) &&
113 // !defined(MEMORY_SANITIZER)
114 #endif // #if BUILDFLAG(IS_WIN)
115
116 // On all other platforms, make sure the basic functionality works when
117 // encryption is both enabled and disabled.
TEST_P(ProcessBoundFeatureTest,Basic)118 TEST_P(ProcessBoundFeatureTest, Basic) {
119 crypto::ProcessBound<std::string> process_bound(std::string("hello"));
120 EXPECT_STREQ("hello", process_bound.value().c_str());
121 }
122
123 INSTANTIATE_TEST_SUITE_P(,
124 ProcessBoundFeatureTest,
125 testing::Bool(),
__anon958389f60202(auto& info) 126 [](auto& info) {
127 return info.param ? "Enabled" : "Disabled";
128 });
129
130 } // namespace crypto
131