All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jes Sorensen <jes.sorensen@gmail.com>
To: linux-fscrypt@vger.kernel.org
Cc: kernel-team@fb.com, Jes Sorensen <jsorensen@fb.com>
Subject: [PATCH 2/7] Restructure fsverity_cmd_sign for shared libraries
Date: Mon, 10 Feb 2020 19:00:32 -0500	[thread overview]
Message-ID: <20200211000037.189180-3-Jes.Sorensen@gmail.com> (raw)
In-Reply-To: <20200211000037.189180-1-Jes.Sorensen@gmail.com>

From: Jes Sorensen <jsorensen@fb.com>

This moves the command line parsing, error reporting etc. to the command
line tool, and turns fsverity_cmd_sign() into a call returning the
digest and the signature.

It is the responsibility of the caller to decide what to do with the
returned objects.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 cmd_sign.c | 132 ++++++-----------------------------------------------
 commands.h |  23 +++++++++-
 fsverity.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 163 insertions(+), 121 deletions(-)

diff --git a/cmd_sign.c b/cmd_sign.c
index dcb37ce..2d3fa54 100644
--- a/cmd_sign.c
+++ b/cmd_sign.c
@@ -8,7 +8,6 @@
  */
 
 #include <fcntl.h>
-#include <getopt.h>
 #include <limits.h>
 #include <openssl/bio.h>
 #include <openssl/err.h>
@@ -38,19 +37,6 @@ struct fsverity_descriptor {
 	__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
- * 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, ...)
 {
@@ -340,18 +326,6 @@ out:
 	return ok;
 }
 
-static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
-{
-	struct filedes file;
-	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);
-	return ok;
-}
-
 #define FS_VERITY_MAX_LEVELS	64
 
 struct block_buffer {
@@ -507,93 +481,27 @@ out:
 	return ok;
 }
 
-enum {
-	OPT_HASH_ALG,
-	OPT_BLOCK_SIZE,
-	OPT_SALT,
-	OPT_KEY,
-	OPT_CERT,
-};
-
-static const struct option longopts[] = {
-	{"hash-alg",	required_argument, NULL, OPT_HASH_ALG},
-	{"block-size",	required_argument, NULL, OPT_BLOCK_SIZE},
-	{"salt",	required_argument, NULL, OPT_SALT},
-	{"key",		required_argument, NULL, OPT_KEY},
-	{"cert",	required_argument, NULL, OPT_CERT},
-	{NULL, 0, NULL, 0}
-};
-
 /* 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[])
+int fsverity_cmd_sign(char *filename, const struct fsverity_hash_alg *hash_alg,
+		      u32 block_size, u8 *salt, u32 salt_size,
+		      const char *keyfile, const char *certfile,
+		      struct fsverity_signed_digest **retdigest,
+		      u8 **sig, u32 *sig_size)
 {
-	const struct fsverity_hash_alg *hash_alg = NULL;
-	u32 block_size = 0;
-	u8 *salt = NULL;
-	u32 salt_size = 0;
-	const char *keyfile = NULL;
-	const char *certfile = NULL;
 	struct fsverity_signed_digest *digest = NULL;
-	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
-	u8 *sig = NULL;
-	u32 sig_size;
 	int status;
-	int c;
-
-	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
-		switch (c) {
-		case OPT_HASH_ALG:
-			if (hash_alg != NULL) {
-				error_msg("--hash-alg can only be specified once");
-				goto out_usage;
-			}
-			hash_alg = find_hash_alg_by_name(optarg);
-			if (hash_alg == NULL)
-				goto out_usage;
-			break;
-		case OPT_BLOCK_SIZE:
-			if (!parse_block_size_option(optarg, &block_size))
-				goto out_usage;
-			break;
-		case OPT_SALT:
-			if (!parse_salt_option(optarg, &salt, &salt_size))
-				goto out_usage;
-			break;
-		case OPT_KEY:
-			if (keyfile != NULL) {
-				error_msg("--key can only be specified once");
-				goto out_usage;
-			}
-			keyfile = optarg;
-			break;
-		case OPT_CERT:
-			if (certfile != NULL) {
-				error_msg("--cert can only be specified once");
-				goto out_usage;
-			}
-			certfile = optarg;
-			break;
-		default:
-			goto out_usage;
-		}
-	}
 
-	argv += optind;
-	argc -= optind;
-
-	if (argc != 2)
-		goto out_usage;
-
-	if (hash_alg == NULL)
-		hash_alg = &fsverity_hash_algs[FS_VERITY_HASH_ALG_DEFAULT];
+	if (hash_alg == NULL) {
+		status = -EINVAL;
+		goto out;
+	}
 
 	if (block_size == 0)
 		block_size = get_default_block_size();
 
 	if (keyfile == NULL) {
-		error_msg("Missing --key argument");
-		goto out_usage;
+		status = -EINVAL;
+		goto out;
 	}
 	if (certfile == NULL)
 		certfile = keyfile;
@@ -603,33 +511,21 @@ 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 (!compute_file_measurement(filename, hash_alg, block_size,
 				      salt, salt_size, digest->digest))
 		goto out_err;
 
 	if (!sign_data(digest, sizeof(*digest) + hash_alg->digest_size,
-		       keyfile, certfile, hash_alg, &sig, &sig_size))
-		goto out_err;
-
-	if (!write_signature(argv[1], sig, sig_size))
+		       keyfile, certfile, hash_alg, 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);
+	*retdigest = digest;
 	status = 0;
 out:
-	free(salt);
-	free(digest);
-	free(sig);
 	return status;
 
 out_err:
 	status = 1;
 	goto out;
 
-out_usage:
-	usage(cmd, stderr);
-	status = 2;
-	goto out;
 }
diff --git a/commands.h b/commands.h
index 98f9745..c38fcea 100644
--- a/commands.h
+++ b/commands.h
@@ -5,17 +5,36 @@
 #include <stdio.h>
 
 #include "util.h"
+#include "hash_algs.h"
+#include "fsverity_uapi.h"
 
 struct fsverity_command;
 
+/*
+ * 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[];
+};
+
+
 void usage(const struct fsverity_command *cmd, FILE *fp);
 
 int fsverity_cmd_enable(const struct fsverity_command *cmd,
 			int argc, char *argv[]);
 int fsverity_cmd_measure(const struct fsverity_command *cmd,
 			 int argc, char *argv[]);
-int fsverity_cmd_sign(const struct fsverity_command *cmd,
-		      int argc, char *argv[]);
+int fsverity_cmd_sign(char *filename, const struct fsverity_hash_alg *hash_alg,
+		      u32 block_size, u8 *salt, u32 salt_size,
+		      const char *keyfile, const char *certfile,
+		      struct fsverity_signed_digest **retdigest,
+		      u8 **sig, u32 *sig_size);
 
 bool parse_block_size_option(const char *arg, u32 *size_ptr);
 u32 get_default_block_size(void);
diff --git a/fsverity.c b/fsverity.c
index 9a44df1..6246031 100644
--- a/fsverity.c
+++ b/fsverity.c
@@ -7,14 +7,141 @@
  * Written by Eric Biggers.
  */
 
+#include <fcntl.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
 
 #include "commands.h"
 #include "hash_algs.h"
 
+enum {
+	OPT_HASH_ALG,
+	OPT_BLOCK_SIZE,
+	OPT_SALT,
+	OPT_KEY,
+	OPT_CERT,
+};
+
+static const struct option longopts[] = {
+	{"hash-alg",	required_argument, NULL, OPT_HASH_ALG},
+	{"block-size",	required_argument, NULL, OPT_BLOCK_SIZE},
+	{"salt",	required_argument, NULL, OPT_SALT},
+	{"key",		required_argument, NULL, OPT_KEY},
+	{"cert",	required_argument, NULL, OPT_CERT},
+	{NULL, 0, NULL, 0}
+};
+
+static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
+{
+	struct filedes file;
+	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);
+	return ok;
+}
+
+int wrap_cmd_sign(const struct fsverity_command *cmd, int argc, char *argv[])
+{
+	struct fsverity_signed_digest *digest = NULL;
+	u8 *sig = NULL;
+	u32 sig_size;
+	const struct fsverity_hash_alg *hash_alg = NULL;
+	u32 block_size = 0;
+	u8 *salt = NULL;
+	u32 salt_size = 0;
+	const char *keyfile = NULL;
+	const char *certfile = NULL;
+	int c, status;
+	char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1];
+
+	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+		switch (c) {
+		case OPT_HASH_ALG:
+			if (hash_alg != NULL) {
+				error_msg("--hash-alg can only be specified once");
+				goto out_usage;
+			}
+			hash_alg = find_hash_alg_by_name(optarg);
+			if (hash_alg == NULL)
+				goto out_usage;
+			break;
+		case OPT_BLOCK_SIZE:
+			if (!parse_block_size_option(optarg, &block_size))
+				goto out_usage;
+			break;
+		case OPT_SALT:
+			if (!parse_salt_option(optarg, &salt, &salt_size))
+				goto out_usage;
+			break;
+		case OPT_KEY:
+			if (keyfile != NULL) {
+				error_msg("--key can only be specified once");
+				goto out_usage;
+			}
+			keyfile = optarg;
+			break;
+		case OPT_CERT:
+			if (certfile != NULL) {
+				error_msg("--cert can only be specified once");
+				goto out_usage;
+			}
+			certfile = optarg;
+			break;
+		default:
+			goto out_usage;
+		}
+	}
+
+	if (keyfile == NULL) {
+		status = -EINVAL;
+		error_msg("Missing --key argument");
+		goto out_usage;
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	if (hash_alg == NULL)
+		hash_alg = &fsverity_hash_algs[FS_VERITY_HASH_ALG_DEFAULT];
+
+	if (argc != 2)
+		goto out_usage;
+
+	status = fsverity_cmd_sign(argv[0], hash_alg, block_size, salt, salt_size,
+				   keyfile, certfile, &digest, &sig, &sig_size);
+	if (status == -EINVAL)
+		goto out_usage;
+	if (status != 0)
+		goto out;
+
+	if (!write_signature(argv[1], sig, sig_size)) {
+		status = -EIO;
+		goto out;
+	}
+
+	bin2hex(digest->digest, hash_alg->digest_size, digest_hex);
+	printf("Signed file '%s' (%s:%s)\n", argv[0], hash_alg->name,
+	       digest_hex);
+
+ out:
+	free(salt);
+	free(digest);
+	free(sig);
+	return status;
+
+ out_usage:
+	usage(cmd, stderr);
+	status = 2;
+	goto out;
+}
+
 static const struct fsverity_command {
 	const char *name;
 	int (*func)(const struct fsverity_command *cmd, int argc, char *argv[]);
@@ -38,7 +165,7 @@ static const struct fsverity_command {
 "    fsverity measure FILE...\n"
 	}, {
 		.name = "sign",
-		.func = fsverity_cmd_sign,
+		.func = wrap_cmd_sign,
 		.short_desc = "Sign a file for fs-verity",
 		.usage_str =
 "    fsverity sign FILE OUT_SIGFILE --key=KEYFILE\n"
-- 
2.24.1


  parent reply	other threads:[~2020-02-11  0:00 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-11  0:00 [PATCH 0/7] Split fsverity-utils into a shared library Jes Sorensen
2020-02-11  0:00 ` [PATCH 1/7] Build basic " Jes Sorensen
2020-02-11  0:00 ` Jes Sorensen [this message]
2020-02-11  0:00 ` [PATCH 3/7] Make fsverity_cmd_measure() a library function Jes Sorensen
2020-02-11  0:00 ` [PATCH 4/7] Make fsverity_cmd_enable a library call() Jes Sorensen
2020-02-11  0:00 ` [PATCH 5/7] Rename commands.h to fsverity.h Jes Sorensen
2020-02-11  0:00 ` [PATCH 6/7] Move cmdline helper functions to fsverity.c Jes Sorensen
2020-02-11  0:00 ` [PATCH 7/7] cmd_sign: fsverity_cmd_sign() into two functions Jes Sorensen
2020-02-11 19:22 ` [PATCH 0/7] Split fsverity-utils into a shared library Eric Biggers
2020-02-11 22:09   ` Jes Sorensen
2020-02-11 23:14     ` Eric Biggers
2020-02-11 23:35       ` Jes Sorensen
2020-02-14 20:35         ` Eric Biggers
2020-02-19 23:49           ` Jes Sorensen
2020-07-30 17:52             ` Eric Biggers
2020-07-31 17:40               ` Jes Sorensen
2020-07-31 17:47                 ` Chris Mason
2020-07-31 19:14                   ` Eric Biggers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200211000037.189180-3-Jes.Sorensen@gmail.com \
    --to=jes.sorensen@gmail.com \
    --cc=jsorensen@fb.com \
    --cc=kernel-team@fb.com \
    --cc=linux-fscrypt@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.