1 // SPDX-License-Identifier: MIT
2 /*
3 * Test libfsverity_compute_digest().
4 *
5 * Copyright 2020 Google LLC
6 *
7 * Use of this source code is governed by an MIT-style
8 * license that can be found in the LICENSE file or at
9 * https://opensource.org/licenses/MIT.
10 */
11
12 #include "utils.h"
13
14 #include <ctype.h>
15 #include <inttypes.h>
16
17 struct mem_file {
18 u8 *data;
19 size_t size;
20 size_t offset;
21 };
22
read_fn(void * fd,void * buf,size_t count)23 static int read_fn(void *fd, void *buf, size_t count)
24 {
25 struct mem_file *f = fd;
26
27 ASSERT(count <= f->size - f->offset);
28 memcpy(buf, &f->data[f->offset], count);
29 f->offset += count;
30 return 0;
31 }
32
error_read_fn(void * fd,void * buf,size_t count)33 static int error_read_fn(void *fd __attribute__((unused)),
34 void *buf __attribute__((unused)),
35 size_t count __attribute__((unused)))
36 {
37 return -EIO;
38 }
39
40 static const struct test_case {
41 u32 hash_algorithm;
42 u32 block_size;
43 const char *salt;
44 u64 file_size;
45 const char *digest;
46 } test_cases[] = {
47 { /* large file */
48 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
49 .file_size = 1000000,
50 .block_size = 4096,
51 .digest = "\x48\xdf\x0c\x46\x23\x29\xcd\x87"
52 "\x96\x61\xbd\x05\xb3\x9a\xa8\x1b"
53 "\x05\xcc\x16\xaf\xd2\x7a\x71\x96"
54 "\xa5\x59\xda\x83\x53\x1d\x39\xd9",
55 }, { /* small file */
56 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
57 .file_size = 100000,
58 .block_size = 4096,
59 .digest = "\xf2\x09\x6a\x36\xc5\xcd\xca\x4f"
60 "\xa3\x3e\xe8\x85\x28\x33\x15\x0b"
61 "\xb3\x24\x99\x2e\x54\x17\xa9\xd5"
62 "\x71\xf1\xbf\xff\xf7\x3b\x9e\xfc",
63 }, { /* single-block file */
64 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
65 .file_size = 4096,
66 .block_size = 4096,
67 .digest = "\x6a\xc3\x99\x79\x01\x6e\x3d\xdf"
68 "\x3d\x39\xff\xf6\xcb\x98\x4f\x7c"
69 "\x11\x8a\xcd\xf1\x85\x29\x19\xf5"
70 "\xc1\x00\xc4\xb1\x42\xc1\x81\x8e",
71 }, { /* tiny file */
72 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
73 .file_size = 1,
74 .block_size = 4096,
75 .digest = "\xb8\x03\x42\x95\x03\xd9\x59\x15"
76 "\x82\x9b\x29\xfd\xbc\x8b\xba\xd1"
77 "\x42\xf3\xab\xfd\x11\xb1\xca\xdf"
78 "\x55\x26\x58\x2e\x68\x5c\x05\x51",
79 }, { /* empty file */
80 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
81 .file_size = 0,
82 .block_size = 4096,
83 .digest = "\x3d\x24\x8c\xa5\x42\xa2\x4f\xc6"
84 "\x2d\x1c\x43\xb9\x16\xea\xe5\x01"
85 "\x68\x78\xe2\x53\x3c\x88\x23\x84"
86 "\x80\xb2\x61\x28\xa1\xf1\xaf\x95",
87 }, { /* salt */
88 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
89 .file_size = 1000000,
90 .block_size = 4096,
91 .salt = "abcd",
92 .digest = "\x91\x79\x00\xb0\xd2\x99\x45\x4a"
93 "\xa3\x04\xd5\xde\xbc\x6f\x39\xe4"
94 "\xaf\x7b\x5a\xbe\x33\xbd\xbc\x56"
95 "\x8d\x5d\x8f\x1e\x5c\x4d\x86\x52",
96 }, { /* max length salt (32 bytes) */
97 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
98 .file_size = 1000000,
99 .block_size = 4096,
100 .salt = "0123456789:;<=>?@ABCDEFGHIJKLMNO",
101 .digest = "\xbc\x2d\x70\x32\x4c\x04\x8c\x22"
102 "\x0a\x2c\xb1\x90\x83\x21\x40\x86"
103 "\x3e\xb2\x68\xe6\x80\x42\x79\x39"
104 "\xe5\xd4\x67\xbe\xa5\xec\x5a\xd9",
105 }, { /* 1K block size */
106 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
107 .file_size = 1000000,
108 .block_size = 1024,
109 .digest = "\xe9\xdf\x92\x7c\x14\xfc\xb9\x61"
110 "\xd5\xf5\x1c\x66\x6d\x8a\xe4\xc1"
111 "\x4f\xe4\xff\x98\xa3\x74\xc7\x33"
112 "\xe8\x98\xd0\x0c\x9e\x74\xa8\xe3",
113 }, { /* 512-byte block size */
114 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
115 .file_size = 1000000,
116 .block_size = 512,
117 .digest = "\x03\x93\xee\x3d\xfd\x4a\x28\x96"
118 "\x6e\x2a\xf4\xe0\x7c\xfa\x5b\x03"
119 "\x2c\x30\xda\x5b\xb8\xe8\xef\x63"
120 "\xb9\xa5\x5b\xf9\x63\x26\x23\x34",
121 }, { /* 64K block size */
122 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
123 .file_size = 1000000,
124 .block_size = 65536,
125 .digest = "\xf3\xb6\x41\x8f\x26\xd4\xd0\xe7"
126 "\x47\x28\x19\x3b\xae\x76\xf1\x5c"
127 "\xb4\xbb\x2c\xe9\x77\x74\x48\xd7"
128 "\x6b\xd8\x13\x8b\x69\xec\x61\xc2",
129 }, { /* SHA-512 */
130 .hash_algorithm = FS_VERITY_HASH_ALG_SHA512,
131 .file_size = 1000000,
132 .block_size = 4096,
133 .salt = "abcd",
134 .digest = "\x84\x25\xc6\xd0\xc9\x4f\x84\xed"
135 "\x90\x4c\x12\x93\x68\x45\xfb\xb7"
136 "\xaf\x99\x53\x75\x37\x89\x71\x2d"
137 "\xcc\x3b\xe1\x42\xdb\x3d\x4b\x6b"
138 "\x47\xa3\x99\xad\x52\xaa\x60\x92"
139 "\x56\xce\x29\xa9\x60\xbf\x4b\xb0"
140 "\xe5\x95\xec\x38\x6c\xa5\x8c\x06"
141 "\x51\x9d\x54\x6d\xc5\xb1\x97\xbb",
142 }, { /* default hash algorithm (SHA-256) and block size (4096) */
143 .file_size = 100000,
144 .digest = "\xf2\x09\x6a\x36\xc5\xcd\xca\x4f"
145 "\xa3\x3e\xe8\x85\x28\x33\x15\x0b"
146 "\xb3\x24\x99\x2e\x54\x17\xa9\xd5"
147 "\x71\xf1\xbf\xff\xf7\x3b\x9e\xfc",
148 },
149 };
150
fix_digest_and_print(const struct test_case * t,const struct libfsverity_digest * d)151 static void fix_digest_and_print(const struct test_case *t,
152 const struct libfsverity_digest *d)
153 {
154 char alg_name[32] = {};
155 size_t i;
156
157 strncpy(alg_name, libfsverity_get_hash_name(t->hash_algorithm),
158 sizeof(alg_name) - 1);
159 for (i = 0; i < sizeof(alg_name) - 1; i++)
160 alg_name[i] = toupper((u8)alg_name[i]);
161
162 printf("\t}, {\n"
163 "\t\t.hash_algorithm = FS_VERITY_HASH_ALG_%s,\n"
164 "\t\t.file_size = %" PRIu64 ",\n"
165 "\t\t.block_size = %u,\n",
166 alg_name, t->file_size, t->block_size);
167 if (t->salt != NULL)
168 printf("\t\t.salt = \"%s\",\n", t->salt);
169 for (i = 0; i < d->digest_size; i++) {
170 if (i == 0)
171 printf("\t\t.digest = \"");
172 else if (i % 8 == 0)
173 printf("\t\t\t \"");
174 printf("\\x%02x", d->digest[i]);
175 if (i + 1 == d->digest_size)
176 printf("\",\n");
177 else if (i % 8 == 7)
178 printf("\"\n");
179 }
180 }
181
test_invalid_params(void)182 static void test_invalid_params(void)
183 {
184 struct mem_file f = { .data = (u8 *)"abcd", .size = 4 };
185 struct libfsverity_merkle_tree_params good_params = {
186 .version = 1,
187 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
188 .file_size = 4,
189 .block_size = 4096,
190 };
191 struct libfsverity_merkle_tree_params params;
192 struct libfsverity_digest *d = NULL;
193
194 libfsverity_set_error_callback(NULL);
195
196 ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, &d) == 0);
197 f.offset = 0;
198 free(d);
199 d = NULL;
200
201 /* missing required arguments */
202 ASSERT(libfsverity_compute_digest(&f, NULL, &good_params, &d) == -EINVAL);
203 ASSERT(libfsverity_compute_digest(&f, read_fn, NULL, &d) == -EINVAL);
204 ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, NULL) == -EINVAL);
205
206 /* bad version */
207 params = good_params;
208 params.version = 0;
209 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
210 params.version = 1000;
211 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
212
213 /* bad hash_algorithm */
214 params = good_params;
215 params.hash_algorithm = 1000;
216 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
217
218 /* bad block_size */
219 params = good_params;
220 params.block_size = 1;
221 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
222 params.block_size = 4097;
223 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
224
225 /* bad salt_size */
226 params = good_params;
227 params.salt_size = 1000;
228 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
229 params.salt = (u8 *)"";
230 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
231
232 /* bad reserved fields */
233 params = good_params;
234 params.reserved1[0] = 1;
235 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
236 params = good_params;
237 params.reserved1[ARRAY_SIZE(params.reserved1) - 1] = 1;
238 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
239 params = good_params;
240 params.reserved2[0] = 1;
241 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
242 params = good_params;
243 params.reserved2[ARRAY_SIZE(params.reserved2) - 1] = 1;
244 ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
245
246 /* error reading file */
247 ASSERT(libfsverity_compute_digest(&f, error_read_fn, &good_params, &d) == -EIO);
248
249 ASSERT(d == NULL);
250 }
251
main(int argc,char * argv[])252 int main(int argc, char *argv[])
253 {
254 const bool update = (argc == 2 && !strcmp(argv[1], "--update"));
255 size_t i;
256 struct mem_file f = {};
257 struct libfsverity_merkle_tree_params params;
258 struct libfsverity_digest *d;
259 int err;
260
261 install_libfsverity_error_handler();
262
263 for (i = 0; i < ARRAY_SIZE(test_cases); i++)
264 f.size = max(f.size, test_cases[i].file_size);
265
266 f.data = xmalloc(f.size);
267 for (i = 0; i < f.size; i++)
268 f.data[i] = (i % 11) + (i % 439) + (i % 1103);
269
270 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
271 u32 expected_alg = test_cases[i].hash_algorithm ?:
272 FS_VERITY_HASH_ALG_SHA256;
273
274 memset(¶ms, 0, sizeof(params));
275 params.version = 1;
276 params.hash_algorithm = test_cases[i].hash_algorithm;
277 params.file_size = test_cases[i].file_size;
278 params.block_size = test_cases[i].block_size;
279 if (test_cases[i].salt) {
280 params.salt = (const u8 *)test_cases[i].salt;
281 params.salt_size = strlen(test_cases[i].salt);
282 }
283
284 f.size = test_cases[i].file_size;
285 f.offset = 0;
286
287 err = libfsverity_compute_digest(&f, read_fn, ¶ms, &d);
288 ASSERT(err == 0);
289
290 ASSERT(d->digest_algorithm == expected_alg);
291 ASSERT(d->digest_size ==
292 libfsverity_get_digest_size(expected_alg));
293 if (update)
294 fix_digest_and_print(&test_cases[i], d);
295 else
296 ASSERT(!memcmp(d->digest, test_cases[i].digest,
297 d->digest_size));
298 free(d);
299 d = NULL;
300 }
301 free(f.data);
302 if (update) {
303 printf("\t}\n");
304 return 1;
305 }
306
307 test_invalid_params();
308 printf("test_compute_digest passed\n");
309 return 0;
310 }
311