From: Jes Sorensen <jsorensen@xxxxxx> This preps the code for splitting the signing into the shared library Signed-off-by: Jes Sorensen <jsorensen@xxxxxx> --- cmd_sign.c | 48 +++++++++++++++++++++++++++++++++++++----------- fsverity.c | 1 + libfsverity.h | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 libfsverity.h diff --git a/cmd_sign.c b/cmd_sign.c index dcb37ce..dcc44f8 100644 --- a/cmd_sign.c +++ b/cmd_sign.c @@ -16,6 +16,8 @@ #include <openssl/pkcs7.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <unistd.h> #include "commands.h" #include "fsverity_uapi.h" @@ -382,11 +384,30 @@ static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur, return next->filled + hash->alg->digest_size > block_size; } +static int full_read_fd(int fd, void *buf, size_t count) +{ + while (count) { + int n = read(fd, buf, min(count, INT_MAX)); + + if (n < 0) { + error_msg_errno("reading from file"); + return n; + } + if (n == 0) { + error_msg("unexpected end-of-file"); + return -ENODATA; + } + buf += n; + count -= n; + } + return 0; +} + /* * Compute the file's Merkle tree root hash using the given hash algorithm, * block size, and salt. */ -static bool compute_root_hash(struct filedes *file, u64 file_size, +static bool compute_root_hash(int fd, u64 file_size, struct hash_ctx *hash, u32 block_size, const u8 *salt, u32 salt_size, u8 *root_hash) { @@ -424,7 +445,7 @@ static bool compute_root_hash(struct filedes *file, u64 file_size, for (offset = 0; offset < file_size; offset += block_size) { buffers[-1].filled = min(block_size, file_size - offset); - if (!full_read(file, buffers[-1].data, buffers[-1].filled)) + if (full_read_fd(fd, buffers[-1].data, buffers[-1].filled)) goto out; level = -1; @@ -457,22 +478,22 @@ out: * The fs-verity measurement is the hash of the fsverity_descriptor, which * contains the Merkle tree properties including the root hash. */ -static bool compute_file_measurement(const char *filename, +static bool compute_file_measurement(int fd, const struct fsverity_hash_alg *hash_alg, u32 block_size, const u8 *salt, u32 salt_size, u8 *measurement) { - struct filedes file = { .fd = -1 }; struct hash_ctx *hash = hash_create(hash_alg); u64 file_size; struct fsverity_descriptor desc; + struct stat stbuf; bool ok = false; - if (!open_file(&file, filename, O_RDONLY, 0)) - goto out; - - if (!get_file_size(&file, &file_size)) + if (fstat(fd, &stbuf) != 0) { + error_msg_errno("can't stat input file"); goto out; + } + file_size = stbuf.st_size; memset(&desc, 0, sizeof(desc)); desc.version = 1; @@ -495,14 +516,13 @@ static bool compute_file_measurement(const char *filename, /* Root hash of empty file is all 0's */ if (file_size != 0 && - !compute_root_hash(&file, file_size, hash, block_size, salt, + !compute_root_hash(fd, file_size, hash, block_size, salt, salt_size, desc.root_hash)) goto out; hash_full(hash, &desc, sizeof(desc), measurement); ok = true; out: - filedes_close(&file); hash_free(hash); return ok; } @@ -529,6 +549,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd, int argc, char *argv[]) { const struct fsverity_hash_alg *hash_alg = NULL; + struct filedes file = { .fd = -1 }; u32 block_size = 0; u8 *salt = NULL; u32 salt_size = 0; @@ -603,10 +624,15 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd, digest->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs); digest->digest_size = cpu_to_le16(hash_alg->digest_size); - if (!compute_file_measurement(argv[0], hash_alg, block_size, + if (!open_file(&file, argv[0], O_RDONLY, 0)) + goto out_err; + + if (!compute_file_measurement(file.fd, hash_alg, block_size, salt, salt_size, digest->digest)) goto out_err; + filedes_close(&file); + if (!sign_data(digest, sizeof(*digest) + hash_alg->digest_size, keyfile, certfile, hash_alg, &sig, &sig_size)) goto out_err; diff --git a/fsverity.c b/fsverity.c index 9a44df1..c8fa1b5 100644 --- a/fsverity.c +++ b/fsverity.c @@ -14,6 +14,7 @@ #include "commands.h" #include "hash_algs.h" +#include "libfsverity.h" static const struct fsverity_command { const char *name; diff --git a/libfsverity.h b/libfsverity.h new file mode 100644 index 0000000..ceebae1 --- /dev/null +++ b/libfsverity.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * libfsverity API + * + * Copyright (C) 2018 Google LLC + * Copyright (C) 2020 Facebook + * + * Written by Eric Biggers and modified by Jes Sorensen. + */ + +#ifndef _LIBFSVERITY_H +#define _LIBFSVERITY_H + +#include <stddef.h> +#include <stdint.h> + +#define FS_VERITY_HASH_ALG_SHA256 1 +#define FS_VERITY_HASH_ALG_SHA512 2 + +struct libfsverity_merkle_tree_params { + uint16_t version; + uint16_t hash_algorithm; + uint32_t block_size; + uint32_t salt_size; + const uint8_t *salt; + uint64_t reserved[11]; +}; + +struct libfsverity_digest { + uint16_t digest_algorithm; + uint16_t digest_size; + uint8_t digest[]; +}; + +struct libfsverity_signature_params { + const char *keyfile; + const char *certfile; + uint64_t reserved[11]; +}; + +#endif -- 2.25.3