@@ -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;
}
@@ -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);
@@ -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"