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