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