1 // Copyright 2017 The Fuchsia 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 #include <digest/digest.h>
6 
7 #include <stdlib.h>
8 
9 #include <zircon/status.h>
10 #include <unittest/unittest.h>
11 
12 #include <utility>
13 
14 // These unit tests are for the Digest object in ulib/digest.
15 
16 namespace {
17 
18 ////////////////
19 // Test support.
20 
21 using digest::Digest;
22 
23 // echo -n | sha256sum
24 const char* kZeroDigest =
25     "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
26 // echo -n | sha256sum | cut -c1-64 | tr -d '\n' | xxd -p -r | sha256sum
27 const char* kDoubleZeroDigest =
28     "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456";
29 
30 ////////////////
31 // Test cases
32 
DigestStrings(void)33 bool DigestStrings(void) {
34     BEGIN_TEST;
35     Digest actual;
36     zx_status_t rc = actual.Parse(kZeroDigest, strlen(kZeroDigest));
37     char buf[(Digest::kLength * 2) + 1];
38     rc = actual.ToString(buf, sizeof(buf));
39     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
40     ASSERT_EQ(strncmp(kZeroDigest, buf, sizeof(buf)), 0, __FUNCTION__);
41     END_TEST;
42 }
43 
DigestZero(void)44 bool DigestZero(void) {
45     BEGIN_TEST;
46     Digest actual, expected;
47     zx_status_t rc = expected.Parse(kZeroDigest, strlen(kZeroDigest));
48     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
49     actual.Hash(nullptr, 0);
50     ASSERT_TRUE(actual == expected, __FUNCTION__);
51     END_TEST;
52 }
53 
DigestSelf(void)54 bool DigestSelf(void) {
55     BEGIN_TEST;
56     Digest actual, expected;
57     zx_status_t rc =
58         expected.Parse(kDoubleZeroDigest, strlen(kDoubleZeroDigest));
59     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
60     rc = actual.Parse(kZeroDigest, strlen(kZeroDigest));
61     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
62     uint8_t buf[Digest::kLength];
63     rc = actual.CopyTo(buf, sizeof(buf));
64     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
65     actual.Hash(buf, Digest::kLength);
66     ASSERT_TRUE(actual == expected, __FUNCTION__);
67     END_TEST;
68 }
69 
DigestSplit(void)70 bool DigestSplit(void) {
71     BEGIN_TEST;
72     Digest actual, expected;
73     actual.Init();
74     size_t n = strlen(kZeroDigest);
75     expected.Hash(kZeroDigest, n);
76     for (size_t i = 1; i < n; ++i) {
77         actual.Init();
78         actual.Update(kZeroDigest, i);
79         actual.Update(kZeroDigest + i, n - i);
80         actual.Final();
81         ASSERT_TRUE(actual == expected, __FUNCTION__);
82     }
83     END_TEST;
84 }
85 
DigestCWrappers(void)86 bool DigestCWrappers(void) {
87     BEGIN_TEST;
88     uint8_t buf[Digest::kLength];
89     zx_status_t rc = digest_hash(nullptr, 0, buf, sizeof(buf) - 1);
90     ASSERT_EQ(rc, ZX_ERR_BUFFER_TOO_SMALL, "Small buffer should be rejected");
91     rc = digest_hash(nullptr, 0, buf, sizeof(buf));
92     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
93     Digest expected;
94     rc = expected.Parse(kZeroDigest, strlen(kZeroDigest));
95     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
96     ASSERT_TRUE(expected == buf, __FUNCTION__);
97     digest_t* digest = nullptr;
98     rc = digest_init(&digest);
99     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
100     expected.Hash(buf, sizeof(buf));
101     digest_update(digest, buf, sizeof(buf));
102     rc = digest_final(digest, buf, sizeof(buf));
103     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
104     ASSERT_TRUE(expected == buf, __FUNCTION__);
105     END_TEST;
106 }
107 
DigestEquality(void)108 bool DigestEquality(void) {
109     BEGIN_TEST;
110     Digest actual, expected;
111     zx_status_t rc = expected.Parse(kZeroDigest, strlen(kZeroDigest));
112     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
113     rc = actual.Parse(kZeroDigest, strlen(kZeroDigest));
114     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
115     ASSERT_FALSE(actual == nullptr, "Does not equal NULL");
116     ASSERT_TRUE(actual == actual, "Equals self");
117     const uint8_t* actual_bytes = actual.AcquireBytes();
118     const uint8_t* expected_bytes = expected.AcquireBytes();
119     ASSERT_TRUE(actual == actual_bytes, "Equals self.bytes_");
120     ASSERT_TRUE(actual == expected, "Equals expected");
121     ASSERT_TRUE(actual == expected_bytes, "Equals expected.bytes_");
122     ASSERT_TRUE(actual != nullptr, "Doesn't equal NULL");
123     ASSERT_FALSE(actual != actual, "Doesn't not equal self");
124     ASSERT_FALSE(actual != actual_bytes, "Doesn't not equal self.bytes_");
125     ASSERT_FALSE(actual != expected, "Doesn't not equal expected");
126     ASSERT_FALSE(actual != expected_bytes, "Doesn't not equal expected.bytes_");
127     expected.ReleaseBytes();
128     actual.ReleaseBytes();
129     END_TEST;
130 }
131 
DigestMove(void)132 bool DigestMove(void) {
133     BEGIN_TEST;
134     const Digest uninitialized_digest;
135     Digest digest1;
136 
137     {
138         // Verify that digest1 is not valid, and that it's current digest value
139         // is all zeros.  Verify that when move digest1 into digest2, that
140         // both retain this property (not valid, digest full of zeros)
141         ASSERT_TRUE(digest1 == uninitialized_digest);
142         ASSERT_FALSE(digest1.is_valid());
143 
144         Digest digest2(std::move(digest1));
145         ASSERT_TRUE(digest1 == uninitialized_digest);
146         ASSERT_FALSE(digest1.is_valid());
147         ASSERT_TRUE(digest2 == uninitialized_digest);
148         ASSERT_FALSE(digest2.is_valid());
149     }
150 
151     // Start a hash operation in digest1, verify that this does not update the
152     // initial hash value.
153     zx_status_t rc = digest1.Init();
154     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
155     ASSERT_TRUE(digest1 == uninitialized_digest);
156     ASSERT_TRUE(digest1.is_valid());
157 
158     // Hash some nothing into the hash.  Again veryify the digest is still
159     // valid, but that the internal result is still full of nothing.
160     digest1.Hash(nullptr, 0);
161     ASSERT_TRUE(digest1 == uninitialized_digest);
162     ASSERT_TRUE(digest1.is_valid());
163 
164     // Move the hash into digest2.  Verify that the context goes with the move
165     // operation.
166     Digest digest2(std::move(digest1));
167     ASSERT_TRUE(digest1 == uninitialized_digest);
168     ASSERT_FALSE(digest1.is_valid());
169     ASSERT_TRUE(digest1 == uninitialized_digest);
170     ASSERT_TRUE(digest2.is_valid());
171 
172     // Finish the hash operation started in digest1 which was moved into
173     // digest2.  Verify that digest2 is no longer valid, but that the result is
174     // what we had expected.
175     Digest zero_digest;
176     rc = zero_digest.Parse(kZeroDigest, strlen(kZeroDigest));
177     ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc));
178     digest2.Final();
179     ASSERT_FALSE(digest2.is_valid());
180     ASSERT_TRUE(digest2 == zero_digest);
181 
182     // Move the result of the hash into a new digest3.  Verify that neither is
183     // valid, but that the result was properly moved.
184     Digest digest3(std::move(digest2));
185     ASSERT_FALSE(digest2.is_valid());
186     ASSERT_FALSE(digest3.is_valid());
187     ASSERT_TRUE(digest2 == uninitialized_digest);
188     ASSERT_TRUE(digest3 == zero_digest);
189 
190     END_TEST;
191 }
192 
193 } // namespace
194 BEGIN_TEST_CASE(DigestTests)
195 RUN_TEST(DigestStrings)
196 RUN_TEST(DigestZero)
197 RUN_TEST(DigestSelf)
198 RUN_TEST(DigestSplit)
199 RUN_TEST(DigestCWrappers)
200 RUN_TEST(DigestEquality)
201 END_TEST_CASE(DigestTests)
202