linux-fscrypt.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/20] Split fsverity-utils into a shared library
@ 2020-04-24 20:54 Jes Sorensen
  2020-04-24 20:54 ` [PATCH 01/20] Build basic shared library framework Jes Sorensen
                   ` (20 more replies)
  0 siblings, 21 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Hi

This is an update to the libfsverity patches I posted about a month
ago, which I believe address all the issues in the feedback I received.

I have a version of rpm that requires this library which is able to
sign files and a plugin which will install fsverity signatures when
the rpm is installed. The code for rpm can be found on github - note
that I do rebase the repo as I fix bugs:
https://github.com/jessorensen/rpm/tree/rpm-fsverity

A git tree with these patches can also be found here:
https://git.kernel.org/pub/scm/linux/kernel/git/jes/fsverity-utils.git

This update changes a number of issues:
- Change the API for libfsverity_compute_digest() to take a callback
  read function, which is needed to deal with the internal cpio
  processing of rpm.
- Provides the option to build fsverity linked statically against
  libfsverity
- Makefile support to install libfsverity.so, libfsverity.h and sets
  the soname
- Make struct fsverity_descriptor and struct fsverity_hash_alg
  internal to the library
- Improved documentation of the API in libfsverity.h

I have a .spec file for it that packages this into an rpm for Fedora,
as well as a packaged version of rpm with fsverity support in it,
which I am happy to share.

Let me know what you think!

Thanks,
Jes


Jes Sorensen (20):
  Build basic shared library framework
  Change compute_file_measurement() to take a file descriptor as
    argument
  Move fsverity_descriptor definition to libfsverity.h
  Move hash algorithm code to shared library
  Create libfsverity_compute_digest() and adapt cmd_sign to use it
  Introduce libfsverity_sign_digest()
  Validate input arguments to libfsverity_compute_digest()
  Validate input parameters for libfsverity_sign_digest()
  Document API of libfsverity
  Change libfsverity_compute_digest() to take a read function
  Make full_{read,write}() return proper error codes instead of bool
  libfsverity: Remove dependencies on util.c
  Update Makefile to install libfsverity and fsverity.h
  Change libfsverity_find_hash_alg_by_name() to return the alg number
  Make libfsverity_find_hash_alg_by_name() private to the shared library
  libfsverity_sign_digest() use ARRAY_SIZE()
  fsverity_cmd_sign() use sizeof() input argument instead of struct
  fsverity_cmd_sign() don't exit on error without closing file
    descriptor
  Improve documentation of libfsverity.h API
  Fixup Makefile

 Makefile              |  49 +++-
 cmd_enable.c          |  19 +-
 cmd_measure.c         |  19 +-
 cmd_sign.c            | 565 +++++------------------------------------
 fsverity.c            |  17 +-
 hash_algs.c           |  95 ++++---
 hash_algs.h           |  36 +--
 helpers.h             |  43 ++++
 libfsverity.h         | 138 ++++++++++
 libfsverity_private.h |  52 ++++
 libverity.c           | 572 ++++++++++++++++++++++++++++++++++++++++++
 util.c                |  15 +-
 util.h                |  62 +----
 13 files changed, 1029 insertions(+), 653 deletions(-)
 create mode 100644 helpers.h
 create mode 100644 libfsverity.h
 create mode 100644 libfsverity_private.h
 create mode 100644 libverity.c

-- 
2.25.3


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/20] Build basic shared library framework
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 02/20] Change compute_file_measurement() to take a file descriptor as argument Jes Sorensen
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This introduces a dummy shared library to start moving things into.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 Makefile    | 18 +++++++++++++++---
 libverity.c | 10 ++++++++++
 2 files changed, 25 insertions(+), 3 deletions(-)
 create mode 100644 libverity.c

diff --git a/Makefile b/Makefile
index b9c09b9..bb85896 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,32 @@
 EXE := fsverity
+LIB := libfsverity.so
 CFLAGS := -O2 -Wall
 CPPFLAGS := -D_FILE_OFFSET_BITS=64
 LDLIBS := -lcrypto
 DESTDIR := /usr/local
+LIBDIR := /usr/lib64
 SRC := $(wildcard *.c)
-OBJ := $(SRC:.c=.o)
+OBJ := fsverity.o hash_algs.o cmd_enable.o cmd_measure.o cmd_sign.o util.o
+SSRC := libverity.c
+SOBJ := libverity.so
 HDRS := $(wildcard *.h)
 
 all:$(EXE)
 
-$(EXE):$(OBJ)
+$(EXE):$(OBJ) $(LIB)
+	$(CC) -o $@ $(OBJ) $(LDLIBS) -L . -l fsverity
 
 $(OBJ): %.o: %.c $(HDRS)
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+
+$(SOBJ): %.so: %.c $(HDRS)
+	$(CC) -c -fPIC $(CFLAGS) $(CPPFLAGS) $< -o $@
+
+libfsverity.so: $(SOBJ)
+	$(CC) $(LDLIBS) -shared -o libfsverity.so $(SOBJ)
 
 clean:
-	rm -f $(EXE) $(OBJ)
+	rm -f $(EXE) $(OBJ) $(SOBJ) $(LIB)
 
 install:all
 	install -Dm755 -t $(DESTDIR)/bin $(EXE)
diff --git a/libverity.c b/libverity.c
new file mode 100644
index 0000000..6821aa2
--- /dev/null
+++ b/libverity.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * The 'fsverity library'
+ *
+ * Copyright (C) 2018 Google LLC
+ * Copyright (C) 2020 Facebook
+ *
+ * Written by Eric Biggers and Jes Sorensen.
+ */
+
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 02/20] Change compute_file_measurement() to take a file descriptor as argument
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
  2020-04-24 20:54 ` [PATCH 01/20] Build basic shared library framework Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 03/20] Move fsverity_descriptor definition to libfsverity.h Jes Sorensen
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This preps the code for splitting the signing into the shared library

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 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


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 03/20] Move fsverity_descriptor definition to libfsverity.h
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
  2020-04-24 20:54 ` [PATCH 01/20] Build basic shared library framework Jes Sorensen
  2020-04-24 20:54 ` [PATCH 02/20] Change compute_file_measurement() to take a file descriptor as argument Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 04/20] Move hash algorithm code to shared library Jes Sorensen
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c    | 19 +------------------
 libfsverity.h | 26 +++++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index dcc44f8..1792084 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -20,26 +20,9 @@
 #include <unistd.h>
 
 #include "commands.h"
-#include "fsverity_uapi.h"
+#include "libfsverity.h"
 #include "hash_algs.h"
 
-/*
- * Merkle tree properties.  The file measurement is the hash of this structure
- * excluding the signature and with the sig_size field set to 0.
- */
-struct fsverity_descriptor {
-	__u8 version;		/* must be 1 */
-	__u8 hash_algorithm;	/* Merkle tree hash algorithm */
-	__u8 log_blocksize;	/* log2 of size of data and tree blocks */
-	__u8 salt_size;		/* size of salt in bytes; 0 if none */
-	__le32 sig_size;	/* size of signature in bytes; 0 if none */
-	__le64 data_size;	/* size of file the Merkle tree is built over */
-	__u8 root_hash[64];	/* Merkle tree root hash */
-	__u8 salt[32];		/* salt prepended to each hashed block */
-	__u8 __reserved[144];	/* must be 0's */
-	__u8 signature[];	/* optional PKCS#7 signature */
-};
-
 /*
  * Format in which verity file measurements are signed.  This is the same as
  * 'struct fsverity_digest', except here some magic bytes are prepended to
diff --git a/libfsverity.h b/libfsverity.h
index ceebae1..396a6ee 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -13,13 +13,14 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <linux/types.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;
+	uint16_t hash_algorithm;	/* Matches the digest_algorithm type */
 	uint32_t block_size;
 	uint32_t salt_size;
 	const uint8_t *salt;
@@ -27,6 +28,7 @@ struct libfsverity_merkle_tree_params {
 };
 
 struct libfsverity_digest {
+	char magic[8];			/* must be "FSVerity" */
 	uint16_t digest_algorithm;
 	uint16_t digest_size;
 	uint8_t digest[];
@@ -38,4 +40,26 @@ struct libfsverity_signature_params {
 	uint64_t reserved[11];
 };
 
+/*
+ * Merkle tree properties.  The file measurement is the hash of this structure
+ * excluding the signature and with the sig_size field set to 0.
+ */
+struct fsverity_descriptor {
+	uint8_t version;	/* must be 1 */
+	uint8_t hash_algorithm;	/* Merkle tree hash algorithm */
+	uint8_t log_blocksize;	/* log2 of size of data and tree blocks */
+	uint8_t salt_size;	/* size of salt in bytes; 0 if none */
+	__le32 sig_size;	/* size of signature in bytes; 0 if none */
+	__le64 data_size;	/* size of file the Merkle tree is built over */
+	uint8_t root_hash[64];	/* Merkle tree root hash */
+	uint8_t salt[32];	/* salt prepended to each hashed block */
+	uint8_t __reserved[144];/* must be 0's */
+	uint8_t signature[];	/* optional PKCS#7 signature */
+};
+
+int
+libfsverity_compute_digest(int fd,
+			   const struct libfsverity_merkle_tree_params *params,
+			   struct libfsverity_digest **digest_ret);
+
 #endif
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 04/20] Move hash algorithm code to shared library
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (2 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 03/20] Move fsverity_descriptor definition to libfsverity.h Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 05/20] Create libfsverity_compute_digest() and adapt cmd_sign to use it Jes Sorensen
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Reimplement show_all_hash_algs() to not rely on direct access to the list,
and add the algorithm number to the struct, so the user can find it easily.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 Makefile      |  6 +++---
 cmd_enable.c  | 11 ++++++++---
 cmd_measure.c |  4 ++--
 cmd_sign.c    | 18 ++++++++++++------
 fsverity.c    | 15 ++++++++++++++-
 hash_algs.c   | 26 +++++++-------------------
 hash_algs.h   | 27 ---------------------------
 libfsverity.h | 22 ++++++++++++++++++++++
 util.h        |  2 ++
 9 files changed, 70 insertions(+), 61 deletions(-)

diff --git a/Makefile b/Makefile
index bb85896..966afa0 100644
--- a/Makefile
+++ b/Makefile
@@ -6,9 +6,9 @@ LDLIBS := -lcrypto
 DESTDIR := /usr/local
 LIBDIR := /usr/lib64
 SRC := $(wildcard *.c)
-OBJ := fsverity.o hash_algs.o cmd_enable.o cmd_measure.o cmd_sign.o util.o
-SSRC := libverity.c
-SOBJ := libverity.so
+OBJ := fsverity.o cmd_enable.o cmd_measure.o cmd_sign.o util.o
+SSRC := libverity.c hash_algs.c
+SOBJ := libverity.so hash_algs.so
 HDRS := $(wildcard *.h)
 
 all:$(EXE)
diff --git a/cmd_enable.c b/cmd_enable.c
index 1646299..1bed3ef 100644
--- a/cmd_enable.c
+++ b/cmd_enable.c
@@ -16,7 +16,7 @@
 
 #include "commands.h"
 #include "fsverity_uapi.h"
-#include "hash_algs.h"
+#include "libfsverity.h"
 
 static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr)
 {
@@ -36,11 +36,16 @@ static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr)
 	}
 
 	/* Specified by name? */
-	alg = find_hash_alg_by_name(arg);
+	alg = libfsverity_find_hash_alg_by_name(arg);
 	if (alg != NULL) {
-		*alg_ptr = alg - fsverity_hash_algs;
+		*alg_ptr = alg->hash_num;
 		return true;
 	}
+	error_msg("unknown hash algorithm: '%s'", arg);
+	fputs("Available hash algorithms: ", stderr);
+	show_all_hash_algs(stderr);
+	putc('\n', stderr);
+
 	return false;
 }
 
diff --git a/cmd_measure.c b/cmd_measure.c
index 574e3ca..4c0777f 100644
--- a/cmd_measure.c
+++ b/cmd_measure.c
@@ -13,7 +13,7 @@
 
 #include "commands.h"
 #include "fsverity_uapi.h"
-#include "hash_algs.h"
+#include "libfsverity.h"
 
 /* Display the measurement of the given verity file(s). */
 int fsverity_cmd_measure(const struct fsverity_command *cmd,
@@ -48,7 +48,7 @@ int fsverity_cmd_measure(const struct fsverity_command *cmd,
 
 		ASSERT(d->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
 		bin2hex(d->digest, d->digest_size, digest_hex);
-		hash_alg = find_hash_alg_by_num(d->digest_algorithm);
+		hash_alg = libfsverity_find_hash_alg_by_num(d->digest_algorithm);
 		if (hash_alg) {
 			hash_alg_name = hash_alg->name;
 		} else {
diff --git a/cmd_sign.c b/cmd_sign.c
index 1792084..5ad4eda 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -466,7 +466,7 @@ static bool compute_file_measurement(int fd,
 				     u32 block_size, const u8 *salt,
 				     u32 salt_size, u8 *measurement)
 {
-	struct hash_ctx *hash = hash_create(hash_alg);
+	struct hash_ctx *hash = hash_alg->create_ctx(hash_alg);
 	u64 file_size;
 	struct fsverity_descriptor desc;
 	struct stat stbuf;
@@ -480,7 +480,7 @@ static bool compute_file_measurement(int fd,
 
 	memset(&desc, 0, sizeof(desc));
 	desc.version = 1;
-	desc.hash_algorithm = hash_alg - fsverity_hash_algs;
+	desc.hash_algorithm = hash_alg->hash_num;
 
 	ASSERT(is_power_of_2(block_size));
 	desc.log_blocksize = ilog2(block_size);
@@ -552,9 +552,15 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 				error_msg("--hash-alg can only be specified once");
 				goto out_usage;
 			}
-			hash_alg = find_hash_alg_by_name(optarg);
-			if (hash_alg == NULL)
+			hash_alg = libfsverity_find_hash_alg_by_name(optarg);
+			if (hash_alg == NULL) {
+				error_msg("unknown hash algorithm: '%s'",
+					  optarg);
+				fputs("Available hash algorithms: ", stderr);
+				show_all_hash_algs(stderr);
+				putc('\n', stderr);
 				goto out_usage;
+			}
 			break;
 		case OPT_BLOCK_SIZE:
 			if (!parse_block_size_option(optarg, &block_size))
@@ -590,7 +596,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 		goto out_usage;
 
 	if (hash_alg == NULL)
-		hash_alg = &fsverity_hash_algs[FS_VERITY_HASH_ALG_DEFAULT];
+		hash_alg = libfsverity_find_hash_alg_by_num(FS_VERITY_HASH_ALG_DEFAULT);
 
 	if (block_size == 0)
 		block_size = get_default_block_size();
@@ -604,7 +610,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 
 	digest = xzalloc(sizeof(*digest) + hash_alg->digest_size);
 	memcpy(digest->magic, "FSVerity", 8);
-	digest->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
+	digest->digest_algorithm = cpu_to_le16(hash_alg->hash_num);
 	digest->digest_size = cpu_to_le16(hash_alg->digest_size);
 
 	if (!open_file(&file, argv[0], O_RDONLY, 0))
diff --git a/fsverity.c b/fsverity.c
index c8fa1b5..f9df72e 100644
--- a/fsverity.c
+++ b/fsverity.c
@@ -13,7 +13,6 @@
 #include <unistd.h>
 
 #include "commands.h"
-#include "hash_algs.h"
 #include "libfsverity.h"
 
 static const struct fsverity_command {
@@ -48,6 +47,20 @@ static const struct fsverity_command {
 	}
 };
 
+void show_all_hash_algs(FILE *fp)
+{
+	int i = 1;
+	const char *sep = "";
+	const struct fsverity_hash_alg *alg;
+
+	while ((alg = libfsverity_find_hash_alg_by_num(i++))) {
+		if (alg && alg->name) {
+			fprintf(fp, "%s%s", sep, alg->name);
+			sep = ", ";
+		}
+	}
+}
+
 static void usage_all(FILE *fp)
 {
 	int i;
diff --git a/hash_algs.c b/hash_algs.c
index 7251bf2..d9f70b4 100644
--- a/hash_algs.c
+++ b/hash_algs.c
@@ -12,6 +12,7 @@
 #include <string.h>
 
 #include "fsverity_uapi.h"
+#include "libfsverity.h"
 #include "hash_algs.h"
 
 /* ========== libcrypto (OpenSSL) wrappers ========== */
@@ -106,17 +107,20 @@ const struct fsverity_hash_alg fsverity_hash_algs[] = {
 		.name = "sha256",
 		.digest_size = 32,
 		.block_size = 64,
+		.hash_num = FS_VERITY_HASH_ALG_SHA256,
 		.create_ctx = create_sha256_ctx,
 	},
 	[FS_VERITY_HASH_ALG_SHA512] = {
 		.name = "sha512",
 		.digest_size = 64,
 		.block_size = 128,
+		.hash_num = FS_VERITY_HASH_ALG_SHA512,
 		.create_ctx = create_sha512_ctx,
 	},
 };
 
-const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name)
+const struct fsverity_hash_alg *
+libfsverity_find_hash_alg_by_name(const char *name)
 {
 	int i;
 
@@ -125,14 +129,11 @@ const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name)
 		    !strcmp(name, fsverity_hash_algs[i].name))
 			return &fsverity_hash_algs[i];
 	}
-	error_msg("unknown hash algorithm: '%s'", name);
-	fputs("Available hash algorithms: ", stderr);
-	show_all_hash_algs(stderr);
-	putc('\n', stderr);
 	return NULL;
 }
 
-const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num)
+const struct fsverity_hash_alg *
+libfsverity_find_hash_alg_by_num(unsigned int num)
 {
 	if (num < ARRAY_SIZE(fsverity_hash_algs) &&
 	    fsverity_hash_algs[num].name)
@@ -141,19 +142,6 @@ const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num)
 	return NULL;
 }
 
-void show_all_hash_algs(FILE *fp)
-{
-	int i;
-	const char *sep = "";
-
-	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
-		if (fsverity_hash_algs[i].name) {
-			fprintf(fp, "%s%s", sep, fsverity_hash_algs[i].name);
-			sep = ", ";
-		}
-	}
-}
-
 /* ->init(), ->update(), and ->final() all in one step */
 void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest)
 {
diff --git a/hash_algs.h b/hash_algs.h
index 3e90f49..2c7269a 100644
--- a/hash_algs.h
+++ b/hash_algs.h
@@ -6,15 +6,6 @@
 
 #include "util.h"
 
-struct fsverity_hash_alg {
-	const char *name;
-	unsigned int digest_size;
-	unsigned int block_size;
-	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
-};
-
-extern const struct fsverity_hash_alg fsverity_hash_algs[];
-
 struct hash_ctx {
 	const struct fsverity_hash_alg *alg;
 	void (*init)(struct hash_ctx *ctx);
@@ -23,24 +14,6 @@ struct hash_ctx {
 	void (*free)(struct hash_ctx *ctx);
 };
 
-const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name);
-const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num);
-void show_all_hash_algs(FILE *fp);
-
-/* The hash algorithm that fsverity-utils assumes when none is specified */
-#define FS_VERITY_HASH_ALG_DEFAULT	FS_VERITY_HASH_ALG_SHA256
-
-/*
- * Largest digest size among all hash algorithms supported by fs-verity.
- * This can be increased if needed.
- */
-#define FS_VERITY_MAX_DIGEST_SIZE	64
-
-static inline struct hash_ctx *hash_create(const struct fsverity_hash_alg *alg)
-{
-	return alg->create_ctx(alg);
-}
-
 static inline void hash_init(struct hash_ctx *ctx)
 {
 	ctx->init(ctx);
diff --git a/libfsverity.h b/libfsverity.h
index 396a6ee..318dcd7 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -18,6 +18,9 @@
 #define FS_VERITY_HASH_ALG_SHA256       1
 #define FS_VERITY_HASH_ALG_SHA512       2
 
+/* The hash algorithm that fsverity-utils assumes when none is specified */
+#define FS_VERITY_HASH_ALG_DEFAULT	FS_VERITY_HASH_ALG_SHA256
+
 struct libfsverity_merkle_tree_params {
 	uint16_t version;
 	uint16_t hash_algorithm;	/* Matches the digest_algorithm type */
@@ -27,6 +30,12 @@ struct libfsverity_merkle_tree_params {
 	uint64_t reserved[11];
 };
 
+/*
+ * Largest digest size among all hash algorithms supported by fs-verity.
+ * This can be increased if needed.
+ */
+#define FS_VERITY_MAX_DIGEST_SIZE	64
+
 struct libfsverity_digest {
 	char magic[8];			/* must be "FSVerity" */
 	uint16_t digest_algorithm;
@@ -57,9 +66,22 @@ struct fsverity_descriptor {
 	uint8_t signature[];	/* optional PKCS#7 signature */
 };
 
+struct fsverity_hash_alg {
+	const char *name;
+	unsigned int digest_size;
+	unsigned int block_size;
+	uint16_t hash_num;
+	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
+};
+
 int
 libfsverity_compute_digest(int fd,
 			   const struct libfsverity_merkle_tree_params *params,
 			   struct libfsverity_digest **digest_ret);
 
+const struct fsverity_hash_alg *
+libfsverity_find_hash_alg_by_name(const char *name);
+const struct fsverity_hash_alg *
+libfsverity_find_hash_alg_by_num(unsigned int num);
+
 #endif
diff --git a/util.h b/util.h
index dfa10f2..dd9b803 100644
--- a/util.h
+++ b/util.h
@@ -122,4 +122,6 @@ bool filedes_close(struct filedes *file);
 bool hex2bin(const char *hex, u8 *bin, size_t bin_len);
 void bin2hex(const u8 *bin, size_t bin_len, char *hex);
 
+void show_all_hash_algs();
+
 #endif /* UTIL_H */
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 05/20] Create libfsverity_compute_digest() and adapt cmd_sign to use it
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (3 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 04/20] Move hash algorithm code to shared library Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 06/20] Introduce libfsverity_sign_digest() Jes Sorensen
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This reorganizes the digest signing code and moves it to the shared library.
In addition libfsverity_private.h is created for library internal data
structures, in particular struct fsverity_decriptor.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c            | 194 ++-------------------------------------
 libfsverity.h         |  17 ----
 libfsverity_private.h |  33 +++++++
 libverity.c           | 207 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 250 insertions(+), 201 deletions(-)
 create mode 100644 libfsverity_private.h

diff --git a/cmd_sign.c b/cmd_sign.c
index 5ad4eda..6a5d185 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -16,12 +16,9 @@
 #include <openssl/pkcs7.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
 
 #include "commands.h"
 #include "libfsverity.h"
-#include "hash_algs.h"
 
 /*
  * Format in which verity file measurements are signed.  This is the same as
@@ -337,179 +334,6 @@ static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
 	return ok;
 }
 
-#define FS_VERITY_MAX_LEVELS	64
-
-struct block_buffer {
-	u32 filled;
-	u8 *data;
-};
-
-/*
- * Hash a block, writing the result to the next level's pending block buffer.
- * Returns true if the next level's block became full, else false.
- */
-static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur,
-			   u32 block_size, const u8 *salt, u32 salt_size)
-{
-	struct block_buffer *next = cur + 1;
-
-	/* Zero-pad the block if it's shorter than block_size. */
-	memset(&cur->data[cur->filled], 0, block_size - cur->filled);
-
-	hash_init(hash);
-	hash_update(hash, salt, salt_size);
-	hash_update(hash, cur->data, block_size);
-	hash_final(hash, &next->data[next->filled]);
-
-	next->filled += hash->alg->digest_size;
-	cur->filled = 0;
-
-	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(int fd, u64 file_size,
-			      struct hash_ctx *hash, u32 block_size,
-			      const u8 *salt, u32 salt_size, u8 *root_hash)
-{
-	const u32 hashes_per_block = block_size / hash->alg->digest_size;
-	const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size);
-	u8 *padded_salt = xzalloc(padded_salt_size);
-	u64 blocks;
-	int num_levels = 0;
-	int level;
-	struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {};
-	struct block_buffer *buffers = &_buffers[1];
-	u64 offset;
-	bool ok = false;
-
-	if (salt_size != 0)
-		memcpy(padded_salt, salt, salt_size);
-
-	/* Compute number of levels */
-	for (blocks = DIV_ROUND_UP(file_size, block_size); blocks > 1;
-	     blocks = DIV_ROUND_UP(blocks, hashes_per_block)) {
-		ASSERT(num_levels < FS_VERITY_MAX_LEVELS);
-		num_levels++;
-	}
-
-	/*
-	 * Allocate the block buffers.  Buffer "-1" is for data blocks.
-	 * Buffers 0 <= level < num_levels are for the actual tree levels.
-	 * Buffer 'num_levels' is for the root hash.
-	 */
-	for (level = -1; level < num_levels; level++)
-		buffers[level].data = xmalloc(block_size);
-	buffers[num_levels].data = root_hash;
-
-	/* Hash each data block, also hashing the tree blocks as they fill up */
-	for (offset = 0; offset < file_size; offset += block_size) {
-		buffers[-1].filled = min(block_size, file_size - offset);
-
-		if (full_read_fd(fd, buffers[-1].data, buffers[-1].filled))
-			goto out;
-
-		level = -1;
-		while (hash_one_block(hash, &buffers[level], block_size,
-				      padded_salt, padded_salt_size)) {
-			level++;
-			ASSERT(level < num_levels);
-		}
-	}
-	/* Finish all nonempty pending tree blocks */
-	for (level = 0; level < num_levels; level++) {
-		if (buffers[level].filled != 0)
-			hash_one_block(hash, &buffers[level], block_size,
-				       padded_salt, padded_salt_size);
-	}
-
-	/* Root hash was filled by the last call to hash_one_block() */
-	ASSERT(buffers[num_levels].filled == hash->alg->digest_size);
-	ok = true;
-out:
-	for (level = -1; level < num_levels; level++)
-		free(buffers[level].data);
-	free(padded_salt);
-	return ok;
-}
-
-/*
- * Compute the fs-verity measurement of the given file.
- *
- * 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(int fd,
-				     const struct fsverity_hash_alg *hash_alg,
-				     u32 block_size, const u8 *salt,
-				     u32 salt_size, u8 *measurement)
-{
-	struct hash_ctx *hash = hash_alg->create_ctx(hash_alg);
-	u64 file_size;
-	struct fsverity_descriptor desc;
-	struct stat stbuf;
-	bool ok = false;
-
-	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;
-	desc.hash_algorithm = hash_alg->hash_num;
-
-	ASSERT(is_power_of_2(block_size));
-	desc.log_blocksize = ilog2(block_size);
-
-	if (salt_size != 0) {
-		if (salt_size > sizeof(desc.salt)) {
-			error_msg("Salt too long (got %u bytes; max is %zu bytes)",
-				  salt_size, sizeof(desc.salt));
-			goto out;
-		}
-		memcpy(desc.salt, salt, salt_size);
-		desc.salt_size = salt_size;
-	}
-
-	desc.data_size = cpu_to_le64(file_size);
-
-	/* Root hash of empty file is all 0's */
-	if (file_size != 0 &&
-	    !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:
-	hash_free(hash);
-	return ok;
-}
-
 enum {
 	OPT_HASH_ALG,
 	OPT_BLOCK_SIZE,
@@ -538,7 +362,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	u32 salt_size = 0;
 	const char *keyfile = NULL;
 	const char *certfile = NULL;
-	struct fsverity_signed_digest *digest = NULL;
+	struct libfsverity_digest *digest = NULL;
+	struct libfsverity_merkle_tree_params params;
 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
 	u8 *sig = NULL;
 	u32 sig_size;
@@ -608,16 +433,17 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	if (certfile == NULL)
 		certfile = keyfile;
 
-	digest = xzalloc(sizeof(*digest) + hash_alg->digest_size);
-	memcpy(digest->magic, "FSVerity", 8);
-	digest->digest_algorithm = cpu_to_le16(hash_alg->hash_num);
-	digest->digest_size = cpu_to_le16(hash_alg->digest_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))
+	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
+	params.version = 1;
+	params.hash_algorithm = hash_alg->hash_num;
+	params.block_size = block_size;
+	params.salt_size = salt_size;
+	params.salt = salt;
+
+	if (libfsverity_compute_digest(file.fd, &params, &digest))
 		goto out_err;
 
 	filedes_close(&file);
diff --git a/libfsverity.h b/libfsverity.h
index 318dcd7..cb5f5b6 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -49,23 +49,6 @@ struct libfsverity_signature_params {
 	uint64_t reserved[11];
 };
 
-/*
- * Merkle tree properties.  The file measurement is the hash of this structure
- * excluding the signature and with the sig_size field set to 0.
- */
-struct fsverity_descriptor {
-	uint8_t version;	/* must be 1 */
-	uint8_t hash_algorithm;	/* Merkle tree hash algorithm */
-	uint8_t log_blocksize;	/* log2 of size of data and tree blocks */
-	uint8_t salt_size;	/* size of salt in bytes; 0 if none */
-	__le32 sig_size;	/* size of signature in bytes; 0 if none */
-	__le64 data_size;	/* size of file the Merkle tree is built over */
-	uint8_t root_hash[64];	/* Merkle tree root hash */
-	uint8_t salt[32];	/* salt prepended to each hashed block */
-	uint8_t __reserved[144];/* must be 0's */
-	uint8_t signature[];	/* optional PKCS#7 signature */
-};
-
 struct fsverity_hash_alg {
 	const char *name;
 	unsigned int digest_size;
diff --git a/libfsverity_private.h b/libfsverity_private.h
new file mode 100644
index 0000000..5f3e1b4
--- /dev/null
+++ b/libfsverity_private.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * libfsverity private interfaces
+ *
+ * Copyright (C) 2018 Google LLC
+ * Copyright (C) 2020 Facebook
+ *
+ * Written by Eric Biggers and modified by Jes Sorensen.
+ */
+#ifndef _LIBFSVERITY_PRIVATE_H
+#define _LIBFSVERITY_PRIVATE_H
+
+#include <stdint.h>
+#include <linux/types.h>
+
+/*
+ * Merkle tree properties.  The file measurement is the hash of this structure
+ * excluding the signature and with the sig_size field set to 0.
+ */
+struct fsverity_descriptor {
+	uint8_t version;	/* must be 1 */
+	uint8_t hash_algorithm;	/* Merkle tree hash algorithm */
+	uint8_t log_blocksize;	/* log2 of size of data and tree blocks */
+	uint8_t salt_size;	/* size of salt in bytes; 0 if none */
+	__le32 sig_size;	/* size of signature in bytes; 0 if none */
+	__le64 data_size;	/* size of file the Merkle tree is built over */
+	uint8_t root_hash[64];	/* Merkle tree root hash */
+	uint8_t salt[32];	/* salt prepended to each hashed block */
+	uint8_t __reserved[144];/* must be 0's */
+	uint8_t signature[];	/* optional PKCS#7 signature */
+};
+
+#endif
diff --git a/libverity.c b/libverity.c
index 6821aa2..19272f7 100644
--- a/libverity.c
+++ b/libverity.c
@@ -8,3 +8,210 @@
  * Written by Eric Biggers and Jes Sorensen.
  */
 
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "libfsverity.h"
+#include "libfsverity_private.h"
+#include "hash_algs.h"
+
+#define FS_VERITY_MAX_LEVELS	64
+
+struct block_buffer {
+	u32 filled;
+	u8 *data;
+};
+
+/*
+ * Hash a block, writing the result to the next level's pending block buffer.
+ * Returns true if the next level's block became full, else false.
+ */
+static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur,
+			   u32 block_size, const u8 *salt, u32 salt_size)
+{
+	struct block_buffer *next = cur + 1;
+
+	/* Zero-pad the block if it's shorter than block_size. */
+	memset(&cur->data[cur->filled], 0, block_size - cur->filled);
+
+	hash_init(hash);
+	hash_update(hash, salt, salt_size);
+	hash_update(hash, cur->data, block_size);
+	hash_final(hash, &next->data[next->filled]);
+
+	next->filled += hash->alg->digest_size;
+	cur->filled = 0;
+
+	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(int fd, u64 file_size,
+			      struct hash_ctx *hash, u32 block_size,
+			      const u8 *salt, u32 salt_size, u8 *root_hash)
+{
+	const u32 hashes_per_block = block_size / hash->alg->digest_size;
+	const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size);
+	u8 *padded_salt = xzalloc(padded_salt_size);
+	u64 blocks;
+	int num_levels = 0;
+	int level;
+	struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {};
+	struct block_buffer *buffers = &_buffers[1];
+	u64 offset;
+	bool ok = false;
+
+	if (salt_size != 0)
+		memcpy(padded_salt, salt, salt_size);
+
+	/* Compute number of levels */
+	for (blocks = DIV_ROUND_UP(file_size, block_size); blocks > 1;
+	     blocks = DIV_ROUND_UP(blocks, hashes_per_block)) {
+		ASSERT(num_levels < FS_VERITY_MAX_LEVELS);
+		num_levels++;
+	}
+
+	/*
+	 * Allocate the block buffers.  Buffer "-1" is for data blocks.
+	 * Buffers 0 <= level < num_levels are for the actual tree levels.
+	 * Buffer 'num_levels' is for the root hash.
+	 */
+	for (level = -1; level < num_levels; level++)
+		buffers[level].data = xmalloc(block_size);
+	buffers[num_levels].data = root_hash;
+
+	/* Hash each data block, also hashing the tree blocks as they fill up */
+	for (offset = 0; offset < file_size; offset += block_size) {
+		buffers[-1].filled = min(block_size, file_size - offset);
+
+		if (full_read_fd(fd, buffers[-1].data, buffers[-1].filled))
+			goto out;
+
+		level = -1;
+		while (hash_one_block(hash, &buffers[level], block_size,
+				      padded_salt, padded_salt_size)) {
+			level++;
+			ASSERT(level < num_levels);
+		}
+	}
+	/* Finish all nonempty pending tree blocks */
+	for (level = 0; level < num_levels; level++) {
+		if (buffers[level].filled != 0)
+			hash_one_block(hash, &buffers[level], block_size,
+				       padded_salt, padded_salt_size);
+	}
+
+	/* Root hash was filled by the last call to hash_one_block() */
+	ASSERT(buffers[num_levels].filled == hash->alg->digest_size);
+	ok = true;
+out:
+	for (level = -1; level < num_levels; level++)
+		free(buffers[level].data);
+	free(padded_salt);
+	return ok;
+}
+
+/*
+ * Compute the fs-verity measurement of the given file.
+ *
+ * The fs-verity measurement is the hash of the fsverity_descriptor, which
+ * contains the Merkle tree properties including the root hash.
+ */
+int
+libfsverity_compute_digest(int fd,
+			   const struct libfsverity_merkle_tree_params *params,
+			   struct libfsverity_digest **digest_ret)
+{
+	const struct fsverity_hash_alg *hash_alg;
+	struct libfsverity_digest *digest;
+	struct hash_ctx *hash;
+	struct fsverity_descriptor desc;
+	struct stat stbuf;
+	u64 file_size;
+	int retval = -EINVAL;
+
+	hash_alg = libfsverity_find_hash_alg_by_num(params->hash_algorithm);
+	hash = hash_alg->create_ctx(hash_alg);
+
+	digest = malloc(sizeof(struct libfsverity_digest) +
+			hash_alg->digest_size);
+	if (!digest_ret)
+		return -ENOMEM;
+	memcpy(digest->magic, "FSVerity", 8);
+	digest->digest_algorithm = cpu_to_le16(hash_alg->hash_num);
+	digest->digest_size = cpu_to_le16(hash_alg->digest_size);
+	memset(digest->digest, 0, hash_alg->digest_size);
+
+	if (fstat(fd, &stbuf) != 0) {
+		error_msg_errno("can't stat input file");
+		retval = -EBADF;
+		goto error_out;
+	}
+	file_size = stbuf.st_size;
+
+	memset(&desc, 0, sizeof(desc));
+	desc.version = 1;
+	desc.hash_algorithm = params->hash_algorithm;
+
+	ASSERT(is_power_of_2(params->block_size));
+	desc.log_blocksize = ilog2(params->block_size);
+
+	if (params->salt_size != 0) {
+		if (params->salt_size > sizeof(desc.salt)) {
+			error_msg("Salt too long (got %u bytes; max is %zu bytes)",
+				  params->salt_size, sizeof(desc.salt));
+			retval = EINVAL;
+			goto error_out;
+		}
+		memcpy(desc.salt, params->salt, params->salt_size);
+		desc.salt_size = params->salt_size;
+	}
+
+	desc.data_size = cpu_to_le64(file_size);
+
+	/* Root hash of empty file is all 0's */
+	if (file_size != 0 &&
+	    !compute_root_hash(fd, file_size, hash, params->block_size,
+			       params->salt, params->salt_size,
+			       desc.root_hash)) {
+		retval = -EAGAIN;
+		goto error_out;
+	}
+
+	hash_full(hash, &desc, sizeof(desc), digest->digest);
+	hash_free(hash);
+	*digest_ret = digest;
+
+	return 0;
+
+ error_out:
+	free(digest);
+	return retval;
+}
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 06/20] Introduce libfsverity_sign_digest()
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (4 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 05/20] Create libfsverity_compute_digest() and adapt cmd_sign to use it Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 07/20] Validate input arguments to libfsverity_compute_digest() Jes Sorensen
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This moves the signing code into libfsverity and switches cmd_sign to use it.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c    | 317 ++------------------------------------------------
 libfsverity.h |  12 ++
 libverity.c   | 309 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+), 309 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index 6a5d185..e48e0aa 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -10,318 +10,12 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <limits.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/pkcs7.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "commands.h"
 #include "libfsverity.h"
 
-/*
- * Format in which verity file measurements are signed.  This is the same as
- * 'struct fsverity_digest', except here some magic bytes are prepended to
- * provide some context about what is being signed in case the same key is used
- * for non-fsverity purposes, and here the fields have fixed endianness.
- */
-struct fsverity_signed_digest {
-	char magic[8];			/* must be "FSVerity" */
-	__le16 digest_algorithm;
-	__le16 digest_size;
-	__u8 digest[];
-};
-
-static void __printf(1, 2) __cold
-error_msg_openssl(const char *format, ...)
-{
-	va_list va;
-
-	va_start(va, format);
-	do_error_msg(format, va, 0);
-	va_end(va);
-
-	if (ERR_peek_error() == 0)
-		return;
-
-	fprintf(stderr, "OpenSSL library errors:\n");
-	ERR_print_errors_fp(stderr);
-}
-
-/* Read a PEM PKCS#8 formatted private key */
-static EVP_PKEY *read_private_key(const char *keyfile)
-{
-	BIO *bio;
-	EVP_PKEY *pkey;
-
-	bio = BIO_new_file(keyfile, "r");
-	if (!bio) {
-		error_msg_openssl("can't open '%s' for reading", keyfile);
-		return NULL;
-	}
-
-	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
-	if (!pkey) {
-		error_msg_openssl("Failed to parse private key file '%s'.\n"
-				  "       Note: it must be in PEM PKCS#8 format.",
-				  keyfile);
-	}
-	BIO_free(bio);
-	return pkey;
-}
-
-/* Read a PEM X.509 formatted certificate */
-static X509 *read_certificate(const char *certfile)
-{
-	BIO *bio;
-	X509 *cert;
-
-	bio = BIO_new_file(certfile, "r");
-	if (!bio) {
-		error_msg_openssl("can't open '%s' for reading", certfile);
-		return NULL;
-	}
-	cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
-	if (!cert) {
-		error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n"
-				  "       Note: it must be in PEM format.",
-				  certfile);
-	}
-	BIO_free(bio);
-	return cert;
-}
-
-#ifdef OPENSSL_IS_BORINGSSL
-
-static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
-		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
-		       u8 **sig_ret, u32 *sig_size_ret)
-{
-	CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo,
-		null, content_info, issuer_and_serial, signer_infos,
-		signer_info, sign_algo, signature;
-	EVP_MD_CTX md_ctx;
-	u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL;
-	size_t pkcs7_data_len, sig_len;
-	int name_der_len, sig_nid;
-	bool ok = false;
-
-	EVP_MD_CTX_init(&md_ctx);
-	BIGNUM *serial = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL);
-
-	if (!CBB_init(&out, 1024)) {
-		error_msg("out of memory");
-		goto out;
-	}
-
-	name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der);
-	if (name_der_len < 0) {
-		error_msg_openssl("i2d_X509_NAME failed");
-		goto out;
-	}
-
-	if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) {
-		error_msg_openssl("EVP_DigestSignInit failed");
-		goto out;
-	}
-
-	sig_len = EVP_PKEY_size(pkey);
-	sig = xmalloc(sig_len);
-	if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) {
-		error_msg_openssl("EVP_DigestSign failed");
-		goto out;
-	}
-
-	sig_nid = EVP_PKEY_id(pkey);
-	/* To mirror OpenSSL behaviour, always use |NID_rsaEncryption| with RSA
-	 * rather than the combined hash+pkey NID. */
-	if (sig_nid != NID_rsaEncryption) {
-		OBJ_find_sigid_by_algs(&sig_nid, EVP_MD_type(md),
-				       EVP_PKEY_id(pkey));
-	}
-
-	// See https://tools.ietf.org/html/rfc2315#section-7
-	if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) ||
-	    !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) ||
-	    !CBB_add_asn1(&outer_seq, &wrapped_seq, CBS_ASN1_CONTEXT_SPECIFIC |
-			  CBS_ASN1_CONSTRUCTED | 0) ||
-	    // See https://tools.ietf.org/html/rfc2315#section-9.1
-	    !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) ||
-	    !CBB_add_asn1_uint64(&seq, 1 /* version */) ||
-	    !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
-	    !CBB_add_asn1(&digest_algos_set, &digest_algo, CBS_ASN1_SEQUENCE) ||
-	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
-	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
-	    !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
-	    !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
-	    !CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) ||
-	    !CBB_add_asn1(&signer_infos, &signer_info, CBS_ASN1_SEQUENCE) ||
-	    !CBB_add_asn1_uint64(&signer_info, 1 /* version */) ||
-	    !CBB_add_asn1(&signer_info, &issuer_and_serial,
-			  CBS_ASN1_SEQUENCE) ||
-	    !CBB_add_bytes(&issuer_and_serial, name_der, name_der_len) ||
-	    !BN_marshal_asn1(&issuer_and_serial, serial) ||
-	    !CBB_add_asn1(&signer_info, &digest_algo, CBS_ASN1_SEQUENCE) ||
-	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
-	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
-	    !CBB_add_asn1(&signer_info, &sign_algo, CBS_ASN1_SEQUENCE) ||
-	    !OBJ_nid2cbb(&sign_algo, sig_nid) ||
-	    !CBB_add_asn1(&sign_algo, &null, CBS_ASN1_NULL) ||
-	    !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) ||
-	    !CBB_add_bytes(&signature, sig, sig_len) ||
-	    !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) {
-		error_msg_openssl("failed to construct PKCS#7 data");
-		goto out;
-	}
-
-	*sig_ret = xmemdup(pkcs7_data, pkcs7_data_len);
-	*sig_size_ret = pkcs7_data_len;
-	ok = true;
-out:
-	BN_free(serial);
-	EVP_MD_CTX_cleanup(&md_ctx);
-	CBB_cleanup(&out);
-	free(sig);
-	OPENSSL_free(name_der);
-	OPENSSL_free(pkcs7_data);
-	return ok;
-}
-
-#else /* OPENSSL_IS_BORINGSSL */
-
-static BIO *new_mem_buf(const void *buf, size_t size)
-{
-	BIO *bio;
-
-	ASSERT(size <= INT_MAX);
-	/*
-	 * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer,
-	 * despite still marking the resulting bio as read-only.  So cast away
-	 * the const to avoid a compiler warning with older OpenSSL versions.
-	 */
-	bio = BIO_new_mem_buf((void *)buf, size);
-	if (!bio)
-		error_msg_openssl("out of memory");
-	return bio;
-}
-
-static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
-		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
-		       u8 **sig_ret, u32 *sig_size_ret)
-{
-	/*
-	 * PKCS#7 signing flags:
-	 *
-	 * - PKCS7_BINARY	signing binary data, so skip MIME translation
-	 *
-	 * - PKCS7_DETACHED	omit the signed data (include signature only)
-	 *
-	 * - PKCS7_NOATTR	omit extra authenticated attributes, such as
-	 *			SMIMECapabilities
-	 *
-	 * - PKCS7_NOCERTS	omit the signer's certificate
-	 *
-	 * - PKCS7_PARTIAL	PKCS7_sign() creates a handle only, then
-	 *			PKCS7_sign_add_signer() can add a signer later.
-	 *			This is necessary to change the message digest
-	 *			algorithm from the default of SHA-1.  Requires
-	 *			OpenSSL 1.0.0 or later.
-	 */
-	int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR |
-			  PKCS7_NOCERTS | PKCS7_PARTIAL;
-	u8 *sig;
-	u32 sig_size;
-	BIO *bio = NULL;
-	PKCS7 *p7 = NULL;
-	bool ok = false;
-
-	bio = new_mem_buf(data_to_sign, data_size);
-	if (!bio)
-		goto out;
-
-	p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags);
-	if (!p7) {
-		error_msg_openssl("failed to initialize PKCS#7 signature object");
-		goto out;
-	}
-
-	if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) {
-		error_msg_openssl("failed to add signer to PKCS#7 signature object");
-		goto out;
-	}
-
-	if (PKCS7_final(p7, bio, pkcs7_flags) != 1) {
-		error_msg_openssl("failed to finalize PKCS#7 signature");
-		goto out;
-	}
-
-	BIO_free(bio);
-	bio = BIO_new(BIO_s_mem());
-	if (!bio) {
-		error_msg_openssl("out of memory");
-		goto out;
-	}
-
-	if (i2d_PKCS7_bio(bio, p7) != 1) {
-		error_msg_openssl("failed to DER-encode PKCS#7 signature object");
-		goto out;
-	}
-
-	sig_size = BIO_get_mem_data(bio, &sig);
-	*sig_ret = xmemdup(sig, sig_size);
-	*sig_size_ret = sig_size;
-	ok = true;
-out:
-	PKCS7_free(p7);
-	BIO_free(bio);
-	return ok;
-}
-
-#endif /* !OPENSSL_IS_BORINGSSL */
-
-/*
- * Sign the specified @data_to_sign of length @data_size bytes using the private
- * key in @keyfile, the certificate in @certfile, and the hash algorithm
- * @hash_alg.  Returns the DER-formatted PKCS#7 signature in @sig_ret and
- * @sig_size_ret.
- */
-static bool sign_data(const void *data_to_sign, size_t data_size,
-		      const char *keyfile, const char *certfile,
-		      const struct fsverity_hash_alg *hash_alg,
-		      u8 **sig_ret, u32 *sig_size_ret)
-{
-	EVP_PKEY *pkey = NULL;
-	X509 *cert = NULL;
-	const EVP_MD *md;
-	bool ok = false;
-
-	pkey = read_private_key(keyfile);
-	if (!pkey)
-		goto out;
-
-	cert = read_certificate(certfile);
-	if (!cert)
-		goto out;
-
-	OpenSSL_add_all_digests();
-	md = EVP_get_digestbyname(hash_alg->name);
-	if (!md) {
-		fprintf(stderr,
-			"Warning: '%s' algorithm not found in OpenSSL library.\n"
-			"         Falling back to SHA-256 signature.\n",
-			hash_alg->name);
-		md = EVP_sha256();
-	}
-
-	ok = sign_pkcs7(data_to_sign, data_size, pkey, cert, md,
-			sig_ret, sig_size_ret);
-out:
-	EVP_PKEY_free(pkey);
-	X509_free(cert);
-	return ok;
-}
-
 static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
 {
 	struct filedes file;
@@ -364,9 +58,10 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	const char *certfile = NULL;
 	struct libfsverity_digest *digest = NULL;
 	struct libfsverity_merkle_tree_params params;
+	struct libfsverity_signature_params sig_params;
 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
 	u8 *sig = NULL;
-	u32 sig_size;
+	size_t sig_size;
 	int status;
 	int c;
 
@@ -448,9 +143,13 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 
 	filedes_close(&file);
 
-	if (!sign_data(digest, sizeof(*digest) + hash_alg->digest_size,
-		       keyfile, certfile, hash_alg, &sig, &sig_size))
+	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
+	sig_params.keyfile = keyfile;
+	sig_params.certfile = certfile;
+	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
+		error_msg("Failed to sign digest");
 		goto out_err;
+	}
 
 	if (!write_signature(argv[1], sig, sig_size))
 		goto out_err;
diff --git a/libfsverity.h b/libfsverity.h
index cb5f5b6..a2abdb3 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -36,6 +36,13 @@ struct libfsverity_merkle_tree_params {
  */
 #define FS_VERITY_MAX_DIGEST_SIZE	64
 
+/*
+ * Format in which verity file measurements are signed.  This is the same as
+ * 'struct fsverity_digest', except here some magic bytes are prepended to
+ * provide some context about what is being signed in case the same key is used
+ * for non-fsverity purposes, and here the fields have fixed endianness.
+ */
+
 struct libfsverity_digest {
 	char magic[8];			/* must be "FSVerity" */
 	uint16_t digest_algorithm;
@@ -62,6 +69,11 @@ libfsverity_compute_digest(int fd,
 			   const struct libfsverity_merkle_tree_params *params,
 			   struct libfsverity_digest **digest_ret);
 
+int
+libfsverity_sign_digest(const struct libfsverity_digest *digest,
+			const struct libfsverity_signature_params *sig_params,
+			uint8_t **sig_ret, size_t *sig_size_ret);
+
 const struct fsverity_hash_alg *
 libfsverity_find_hash_alg_by_name(const char *name);
 const struct fsverity_hash_alg *
diff --git a/libverity.c b/libverity.c
index 19272f7..183259e 100644
--- a/libverity.c
+++ b/libverity.c
@@ -215,3 +215,312 @@ libfsverity_compute_digest(int fd,
 	free(digest);
 	return retval;
 }
+
+static void __printf(1, 2) __cold
+error_msg_openssl(const char *format, ...)
+{
+	va_list va;
+
+	va_start(va, format);
+	do_error_msg(format, va, 0);
+	va_end(va);
+
+	if (ERR_peek_error() == 0)
+		return;
+
+	fprintf(stderr, "OpenSSL library errors:\n");
+	ERR_print_errors_fp(stderr);
+}
+
+/* Read a PEM PKCS#8 formatted private key */
+static EVP_PKEY *read_private_key(const char *keyfile)
+{
+	BIO *bio;
+	EVP_PKEY *pkey;
+
+	bio = BIO_new_file(keyfile, "r");
+	if (!bio) {
+		error_msg_openssl("can't open '%s' for reading", keyfile);
+		return NULL;
+	}
+
+	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+	if (!pkey) {
+		error_msg_openssl("Failed to parse private key file '%s'.\n"
+				  "       Note: it must be in PEM PKCS#8 format.",
+				  keyfile);
+	}
+	BIO_free(bio);
+	return pkey;
+}
+
+/* Read a PEM X.509 formatted certificate */
+static X509 *read_certificate(const char *certfile)
+{
+	BIO *bio;
+	X509 *cert;
+
+	bio = BIO_new_file(certfile, "r");
+	if (!bio) {
+		error_msg_openssl("can't open '%s' for reading", certfile);
+		return NULL;
+	}
+	cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+	if (!cert) {
+		error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n"
+				  "       Note: it must be in PEM format.",
+				  certfile);
+	}
+	BIO_free(bio);
+	return cert;
+}
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
+		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
+		       u8 **sig_ret, size_t *sig_size_ret)
+{
+	CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo,
+		null, content_info, issuer_and_serial, signer_infos,
+		signer_info, sign_algo, signature;
+	EVP_MD_CTX md_ctx;
+	u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL;
+	size_t pkcs7_data_len, sig_len;
+	int name_der_len, sig_nid;
+	bool ok = false;
+
+	EVP_MD_CTX_init(&md_ctx);
+	BIGNUM *serial = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL);
+
+	if (!CBB_init(&out, 1024)) {
+		error_msg("out of memory");
+		goto out;
+	}
+
+	name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der);
+	if (name_der_len < 0) {
+		error_msg_openssl("i2d_X509_NAME failed");
+		goto out;
+	}
+
+	if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) {
+		error_msg_openssl("EVP_DigestSignInit failed");
+		goto out;
+	}
+
+	sig_len = EVP_PKEY_size(pkey);
+	sig = xmalloc(sig_len);
+	if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) {
+		error_msg_openssl("EVP_DigestSign failed");
+		goto out;
+	}
+
+	sig_nid = EVP_PKEY_id(pkey);
+	/* To mirror OpenSSL behaviour, always use |NID_rsaEncryption| with RSA
+	 * rather than the combined hash+pkey NID. */
+	if (sig_nid != NID_rsaEncryption) {
+		OBJ_find_sigid_by_algs(&sig_nid, EVP_MD_type(md),
+				       EVP_PKEY_id(pkey));
+	}
+
+	// See https://tools.ietf.org/html/rfc2315#section-7
+	if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) ||
+	    !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) ||
+	    !CBB_add_asn1(&outer_seq, &wrapped_seq, CBS_ASN1_CONTEXT_SPECIFIC |
+			  CBS_ASN1_CONSTRUCTED | 0) ||
+	    // See https://tools.ietf.org/html/rfc2315#section-9.1
+	    !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) ||
+	    !CBB_add_asn1_uint64(&seq, 1 /* version */) ||
+	    !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
+	    !CBB_add_asn1(&digest_algos_set, &digest_algo, CBS_ASN1_SEQUENCE) ||
+	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
+	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
+	    !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
+	    !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
+	    !CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) ||
+	    !CBB_add_asn1(&signer_infos, &signer_info, CBS_ASN1_SEQUENCE) ||
+	    !CBB_add_asn1_uint64(&signer_info, 1 /* version */) ||
+	    !CBB_add_asn1(&signer_info, &issuer_and_serial,
+			  CBS_ASN1_SEQUENCE) ||
+	    !CBB_add_bytes(&issuer_and_serial, name_der, name_der_len) ||
+	    !BN_marshal_asn1(&issuer_and_serial, serial) ||
+	    !CBB_add_asn1(&signer_info, &digest_algo, CBS_ASN1_SEQUENCE) ||
+	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
+	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
+	    !CBB_add_asn1(&signer_info, &sign_algo, CBS_ASN1_SEQUENCE) ||
+	    !OBJ_nid2cbb(&sign_algo, sig_nid) ||
+	    !CBB_add_asn1(&sign_algo, &null, CBS_ASN1_NULL) ||
+	    !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) ||
+	    !CBB_add_bytes(&signature, sig, sig_len) ||
+	    !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) {
+		error_msg_openssl("failed to construct PKCS#7 data");
+		goto out;
+	}
+
+	*sig_ret = xmemdup(pkcs7_data, pkcs7_data_len);
+	*sig_size_ret = pkcs7_data_len;
+	ok = true;
+out:
+	BN_free(serial);
+	EVP_MD_CTX_cleanup(&md_ctx);
+	CBB_cleanup(&out);
+	free(sig);
+	OPENSSL_free(name_der);
+	OPENSSL_free(pkcs7_data);
+	return ok;
+}
+
+#else /* OPENSSL_IS_BORINGSSL */
+
+static BIO *new_mem_buf(const void *buf, size_t size)
+{
+	BIO *bio;
+
+	ASSERT(size <= INT_MAX);
+	/*
+	 * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer,
+	 * despite still marking the resulting bio as read-only.  So cast away
+	 * the const to avoid a compiler warning with older OpenSSL versions.
+	 */
+	bio = BIO_new_mem_buf((void *)buf, size);
+	if (!bio)
+		error_msg_openssl("out of memory");
+	return bio;
+}
+
+static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
+		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
+		       u8 **sig_ret, size_t *sig_size_ret)
+{
+	/*
+	 * PKCS#7 signing flags:
+	 *
+	 * - PKCS7_BINARY	signing binary data, so skip MIME translation
+	 *
+	 * - PKCS7_DETACHED	omit the signed data (include signature only)
+	 *
+	 * - PKCS7_NOATTR	omit extra authenticated attributes, such as
+	 *			SMIMECapabilities
+	 *
+	 * - PKCS7_NOCERTS	omit the signer's certificate
+	 *
+	 * - PKCS7_PARTIAL	PKCS7_sign() creates a handle only, then
+	 *			PKCS7_sign_add_signer() can add a signer later.
+	 *			This is necessary to change the message digest
+	 *			algorithm from the default of SHA-1.  Requires
+	 *			OpenSSL 1.0.0 or later.
+	 */
+	int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR |
+			  PKCS7_NOCERTS | PKCS7_PARTIAL;
+	u8 *sig;
+	u32 sig_size;
+	BIO *bio = NULL;
+	PKCS7 *p7 = NULL;
+	bool ok = false;
+
+	bio = new_mem_buf(data_to_sign, data_size);
+	if (!bio)
+		goto out;
+
+	p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags);
+	if (!p7) {
+		error_msg_openssl("failed to initialize PKCS#7 signature object");
+		goto out;
+	}
+
+	if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) {
+		error_msg_openssl("failed to add signer to PKCS#7 signature object");
+		goto out;
+	}
+
+	if (PKCS7_final(p7, bio, pkcs7_flags) != 1) {
+		error_msg_openssl("failed to finalize PKCS#7 signature");
+		goto out;
+	}
+
+	BIO_free(bio);
+	bio = BIO_new(BIO_s_mem());
+	if (!bio) {
+		error_msg_openssl("out of memory");
+		goto out;
+	}
+
+	if (i2d_PKCS7_bio(bio, p7) != 1) {
+		error_msg_openssl("failed to DER-encode PKCS#7 signature object");
+		goto out;
+	}
+
+	sig_size = BIO_get_mem_data(bio, &sig);
+	*sig_ret = xmemdup(sig, sig_size);
+	*sig_size_ret = sig_size;
+	ok = true;
+out:
+	PKCS7_free(p7);
+	BIO_free(bio);
+	return ok;
+}
+
+#endif /* !OPENSSL_IS_BORINGSSL */
+
+/*
+ * Sign the digest using the private key in @keyfile, the certificate in
+ * @certfile, and the hash algorithm specified in the digest.
+ * Return 0 on success, the DER-formatted PKCS#7 signature in @sig_ret and
+ * it's size in @sig_size_ret.
+ */
+int
+libfsverity_sign_digest(const struct libfsverity_digest *digest,
+			const struct libfsverity_signature_params *sig_params,
+			uint8_t **sig_ret, size_t *sig_size_ret)
+{
+	const struct fsverity_hash_alg *hash_alg;
+	EVP_PKEY *pkey = NULL;
+	X509 *cert = NULL;
+	const EVP_MD *md;
+	size_t data_size;
+	uint16_t alg_nr;
+	int retval = -EAGAIN;
+
+	data_size = sizeof(struct libfsverity_digest) +
+		le16_to_cpu(digest->digest_size);
+	alg_nr = le16_to_cpu(digest->digest_algorithm);
+	hash_alg = libfsverity_find_hash_alg_by_num(alg_nr);
+
+	if (!hash_alg) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	pkey = read_private_key(sig_params->keyfile);
+	if (!pkey) {
+		retval = -EAGAIN;
+		goto out;
+	}
+
+	cert = read_certificate(sig_params->certfile);
+	if (!cert) {
+		retval = -EAGAIN;
+		goto out;
+	}
+
+	OpenSSL_add_all_digests();
+
+	md = EVP_get_digestbyname(hash_alg->name);
+	if (!md) {
+		fprintf(stderr,
+			"Warning: '%s' algorithm not found in OpenSSL library.\n"
+			"         Falling back to SHA-256 signature.\n",
+			hash_alg->name);
+		md = EVP_sha256();
+	}
+
+	if (sign_pkcs7(digest, data_size, pkey, cert, md,
+		       sig_ret, sig_size_ret))
+		retval = 0;
+
+ out:
+	EVP_PKEY_free(pkey);
+	X509_free(cert);
+	return retval;
+}
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 07/20] Validate input arguments to libfsverity_compute_digest()
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (5 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 06/20] Introduce libfsverity_sign_digest() Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 08/20] Validate input parameters for libfsverity_sign_digest() Jes Sorensen
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

If any argument is invalid, return -EINVAL. Similarly
if any of the reserved fields in the params struct
are set, return -EINVAL;

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 libverity.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/libverity.c b/libverity.c
index 183259e..1cef544 100644
--- a/libverity.c
+++ b/libverity.c
@@ -155,9 +155,31 @@ libfsverity_compute_digest(int fd,
 	struct fsverity_descriptor desc;
 	struct stat stbuf;
 	u64 file_size;
-	int retval = -EINVAL;
+	int i, retval = -EINVAL;
+
+	if (!digest_ret)
+		return -EINVAL;
+	if (params->version != 1)
+		return -EINVAL;
+	if (!is_power_of_2(params->block_size))
+		return -EINVAL;
+	if (params->salt_size > sizeof(desc.salt)) {
+		error_msg("Salt too long (got %u bytes; max is %zu bytes)",
+			  params->salt_size, sizeof(desc.salt));
+		return -EINVAL;
+	}
+	if (params->salt_size && !params->salt)
+		return -EINVAL;
+	for (i = 0;
+	     i < sizeof(params->reserved) / sizeof(params->reserved[0]); i++) {
+		if (params->reserved[i])
+			return -EINVAL;
+	}
 
 	hash_alg = libfsverity_find_hash_alg_by_num(params->hash_algorithm);
+	if (!hash_alg)
+		return -EINVAL;
+
 	hash = hash_alg->create_ctx(hash_alg);
 
 	digest = malloc(sizeof(struct libfsverity_digest) +
@@ -180,16 +202,9 @@ libfsverity_compute_digest(int fd,
 	desc.version = 1;
 	desc.hash_algorithm = params->hash_algorithm;
 
-	ASSERT(is_power_of_2(params->block_size));
 	desc.log_blocksize = ilog2(params->block_size);
 
 	if (params->salt_size != 0) {
-		if (params->salt_size > sizeof(desc.salt)) {
-			error_msg("Salt too long (got %u bytes; max is %zu bytes)",
-				  params->salt_size, sizeof(desc.salt));
-			retval = EINVAL;
-			goto error_out;
-		}
 		memcpy(desc.salt, params->salt, params->salt_size);
 		desc.salt_size = params->salt_size;
 	}
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 08/20] Validate input parameters for libfsverity_sign_digest()
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (6 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 07/20] Validate input arguments to libfsverity_compute_digest() Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 09/20] Document API of libfsverity Jes Sorensen
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Return -EINVAL on any invalid input argument, as well
as if any of the reserved fields are set in
struct libfsverity_signature_digest

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 libverity.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/libverity.c b/libverity.c
index 1cef544..e16306d 100644
--- a/libverity.c
+++ b/libverity.c
@@ -494,18 +494,36 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
 	X509 *cert = NULL;
 	const EVP_MD *md;
 	size_t data_size;
-	uint16_t alg_nr;
-	int retval = -EAGAIN;
+	uint16_t alg_nr, digest_size;
+	int i, retval = -EAGAIN;
+	const char magic[8] = "FSVerity";
+
+	if (!digest || !sig_params || !sig_ret || !sig_size_ret)
+		return -EINVAL;
+
+	if (strncmp(digest->magic, magic, sizeof(magic)))
+		return -EINVAL;
+
+	if (!sig_params->keyfile || !sig_params->certfile)
+		return -EINVAL;
+
+	for (i = 0; i < sizeof(sig_params->reserved) /
+		     sizeof(sig_params->reserved[0]); i++) {
+		if (sig_params->reserved[i])
+			return -EINVAL;
+	}
+
+	digest_size = le16_to_cpu(digest->digest_size);
+	data_size = sizeof(struct libfsverity_digest) + digest_size;
 
-	data_size = sizeof(struct libfsverity_digest) +
-		le16_to_cpu(digest->digest_size);
 	alg_nr = le16_to_cpu(digest->digest_algorithm);
 	hash_alg = libfsverity_find_hash_alg_by_num(alg_nr);
 
-	if (!hash_alg) {
-		retval = -EINVAL;
-		goto out;
-	}
+	if (!hash_alg)
+		return -EINVAL;
+
+	if (digest_size != hash_alg->digest_size)
+		return -EINVAL;
 
 	pkey = read_private_key(sig_params->keyfile);
 	if (!pkey) {
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 09/20] Document API of libfsverity
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (7 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 08/20] Validate input parameters for libfsverity_sign_digest() Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 10/20] Change libfsverity_compute_digest() to take a read function Jes Sorensen
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 libfsverity.h | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/libfsverity.h b/libfsverity.h
index a2abdb3..f6c4b13 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -64,18 +64,63 @@ struct fsverity_hash_alg {
 	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
 };
 
+/*
+ * libfsverity_compute_digest - Compute digest of a file
+ * @fd: open file descriptor of file to compute digest for
+ * @params: struct libfsverity_merkle_tree_params specifying hash algorithm,
+ *	    block size, version, and optional salt parameters.
+ *	    reserved parameters must be zero.
+ * @digest_ret: Pointer to pointer for computed digest
+ *
+ * Returns:
+ * * 0 for success, -EINVAL for invalid input arguments, -ENOMEM if failed
+ *   to allocate memory, -EBADF if fd is invalid, and -EAGAIN if root hash
+ *   fails to compute.
+ * * digest_ret returns a pointer to the digest on success.
+ */
 int
 libfsverity_compute_digest(int fd,
 			   const struct libfsverity_merkle_tree_params *params,
 			   struct libfsverity_digest **digest_ret);
 
+/*
+ * libfsverity_sign_digest - Sign previously computed digest of a file
+ * @digest: pointer to previously computed digest
+ * @sig_params: struct libfsverity_signature_params providing filenames of
+ *          the keyfile and certificate file. Reserved parameters must be zero.
+ * @sig_ret: Pointer to pointer for signed digest
+ * @sig_size_ret: Pointer to size of signed return digest
+ *
+ * Returns:
+ * * 0 for success, -EINVAL for invalid input arguments, -EAGAIN if key or
+ *   certificate files fail to read, or if signing the digest fails.
+ * * sig_ret returns a pointer to the signed digest on success.
+ * * sig_size_ret returns the size of the signed digest on success.
+ */
 int
 libfsverity_sign_digest(const struct libfsverity_digest *digest,
 			const struct libfsverity_signature_params *sig_params,
 			uint8_t **sig_ret, size_t *sig_size_ret);
 
+/*
+ * libfsverity_find_hash_alg_by_name - Find hash algorithm by name
+ * @name: Pointer to name of hash algorithm
+ *
+ * Returns:
+ * struct fsverity_hash_alg success
+ * NULL on error
+ */
 const struct fsverity_hash_alg *
 libfsverity_find_hash_alg_by_name(const char *name);
+
+/*
+ * libfsverity_find_hash_alg_by_num - Find hash algorithm by number
+ * @name: Number of hash algorithm
+ *
+ * Returns:
+ * struct fsverity_hash_alg success
+ * NULL on error
+ */
 const struct fsverity_hash_alg *
 libfsverity_find_hash_alg_by_num(unsigned int num);
 
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 10/20] Change libfsverity_compute_digest() to take a read function
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (8 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 09/20] Document API of libfsverity Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 11/20] Make full_{read,write}() return proper error codes instead of bool Jes Sorensen
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This changes the library to take a read_fn as callback and a pointer to
an opaque file descriptor. This allows us to provide a custome read function
for things like rpm which reads from an cpio archive instead of a file on
disk.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c    | 20 +++++++++++++++++++-
 libfsverity.h |  3 ++-
 libverity.c   | 39 +++++++--------------------------------
 3 files changed, 28 insertions(+), 34 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index e48e0aa..15d0937 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -12,6 +12,7 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include "commands.h"
 #include "libfsverity.h"
@@ -45,6 +46,16 @@ static const struct option longopts[] = {
 	{NULL, 0, NULL, 0}
 };
 
+static int read_callback(void *opague, void *buf, size_t count)
+{
+	int retval = -EBADF;
+
+	if (full_read(opague, buf, count))
+		retval = 0;
+
+	return retval;
+}
+
 /* Sign a file for fs-verity by computing its measurement, then signing it. */
 int fsverity_cmd_sign(const struct fsverity_command *cmd,
 		      int argc, char *argv[])
@@ -59,6 +70,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	struct libfsverity_digest *digest = NULL;
 	struct libfsverity_merkle_tree_params params;
 	struct libfsverity_signature_params sig_params;
+	u64 file_size;
 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
 	u8 *sig = NULL;
 	size_t sig_size;
@@ -131,6 +143,11 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	if (!open_file(&file, argv[0], O_RDONLY, 0))
 		goto out_err;
 
+	if (!get_file_size(&file, &file_size)) {
+		error_msg_errno("unable to get file size");
+		goto out_err;
+	}
+
 	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
 	params.version = 1;
 	params.hash_algorithm = hash_alg->hash_num;
@@ -138,7 +155,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	params.salt_size = salt_size;
 	params.salt = salt;
 
-	if (libfsverity_compute_digest(file.fd, &params, &digest))
+	if (libfsverity_compute_digest(&file, file_size, read_callback,
+				       &params, &digest))
 		goto out_err;
 
 	filedes_close(&file);
diff --git a/libfsverity.h b/libfsverity.h
index f6c4b13..ea36b8e 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -79,7 +79,8 @@ struct fsverity_hash_alg {
  * * digest_ret returns a pointer to the digest on success.
  */
 int
-libfsverity_compute_digest(int fd,
+libfsverity_compute_digest(void *fd, size_t file_size,
+			   int (*read_fn)(void *, void *buf, size_t count),
 			   const struct libfsverity_merkle_tree_params *params,
 			   struct libfsverity_digest **digest_ret);
 
diff --git a/libverity.c b/libverity.c
index e16306d..f82f2d6 100644
--- a/libverity.c
+++ b/libverity.c
@@ -50,30 +50,13 @@ 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(int fd, u64 file_size,
+static bool compute_root_hash(void *fd,
+			      int (*read_fn)(void *, void *buf, size_t count),
+			      u64 file_size,
 			      struct hash_ctx *hash, u32 block_size,
 			      const u8 *salt, u32 salt_size, u8 *root_hash)
 {
@@ -111,7 +94,7 @@ static bool compute_root_hash(int fd, u64 file_size,
 	for (offset = 0; offset < file_size; offset += block_size) {
 		buffers[-1].filled = min(block_size, file_size - offset);
 
-		if (full_read_fd(fd, buffers[-1].data, buffers[-1].filled))
+		if (read_fn(fd, buffers[-1].data, buffers[-1].filled))
 			goto out;
 
 		level = -1;
@@ -145,7 +128,8 @@ out:
  * contains the Merkle tree properties including the root hash.
  */
 int
-libfsverity_compute_digest(int fd,
+libfsverity_compute_digest(void *fd, size_t file_size,
+			   int (*read_fn)(void *, void *buf, size_t count),
 			   const struct libfsverity_merkle_tree_params *params,
 			   struct libfsverity_digest **digest_ret)
 {
@@ -153,8 +137,6 @@ libfsverity_compute_digest(int fd,
 	struct libfsverity_digest *digest;
 	struct hash_ctx *hash;
 	struct fsverity_descriptor desc;
-	struct stat stbuf;
-	u64 file_size;
 	int i, retval = -EINVAL;
 
 	if (!digest_ret)
@@ -191,13 +173,6 @@ libfsverity_compute_digest(int fd,
 	digest->digest_size = cpu_to_le16(hash_alg->digest_size);
 	memset(digest->digest, 0, hash_alg->digest_size);
 
-	if (fstat(fd, &stbuf) != 0) {
-		error_msg_errno("can't stat input file");
-		retval = -EBADF;
-		goto error_out;
-	}
-	file_size = stbuf.st_size;
-
 	memset(&desc, 0, sizeof(desc));
 	desc.version = 1;
 	desc.hash_algorithm = params->hash_algorithm;
@@ -213,7 +188,7 @@ libfsverity_compute_digest(int fd,
 
 	/* Root hash of empty file is all 0's */
 	if (file_size != 0 &&
-	    !compute_root_hash(fd, file_size, hash, params->block_size,
+	    !compute_root_hash(fd, read_fn, file_size, hash, params->block_size,
 			       params->salt, params->salt_size,
 			       desc.root_hash)) {
 		retval = -EAGAIN;
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 11/20] Make full_{read,write}() return proper error codes instead of bool
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (9 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 10/20] Change libfsverity_compute_digest() to take a read function Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 12/20] libfsverity: Remove dependencies on util.c Jes Sorensen
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This allows for better error reporting, and simplifies the read callback
handler.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_enable.c |  4 +++-
 cmd_sign.c   | 13 +++++--------
 util.c       | 14 +++++++-------
 util.h       |  4 ++--
 4 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/cmd_enable.c b/cmd_enable.c
index 1bed3ef..9612778 100644
--- a/cmd_enable.c
+++ b/cmd_enable.c
@@ -56,6 +56,7 @@ static bool read_signature(const char *filename, u8 **sig_ret,
 	u64 file_size;
 	u8 *sig = NULL;
 	bool ok = false;
+	int status;
 
 	if (!open_file(&file, filename, O_RDONLY, 0))
 		goto out;
@@ -70,7 +71,8 @@ static bool read_signature(const char *filename, u8 **sig_ret,
 		goto out;
 	}
 	sig = xmalloc(file_size);
-	if (!full_read(&file, sig, file_size))
+	status = full_read(&file, sig, file_size);
+	if (status < 0)
 		goto out;
 	*sig_ret = sig;
 	*sig_size_ret = file_size;
diff --git a/cmd_sign.c b/cmd_sign.c
index 15d0937..959e6d9 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -13,6 +13,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include "commands.h"
 #include "libfsverity.h"
@@ -20,12 +21,13 @@
 static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
 {
 	struct filedes file;
+	int status;
 	bool ok;
 
 	if (!open_file(&file, filename, O_WRONLY|O_CREAT|O_TRUNC, 0644))
 		return false;
-	ok = full_write(&file, sig, sig_size);
-	ok &= filedes_close(&file);
+	status = full_write(&file, sig, sig_size);
+	ok = (!status && filedes_close(&file));
 	return ok;
 }
 
@@ -48,12 +50,7 @@ static const struct option longopts[] = {
 
 static int read_callback(void *opague, void *buf, size_t count)
 {
-	int retval = -EBADF;
-
-	if (full_read(opague, buf, count))
-		retval = 0;
-
-	return retval;
+	return full_read(opague, buf, count);
 }
 
 /* Sign a file for fs-verity by computing its measurement, then signing it. */
diff --git a/util.c b/util.c
index 2218f2e..586d2b0 100644
--- a/util.c
+++ b/util.c
@@ -117,38 +117,38 @@ bool get_file_size(struct filedes *file, u64 *size_ret)
 	return true;
 }
 
-bool full_read(struct filedes *file, void *buf, size_t count)
+int full_read(struct filedes *file, void *buf, size_t count)
 {
 	while (count) {
 		int n = read(file->fd, buf, min(count, INT_MAX));
 
 		if (n < 0) {
 			error_msg_errno("reading from '%s'", file->name);
-			return false;
+			return n;
 		}
 		if (n == 0) {
 			error_msg("unexpected end-of-file on '%s'", file->name);
-			return false;
+			return -EBADFD;
 		}
 		buf += n;
 		count -= n;
 	}
-	return true;
+	return 0;
 }
 
-bool full_write(struct filedes *file, const void *buf, size_t count)
+int full_write(struct filedes *file, const void *buf, size_t count)
 {
 	while (count) {
 		int n = write(file->fd, buf, min(count, INT_MAX));
 
 		if (n < 0) {
 			error_msg_errno("writing to '%s'", file->name);
-			return false;
+			return n;
 		}
 		buf += n;
 		count -= n;
 	}
-	return true;
+	return 0;
 }
 
 bool filedes_close(struct filedes *file)
diff --git a/util.h b/util.h
index dd9b803..c4dc066 100644
--- a/util.h
+++ b/util.h
@@ -113,8 +113,8 @@ struct filedes {
 
 bool open_file(struct filedes *file, const char *filename, int flags, int mode);
 bool get_file_size(struct filedes *file, u64 *size_ret);
-bool full_read(struct filedes *file, void *buf, size_t count);
-bool full_write(struct filedes *file, const void *buf, size_t count);
+int full_read(struct filedes *file, void *buf, size_t count);
+int full_write(struct filedes *file, const void *buf, size_t count);
 bool filedes_close(struct filedes *file);
 
 /* ========== String utilities ========== */
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 12/20] libfsverity: Remove dependencies on util.c
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (10 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 11/20] Make full_{read,write}() return proper error codes instead of bool Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 13/20] Update Makefile to install libfsverity and fsverity.h Jes Sorensen
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

There were a ton of cross dependencies to util.c. This gets rid of all
the use of string function wrappers, u<x> data types, and various debug
functions. Useful independent macros and inline functions are moved to
helpers.h which may be included by both libfsverity and the fsverity
application.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 fsverity.c  |   1 +
 hash_algs.c |  47 ++++++++++-----
 hash_algs.h |   9 ++-
 helpers.h   |  43 ++++++++++++++
 libverity.c | 165 ++++++++++++++++++++++++++++++++--------------------
 util.c      |   1 +
 util.h      |  56 ------------------
 7 files changed, 184 insertions(+), 138 deletions(-)
 create mode 100644 helpers.h

diff --git a/fsverity.c b/fsverity.c
index f9df72e..a176ead 100644
--- a/fsverity.c
+++ b/fsverity.c
@@ -13,6 +13,7 @@
 #include <unistd.h>
 
 #include "commands.h"
+#include "helpers.h"
 #include "libfsverity.h"
 
 static const struct fsverity_command {
diff --git a/hash_algs.c b/hash_algs.c
index d9f70b4..3066d87 100644
--- a/hash_algs.c
+++ b/hash_algs.c
@@ -10,7 +10,9 @@
 #include <openssl/evp.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
+#include "helpers.h"
 #include "fsverity_uapi.h"
 #include "libfsverity.h"
 #include "hash_algs.h"
@@ -27,9 +29,12 @@ static void openssl_digest_init(struct hash_ctx *_ctx)
 {
 	struct openssl_hash_ctx *ctx = (void *)_ctx;
 
-	if (EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL) != 1)
-		fatal_error("EVP_DigestInit_ex() failed for algorithm '%s'",
-			    ctx->base.alg->name);
+	if (EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL) != 1) {
+		fprintf(stderr,
+			"%s: EVP_DigestInit_ex() failed for algorithm '%s'",
+			__func__, ctx->base.alg->name);
+		abort();
+	}
 }
 
 static void openssl_digest_update(struct hash_ctx *_ctx,
@@ -37,18 +42,24 @@ static void openssl_digest_update(struct hash_ctx *_ctx,
 {
 	struct openssl_hash_ctx *ctx = (void *)_ctx;
 
-	if (EVP_DigestUpdate(ctx->md_ctx, data, size) != 1)
-		fatal_error("EVP_DigestUpdate() failed for algorithm '%s'",
-			    ctx->base.alg->name);
+	if (EVP_DigestUpdate(ctx->md_ctx, data, size) != 1) {
+		fprintf(stderr,
+			"%s: EVP_DigestUpdate() failed for algorithm '%s'",
+			__func__, ctx->base.alg->name);
+		abort();
+	}
 }
 
-static void openssl_digest_final(struct hash_ctx *_ctx, u8 *digest)
+static void openssl_digest_final(struct hash_ctx *_ctx, uint8_t *digest)
 {
 	struct openssl_hash_ctx *ctx = (void *)_ctx;
 
-	if (EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL) != 1)
-		fatal_error("EVP_DigestFinal_ex() failed for algorithm '%s'",
-			    ctx->base.alg->name);
+	if (EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL) != 1) {
+		fprintf(stderr,
+			"%s: EVP_DigestFinal_ex() failed for algorithm '%s'",
+			__func__, ctx->base.alg->name);
+		abort();
+	}
 }
 
 static void openssl_digest_ctx_free(struct hash_ctx *_ctx)
@@ -69,7 +80,10 @@ openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md)
 {
 	struct openssl_hash_ctx *ctx;
 
-	ctx = xzalloc(sizeof(*ctx));
+	ctx = malloc(sizeof(*ctx));
+	if (!ctx)
+		goto out_of_memory;
+	memset(ctx, 0, sizeof(*ctx));
 	ctx->base.alg = alg;
 	ctx->base.init = openssl_digest_init;
 	ctx->base.update = openssl_digest_update;
@@ -82,12 +96,16 @@ openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md)
 	 */
 	ctx->md_ctx = EVP_MD_CTX_create();
 	if (!ctx->md_ctx)
-		fatal_error("out of memory");
+		goto out_of_memory;
 
 	ctx->md = md;
-	ASSERT(EVP_MD_size(md) == alg->digest_size);
+	assert(EVP_MD_size(md) == alg->digest_size);
 
 	return &ctx->base;
+
+ out_of_memory:
+	fprintf(stderr, "%s: out of memory", __func__);
+	abort();
 }
 
 static struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg)
@@ -143,7 +161,8 @@ libfsverity_find_hash_alg_by_num(unsigned int num)
 }
 
 /* ->init(), ->update(), and ->final() all in one step */
-void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest)
+void hash_full(struct hash_ctx *ctx, const void *data, size_t size,
+	       uint8_t *digest)
 {
 	hash_init(ctx);
 	hash_update(ctx, data, size);
diff --git a/hash_algs.h b/hash_algs.h
index 2c7269a..546a601 100644
--- a/hash_algs.h
+++ b/hash_algs.h
@@ -4,13 +4,11 @@
 
 #include <stdio.h>
 
-#include "util.h"
-
 struct hash_ctx {
 	const struct fsverity_hash_alg *alg;
 	void (*init)(struct hash_ctx *ctx);
 	void (*update)(struct hash_ctx *ctx, const void *data, size_t size);
-	void (*final)(struct hash_ctx *ctx, u8 *out);
+	void (*final)(struct hash_ctx *ctx, uint8_t *out);
 	void (*free)(struct hash_ctx *ctx);
 };
 
@@ -25,7 +23,7 @@ static inline void hash_update(struct hash_ctx *ctx,
 	ctx->update(ctx, data, size);
 }
 
-static inline void hash_final(struct hash_ctx *ctx, u8 *digest)
+static inline void hash_final(struct hash_ctx *ctx, uint8_t *digest)
 {
 	ctx->final(ctx, digest);
 }
@@ -36,6 +34,7 @@ static inline void hash_free(struct hash_ctx *ctx)
 		ctx->free(ctx);
 }
 
-void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest);
+void hash_full(struct hash_ctx *ctx, const void *data, size_t size,
+	       uint8_t *digest);
 
 #endif /* HASH_ALGS_H */
diff --git a/helpers.h b/helpers.h
new file mode 100644
index 0000000..35ce626
--- /dev/null
+++ b/helpers.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Helper macros and inline functions for fsverity and libfsverity
+ *
+ * Copyright (C) 2018 Google LLC
+ * Copyright (C) 2020 Facebook
+ */
+#ifndef HELPERS_H
+#define HELPERS_H
+
+#include <stdbool.h>
+
+#define ARRAY_SIZE(A)		(sizeof(A) / sizeof((A)[0]))
+
+#define min(a, b) ({			\
+	__typeof__(a) _a = (a);		\
+	__typeof__(b) _b = (b);		\
+	_a < _b ? _a : _b;		\
+})
+#define max(a, b) ({			\
+	__typeof__(a) _a = (a);		\
+	__typeof__(b) _b = (b);		\
+	_a > _b ? _a : _b;		\
+})
+
+static inline bool is_power_of_2(unsigned long n)
+{
+	return n != 0 && ((n & (n - 1)) == 0);
+}
+
+static inline int ilog2(unsigned long n)
+{
+	return (8 * sizeof(n) - 1) - __builtin_clzl(n);
+}
+
+#define roundup(x, y) ({		\
+	__typeof__(y) _y = (y);		\
+	(((x) + _y - 1) / _y) * _y;	\
+})
+
+#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
+
+#endif
diff --git a/libverity.c b/libverity.c
index f82f2d6..975d86e 100644
--- a/libverity.c
+++ b/libverity.c
@@ -14,17 +14,47 @@
 #include <openssl/pkcs7.h>
 #include <string.h>
 #include <sys/stat.h>
-#include <unistd.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
 
 #include "libfsverity.h"
 #include "libfsverity_private.h"
 #include "hash_algs.h"
+#include "helpers.h"
 
 #define FS_VERITY_MAX_LEVELS	64
 
+#ifndef __force
+#  ifdef __CHECKER__
+#    define __force	__attribute__((force))
+#  else
+#    define __force
+#  endif
+#endif
+
+/* ========== Endianness conversion ========== */
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#  define cpu_to_le16(v)	((__force __le16)(uint16_t)(v))
+#  define le16_to_cpu(v)	((__force uint16_t)(__le16)(v))
+#  define cpu_to_le32(v)	((__force __le32)(uint32_t)(v))
+#  define le32_to_cpu(v)	((__force uint32_t)(__le32)(v))
+#  define cpu_to_le64(v)	((__force __le64)(uint64_t)(v))
+#  define le64_to_cpu(v)	((__force uint64_t)(__le64)(v))
+#else
+#  define cpu_to_le16(v)	((__force __le16)__builtin_bswap16(v))
+#  define le16_to_cpu(v)	(__builtin_bswap16((__force uint16_t)(v)))
+#  define cpu_to_le32(v)	((__force __le32)__builtin_bswap32(v))
+#  define le32_to_cpu(v)	(__builtin_bswap32((__force uint32_t)(v)))
+#  define cpu_to_le64(v)	((__force __le64)__builtin_bswap64(v))
+#  define le64_to_cpu(v)	(__builtin_bswap64((__force uint64_t)(v)))
+#endif
+
 struct block_buffer {
-	u32 filled;
-	u8 *data;
+	uint32_t filled;
+	uint8_t *data;
 };
 
 /*
@@ -32,7 +62,8 @@ struct block_buffer {
  * Returns true if the next level's block became full, else false.
  */
 static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur,
-			   u32 block_size, const u8 *salt, u32 salt_size)
+			   uint32_t block_size, const uint8_t *salt,
+			   uint32_t salt_size)
 {
 	struct block_buffer *next = cur + 1;
 
@@ -56,28 +87,33 @@ static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur,
  */
 static bool compute_root_hash(void *fd,
 			      int (*read_fn)(void *, void *buf, size_t count),
-			      u64 file_size,
-			      struct hash_ctx *hash, u32 block_size,
-			      const u8 *salt, u32 salt_size, u8 *root_hash)
+			      uint64_t file_size, struct hash_ctx *hash,
+			      uint32_t block_size, const uint8_t *salt,
+			      uint32_t salt_size, uint8_t *root_hash)
 {
-	const u32 hashes_per_block = block_size / hash->alg->digest_size;
-	const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size);
-	u8 *padded_salt = xzalloc(padded_salt_size);
-	u64 blocks;
+	const uint32_t hashes_per_block = block_size / hash->alg->digest_size;
+	const uint32_t padded_salt_size = roundup(salt_size, hash->alg->block_size);
+	uint8_t *padded_salt = NULL;
+	uint64_t blocks;
 	int num_levels = 0;
 	int level;
 	struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {};
 	struct block_buffer *buffers = &_buffers[1];
-	u64 offset;
+	uint64_t offset;
 	bool ok = false;
 
-	if (salt_size != 0)
+	if (salt_size != 0) {
+		padded_salt = malloc(padded_salt_size);
+		assert(padded_salt);
+		memset(padded_salt, 0, padded_salt_size);
+
 		memcpy(padded_salt, salt, salt_size);
+	}
 
 	/* Compute number of levels */
 	for (blocks = DIV_ROUND_UP(file_size, block_size); blocks > 1;
 	     blocks = DIV_ROUND_UP(blocks, hashes_per_block)) {
-		ASSERT(num_levels < FS_VERITY_MAX_LEVELS);
+		assert(num_levels < FS_VERITY_MAX_LEVELS);
 		num_levels++;
 	}
 
@@ -86,8 +122,10 @@ static bool compute_root_hash(void *fd,
 	 * Buffers 0 <= level < num_levels are for the actual tree levels.
 	 * Buffer 'num_levels' is for the root hash.
 	 */
-	for (level = -1; level < num_levels; level++)
-		buffers[level].data = xmalloc(block_size);
+	for (level = -1; level < num_levels; level++) {
+		buffers[level].data = malloc(block_size);
+		assert (buffers[level].data);
+	}
 	buffers[num_levels].data = root_hash;
 
 	/* Hash each data block, also hashing the tree blocks as they fill up */
@@ -101,7 +139,7 @@ static bool compute_root_hash(void *fd,
 		while (hash_one_block(hash, &buffers[level], block_size,
 				      padded_salt, padded_salt_size)) {
 			level++;
-			ASSERT(level < num_levels);
+			assert(level < num_levels);
 		}
 	}
 	/* Finish all nonempty pending tree blocks */
@@ -112,7 +150,7 @@ static bool compute_root_hash(void *fd,
 	}
 
 	/* Root hash was filled by the last call to hash_one_block() */
-	ASSERT(buffers[num_levels].filled == hash->alg->digest_size);
+	assert(buffers[num_levels].filled == hash->alg->digest_size);
 	ok = true;
 out:
 	for (level = -1; level < num_levels; level++)
@@ -146,8 +184,9 @@ libfsverity_compute_digest(void *fd, size_t file_size,
 	if (!is_power_of_2(params->block_size))
 		return -EINVAL;
 	if (params->salt_size > sizeof(desc.salt)) {
-		error_msg("Salt too long (got %u bytes; max is %zu bytes)",
-			  params->salt_size, sizeof(desc.salt));
+		fprintf(stderr,
+			"%s: Salt too long (got %u bytes; max is %zu bytes)",
+			__func__, params->salt_size, sizeof(desc.salt));
 		return -EINVAL;
 	}
 	if (params->salt_size && !params->salt)
@@ -206,22 +245,6 @@ libfsverity_compute_digest(void *fd, size_t file_size,
 	return retval;
 }
 
-static void __printf(1, 2) __cold
-error_msg_openssl(const char *format, ...)
-{
-	va_list va;
-
-	va_start(va, format);
-	do_error_msg(format, va, 0);
-	va_end(va);
-
-	if (ERR_peek_error() == 0)
-		return;
-
-	fprintf(stderr, "OpenSSL library errors:\n");
-	ERR_print_errors_fp(stderr);
-}
-
 /* Read a PEM PKCS#8 formatted private key */
 static EVP_PKEY *read_private_key(const char *keyfile)
 {
@@ -230,15 +253,16 @@ static EVP_PKEY *read_private_key(const char *keyfile)
 
 	bio = BIO_new_file(keyfile, "r");
 	if (!bio) {
-		error_msg_openssl("can't open '%s' for reading", keyfile);
+		fprintf(stderr, "%s: can't open '%s' for reading",
+			__func__, keyfile);
 		return NULL;
 	}
 
 	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
 	if (!pkey) {
-		error_msg_openssl("Failed to parse private key file '%s'.\n"
-				  "       Note: it must be in PEM PKCS#8 format.",
-				  keyfile);
+		fprintf(stderr, "%s: Failed to parse private key file '%s'.\n"
+			"       Note: it must be in PEM PKCS#8 format.",
+			__func__, keyfile);
 	}
 	BIO_free(bio);
 	return pkey;
@@ -252,14 +276,16 @@ static X509 *read_certificate(const char *certfile)
 
 	bio = BIO_new_file(certfile, "r");
 	if (!bio) {
-		error_msg_openssl("can't open '%s' for reading", certfile);
+		fprintf(stderr, "%s: can't open '%s' for reading",
+			__func__, certfile);
 		return NULL;
 	}
 	cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
 	if (!cert) {
-		error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n"
-				  "       Note: it must be in PEM format.",
-				  certfile);
+		fprintf(stderr,
+			"%s: Failed to parse X.509 certificate file '%s'.\n"
+			"       Note: it must be in PEM format.",
+			__func__, certfile);
 	}
 	BIO_free(bio);
 	return cert;
@@ -269,13 +295,13 @@ static X509 *read_certificate(const char *certfile)
 
 static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
-		       u8 **sig_ret, size_t *sig_size_ret)
+		       uint8_t **sig_ret, size_t *sig_size_ret)
 {
 	CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo,
 		null, content_info, issuer_and_serial, signer_infos,
 		signer_info, sign_algo, signature;
 	EVP_MD_CTX md_ctx;
-	u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL;
+	uint8_t *name_der = NULL, *sig = NULL, *pkcs7_data = NULL;
 	size_t pkcs7_data_len, sig_len;
 	int name_der_len, sig_nid;
 	bool ok = false;
@@ -290,19 +316,20 @@ static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 
 	name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der);
 	if (name_der_len < 0) {
-		error_msg_openssl("i2d_X509_NAME failed");
+		fprintf(stderr, "%s: i2d_X509_NAME failed", __func__);
 		goto out;
 	}
 
 	if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) {
-		error_msg_openssl("EVP_DigestSignInit failed");
+		fprintf(stderr, "%s: EVP_DigestSignInit failed", __func__);
 		goto out;
 	}
 
 	sig_len = EVP_PKEY_size(pkey);
-	sig = xmalloc(sig_len);
+	sig = malloc(sig_len);
+	assert(sig);
 	if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) {
-		error_msg_openssl("EVP_DigestSign failed");
+		fprintf(stderr, "%s: EVP_DigestSign failed", __func__);
 		goto out;
 	}
 
@@ -344,11 +371,14 @@ static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 	    !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) ||
 	    !CBB_add_bytes(&signature, sig, sig_len) ||
 	    !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) {
-		error_msg_openssl("failed to construct PKCS#7 data");
+		fprintf(stderr, "%s: failed to construct PKCS#7 data",
+			__func__);
 		goto out;
 	}
 
-	*sig_ret = xmemdup(pkcs7_data, pkcs7_data_len);
+	*sig_ret = malloc(pkcs7_data_len);
+	assert(*sig_ret);
+	memcpy(*sig_ret, pkcs7_data, pkcs7_data_len);
 	*sig_size_ret = pkcs7_data_len;
 	ok = true;
 out:
@@ -367,7 +397,7 @@ static BIO *new_mem_buf(const void *buf, size_t size)
 {
 	BIO *bio;
 
-	ASSERT(size <= INT_MAX);
+	assert(size <= INT_MAX);
 	/*
 	 * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer,
 	 * despite still marking the resulting bio as read-only.  So cast away
@@ -375,13 +405,13 @@ static BIO *new_mem_buf(const void *buf, size_t size)
 	 */
 	bio = BIO_new_mem_buf((void *)buf, size);
 	if (!bio)
-		error_msg_openssl("out of memory");
+		fprintf(stderr, "%s: out of memory", __func__);
 	return bio;
 }
 
 static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 		       EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
-		       u8 **sig_ret, size_t *sig_size_ret)
+		       uint8_t **sig_ret, size_t *sig_size_ret)
 {
 	/*
 	 * PKCS#7 signing flags:
@@ -403,8 +433,8 @@ static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 	 */
 	int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR |
 			  PKCS7_NOCERTS | PKCS7_PARTIAL;
-	u8 *sig;
-	u32 sig_size;
+	uint8_t *sig;
+	uint32_t sig_size;
 	BIO *bio = NULL;
 	PKCS7 *p7 = NULL;
 	bool ok = false;
@@ -415,34 +445,43 @@ static bool sign_pkcs7(const void *data_to_sign, size_t data_size,
 
 	p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags);
 	if (!p7) {
-		error_msg_openssl("failed to initialize PKCS#7 signature object");
+		fprintf(stderr,
+			"%s: failed to initialize PKCS#7 signature object",
+			__func__);
 		goto out;
 	}
 
 	if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) {
-		error_msg_openssl("failed to add signer to PKCS#7 signature object");
+		fprintf(stderr,
+			"%s: failed to add signer to PKCS#7 signature object",
+			__func__);
 		goto out;
 	}
 
 	if (PKCS7_final(p7, bio, pkcs7_flags) != 1) {
-		error_msg_openssl("failed to finalize PKCS#7 signature");
+		fprintf(stderr, "%s: failed to finalize PKCS#7 signature",
+			__func__);
 		goto out;
 	}
 
 	BIO_free(bio);
 	bio = BIO_new(BIO_s_mem());
 	if (!bio) {
-		error_msg_openssl("out of memory");
+		fprintf(stderr, "%s: out of memory", __func__);
 		goto out;
 	}
 
 	if (i2d_PKCS7_bio(bio, p7) != 1) {
-		error_msg_openssl("failed to DER-encode PKCS#7 signature object");
+		fprintf(stderr,
+			"%s: failed to DER-encode PKCS#7 signature object",
+			__func__);
 		goto out;
 	}
 
 	sig_size = BIO_get_mem_data(bio, &sig);
-	*sig_ret = xmemdup(sig, sig_size);
+	*sig_ret = malloc(sig_size);
+	assert(*sig_ret);
+	memcpy(*sig_ret, sig, sig_size);
 	*sig_size_ret = sig_size;
 	ok = true;
 out:
diff --git a/util.c b/util.c
index 586d2b0..0c4bf79 100644
--- a/util.c
+++ b/util.c
@@ -18,6 +18,7 @@
 #include <unistd.h>
 
 #include "util.h"
+#include "helpers.h"
 
 /* ========== Memory allocation ========== */
 
diff --git a/util.h b/util.h
index c4dc066..bd7ab9c 100644
--- a/util.h
+++ b/util.h
@@ -17,14 +17,6 @@ typedef uint16_t u16;
 typedef uint32_t u32;
 typedef uint64_t u64;
 
-#ifndef __force
-#  ifdef __CHECKER__
-#    define __force	__attribute__((force))
-#  else
-#    define __force
-#  endif
-#endif
-
 #ifndef __printf
 #  define __printf(fmt_idx, vargs_idx) \
 	__attribute__((format(printf, fmt_idx, vargs_idx)))
@@ -38,54 +30,6 @@ typedef uint64_t u64;
 #  define __cold	__attribute__((cold))
 #endif
 
-#define min(a, b) ({			\
-	__typeof__(a) _a = (a);		\
-	__typeof__(b) _b = (b);		\
-	_a < _b ? _a : _b;		\
-})
-#define max(a, b) ({			\
-	__typeof__(a) _a = (a);		\
-	__typeof__(b) _b = (b);		\
-	_a > _b ? _a : _b;		\
-})
-
-#define roundup(x, y) ({		\
-	__typeof__(y) _y = (y);		\
-	(((x) + _y - 1) / _y) * _y;	\
-})
-
-#define ARRAY_SIZE(A)		(sizeof(A) / sizeof((A)[0]))
-
-#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
-
-static inline bool is_power_of_2(unsigned long n)
-{
-	return n != 0 && ((n & (n - 1)) == 0);
-}
-
-static inline int ilog2(unsigned long n)
-{
-	return (8 * sizeof(n) - 1) - __builtin_clzl(n);
-}
-
-/* ========== Endianness conversion ========== */
-
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-#  define cpu_to_le16(v)	((__force __le16)(u16)(v))
-#  define le16_to_cpu(v)	((__force u16)(__le16)(v))
-#  define cpu_to_le32(v)	((__force __le32)(u32)(v))
-#  define le32_to_cpu(v)	((__force u32)(__le32)(v))
-#  define cpu_to_le64(v)	((__force __le64)(u64)(v))
-#  define le64_to_cpu(v)	((__force u64)(__le64)(v))
-#else
-#  define cpu_to_le16(v)	((__force __le16)__builtin_bswap16(v))
-#  define le16_to_cpu(v)	(__builtin_bswap16((__force u16)(v)))
-#  define cpu_to_le32(v)	((__force __le32)__builtin_bswap32(v))
-#  define le32_to_cpu(v)	(__builtin_bswap32((__force u32)(v)))
-#  define cpu_to_le64(v)	((__force __le64)__builtin_bswap64(v))
-#  define le64_to_cpu(v)	(__builtin_bswap64((__force u64)(v)))
-#endif
-
 /* ========== Memory allocation ========== */
 
 void *xmalloc(size_t size);
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 13/20] Update Makefile to install libfsverity and fsverity.h
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (11 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 12/20] libfsverity: Remove dependencies on util.c Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 14/20] Change libfsverity_find_hash_alg_by_name() to return the alg number Jes Sorensen
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

In addition this adds a 'static' build target, which links in libfsverity
statically rather than relying on the shared library.

This also honors PREFIX for installation location.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 Makefile | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index 966afa0..5bbcd87 100644
--- a/Makefile
+++ b/Makefile
@@ -1,34 +1,52 @@
 EXE := fsverity
+STATIC := fsverity-static
 LIB := libfsverity.so
+INC := libfsverity.h
 CFLAGS := -O2 -Wall
 CPPFLAGS := -D_FILE_OFFSET_BITS=64
 LDLIBS := -lcrypto
-DESTDIR := /usr/local
-LIBDIR := /usr/lib64
+PREFIX = /usr
+BINDIR := $(PREFIX)/bin
+LIBDIR := $(PREFIX)/lib64
+INCDIR := $(PREFIX)/include
 SRC := $(wildcard *.c)
 OBJ := fsverity.o cmd_enable.o cmd_measure.o cmd_sign.o util.o
 SSRC := libverity.c hash_algs.c
-SOBJ := libverity.so hash_algs.so
+SHOBJ := libverity.so hash_algs.so
+STOBJ := libverity.o hash_algs.o
 HDRS := $(wildcard *.h)
 
 all:$(EXE)
 
+static:$(STATIC)
+
 $(EXE):$(OBJ) $(LIB)
 	$(CC) -o $@ $(OBJ) $(LDLIBS) -L . -l fsverity
 
+$(STATIC):$(OBJ) $(STOBJ)
+	$(CC) -o $@ $(OBJ) $(STOBJ) $(LDLIBS)
+
 $(OBJ): %.o: %.c $(HDRS)
 	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
 
-$(SOBJ): %.so: %.c $(HDRS)
+$(STOBJ): %.o: %.c $(HDRS)
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+
+$(SHOBJ): %.so: %.c $(HDRS)
 	$(CC) -c -fPIC $(CFLAGS) $(CPPFLAGS) $< -o $@
 
-libfsverity.so: $(SOBJ)
-	$(CC) $(LDLIBS) -shared -o libfsverity.so $(SOBJ)
+libfsverity.so: $(SHOBJ)
+	$(CC) $(LDLIBS) -shared -o $@ $(SHOBJ)
 
 clean:
-	rm -f $(EXE) $(OBJ) $(SOBJ) $(LIB)
+	rm -f $(EXE) $(OBJ) $(SHOBJ) $(LIB) $(STOBJ) $(STATIC)
 
 install:all
-	install -Dm755 -t $(DESTDIR)/bin $(EXE)
+	install -Dm755 -t $(BINDIR) $(EXE)
+	install -Dm755 -t $(LIBDIR) $(LIB)
+	install -Dm644 -t $(INCDIR) $(INC)
+
+install-static:static
+	install -Dm755 -t $(BINDIR) $(STATIC)
 
 .PHONY: all clean install
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 14/20] Change libfsverity_find_hash_alg_by_name() to return the alg number
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (12 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 13/20] Update Makefile to install libfsverity and fsverity.h Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:54 ` [PATCH 15/20] Make libfsverity_find_hash_alg_by_name() private to the shared library Jes Sorensen
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This elimnates the need for struct fsverity_hash_alg in the use case
of libfsverity_find_hash_alg_by_name(). In addition this introduces a
libfsverity_digest_size() which returns the size of the digest for the
given algorithm, and libfsverity_hash_name() which returns a string
with the name of the algorithm. Note the returned string must be
freed by the caller.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_enable.c  |  6 +++---
 cmd_sign.c    | 25 +++++++++++++++----------
 hash_algs.c   | 35 ++++++++++++++++++++++++++++++-----
 libfsverity.h | 28 +++++++++++++++++++++++-----
 4 files changed, 71 insertions(+), 23 deletions(-)

diff --git a/cmd_enable.c b/cmd_enable.c
index 9612778..ac977e7 100644
--- a/cmd_enable.c
+++ b/cmd_enable.c
@@ -22,7 +22,7 @@ static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr)
 {
 	char *end;
 	unsigned long n = strtoul(arg, &end, 10);
-	const struct fsverity_hash_alg *alg;
+	uint16_t alg;
 
 	if (*alg_ptr != 0) {
 		error_msg("--hash-alg can only be specified once");
@@ -37,8 +37,8 @@ static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr)
 
 	/* Specified by name? */
 	alg = libfsverity_find_hash_alg_by_name(arg);
-	if (alg != NULL) {
-		*alg_ptr = alg->hash_num;
+	if (alg) {
+		*alg_ptr = alg;
 		return true;
 	}
 	error_msg("unknown hash algorithm: '%s'", arg);
diff --git a/cmd_sign.c b/cmd_sign.c
index 959e6d9..80e62d5 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -57,7 +57,6 @@ static int read_callback(void *opague, void *buf, size_t count)
 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;
@@ -69,7 +68,10 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	struct libfsverity_signature_params sig_params;
 	u64 file_size;
 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
+	char *hash_name = NULL;
 	u8 *sig = NULL;
+	u16 alg_nr = 0;
+	int digest_size;
 	size_t sig_size;
 	int status;
 	int c;
@@ -77,12 +79,12 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
 		switch (c) {
 		case OPT_HASH_ALG:
-			if (hash_alg != NULL) {
+			if (alg_nr) {
 				error_msg("--hash-alg can only be specified once");
 				goto out_usage;
 			}
-			hash_alg = libfsverity_find_hash_alg_by_name(optarg);
-			if (hash_alg == NULL) {
+			alg_nr = libfsverity_find_hash_alg_by_name(optarg);
+			if (!alg_nr) {
 				error_msg("unknown hash algorithm: '%s'",
 					  optarg);
 				fputs("Available hash algorithms: ", stderr);
@@ -124,8 +126,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	if (argc != 2)
 		goto out_usage;
 
-	if (hash_alg == NULL)
-		hash_alg = libfsverity_find_hash_alg_by_num(FS_VERITY_HASH_ALG_DEFAULT);
+	if (!alg_nr)
+		alg_nr = FS_VERITY_HASH_ALG_DEFAULT;
 
 	if (block_size == 0)
 		block_size = get_default_block_size();
@@ -147,7 +149,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 
 	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
 	params.version = 1;
-	params.hash_algorithm = hash_alg->hash_num;
+	params.hash_algorithm = alg_nr;
 	params.block_size = block_size;
 	params.salt_size = salt_size;
 	params.salt = salt;
@@ -158,6 +160,8 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 
 	filedes_close(&file);
 
+	digest_size = libfsverity_digest_size(alg_nr);
+
 	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
 	sig_params.keyfile = keyfile;
 	sig_params.certfile = certfile;
@@ -169,9 +173,10 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	if (!write_signature(argv[1], sig, sig_size))
 		goto out_err;
 
-	bin2hex(digest->digest, hash_alg->digest_size, digest_hex);
-	printf("Signed file '%s' (%s:%s)\n", argv[0], hash_alg->name,
-	       digest_hex);
+	hash_name = libfsverity_hash_name(alg_nr);
+	bin2hex(digest->digest, digest_size, digest_hex);
+	printf("Signed file '%s' (%s:%s)\n", argv[0], hash_name, digest_hex);
+	free(hash_name);
 	status = 0;
 out:
 	free(salt);
diff --git a/hash_algs.c b/hash_algs.c
index 3066d87..120d1be 100644
--- a/hash_algs.c
+++ b/hash_algs.c
@@ -137,17 +137,17 @@ const struct fsverity_hash_alg fsverity_hash_algs[] = {
 	},
 };
 
-const struct fsverity_hash_alg *
-libfsverity_find_hash_alg_by_name(const char *name)
+uint16_t libfsverity_find_hash_alg_by_name(const char *name)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
 		if (fsverity_hash_algs[i].name &&
-		    !strcmp(name, fsverity_hash_algs[i].name))
-			return &fsverity_hash_algs[i];
+		    !strcmp(name, fsverity_hash_algs[i].name)) {
+			return fsverity_hash_algs[i].hash_num;
+		}
 	}
-	return NULL;
+	return 0;
 }
 
 const struct fsverity_hash_alg *
@@ -160,6 +160,31 @@ libfsverity_find_hash_alg_by_num(unsigned int num)
 	return NULL;
 }
 
+int libfsverity_digest_size(uint16_t alg_nr)
+{
+	if (alg_nr < ARRAY_SIZE(fsverity_hash_algs) &&
+	    fsverity_hash_algs[alg_nr].name)
+		return fsverity_hash_algs[alg_nr].digest_size;
+
+	return -1;
+}
+
+char *libfsverity_hash_name(uint16_t alg_nr)
+{
+	int namelen;
+	char *hash_name = NULL;
+
+	if (alg_nr < ARRAY_SIZE(fsverity_hash_algs) &&
+	    fsverity_hash_algs[alg_nr].name) {
+		namelen = strlen(fsverity_hash_algs[alg_nr].name);
+		hash_name = malloc(namelen + 1);
+		if (hash_name)
+			strcpy(hash_name, fsverity_hash_algs[alg_nr].name);
+	}
+
+	return hash_name;
+}
+
 /* ->init(), ->update(), and ->final() all in one step */
 void hash_full(struct hash_ctx *ctx, const void *data, size_t size,
 	       uint8_t *digest)
diff --git a/libfsverity.h b/libfsverity.h
index ea36b8e..a505cbe 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -58,7 +58,7 @@ struct libfsverity_signature_params {
 
 struct fsverity_hash_alg {
 	const char *name;
-	unsigned int digest_size;
+	int digest_size;
 	unsigned int block_size;
 	uint16_t hash_num;
 	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
@@ -108,11 +108,9 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
  * @name: Pointer to name of hash algorithm
  *
  * Returns:
- * struct fsverity_hash_alg success
- * NULL on error
+ * uint16_t containing hash algorithm number, zero on error.
  */
-const struct fsverity_hash_alg *
-libfsverity_find_hash_alg_by_name(const char *name);
+uint16_t libfsverity_find_hash_alg_by_name(const char *name);
 
 /*
  * libfsverity_find_hash_alg_by_num - Find hash algorithm by number
@@ -125,4 +123,24 @@ libfsverity_find_hash_alg_by_name(const char *name);
 const struct fsverity_hash_alg *
 libfsverity_find_hash_alg_by_num(unsigned int num);
 
+/*
+ * libfsverity_digest_size - Return size of digest for a given algorithm
+ * @alg_nr: Valid hash algorithm number
+ *
+ * Returns:
+ * int containing size of digest, -1 on error.
+ */
+int libfsverity_digest_size(uint16_t alg_nr);
+
+/*
+ * libfsverity_find_hash_name - Find name of hash algorithm by number
+ * @name: Number of hash algorithm
+ *
+ * Returns:
+ *  New allocated string containing name of algorithm.
+ *  String must be freed by caller.
+ * NULL on error
+ */
+char *libfsverity_hash_name(uint16_t num);
+
 #endif
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 15/20] Make libfsverity_find_hash_alg_by_name() private to the shared library
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (13 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 14/20] Change libfsverity_find_hash_alg_by_name() to return the alg number Jes Sorensen
@ 2020-04-24 20:54 ` Jes Sorensen
  2020-04-24 20:55 ` [PATCH 16/20] libfsverity_sign_digest() use ARRAY_SIZE() Jes Sorensen
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:54 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

This moves struct fsverity_hash_alg out of the public API. Instead
implement show_all_hash_algs() by calling libfsverity_hash_name()
until it returns null.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_enable.c          |  2 +-
 cmd_measure.c         | 17 ++++++++---------
 cmd_sign.c            |  2 +-
 fsverity.c            | 16 +++++++---------
 hash_algs.c           |  1 +
 libfsverity.h         | 19 -------------------
 libfsverity_private.h | 19 +++++++++++++++++++
 7 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/cmd_enable.c b/cmd_enable.c
index ac977e7..632ac84 100644
--- a/cmd_enable.c
+++ b/cmd_enable.c
@@ -42,7 +42,7 @@ static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr)
 		return true;
 	}
 	error_msg("unknown hash algorithm: '%s'", arg);
-	fputs("Available hash algorithms: ", stderr);
+	fputs("Available hash algorithms:", stderr);
 	show_all_hash_algs(stderr);
 	putc('\n', stderr);
 
diff --git a/cmd_measure.c b/cmd_measure.c
index 4c0777f..df39da0 100644
--- a/cmd_measure.c
+++ b/cmd_measure.c
@@ -22,9 +22,8 @@ int fsverity_cmd_measure(const struct fsverity_command *cmd,
 	struct fsverity_digest *d = NULL;
 	struct filedes file;
 	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
-	const struct fsverity_hash_alg *hash_alg;
 	char _hash_alg_name[32];
-	const char *hash_alg_name;
+	char *hash_alg_name;
 	int status;
 	int i;
 
@@ -48,14 +47,14 @@ int fsverity_cmd_measure(const struct fsverity_command *cmd,
 
 		ASSERT(d->digest_size <= FS_VERITY_MAX_DIGEST_SIZE);
 		bin2hex(d->digest, d->digest_size, digest_hex);
-		hash_alg = libfsverity_find_hash_alg_by_num(d->digest_algorithm);
-		if (hash_alg) {
-			hash_alg_name = hash_alg->name;
-		} else {
+		hash_alg_name = libfsverity_hash_name(d->digest_algorithm);
+		if (!hash_alg_name)
 			sprintf(_hash_alg_name, "ALG_%u", d->digest_algorithm);
-			hash_alg_name = _hash_alg_name;
-		}
-		printf("%s:%s %s\n", hash_alg_name, digest_hex, argv[i]);
+
+		printf("%s:%s %s\n",
+		       hash_alg_name ? hash_alg_name :_hash_alg_name,
+		       digest_hex, argv[i]);
+		free(hash_alg_name);
 	}
 	status = 0;
 out:
diff --git a/cmd_sign.c b/cmd_sign.c
index 80e62d5..57a9250 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -87,7 +87,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 			if (!alg_nr) {
 				error_msg("unknown hash algorithm: '%s'",
 					  optarg);
-				fputs("Available hash algorithms: ", stderr);
+				fputs("Available hash algorithms:", stderr);
 				show_all_hash_algs(stderr);
 				putc('\n', stderr);
 				goto out_usage;
diff --git a/fsverity.c b/fsverity.c
index a176ead..2e2b553 100644
--- a/fsverity.c
+++ b/fsverity.c
@@ -51,14 +51,12 @@ static const struct fsverity_command {
 void show_all_hash_algs(FILE *fp)
 {
 	int i = 1;
-	const char *sep = "";
-	const struct fsverity_hash_alg *alg;
-
-	while ((alg = libfsverity_find_hash_alg_by_num(i++))) {
-		if (alg && alg->name) {
-			fprintf(fp, "%s%s", sep, alg->name);
-			sep = ", ";
-		}
+	const char *sep = " ";
+	char *alg;
+
+	while ((alg = libfsverity_hash_name(i++))) {
+		fprintf(fp, "%s%s", sep, alg);
+		free(alg);
 	}
 }
 
@@ -75,7 +73,7 @@ static void usage_all(FILE *fp)
 "    fsverity --help\n"
 "    fsverity --version\n"
 "\n"
-"Available hash algorithms: ", fp);
+"Available hash algorithms:", fp);
 	show_all_hash_algs(fp);
 	putc('\n', fp);
 }
diff --git a/hash_algs.c b/hash_algs.c
index 120d1be..03b9de9 100644
--- a/hash_algs.c
+++ b/hash_algs.c
@@ -15,6 +15,7 @@
 #include "helpers.h"
 #include "fsverity_uapi.h"
 #include "libfsverity.h"
+#include "libfsverity_private.h"
 #include "hash_algs.h"
 
 /* ========== libcrypto (OpenSSL) wrappers ========== */
diff --git a/libfsverity.h b/libfsverity.h
index a505cbe..4f0f885 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -56,14 +56,6 @@ struct libfsverity_signature_params {
 	uint64_t reserved[11];
 };
 
-struct fsverity_hash_alg {
-	const char *name;
-	int digest_size;
-	unsigned int block_size;
-	uint16_t hash_num;
-	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
-};
-
 /*
  * libfsverity_compute_digest - Compute digest of a file
  * @fd: open file descriptor of file to compute digest for
@@ -112,17 +104,6 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
  */
 uint16_t libfsverity_find_hash_alg_by_name(const char *name);
 
-/*
- * libfsverity_find_hash_alg_by_num - Find hash algorithm by number
- * @name: Number of hash algorithm
- *
- * Returns:
- * struct fsverity_hash_alg success
- * NULL on error
- */
-const struct fsverity_hash_alg *
-libfsverity_find_hash_alg_by_num(unsigned int num);
-
 /*
  * libfsverity_digest_size - Return size of digest for a given algorithm
  * @alg_nr: Valid hash algorithm number
diff --git a/libfsverity_private.h b/libfsverity_private.h
index 5f3e1b4..f8eebe2 100644
--- a/libfsverity_private.h
+++ b/libfsverity_private.h
@@ -30,4 +30,23 @@ struct fsverity_descriptor {
 	uint8_t signature[];	/* optional PKCS#7 signature */
 };
 
+struct fsverity_hash_alg {
+	const char *name;
+	int digest_size;
+	unsigned int block_size;
+	uint16_t hash_num;
+	struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg);
+};
+
+/*
+ * libfsverity_find_hash_alg_by_num - Find hash algorithm by number
+ * @name: Number of hash algorithm
+ *
+ * Returns:
+ * struct fsverity_hash_alg success
+ * NULL on error
+ */
+const struct fsverity_hash_alg *
+libfsverity_find_hash_alg_by_num(unsigned int num);
+
 #endif
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 16/20] libfsverity_sign_digest() use ARRAY_SIZE()
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (14 preceding siblings ...)
  2020-04-24 20:54 ` [PATCH 15/20] Make libfsverity_find_hash_alg_by_name() private to the shared library Jes Sorensen
@ 2020-04-24 20:55 ` Jes Sorensen
  2020-04-24 20:55 ` [PATCH 17/20] fsverity_cmd_sign() use sizeof() input argument instead of struct Jes Sorensen
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:55 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 libverity.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libverity.c b/libverity.c
index 975d86e..7908dcd 100644
--- a/libverity.c
+++ b/libverity.c
@@ -521,8 +521,7 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
 	if (!sig_params->keyfile || !sig_params->certfile)
 		return -EINVAL;
 
-	for (i = 0; i < sizeof(sig_params->reserved) /
-		     sizeof(sig_params->reserved[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(sig_params->reserved); i++) {
 		if (sig_params->reserved[i])
 			return -EINVAL;
 	}
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 17/20] fsverity_cmd_sign() use sizeof() input argument instead of struct
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (15 preceding siblings ...)
  2020-04-24 20:55 ` [PATCH 16/20] libfsverity_sign_digest() use ARRAY_SIZE() Jes Sorensen
@ 2020-04-24 20:55 ` Jes Sorensen
  2020-04-24 20:55 ` [PATCH 18/20] fsverity_cmd_sign() don't exit on error without closing file descriptor Jes Sorensen
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:55 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index 57a9250..d699d85 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -147,7 +147,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 		goto out_err;
 	}
 
-	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
+	memset(&params, 0, sizeof(params));
 	params.version = 1;
 	params.hash_algorithm = alg_nr;
 	params.block_size = block_size;
@@ -162,7 +162,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 
 	digest_size = libfsverity_digest_size(alg_nr);
 
-	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
+	memset(&sig_params, 0, sizeof(sig_params));
 	sig_params.keyfile = keyfile;
 	sig_params.certfile = certfile;
 	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 18/20] fsverity_cmd_sign() don't exit on error without closing file descriptor
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (16 preceding siblings ...)
  2020-04-24 20:55 ` [PATCH 17/20] fsverity_cmd_sign() use sizeof() input argument instead of struct Jes Sorensen
@ 2020-04-24 20:55 ` Jes Sorensen
  2020-04-24 20:55 ` [PATCH 19/20] Improve documentation of libfsverity.h API Jes Sorensen
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:55 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index d699d85..7d8ec58 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -73,7 +73,7 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	u16 alg_nr = 0;
 	int digest_size;
 	size_t sig_size;
-	int status;
+	int status, ret;
 	int c;
 
 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
@@ -154,12 +154,13 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
 	params.salt_size = salt_size;
 	params.salt = salt;
 
-	if (libfsverity_compute_digest(&file, file_size, read_callback,
-				       &params, &digest))
-		goto out_err;
-
+	ret = libfsverity_compute_digest(&file, file_size, read_callback,
+					 &params, &digest);
 	filedes_close(&file);
 
+	if (ret)
+		goto out_err;
+
 	digest_size = libfsverity_digest_size(alg_nr);
 
 	memset(&sig_params, 0, sizeof(sig_params));
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 19/20] Improve documentation of libfsverity.h API
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (17 preceding siblings ...)
  2020-04-24 20:55 ` [PATCH 18/20] fsverity_cmd_sign() don't exit on error without closing file descriptor Jes Sorensen
@ 2020-04-24 20:55 ` Jes Sorensen
  2020-04-24 20:55 ` [PATCH 20/20] Fixup Makefile Jes Sorensen
  2020-05-07 14:03 ` [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:55 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 libfsverity.h | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/libfsverity.h b/libfsverity.h
index 4f0f885..c4f6b8d 100644
--- a/libfsverity.h
+++ b/libfsverity.h
@@ -58,17 +58,21 @@ struct libfsverity_signature_params {
 
 /*
  * libfsverity_compute_digest - Compute digest of a file
+ *          An fsverity digest is the root of the Merkle tree of the file.
+ *          Not to be confused with a traditional file digests computed over
+ *          the entire file.
  * @fd: open file descriptor of file to compute digest for
  * @params: struct libfsverity_merkle_tree_params specifying hash algorithm,
  *	    block size, version, and optional salt parameters.
  *	    reserved parameters must be zero.
- * @digest_ret: Pointer to pointer for computed digest
+ * @digest_ret: Pointer to pointer for computed digest.
  *
  * Returns:
  * * 0 for success, -EINVAL for invalid input arguments, -ENOMEM if failed
  *   to allocate memory, -EBADF if fd is invalid, and -EAGAIN if root hash
  *   fails to compute.
- * * digest_ret returns a pointer to the digest on success.
+ * * digest_ret returns a pointer to the digest on success. The digest object
+ *   is allocated by libfsverity and must be freed by the caller.
  */
 int
 libfsverity_compute_digest(void *fd, size_t file_size,
@@ -78,6 +82,12 @@ libfsverity_compute_digest(void *fd, size_t file_size,
 
 /*
  * libfsverity_sign_digest - Sign previously computed digest of a file
+ *          This is signature is used by the file system to validate the
+ *          signed file measurement against a public key loaded into the
+ *          .fs-verity kernel keyring, when CONFIG_FS_VERITY_BUILTIN_SIGNATURES
+ *          is enabled. The signature is formatted as PKCS#7 stored in DER
+ *          format. See Documentation/filesystems/fsverity.rst for further
+ *          details.
  * @digest: pointer to previously computed digest
  * @sig_params: struct libfsverity_signature_params providing filenames of
  *          the keyfile and certificate file. Reserved parameters must be zero.
@@ -87,7 +97,8 @@ libfsverity_compute_digest(void *fd, size_t file_size,
  * Returns:
  * * 0 for success, -EINVAL for invalid input arguments, -EAGAIN if key or
  *   certificate files fail to read, or if signing the digest fails.
- * * sig_ret returns a pointer to the signed digest on success.
+ * * sig_ret returns a pointer to the signed digest on success. This object
+ *   is allocated by libfsverity_sign_digest and must be freed by the caller.
  * * sig_size_ret returns the size of the signed digest on success.
  */
 int
@@ -100,7 +111,7 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
  * @name: Pointer to name of hash algorithm
  *
  * Returns:
- * uint16_t containing hash algorithm number, zero on error.
+ * uint16_t containing hash algorithm number, zero if not found.
  */
 uint16_t libfsverity_find_hash_alg_by_name(const char *name);
 
@@ -109,7 +120,7 @@ uint16_t libfsverity_find_hash_alg_by_name(const char *name);
  * @alg_nr: Valid hash algorithm number
  *
  * Returns:
- * int containing size of digest, -1 on error.
+ * int containing size of digest, -1 if algorithm is not known.
  */
 int libfsverity_digest_size(uint16_t alg_nr);
 
@@ -118,9 +129,9 @@ int libfsverity_digest_size(uint16_t alg_nr);
  * @name: Number of hash algorithm
  *
  * Returns:
- *  New allocated string containing name of algorithm.
- *  String must be freed by caller.
- * NULL on error
+ * New allocated string containing name of algorithm.
+ *  The string must be freed by caller.
+ * NULL if algorithm is not known.
  */
 char *libfsverity_hash_name(uint16_t num);
 
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 20/20] Fixup Makefile
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (18 preceding siblings ...)
  2020-04-24 20:55 ` [PATCH 19/20] Improve documentation of libfsverity.h API Jes Sorensen
@ 2020-04-24 20:55 ` Jes Sorensen
  2020-05-07 14:03 ` [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
  20 siblings, 0 replies; 23+ messages in thread
From: Jes Sorensen @ 2020-04-24 20:55 UTC (permalink / raw)
  To: linux-fscrypt; +Cc: ebiggers, kernel-team, jsorensen

From: Jes Sorensen <jsorensen@fb.com>

Set soname for libfsverity, install shared library and header file,
and make clean handle shared library too.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 Makefile | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index 5bbcd87..0b82c82 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,5 @@
 EXE := fsverity
 STATIC := fsverity-static
-LIB := libfsverity.so
 INC := libfsverity.h
 CFLAGS := -O2 -Wall
 CPPFLAGS := -D_FILE_OFFSET_BITS=64
@@ -15,12 +14,17 @@ SSRC := libverity.c hash_algs.c
 SHOBJ := libverity.so hash_algs.so
 STOBJ := libverity.o hash_algs.o
 HDRS := $(wildcard *.h)
+LIB_MAJOR := 1
+LIB_MINOR := 0.0
+LIB_SO := libfsverity.so
+LIB_SONAME := $(LIB_SO).$(LIB_MAJOR)
+LIB_FULL := $(LIB_SONAME).$(LIB_MINOR)
 
 all:$(EXE)
 
 static:$(STATIC)
 
-$(EXE):$(OBJ) $(LIB)
+$(EXE):$(OBJ) $(LIB_FULL)
 	$(CC) -o $@ $(OBJ) $(LDLIBS) -L . -l fsverity
 
 $(STATIC):$(OBJ) $(STOBJ)
@@ -35,16 +39,21 @@ $(STOBJ): %.o: %.c $(HDRS)
 $(SHOBJ): %.so: %.c $(HDRS)
 	$(CC) -c -fPIC $(CFLAGS) $(CPPFLAGS) $< -o $@
 
-libfsverity.so: $(SHOBJ)
-	$(CC) $(LDLIBS) -shared -o $@ $(SHOBJ)
+$(LIB_FULL): $(SHOBJ)
+	$(CC) $(LDLIBS) -shared -Wl,-soname,$(LIB_SONAME) -o $@ $(SHOBJ)
+	rm -f $(LIB_SONAME) $(LIB_SO)
+	ln -s $(LIB_FULL) $(LIB_SONAME)
+	ln -s $(LIB_SONAME) $(LIB_SO)
 
 clean:
-	rm -f $(EXE) $(OBJ) $(SHOBJ) $(LIB) $(STOBJ) $(STATIC)
+	rm -f $(EXE) $(OBJ) $(SHOBJ) $(LIB_SONAME) $(LIB_SO) $(LIB_FULL) $(STOBJ) $(STATIC)
 
 install:all
-	install -Dm755 -t $(BINDIR) $(EXE)
-	install -Dm755 -t $(LIBDIR) $(LIB)
-	install -Dm644 -t $(INCDIR) $(INC)
+	install -Dm755 -t $(DESTDIR)$(BINDIR) $(EXE)
+	install -Dm755 -t $(DESTDIR)$(LIBDIR) $(LIB_FULL)
+	ln -s $(LIB_FULL) $(DESTDIR)$(LIBDIR)/$(LIB_SONAME)
+	ln -s $(LIB_SONAME) $(DESTDIR)$(LIBDIR)/$(LIB_SO)
+	install -Dm644 -t $(DESTDIR)$(INCDIR) $(INC)
 
 install-static:static
 	install -Dm755 -t $(BINDIR) $(STATIC)
-- 
2.25.3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v4 00/20] Split fsverity-utils into a shared library
  2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
                   ` (19 preceding siblings ...)
  2020-04-24 20:55 ` [PATCH 20/20] Fixup Makefile Jes Sorensen
@ 2020-05-07 14:03 ` Jes Sorensen
  2020-05-07 17:35   ` Eric Biggers
  20 siblings, 1 reply; 23+ messages in thread
From: Jes Sorensen @ 2020-05-07 14:03 UTC (permalink / raw)
  To: ebiggers; +Cc: Jes Sorensen, linux-fscrypt, kernel-team

On 4/24/20 4:54 PM, Jes Sorensen wrote:
> From: Jes Sorensen <jsorensen@fb.com>
> 
> Hi
> 
> This is an update to the libfsverity patches I posted about a month
> ago, which I believe address all the issues in the feedback I received.

Hi Eric,

Wanted to check in and hear if you had a chance to look at this?

Thanks,
Jes


> I have a version of rpm that requires this library which is able to
> sign files and a plugin which will install fsverity signatures when
> the rpm is installed. The code for rpm can be found on github - note
> that I do rebase the repo as I fix bugs:
> https://github.com/jessorensen/rpm/tree/rpm-fsverity
> 
> A git tree with these patches can also be found here:
> https://git.kernel.org/pub/scm/linux/kernel/git/jes/fsverity-utils.git
> 
> This update changes a number of issues:
> - Change the API for libfsverity_compute_digest() to take a callback
>   read function, which is needed to deal with the internal cpio
>   processing of rpm.
> - Provides the option to build fsverity linked statically against
>   libfsverity
> - Makefile support to install libfsverity.so, libfsverity.h and sets
>   the soname
> - Make struct fsverity_descriptor and struct fsverity_hash_alg
>   internal to the library
> - Improved documentation of the API in libfsverity.h
> 
> I have a .spec file for it that packages this into an rpm for Fedora,
> as well as a packaged version of rpm with fsverity support in it,
> which I am happy to share.
> 
> Let me know what you think!
> 
> Thanks,
> Jes
> 
> 
> Jes Sorensen (20):
>   Build basic shared library framework
>   Change compute_file_measurement() to take a file descriptor as
>     argument
>   Move fsverity_descriptor definition to libfsverity.h
>   Move hash algorithm code to shared library
>   Create libfsverity_compute_digest() and adapt cmd_sign to use it
>   Introduce libfsverity_sign_digest()
>   Validate input arguments to libfsverity_compute_digest()
>   Validate input parameters for libfsverity_sign_digest()
>   Document API of libfsverity
>   Change libfsverity_compute_digest() to take a read function
>   Make full_{read,write}() return proper error codes instead of bool
>   libfsverity: Remove dependencies on util.c
>   Update Makefile to install libfsverity and fsverity.h
>   Change libfsverity_find_hash_alg_by_name() to return the alg number
>   Make libfsverity_find_hash_alg_by_name() private to the shared library
>   libfsverity_sign_digest() use ARRAY_SIZE()
>   fsverity_cmd_sign() use sizeof() input argument instead of struct
>   fsverity_cmd_sign() don't exit on error without closing file
>     descriptor
>   Improve documentation of libfsverity.h API
>   Fixup Makefile
> 
>  Makefile              |  49 +++-
>  cmd_enable.c          |  19 +-
>  cmd_measure.c         |  19 +-
>  cmd_sign.c            | 565 +++++------------------------------------
>  fsverity.c            |  17 +-
>  hash_algs.c           |  95 ++++---
>  hash_algs.h           |  36 +--
>  helpers.h             |  43 ++++
>  libfsverity.h         | 138 ++++++++++
>  libfsverity_private.h |  52 ++++
>  libverity.c           | 572 ++++++++++++++++++++++++++++++++++++++++++
>  util.c                |  15 +-
>  util.h                |  62 +----
>  13 files changed, 1029 insertions(+), 653 deletions(-)
>  create mode 100644 helpers.h
>  create mode 100644 libfsverity.h
>  create mode 100644 libfsverity_private.h
>  create mode 100644 libverity.c
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v4 00/20] Split fsverity-utils into a shared library
  2020-05-07 14:03 ` [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
@ 2020-05-07 17:35   ` Eric Biggers
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Biggers @ 2020-05-07 17:35 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Jes Sorensen, linux-fscrypt, kernel-team

On Thu, May 07, 2020 at 10:03:47AM -0400, Jes Sorensen wrote:
> On 4/24/20 4:54 PM, Jes Sorensen wrote:
> > From: Jes Sorensen <jsorensen@fb.com>
> > 
> > Hi
> > 
> > This is an update to the libfsverity patches I posted about a month
> > ago, which I believe address all the issues in the feedback I received.
> 
> Hi Eric,
> 
> Wanted to check in and hear if you had a chance to look at this?
> 
> Thanks,
> Jes
> 

No, it's on my list of things to review though.

- Eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2020-05-07 17:35 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-04-24 20:54 [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
2020-04-24 20:54 ` [PATCH 01/20] Build basic shared library framework Jes Sorensen
2020-04-24 20:54 ` [PATCH 02/20] Change compute_file_measurement() to take a file descriptor as argument Jes Sorensen
2020-04-24 20:54 ` [PATCH 03/20] Move fsverity_descriptor definition to libfsverity.h Jes Sorensen
2020-04-24 20:54 ` [PATCH 04/20] Move hash algorithm code to shared library Jes Sorensen
2020-04-24 20:54 ` [PATCH 05/20] Create libfsverity_compute_digest() and adapt cmd_sign to use it Jes Sorensen
2020-04-24 20:54 ` [PATCH 06/20] Introduce libfsverity_sign_digest() Jes Sorensen
2020-04-24 20:54 ` [PATCH 07/20] Validate input arguments to libfsverity_compute_digest() Jes Sorensen
2020-04-24 20:54 ` [PATCH 08/20] Validate input parameters for libfsverity_sign_digest() Jes Sorensen
2020-04-24 20:54 ` [PATCH 09/20] Document API of libfsverity Jes Sorensen
2020-04-24 20:54 ` [PATCH 10/20] Change libfsverity_compute_digest() to take a read function Jes Sorensen
2020-04-24 20:54 ` [PATCH 11/20] Make full_{read,write}() return proper error codes instead of bool Jes Sorensen
2020-04-24 20:54 ` [PATCH 12/20] libfsverity: Remove dependencies on util.c Jes Sorensen
2020-04-24 20:54 ` [PATCH 13/20] Update Makefile to install libfsverity and fsverity.h Jes Sorensen
2020-04-24 20:54 ` [PATCH 14/20] Change libfsverity_find_hash_alg_by_name() to return the alg number Jes Sorensen
2020-04-24 20:54 ` [PATCH 15/20] Make libfsverity_find_hash_alg_by_name() private to the shared library Jes Sorensen
2020-04-24 20:55 ` [PATCH 16/20] libfsverity_sign_digest() use ARRAY_SIZE() Jes Sorensen
2020-04-24 20:55 ` [PATCH 17/20] fsverity_cmd_sign() use sizeof() input argument instead of struct Jes Sorensen
2020-04-24 20:55 ` [PATCH 18/20] fsverity_cmd_sign() don't exit on error without closing file descriptor Jes Sorensen
2020-04-24 20:55 ` [PATCH 19/20] Improve documentation of libfsverity.h API Jes Sorensen
2020-04-24 20:55 ` [PATCH 20/20] Fixup Makefile Jes Sorensen
2020-05-07 14:03 ` [PATCH v4 00/20] Split fsverity-utils into a shared library Jes Sorensen
2020-05-07 17:35   ` Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).