Linux-FSCrypt Archive on lore.kernel.org
 help / color / 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
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 index

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

Linux-FSCrypt Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-fscrypt/0 linux-fscrypt/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-fscrypt linux-fscrypt/ https://lore.kernel.org/linux-fscrypt \
		linux-fscrypt@vger.kernel.org
	public-inbox-index linux-fscrypt

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-fscrypt


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git