• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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