xref: /aosp_15_r20/external/libbrillo/brillo/secure_blob_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
1*1a96fba6SXin Li // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li 
5*1a96fba6SXin Li // Unit tests for SecureBlob.
6*1a96fba6SXin Li 
7*1a96fba6SXin Li #include "brillo/asan.h"
8*1a96fba6SXin Li #include "brillo/secure_allocator.h"
9*1a96fba6SXin Li #include "brillo/secure_blob.h"
10*1a96fba6SXin Li 
11*1a96fba6SXin Li #include <algorithm>
12*1a96fba6SXin Li #include <iterator>
13*1a96fba6SXin Li #include <limits>
14*1a96fba6SXin Li #include <numeric>
15*1a96fba6SXin Li 
16*1a96fba6SXin Li #include <base/logging.h>
17*1a96fba6SXin Li #include <gtest/gtest.h>
18*1a96fba6SXin Li 
19*1a96fba6SXin Li namespace brillo {
20*1a96fba6SXin Li using std::string;
21*1a96fba6SXin Li 
22*1a96fba6SXin Li // Tests BlobToString() and BlobFromString().
TEST(BlobTest,StringConversions)23*1a96fba6SXin Li TEST(BlobTest, StringConversions) {
24*1a96fba6SXin Li   const char kTestBytes[] = {'\0', '\x1', 'a', std::numeric_limits<char>::min(),
25*1a96fba6SXin Li                              std::numeric_limits<char>::max()};
26*1a96fba6SXin Li   const Blob blob(std::begin(kTestBytes), std::end(kTestBytes));
27*1a96fba6SXin Li   const string obtained_string = BlobToString(blob);
28*1a96fba6SXin Li   EXPECT_EQ(string(std::begin(kTestBytes), std::end(kTestBytes)),
29*1a96fba6SXin Li             obtained_string);
30*1a96fba6SXin Li   const Blob obtained_blob = BlobFromString(obtained_string);
31*1a96fba6SXin Li   EXPECT_EQ(blob, obtained_blob);
32*1a96fba6SXin Li }
33*1a96fba6SXin Li 
34*1a96fba6SXin Li // Tests CombineBlobs().
TEST(BlobTest,CombineBlobs)35*1a96fba6SXin Li TEST(BlobTest, CombineBlobs) {
36*1a96fba6SXin Li   const Blob kEmpty;
37*1a96fba6SXin Li   const Blob kBlob1 = {1};
38*1a96fba6SXin Li   const Blob kBlob2 = {2};
39*1a96fba6SXin Li   const Blob kBlob3 = {3};
40*1a96fba6SXin Li   const Blob kBlob12 = {1, 2};
41*1a96fba6SXin Li   const Blob kBlob123 = {1, 2, 3};
42*1a96fba6SXin Li   EXPECT_EQ(kBlob123, CombineBlobs({kBlob12, kBlob3}));
43*1a96fba6SXin Li   EXPECT_EQ(kBlob123, CombineBlobs({kBlob1, kBlob2, kBlob3}));
44*1a96fba6SXin Li   EXPECT_EQ(kBlob12, CombineBlobs({kBlob12}));
45*1a96fba6SXin Li   EXPECT_EQ(kBlob12, CombineBlobs({kEmpty, kBlob1, kEmpty, kBlob2, kEmpty}));
46*1a96fba6SXin Li   EXPECT_EQ(kEmpty, CombineBlobs({}));
47*1a96fba6SXin Li }
48*1a96fba6SXin Li 
49*1a96fba6SXin Li class SecureBlobTest : public ::testing::Test {
50*1a96fba6SXin Li  public:
SecureBlobTest()51*1a96fba6SXin Li   SecureBlobTest() {}
~SecureBlobTest()52*1a96fba6SXin Li   virtual ~SecureBlobTest() {}
53*1a96fba6SXin Li 
FindBlobInBlob(const brillo::SecureBlob & haystack,const brillo::SecureBlob & needle)54*1a96fba6SXin Li   static bool FindBlobInBlob(const brillo::SecureBlob& haystack,
55*1a96fba6SXin Li                              const brillo::SecureBlob& needle) {
56*1a96fba6SXin Li     auto pos = std::search(
57*1a96fba6SXin Li         haystack.begin(), haystack.end(), needle.begin(), needle.end());
58*1a96fba6SXin Li     return (pos != haystack.end());
59*1a96fba6SXin Li   }
60*1a96fba6SXin Li 
FindBlobIndexInBlob(const brillo::SecureBlob & haystack,const brillo::SecureBlob & needle)61*1a96fba6SXin Li   static int FindBlobIndexInBlob(const brillo::SecureBlob& haystack,
62*1a96fba6SXin Li                                  const brillo::SecureBlob& needle) {
63*1a96fba6SXin Li     auto pos = std::search(
64*1a96fba6SXin Li         haystack.begin(), haystack.end(), needle.begin(), needle.end());
65*1a96fba6SXin Li     if (pos == haystack.end()) {
66*1a96fba6SXin Li       return -1;
67*1a96fba6SXin Li     }
68*1a96fba6SXin Li     return std::distance(haystack.begin(), pos);
69*1a96fba6SXin Li   }
70*1a96fba6SXin Li 
71*1a96fba6SXin Li  private:
72*1a96fba6SXin Li   DISALLOW_COPY_AND_ASSIGN(SecureBlobTest);
73*1a96fba6SXin Li };
74*1a96fba6SXin Li 
TEST_F(SecureBlobTest,AllocationSizeTest)75*1a96fba6SXin Li TEST_F(SecureBlobTest, AllocationSizeTest) {
76*1a96fba6SXin Li   // Checks that allocating a SecureBlob of a specified size works.
77*1a96fba6SXin Li   SecureBlob blob(32);
78*1a96fba6SXin Li 
79*1a96fba6SXin Li   EXPECT_EQ(32, blob.size());
80*1a96fba6SXin Li }
81*1a96fba6SXin Li 
TEST_F(SecureBlobTest,ConstructorCountValueTest)82*1a96fba6SXin Li TEST_F(SecureBlobTest, ConstructorCountValueTest) {
83*1a96fba6SXin Li   // Checks that constructing a SecureBlob with |count| copies of |value| works.
84*1a96fba6SXin Li   SecureBlob blob(32, 'a');
85*1a96fba6SXin Li 
86*1a96fba6SXin Li   for (size_t i = 0; i < blob.size(); i++) {
87*1a96fba6SXin Li     EXPECT_EQ('a', blob[i]);
88*1a96fba6SXin Li   }
89*1a96fba6SXin Li }
90*1a96fba6SXin Li 
TEST_F(SecureBlobTest,ConstructorAmbiguousTest)91*1a96fba6SXin Li TEST_F(SecureBlobTest, ConstructorAmbiguousTest) {
92*1a96fba6SXin Li   // This test will become important once SecureBlob stops inheriting from Blob.
93*1a96fba6SXin Li   SecureBlob blob(32, 0);
94*1a96fba6SXin Li 
95*1a96fba6SXin Li   for (size_t i = 0; i < blob.size(); i++) {
96*1a96fba6SXin Li     EXPECT_EQ(0, blob[i]);
97*1a96fba6SXin Li   }
98*1a96fba6SXin Li }
99*1a96fba6SXin Li 
TEST_F(SecureBlobTest,ConstructorIteratorTest)100*1a96fba6SXin Li TEST_F(SecureBlobTest, ConstructorIteratorTest) {
101*1a96fba6SXin Li   // Checks that constructing a SecureBlob with an iterator works.
102*1a96fba6SXin Li   unsigned char from_data[32];
103*1a96fba6SXin Li   std::iota(std::begin(from_data), std::end(from_data), 0);
104*1a96fba6SXin Li 
105*1a96fba6SXin Li   SecureBlob blob(std::begin(from_data), std::end(from_data));
106*1a96fba6SXin Li 
107*1a96fba6SXin Li   EXPECT_EQ(sizeof(from_data), blob.size());
108*1a96fba6SXin Li 
109*1a96fba6SXin Li   for (unsigned int i = 0; i < sizeof(from_data); i++) {
110*1a96fba6SXin Li     EXPECT_EQ(from_data[i], blob[i]);
111*1a96fba6SXin Li   }
112*1a96fba6SXin Li }
113*1a96fba6SXin Li 
TEST_F(SecureBlobTest,BlobConstructorTest)114*1a96fba6SXin Li TEST_F(SecureBlobTest, BlobConstructorTest) {
115*1a96fba6SXin Li   // Check that constructing a SecureBlob from a Blob works.
116*1a96fba6SXin Li   const std::vector<uint8_t> bytes = {0, 1, 255};
117*1a96fba6SXin Li   const Blob blob(bytes);
118*1a96fba6SXin Li   const SecureBlob secure_blob(blob);
119*1a96fba6SXin Li   EXPECT_EQ(bytes,
120*1a96fba6SXin Li             std::vector<uint8_t>(secure_blob.begin(), secure_blob.end()));
121*1a96fba6SXin Li }
122*1a96fba6SXin Li 
TEST_F(SecureBlobTest,IteratorTest)123*1a96fba6SXin Li TEST_F(SecureBlobTest, IteratorTest) {
124*1a96fba6SXin Li   // Checks that SecureBlob::begin(), SecureBlob::end() work.
125*1a96fba6SXin Li   unsigned char from_data[32];
126*1a96fba6SXin Li   std::iota(std::begin(from_data), std::end(from_data), 0);
127*1a96fba6SXin Li 
128*1a96fba6SXin Li   SecureBlob blob(std::begin(from_data), std::end(from_data));
129*1a96fba6SXin Li 
130*1a96fba6SXin Li   EXPECT_EQ(sizeof(from_data), blob.size());
131*1a96fba6SXin Li 
132*1a96fba6SXin Li   size_t i = 0;
133*1a96fba6SXin Li   for (auto it = blob.begin(); it != blob.end(); ++it) {
134*1a96fba6SXin Li     EXPECT_EQ(from_data[i], *it);
135*1a96fba6SXin Li     ++i;
136*1a96fba6SXin Li   }
137*1a96fba6SXin Li }
138*1a96fba6SXin Li 
TEST_F(SecureBlobTest,AssignTest)139*1a96fba6SXin Li TEST_F(SecureBlobTest, AssignTest) {
140*1a96fba6SXin Li   // Checks that .assign() works.
141*1a96fba6SXin Li   unsigned char from_data[32];
142*1a96fba6SXin Li   std::iota(std::begin(from_data), std::end(from_data), 0);
143*1a96fba6SXin Li 
144*1a96fba6SXin Li   SecureBlob blob;
145*1a96fba6SXin Li   blob.assign(std::begin(from_data), std::end(from_data));
146*1a96fba6SXin Li 
147*1a96fba6SXin Li   EXPECT_EQ(sizeof(from_data), blob.size());
148*1a96fba6SXin Li 
149*1a96fba6SXin Li   size_t i = 0;
150*1a96fba6SXin Li   for (auto it = blob.begin(); it != blob.end(); ++it) {
151*1a96fba6SXin Li     EXPECT_EQ(from_data[i], *it);
152*1a96fba6SXin Li     ++i;
153*1a96fba6SXin Li   }
154*1a96fba6SXin Li 
155*1a96fba6SXin Li   SecureBlob blob2;
156*1a96fba6SXin Li   blob2.assign(blob.begin(), blob.end());
157*1a96fba6SXin Li 
158*1a96fba6SXin Li   EXPECT_EQ(blob, blob2);
159*1a96fba6SXin Li }
160*1a96fba6SXin Li 
161*1a96fba6SXin Li // Disable ResizeTest with Address Sanitizer.
162*1a96fba6SXin Li // https://crbug.com/806013
163*1a96fba6SXin Li #ifndef BRILLO_ASAN_BUILD
TEST_F(SecureBlobTest,ResizeTest)164*1a96fba6SXin Li TEST_F(SecureBlobTest, ResizeTest) {
165*1a96fba6SXin Li   // Check that resizing a SecureBlob wipes the excess memory. The test assumes
166*1a96fba6SXin Li   // that resize() down by one will not re-allocate the memory, so the last byte
167*1a96fba6SXin Li   // will still be part of the SecureBlob's allocation.
168*1a96fba6SXin Li   size_t length = 1024;
169*1a96fba6SXin Li   SecureBlob blob(length);
170*1a96fba6SXin Li   void* original_data = blob.data();
171*1a96fba6SXin Li   for (size_t i = 0; i < length; i++) {
172*1a96fba6SXin Li     blob[i] = i;
173*1a96fba6SXin Li   }
174*1a96fba6SXin Li 
175*1a96fba6SXin Li   blob.resize(length - 1);
176*1a96fba6SXin Li 
177*1a96fba6SXin Li   EXPECT_EQ(original_data, blob.data());
178*1a96fba6SXin Li   EXPECT_EQ(length - 1, blob.size());
179*1a96fba6SXin Li   EXPECT_EQ(0, blob.data()[length - 1]);
180*1a96fba6SXin Li }
181*1a96fba6SXin Li #endif
182*1a96fba6SXin Li 
TEST_F(SecureBlobTest,CombineTest)183*1a96fba6SXin Li TEST_F(SecureBlobTest, CombineTest) {
184*1a96fba6SXin Li   SecureBlob blob1(32);
185*1a96fba6SXin Li   SecureBlob blob2(32);
186*1a96fba6SXin Li   std::iota(blob1.begin(), blob1.end(), 0);
187*1a96fba6SXin Li   std::iota(blob2.begin(), blob2.end(), 32);
188*1a96fba6SXin Li   SecureBlob combined_blob = SecureBlob::Combine(blob1, blob2);
189*1a96fba6SXin Li   EXPECT_EQ(combined_blob.size(), (blob1.size() + blob2.size()));
190*1a96fba6SXin Li   EXPECT_TRUE(SecureBlobTest::FindBlobInBlob(combined_blob, blob1));
191*1a96fba6SXin Li   EXPECT_TRUE(SecureBlobTest::FindBlobInBlob(combined_blob, blob2));
192*1a96fba6SXin Li   int blob1_index = SecureBlobTest::FindBlobIndexInBlob(combined_blob, blob1);
193*1a96fba6SXin Li   int blob2_index = SecureBlobTest::FindBlobIndexInBlob(combined_blob, blob2);
194*1a96fba6SXin Li   EXPECT_EQ(blob1_index, 0);
195*1a96fba6SXin Li   EXPECT_EQ(blob2_index, 32);
196*1a96fba6SXin Li }
197*1a96fba6SXin Li 
TEST_F(SecureBlobTest,BlobToStringTest)198*1a96fba6SXin Li TEST_F(SecureBlobTest, BlobToStringTest) {
199*1a96fba6SXin Li   std::string test_string("Test String");
200*1a96fba6SXin Li   SecureBlob blob = SecureBlob(test_string.begin(), test_string.end());
201*1a96fba6SXin Li   EXPECT_EQ(blob.size(), test_string.length());
202*1a96fba6SXin Li   std::string result_string = blob.to_string();
203*1a96fba6SXin Li   EXPECT_EQ(test_string.compare(result_string), 0);
204*1a96fba6SXin Li }
205*1a96fba6SXin Li 
TEST_F(SecureBlobTest,HexStringToSecureBlob)206*1a96fba6SXin Li TEST_F(SecureBlobTest, HexStringToSecureBlob) {
207*1a96fba6SXin Li   std::string hex_string("112233445566778899aabbccddeeff0f");
208*1a96fba6SXin Li 
209*1a96fba6SXin Li   SecureBlob blob;
210*1a96fba6SXin Li   SecureBlob::HexStringToSecureBlob(hex_string, &blob);
211*1a96fba6SXin Li 
212*1a96fba6SXin Li   EXPECT_EQ(blob.size(), 16u);
213*1a96fba6SXin Li   EXPECT_EQ(blob[0],  0x11);
214*1a96fba6SXin Li   EXPECT_EQ(blob[1],  0x22);
215*1a96fba6SXin Li   EXPECT_EQ(blob[2],  0x33);
216*1a96fba6SXin Li   EXPECT_EQ(blob[3],  0x44);
217*1a96fba6SXin Li   EXPECT_EQ(blob[4],  0x55);
218*1a96fba6SXin Li   EXPECT_EQ(blob[5],  0x66);
219*1a96fba6SXin Li   EXPECT_EQ(blob[6],  0x77);
220*1a96fba6SXin Li   EXPECT_EQ(blob[7],  0x88);
221*1a96fba6SXin Li   EXPECT_EQ(blob[8],  0x99);
222*1a96fba6SXin Li   EXPECT_EQ(blob[9],  0xaa);
223*1a96fba6SXin Li   EXPECT_EQ(blob[10], 0xbb);
224*1a96fba6SXin Li   EXPECT_EQ(blob[11], 0xcc);
225*1a96fba6SXin Li   EXPECT_EQ(blob[12], 0xdd);
226*1a96fba6SXin Li   EXPECT_EQ(blob[13], 0xee);
227*1a96fba6SXin Li   EXPECT_EQ(blob[14], 0xff);
228*1a96fba6SXin Li   EXPECT_EQ(blob[15], 0x0f);
229*1a96fba6SXin Li }
230*1a96fba6SXin Li 
231*1a96fba6SXin Li // Override clear_contents() to check whether memory has been cleared.
232*1a96fba6SXin Li template <typename T>
233*1a96fba6SXin Li class TestSecureAllocator : public SecureAllocator<T> {
234*1a96fba6SXin Li  public:
235*1a96fba6SXin Li   using typename SecureAllocator<T>::size_type;
236*1a96fba6SXin Li   using typename SecureAllocator<T>::value_type;
237*1a96fba6SXin Li 
GetErasedCount()238*1a96fba6SXin Li   int GetErasedCount() { return erased_count; }
239*1a96fba6SXin Li 
240*1a96fba6SXin Li  protected:
clear_contents(value_type * p,size_type n)241*1a96fba6SXin Li   void clear_contents(value_type* p, size_type n) override {
242*1a96fba6SXin Li     SecureAllocator<T>::clear_contents(p, n);
243*1a96fba6SXin Li     unsigned char *v = reinterpret_cast<unsigned char*>(p);
244*1a96fba6SXin Li     for (int i = 0; i < n; i++) {
245*1a96fba6SXin Li       EXPECT_EQ(v[i], 0);
246*1a96fba6SXin Li       erased_count++;
247*1a96fba6SXin Li     }
248*1a96fba6SXin Li   }
249*1a96fba6SXin Li 
250*1a96fba6SXin Li  private:
251*1a96fba6SXin Li   int erased_count = 0;
252*1a96fba6SXin Li };
253*1a96fba6SXin Li 
TEST(SecureAllocator,ErasureOnDeallocation)254*1a96fba6SXin Li TEST(SecureAllocator, ErasureOnDeallocation) {
255*1a96fba6SXin Li   // Make sure that the contents are cleared on deallocation.
256*1a96fba6SXin Li   TestSecureAllocator<char> e;
257*1a96fba6SXin Li   constexpr size_t test_string_sz = 15;
258*1a96fba6SXin Li 
259*1a96fba6SXin Li   char *test_string_addr = e.allocate(test_string_sz);
260*1a96fba6SXin Li   snprintf(test_string_addr, test_string_sz, "Test String");
261*1a96fba6SXin Li 
262*1a96fba6SXin Li   // Deallocate memory; the mock class should check for cleared data.
263*1a96fba6SXin Li   e.deallocate(test_string_addr, 15);
264*1a96fba6SXin Li   // The deallocation should have traversed the complete page.
265*1a96fba6SXin Li   EXPECT_EQ(e.GetErasedCount(), 4096);
266*1a96fba6SXin Li }
267*1a96fba6SXin Li 
TEST(SecureAllocator,MultiPageCorrectness)268*1a96fba6SXin Li TEST(SecureAllocator, MultiPageCorrectness) {
269*1a96fba6SXin Li   // Make sure that the contents are cleared on deallocation.
270*1a96fba6SXin Li   TestSecureAllocator<uint64_t> e;
271*1a96fba6SXin Li 
272*1a96fba6SXin Li   // Allocate 4100*8 bytes.
273*1a96fba6SXin Li   uint64_t *test_array = e.allocate(4100);
274*1a96fba6SXin Li 
275*1a96fba6SXin Li   // Check if the space was correctly allocated for long long.
276*1a96fba6SXin Li   for (int i = 0; i < 4100; i++)
277*1a96fba6SXin Li       test_array[i] = 0xF0F0F0F0F0F0F0F0;
278*1a96fba6SXin Li 
279*1a96fba6SXin Li   // Deallocate memory; the mock class should check for cleared data.
280*1a96fba6SXin Li   e.deallocate(test_array, 4100);
281*1a96fba6SXin Li   // 36864 bytes is the next highest size that is a multiple of the page size.
282*1a96fba6SXin Li   EXPECT_EQ(e.GetErasedCount(), 36864);
283*1a96fba6SXin Li }
284*1a96fba6SXin Li 
285*1a96fba6SXin Li // DeathTests fork a new process and check how it proceeds. Take advantage
286*1a96fba6SXin Li // of this and check if the value of SecureString is passed on to
287*1a96fba6SXin Li // forked children.
288*1a96fba6SXin Li #if GTEST_IS_THREADSAFE
289*1a96fba6SXin Li // Check if the contents of the container are zeroed out.
CheckPropagationOnFork(const brillo::SecureBlob & forked_blob,const Blob & reference)290*1a96fba6SXin Li void CheckPropagationOnFork(const brillo::SecureBlob& forked_blob,
291*1a96fba6SXin Li                             const Blob& reference) {
292*1a96fba6SXin Li   LOG(INFO) << forked_blob.to_string();
293*1a96fba6SXin Li   for (int i = 0; i < forked_blob.size(); i++) {
294*1a96fba6SXin Li     CHECK_NE(reference[i], forked_blob[i]);
295*1a96fba6SXin Li     CHECK_EQ(forked_blob[i], 0);
296*1a96fba6SXin Li   }
297*1a96fba6SXin Li   exit(0);
298*1a96fba6SXin Li }
299*1a96fba6SXin Li 
TEST(SecureAllocatorDeathTest,ErasureOnFork)300*1a96fba6SXin Li TEST(SecureAllocatorDeathTest, ErasureOnFork) {
301*1a96fba6SXin Li   Blob reference = BlobFromString("Test String");
302*1a96fba6SXin Li   SecureBlob erasable_blob(reference.begin(), reference.end());
303*1a96fba6SXin Li 
304*1a96fba6SXin Li   EXPECT_EXIT(CheckPropagationOnFork(erasable_blob, reference),
305*1a96fba6SXin Li               ::testing::ExitedWithCode(0), "");
306*1a96fba6SXin Li 
307*1a96fba6SXin Li   // In the original process, check the SecureBlob to see if it has not
308*1a96fba6SXin Li   // changed.
309*1a96fba6SXin Li   for (int i = 0; i < erasable_blob.size(); i++)
310*1a96fba6SXin Li     EXPECT_EQ(erasable_blob[i], reference[i]);
311*1a96fba6SXin Li }
312*1a96fba6SXin Li #endif  // GTEST_IS_THREADSAFE
313*1a96fba6SXin Li 
314*1a96fba6SXin Li }  // namespace brillo
315