mirror of
https://github.com/openharmony/third_party_fsverity-utils.git
synced 2026-07-01 10:05:35 -04:00
ab794fd565
This allows libfsverity to be used by software with other common licenses, e.g. LGPL, MIT, BSD, and Apache 2.0. It also avoids the incompatibility that some people perceive between OpenSSL and the GPL. See discussion at https://lkml.kernel.org/linux-fscrypt/20200211000037.189180-1-Jes.Sorensen@gmail.com/T/#u Link: https://lkml.kernel.org/linux-fscrypt/20200731191156.22602-1-ebiggers@kernel.org Acked-by: Chris Mason <clm@fb.com> # FB copyrighted material Acked-by: Jes Sorensen <jsorensen@fb.com> Signed-off-by: Eric Biggers <ebiggers@google.com>
307 lines
8.9 KiB
C
307 lines
8.9 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Test libfsverity_compute_digest().
|
|
*
|
|
* Copyright 2020 Google LLC
|
|
*
|
|
* Use of this source code is governed by an MIT-style
|
|
* license that can be found in the LICENSE file or at
|
|
* https://opensource.org/licenses/MIT.
|
|
*/
|
|
|
|
#include "utils.h"
|
|
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
|
|
struct mem_file {
|
|
u8 *data;
|
|
size_t size;
|
|
size_t offset;
|
|
};
|
|
|
|
static int read_fn(void *fd, void *buf, size_t count)
|
|
{
|
|
struct mem_file *f = fd;
|
|
|
|
ASSERT(count <= f->size - f->offset);
|
|
memcpy(buf, &f->data[f->offset], count);
|
|
f->offset += count;
|
|
return 0;
|
|
}
|
|
|
|
static int error_read_fn(void *fd __attribute__((unused)),
|
|
void *buf __attribute__((unused)),
|
|
size_t count __attribute__((unused)))
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
static const struct test_case {
|
|
u32 hash_algorithm;
|
|
u32 block_size;
|
|
const char *salt;
|
|
u64 file_size;
|
|
const char *digest;
|
|
} test_cases[] = {
|
|
{ /* large file */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 4096,
|
|
.digest = "\x48\xdf\x0c\x46\x23\x29\xcd\x87"
|
|
"\x96\x61\xbd\x05\xb3\x9a\xa8\x1b"
|
|
"\x05\xcc\x16\xaf\xd2\x7a\x71\x96"
|
|
"\xa5\x59\xda\x83\x53\x1d\x39\xd9",
|
|
}, { /* small file */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 100000,
|
|
.block_size = 4096,
|
|
.digest = "\xf2\x09\x6a\x36\xc5\xcd\xca\x4f"
|
|
"\xa3\x3e\xe8\x85\x28\x33\x15\x0b"
|
|
"\xb3\x24\x99\x2e\x54\x17\xa9\xd5"
|
|
"\x71\xf1\xbf\xff\xf7\x3b\x9e\xfc",
|
|
}, { /* single-block file */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 4096,
|
|
.block_size = 4096,
|
|
.digest = "\x6a\xc3\x99\x79\x01\x6e\x3d\xdf"
|
|
"\x3d\x39\xff\xf6\xcb\x98\x4f\x7c"
|
|
"\x11\x8a\xcd\xf1\x85\x29\x19\xf5"
|
|
"\xc1\x00\xc4\xb1\x42\xc1\x81\x8e",
|
|
}, { /* tiny file */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1,
|
|
.block_size = 4096,
|
|
.digest = "\xb8\x03\x42\x95\x03\xd9\x59\x15"
|
|
"\x82\x9b\x29\xfd\xbc\x8b\xba\xd1"
|
|
"\x42\xf3\xab\xfd\x11\xb1\xca\xdf"
|
|
"\x55\x26\x58\x2e\x68\x5c\x05\x51",
|
|
}, { /* empty file */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 0,
|
|
.block_size = 4096,
|
|
.digest = "\x3d\x24\x8c\xa5\x42\xa2\x4f\xc6"
|
|
"\x2d\x1c\x43\xb9\x16\xea\xe5\x01"
|
|
"\x68\x78\xe2\x53\x3c\x88\x23\x84"
|
|
"\x80\xb2\x61\x28\xa1\xf1\xaf\x95",
|
|
}, { /* salt */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 4096,
|
|
.salt = "abcd",
|
|
.digest = "\x91\x79\x00\xb0\xd2\x99\x45\x4a"
|
|
"\xa3\x04\xd5\xde\xbc\x6f\x39\xe4"
|
|
"\xaf\x7b\x5a\xbe\x33\xbd\xbc\x56"
|
|
"\x8d\x5d\x8f\x1e\x5c\x4d\x86\x52",
|
|
}, { /* max length salt (32 bytes) */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 4096,
|
|
.salt = "0123456789:;<=>?@ABCDEFGHIJKLMNO",
|
|
.digest = "\xbc\x2d\x70\x32\x4c\x04\x8c\x22"
|
|
"\x0a\x2c\xb1\x90\x83\x21\x40\x86"
|
|
"\x3e\xb2\x68\xe6\x80\x42\x79\x39"
|
|
"\xe5\xd4\x67\xbe\xa5\xec\x5a\xd9",
|
|
}, { /* 1K block size */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 1024,
|
|
.digest = "\xe9\xdf\x92\x7c\x14\xfc\xb9\x61"
|
|
"\xd5\xf5\x1c\x66\x6d\x8a\xe4\xc1"
|
|
"\x4f\xe4\xff\x98\xa3\x74\xc7\x33"
|
|
"\xe8\x98\xd0\x0c\x9e\x74\xa8\xe3",
|
|
}, { /* 512-byte block size */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 512,
|
|
.digest = "\x03\x93\xee\x3d\xfd\x4a\x28\x96"
|
|
"\x6e\x2a\xf4\xe0\x7c\xfa\x5b\x03"
|
|
"\x2c\x30\xda\x5b\xb8\xe8\xef\x63"
|
|
"\xb9\xa5\x5b\xf9\x63\x26\x23\x34",
|
|
}, { /* 64K block size */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 1000000,
|
|
.block_size = 65536,
|
|
.digest = "\xf3\xb6\x41\x8f\x26\xd4\xd0\xe7"
|
|
"\x47\x28\x19\x3b\xae\x76\xf1\x5c"
|
|
"\xb4\xbb\x2c\xe9\x77\x74\x48\xd7"
|
|
"\x6b\xd8\x13\x8b\x69\xec\x61\xc2",
|
|
}, { /* SHA-512 */
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA512,
|
|
.file_size = 1000000,
|
|
.block_size = 4096,
|
|
.salt = "abcd",
|
|
.digest = "\x84\x25\xc6\xd0\xc9\x4f\x84\xed"
|
|
"\x90\x4c\x12\x93\x68\x45\xfb\xb7"
|
|
"\xaf\x99\x53\x75\x37\x89\x71\x2d"
|
|
"\xcc\x3b\xe1\x42\xdb\x3d\x4b\x6b"
|
|
"\x47\xa3\x99\xad\x52\xaa\x60\x92"
|
|
"\x56\xce\x29\xa9\x60\xbf\x4b\xb0"
|
|
"\xe5\x95\xec\x38\x6c\xa5\x8c\x06"
|
|
"\x51\x9d\x54\x6d\xc5\xb1\x97\xbb",
|
|
}
|
|
};
|
|
|
|
static void fix_digest_and_print(const struct test_case *t,
|
|
const struct libfsverity_digest *d)
|
|
{
|
|
char alg_name[32] = {};
|
|
size_t i;
|
|
|
|
strncpy(alg_name, libfsverity_get_hash_name(t->hash_algorithm),
|
|
sizeof(alg_name) - 1);
|
|
for (i = 0; i < sizeof(alg_name) - 1; i++)
|
|
alg_name[i] = toupper((u8)alg_name[i]);
|
|
|
|
printf("\t}, {\n"
|
|
"\t\t.hash_algorithm = FS_VERITY_HASH_ALG_%s,\n"
|
|
"\t\t.file_size = %" PRIu64 ",\n"
|
|
"\t\t.block_size = %u,\n",
|
|
alg_name, t->file_size, t->block_size);
|
|
if (t->salt != NULL)
|
|
printf("\t\t.salt = \"%s\",\n", t->salt);
|
|
for (i = 0; i < d->digest_size; i++) {
|
|
if (i == 0)
|
|
printf("\t\t.digest = \"");
|
|
else if (i % 8 == 0)
|
|
printf("\t\t\t \"");
|
|
printf("\\x%02x", d->digest[i]);
|
|
if (i + 1 == d->digest_size)
|
|
printf("\",\n");
|
|
else if (i % 8 == 7)
|
|
printf("\"\n");
|
|
}
|
|
}
|
|
|
|
static void test_invalid_params(void)
|
|
{
|
|
struct mem_file f = { .data = (u8 *)"abcd", .size = 4 };
|
|
struct libfsverity_merkle_tree_params good_params = {
|
|
.version = 1,
|
|
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
|
|
.file_size = 4,
|
|
.block_size = 4096,
|
|
};
|
|
struct libfsverity_merkle_tree_params params;
|
|
struct libfsverity_digest *d = NULL;
|
|
|
|
libfsverity_set_error_callback(NULL);
|
|
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, &d) == 0);
|
|
f.offset = 0;
|
|
free(d);
|
|
d = NULL;
|
|
|
|
/* missing required arguments */
|
|
ASSERT(libfsverity_compute_digest(&f, NULL, &good_params, &d) == -EINVAL);
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, NULL, &d) == -EINVAL);
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, NULL) == -EINVAL);
|
|
|
|
/* bad version */
|
|
params = good_params;
|
|
params.version = 0;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params.version = 1000;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
|
|
/* bad hash_algorithm */
|
|
params = good_params;
|
|
params.hash_algorithm = 0;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params.hash_algorithm = 1000;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
|
|
/* bad block_size */
|
|
params = good_params;
|
|
params.block_size = 0;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params.block_size = 1;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params.block_size = 4097;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
|
|
/* bad salt_size */
|
|
params = good_params;
|
|
params.salt_size = 1000;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params.salt = (u8 *)"";
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
|
|
/* bad reserved fields */
|
|
params = good_params;
|
|
params.reserved1[0] = 1;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params = good_params;
|
|
params.reserved1[ARRAY_SIZE(params.reserved1) - 1] = 1;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params = good_params;
|
|
params.reserved2[0] = 1;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
params = good_params;
|
|
params.reserved2[ARRAY_SIZE(params.reserved2) - 1] = 1;
|
|
ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL);
|
|
|
|
/* error reading file */
|
|
ASSERT(libfsverity_compute_digest(&f, error_read_fn, &good_params, &d) == -EIO);
|
|
|
|
ASSERT(d == NULL);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
const bool update = (argc == 2 && !strcmp(argv[1], "--update"));
|
|
size_t i;
|
|
struct mem_file f = {};
|
|
struct libfsverity_merkle_tree_params params;
|
|
struct libfsverity_digest *d;
|
|
int err;
|
|
|
|
install_libfsverity_error_handler();
|
|
|
|
for (i = 0; i < ARRAY_SIZE(test_cases); i++)
|
|
f.size = max(f.size, test_cases[i].file_size);
|
|
|
|
f.data = xmalloc(f.size);
|
|
for (i = 0; i < f.size; i++)
|
|
f.data[i] = (i % 11) + (i % 439) + (i % 1103);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.version = 1;
|
|
params.hash_algorithm = test_cases[i].hash_algorithm;
|
|
params.file_size = test_cases[i].file_size;
|
|
params.block_size = test_cases[i].block_size;
|
|
if (test_cases[i].salt) {
|
|
params.salt = (const u8 *)test_cases[i].salt;
|
|
params.salt_size = strlen(test_cases[i].salt);
|
|
}
|
|
|
|
f.size = test_cases[i].file_size;
|
|
f.offset = 0;
|
|
|
|
err = libfsverity_compute_digest(&f, read_fn, ¶ms, &d);
|
|
ASSERT(err == 0);
|
|
|
|
ASSERT(d->digest_algorithm == test_cases[i].hash_algorithm);
|
|
ASSERT(d->digest_size ==
|
|
libfsverity_get_digest_size(test_cases[i].hash_algorithm));
|
|
if (update)
|
|
fix_digest_and_print(&test_cases[i], d);
|
|
else
|
|
ASSERT(!memcmp(d->digest, test_cases[i].digest,
|
|
d->digest_size));
|
|
free(d);
|
|
d = NULL;
|
|
}
|
|
free(f.data);
|
|
if (update) {
|
|
printf("\t}\n");
|
|
return 1;
|
|
}
|
|
|
|
test_invalid_params();
|
|
printf("test_compute_digest passed\n");
|
|
return 0;
|
|
}
|