aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2022-01-05 18:29:22 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-01-05 18:29:22 +0000
commit2fc32129e94a96eac3511406796cc37d078d696f (patch)
tree200c870b269156ade8fbd2924548ddda83f21a07
parentc829e950b7fdb0bb77c75ebc3d52151ea22ab239 (diff)
parent456606b97ff7db5059d240faeccc5b261a4f6d2a (diff)
downloadfsverity-utils-2fc32129e94a96eac3511406796cc37d078d696f.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' am: b820c71271 am: 456606b97f
Original change: https://android-review.googlesource.com/c/platform/external/fsverity-utils/+/1927574 Change-Id: I2bcc38d0ee9c5c395c327a24d4a54fc225f4a31d
-rw-r--r--METADATA6
-rw-r--r--Makefile8
-rw-r--r--include/libfsverity.h44
-rw-r--r--lib/lib_private.h5
-rw-r--r--lib/sign_digest.c96
-rw-r--r--lib/utils.c34
-rw-r--r--man/fsverity.1.md28
-rw-r--r--programs/cmd_sign.c48
-rw-r--r--programs/fsverity.c5
-rw-r--r--programs/fsverity.h3
-rwxr-xr-xscripts/run-tests.sh9
11 files changed, 211 insertions, 75 deletions
diff --git a/METADATA b/METADATA
index c6dc55d..52ec89e 100644
--- a/METADATA
+++ b/METADATA
@@ -5,12 +5,12 @@ third_party {
type: GIT
value: "https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git"
}
- version: "v1.4"
+ version: "4258209301d54512956d536149b0eef0c695cfe6"
# would be NOTICE save for common/fsverity_uapi.h
license_type: RESTRICTED
last_upgrade_date {
year: 2021
- month: 6
- day: 15
+ month: 12
+ day: 20
}
}
diff --git a/Makefile b/Makefile
index c97790e..81b7b6d 100644
--- a/Makefile
+++ b/Makefile
@@ -44,8 +44,13 @@ ifneq ($(findstring -mingw,$(shell $(CC) -dumpmachine 2>/dev/null)),)
MINGW = 1
endif
+# Set the CFLAGS. First give the warning-related flags (unconditionally, though
+# the user can override any of them by specifying the opposite flag); then give
+# the user-specifed CFLAGS, defaulting to -O2 if none were specified.
+#
+# Use -Wno-deprecated-declarations to avoid warnings about the Engine API having
+# been deprecated in OpenSSL 3.0; the replacement isn't ready yet.
CFLAGS ?= -O2
-
override CFLAGS := -Wall -Wundef \
$(call cc-option,-Wdeclaration-after-statement) \
$(call cc-option,-Wimplicit-fallthrough) \
@@ -54,6 +59,7 @@ override CFLAGS := -Wall -Wundef \
$(call cc-option,-Wstrict-prototypes) \
$(call cc-option,-Wunused-parameter) \
$(call cc-option,-Wvla) \
+ $(call cc-option,-Wno-deprecated-declarations) \
$(CFLAGS)
override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(CPPFLAGS)
diff --git a/include/libfsverity.h b/include/libfsverity.h
index 6cefa2b..fe89371 100644
--- a/include/libfsverity.h
+++ b/include/libfsverity.h
@@ -81,11 +81,44 @@ struct libfsverity_digest {
uint8_t digest[]; /* the actual digest */
};
+/**
+ * struct libfsverity_signature_params - certificate and private key information
+ *
+ * Zero this, then set @certfile. Then, to specify the private key by key file,
+ * set @keyfile. Alternatively, to specify the private key by PKCS#11 token,
+ * set @pkcs11_engine, @pkcs11_module, and optionally @pkcs11_keyid.
+ *
+ * Support for PKCS#11 tokens is unavailable when libfsverity was linked to
+ * BoringSSL rather than OpenSSL.
+ */
struct libfsverity_signature_params {
- const char *keyfile; /* path to key file (PEM format) */
- const char *certfile; /* path to certificate (PEM format) */
- uint64_t reserved1[8]; /* must be 0 */
- uintptr_t reserved2[8]; /* must be 0 */
+
+ /** @keyfile: the path to the key file in PEM format, when applicable */
+ const char *keyfile;
+
+ /** @certfile: the path to the certificate file in PEM format */
+ const char *certfile;
+
+ /** @reserved1: must be 0 */
+ uint64_t reserved1[8];
+
+ /**
+ * @pkcs11_engine: the path to the PKCS#11 engine .so file, when
+ * applicable
+ */
+ const char *pkcs11_engine;
+
+ /**
+ * @pkcs11_module: the path to the PKCS#11 module .so file, when
+ * applicable
+ */
+ const char *pkcs11_module;
+
+ /** @pkcs11_keyid: the PKCS#11 key identifier, when applicable */
+ const char *pkcs11_keyid;
+
+ /** @reserved2: must be 0 */
+ uintptr_t reserved2[5];
};
struct libfsverity_metadata_callbacks {
@@ -161,8 +194,7 @@ libfsverity_compute_digest(void *fd, libfsverity_read_fn_t read_fn,
* Documentation/filesystems/fsverity.rst in the kernel source tree for
* further details.
* @digest: pointer to previously computed digest
- * @sig_params: struct libfsverity_signature_params providing filenames of
- * the keyfile and certificate file. Reserved fields must be zero.
+ * @sig_params: pointer to the certificate and private key information
* @sig_ret: Pointer to pointer for signed digest
* @sig_size_ret: Pointer to size of signed return digest
*
diff --git a/lib/lib_private.h b/lib/lib_private.h
index 7768eea..8532636 100644
--- a/lib/lib_private.h
+++ b/lib/lib_private.h
@@ -58,14 +58,11 @@ void *libfsverity_zalloc(size_t size);
void *libfsverity_memdup(const void *mem, size_t size);
__cold void
-libfsverity_do_error_msg(const char *format, va_list va, int err);
+libfsverity_do_error_msg(const char *format, va_list va);
__printf(1, 2) __cold void
libfsverity_error_msg(const char *format, ...);
-__printf(1, 2) __cold void
-libfsverity_error_msg_errno(const char *format, ...);
-
__cold void
libfsverity_warn_on(const char *condition, const char *file, int line);
diff --git a/lib/sign_digest.c b/lib/sign_digest.c
index 9a35256..d726772 100644
--- a/lib/sign_digest.c
+++ b/lib/sign_digest.c
@@ -19,6 +19,10 @@
#include <openssl/pkcs7.h>
#include <string.h>
+#ifndef OPENSSL_IS_BORINGSSL
+#include <openssl/engine.h>
+#endif
+
static int print_openssl_err_cb(const char *str,
size_t len __attribute__((unused)),
void *u __attribute__((unused)))
@@ -34,7 +38,7 @@ error_msg_openssl(const char *format, ...)
va_list va;
va_start(va, format);
- libfsverity_do_error_msg(format, va, 0);
+ libfsverity_do_error_msg(format, va);
va_end(va);
if (ERR_peek_error() == 0)
@@ -81,6 +85,11 @@ static int read_certificate(const char *certfile, X509 **cert_ret)
X509 *cert;
int err;
+ if (!certfile) {
+ libfsverity_error_msg("no certificate specified");
+ return -EINVAL;
+ }
+
errno = 0;
bio = BIO_new_file(certfile, "r");
if (!bio) {
@@ -212,6 +221,15 @@ out:
return err;
}
+static int
+load_pkcs11_private_key(const struct libfsverity_signature_params *sig_params
+ __attribute__((unused)),
+ EVP_PKEY **pkey_ret __attribute__((unused)))
+{
+ libfsverity_error_msg("BoringSSL doesn't support PKCS#11 tokens");
+ return -EINVAL;
+}
+
#else /* OPENSSL_IS_BORINGSSL */
static BIO *new_mem_buf(const void *buf, size_t size)
@@ -315,16 +333,79 @@ out:
return err;
}
+static int
+load_pkcs11_private_key(const struct libfsverity_signature_params *sig_params,
+ EVP_PKEY **pkey_ret)
+{
+ ENGINE *engine;
+
+ if (!sig_params->pkcs11_engine) {
+ libfsverity_error_msg("no PKCS#11 engine specified");
+ return -EINVAL;
+ }
+ if (!sig_params->pkcs11_module) {
+ libfsverity_error_msg("no PKCS#11 module specified");
+ return -EINVAL;
+ }
+ ENGINE_load_dynamic();
+ engine = ENGINE_by_id("dynamic");
+ if (!engine) {
+ error_msg_openssl("failed to initialize OpenSSL PKCS#11 engine");
+ return -EINVAL;
+ }
+ if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH",
+ sig_params->pkcs11_engine, 0) ||
+ !ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) ||
+ !ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) ||
+ !ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0) ||
+ !ENGINE_ctrl_cmd_string(engine, "MODULE_PATH",
+ sig_params->pkcs11_module, 0) ||
+ !ENGINE_init(engine)) {
+ error_msg_openssl("failed to initialize OpenSSL PKCS#11 engine");
+ ENGINE_free(engine);
+ return -EINVAL;
+ }
+ *pkey_ret = ENGINE_load_private_key(engine, sig_params->pkcs11_keyid,
+ NULL, NULL);
+ ENGINE_finish(engine);
+ ENGINE_free(engine);
+ if (!*pkey_ret) {
+ error_msg_openssl("failed to load private key from PKCS#11 token");
+ return -EINVAL;
+ }
+ return 0;
+}
+
#endif /* !OPENSSL_IS_BORINGSSL */
+/* Get a private key, either from disk or from a PKCS#11 token. */
+static int
+get_private_key(const struct libfsverity_signature_params *sig_params,
+ EVP_PKEY **pkey_ret)
+{
+ if (sig_params->pkcs11_engine || sig_params->pkcs11_module ||
+ sig_params->pkcs11_keyid) {
+ if (sig_params->keyfile) {
+ libfsverity_error_msg("private key must be specified either by file or by PKCS#11 token, not both");
+ return -EINVAL;
+ }
+ return load_pkcs11_private_key(sig_params, pkey_ret);
+ }
+ if (!sig_params->keyfile) {
+ libfsverity_error_msg("no private key specified");
+ return -EINVAL;
+ }
+ return read_private_key(sig_params->keyfile, pkey_ret);
+}
+
LIBEXPORT int
libfsverity_sign_digest(const struct libfsverity_digest *digest,
const struct libfsverity_signature_params *sig_params,
u8 **sig_ret, size_t *sig_size_ret)
{
const struct fsverity_hash_alg *hash_alg;
- EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
+ EVP_PKEY *pkey = NULL;
const EVP_MD *md;
struct fsverity_formatted_digest *d = NULL;
int err;
@@ -334,11 +415,6 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
return -EINVAL;
}
- if (!sig_params->keyfile || !sig_params->certfile) {
- libfsverity_error_msg("keyfile and certfile must be specified");
- return -EINVAL;
- }
-
if (!libfsverity_mem_is_zeroed(sig_params->reserved1,
sizeof(sig_params->reserved1)) ||
!libfsverity_mem_is_zeroed(sig_params->reserved2,
@@ -353,11 +429,11 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
return -EINVAL;
}
- err = read_private_key(sig_params->keyfile, &pkey);
+ err = read_certificate(sig_params->certfile, &cert);
if (err)
goto out;
- err = read_certificate(sig_params->certfile, &cert);
+ err = get_private_key(sig_params, &pkey);
if (err)
goto out;
@@ -383,8 +459,8 @@ libfsverity_sign_digest(const struct libfsverity_digest *digest,
err = sign_pkcs7(d, sizeof(*d) + digest->digest_size,
pkey, cert, md, sig_ret, sig_size_ret);
out:
- EVP_PKEY_free(pkey);
X509_free(cert);
+ EVP_PKEY_free(pkey);
free(d);
return err;
}
diff --git a/lib/utils.c b/lib/utils.c
index 036dd60..d506ef1 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -51,16 +51,7 @@ libfsverity_set_error_callback(void (*cb)(const char *msg))
libfsverity_error_cb = cb;
}
-#ifdef _WIN32
-static char *strerror_r(int errnum, char *buf, size_t buflen)
-{
- strerror_s(buf, buflen, errnum);
-
- return buf;
-}
-#endif
-
-void libfsverity_do_error_msg(const char *format, va_list va, int err)
+void libfsverity_do_error_msg(const char *format, va_list va)
{
int saved_errno = errno;
char *msg = NULL;
@@ -71,18 +62,8 @@ void libfsverity_do_error_msg(const char *format, va_list va, int err)
if (vasprintf(&msg, format, va) < 0)
goto out;
- if (err) {
- char *msg2 = NULL;
- char errbuf[64];
-
- if (asprintf(&msg2, "%s: %s", msg,
- strerror_r(err, errbuf, sizeof(errbuf))) < 0)
- goto out2;
- free(msg);
- msg = msg2;
- }
(*libfsverity_error_cb)(msg);
-out2:
+
free(msg);
out:
errno = saved_errno;
@@ -93,16 +74,7 @@ void libfsverity_error_msg(const char *format, ...)
va_list va;
va_start(va, format);
- libfsverity_do_error_msg(format, va, 0);
- va_end(va);
-}
-
-void libfsverity_error_msg_errno(const char *format, ...)
-{
- va_list va;
-
- va_start(va, format);
- libfsverity_do_error_msg(format, va, errno);
+ libfsverity_do_error_msg(format, va);
va_end(va);
}
diff --git a/man/fsverity.1.md b/man/fsverity.1.md
index e1007f5..a983912 100644
--- a/man/fsverity.1.md
+++ b/man/fsverity.1.md
@@ -11,7 +11,7 @@ fsverity - userspace utility for fs-verity
**fsverity dump_metadata** [*OPTION*...] *TYPE* *FILE* \
**fsverity enable** [*OPTION*...] *FILE* \
**fsverity measure** *FILE*... \
-**fsverity sign \-\-key**=*KEYFILE* [*OPTION*...] *FILE* *OUT_SIGFILE*
+**fsverity sign** [*OPTION*...] *FILE* *OUT_SIGFILE*
# DESCRIPTION
@@ -149,12 +149,18 @@ for each file regardless of the size of the file.
**fsverity measure** does not accept any options.
-## **fsverity sign** **\-\-key**=*KEYFILE* [*OPTION*...] *FILE* *OUT_SIGFILE*
+## **fsverity sign** [*OPTION*...] *FILE* *OUT_SIGFILE*
Sign the given file for fs-verity, in a way that is compatible with the Linux
kernel's fs-verity built-in signature verification support. The signature will
be written to *OUT_SIGFILE* in PKCS#7 DER format.
+The private key can be specified either by key file or by PKCS#11 token. To use
+a key file, provide **\-\-key** and optionally **\-\-cert**. To use a PKCS#11
+token, provide **\-\-pkcs11-engine**, **\-\-pkcs11-module**, **\-\-cert**, and
+optionally **\-\-pkcs11-keyid**. PKCS#11 token support is unavailable when
+fsverity-utils was built with BoringSSL rather than OpenSSL.
+
Options accepted by **fsverity sign**:
**\-\-block-size**=*BLOCK_SIZE*
@@ -163,14 +169,14 @@ Options accepted by **fsverity sign**:
**\-\-cert**=*CERTFILE*
: Specifies the file that contains the certificate, in PEM format. This
option is required if *KEYFILE* contains only the private key and not also
- the certificate.
+ the certificate, or if a PKCS#11 token is used.
**\-\-hash-alg**=*HASH_ALG*
: Same as for **fsverity digest**.
**\-\-key**=*KEYFILE*
: Specifies the file that contains the private key, in PEM format. This
- option is required.
+ option is required when not using a PKCS#11 token.
**\-\-out-descriptor**=*FILE*
: Same as for **fsverity digest**.
@@ -178,6 +184,20 @@ Options accepted by **fsverity sign**:
**\-\-out-merkle-tree**=*FILE*
: Same as for **fsverity digest**.
+**\-\-pkcs11-engine**=*SOFILE*
+: Specifies the path to the OpenSSL PKCS#11 engine file. This typically will
+ be a path to the libp11 .so file. This option is required when using a
+ PKCS#11 token.
+
+**\-\-pkcs11-keyid**=*KEYID*
+: Specifies the key identifier in the form of a PKCS#11 URI. If not provided,
+ the default key associated with the token is used. This option is only
+ applicable when using a PKCS#11 token.
+
+**\-\-pkcs11-module**=*SOFILE*
+: Specifies the path to the PKCS#11 token-specific module library. This
+ option is required when using a PKCS#11 token.
+
**\-\-salt**=*SALT*
: Same as for **fsverity digest**.
diff --git a/programs/cmd_sign.c b/programs/cmd_sign.c
index 81a4ddc..aab8f00 100644
--- a/programs/cmd_sign.c
+++ b/programs/cmd_sign.c
@@ -27,13 +27,16 @@ static bool write_signature(const char *filename, const u8 *sig, u32 sig_size)
}
static const struct option longopts[] = {
+ {"key", required_argument, NULL, OPT_KEY},
+ {"cert", required_argument, NULL, OPT_CERT},
+ {"pkcs11-engine", required_argument, NULL, OPT_PKCS11_ENGINE},
+ {"pkcs11-module", required_argument, NULL, OPT_PKCS11_MODULE},
+ {"pkcs11-keyid", required_argument, NULL, OPT_PKCS11_KEYID},
{"hash-alg", required_argument, NULL, OPT_HASH_ALG},
{"block-size", required_argument, NULL, OPT_BLOCK_SIZE},
{"salt", required_argument, NULL, OPT_SALT},
{"out-merkle-tree", required_argument, NULL, OPT_OUT_MERKLE_TREE},
{"out-descriptor", required_argument, NULL, OPT_OUT_DESCRIPTOR},
- {"key", required_argument, NULL, OPT_KEY},
- {"cert", required_argument, NULL, OPT_CERT},
{NULL, 0, NULL, 0}
};
@@ -53,14 +56,6 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
switch (c) {
- case OPT_HASH_ALG:
- case OPT_BLOCK_SIZE:
- case OPT_SALT:
- case OPT_OUT_MERKLE_TREE:
- case OPT_OUT_DESCRIPTOR:
- if (!parse_tree_param(c, optarg, &tree_params))
- goto out_usage;
- break;
case OPT_KEY:
if (sig_params.keyfile != NULL) {
error_msg("--key can only be specified once");
@@ -75,6 +70,35 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
}
sig_params.certfile = optarg;
break;
+ case OPT_PKCS11_ENGINE:
+ if (sig_params.pkcs11_engine != NULL) {
+ error_msg("--pkcs11-engine can only be specified once");
+ goto out_usage;
+ }
+ sig_params.pkcs11_engine = optarg;
+ break;
+ case OPT_PKCS11_MODULE:
+ if (sig_params.pkcs11_module != NULL) {
+ error_msg("--pkcs11-module can only be specified once");
+ goto out_usage;
+ }
+ sig_params.pkcs11_module = optarg;
+ break;
+ case OPT_PKCS11_KEYID:
+ if (sig_params.pkcs11_keyid != NULL) {
+ error_msg("--pkcs11-keyid can only be specified once");
+ goto out_usage;
+ }
+ sig_params.pkcs11_keyid = optarg;
+ break;
+ case OPT_HASH_ALG:
+ case OPT_BLOCK_SIZE:
+ case OPT_SALT:
+ case OPT_OUT_MERKLE_TREE:
+ case OPT_OUT_DESCRIPTOR:
+ if (!parse_tree_param(c, optarg, &tree_params))
+ goto out_usage;
+ break;
default:
goto out_usage;
}
@@ -86,10 +110,6 @@ int fsverity_cmd_sign(const struct fsverity_command *cmd,
if (argc != 2)
goto out_usage;
- if (sig_params.keyfile == NULL) {
- error_msg("Missing --key argument");
- goto out_usage;
- }
if (sig_params.certfile == NULL)
sig_params.certfile = sig_params.keyfile;
diff --git a/programs/fsverity.c b/programs/fsverity.c
index f6aff3a..813ea2a 100644
--- a/programs/fsverity.c
+++ b/programs/fsverity.c
@@ -58,10 +58,11 @@ static const struct fsverity_command {
.func = fsverity_cmd_sign,
.short_desc = "Sign a file for fs-verity",
.usage_str =
-" fsverity sign FILE OUT_SIGFILE --key=KEYFILE\n"
+" fsverity sign FILE OUT_SIGFILE\n"
+" [--key=KEYFILE] [--cert=CERTFILE] [--pkcs11-engine=SOFILE]\n"
+" [--pkcs11-module=SOFILE] [--pkcs11-keyid=KEYID]\n"
" [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
" [--out-merkle-tree=FILE] [--out-descriptor=FILE]\n"
-" [--cert=CERTFILE]\n"
}
};
diff --git a/programs/fsverity.h b/programs/fsverity.h
index fe24087..ad54cc2 100644
--- a/programs/fsverity.h
+++ b/programs/fsverity.h
@@ -31,6 +31,9 @@ enum {
OPT_OFFSET,
OPT_OUT_DESCRIPTOR,
OPT_OUT_MERKLE_TREE,
+ OPT_PKCS11_ENGINE,
+ OPT_PKCS11_KEYID,
+ OPT_PKCS11_MODULE,
OPT_SALT,
OPT_SIGNATURE,
};
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index 9cdc7c1..fb21c39 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -163,6 +163,15 @@ BSSL=$HOME/src/boringssl
$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L$BSSL/build/crypto" \
CPPFLAGS="-I$BSSL/include" LDLIBS="-lcrypto -lpthread" check
+log "Build and test using OpenSSL 1.0"
+$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L/usr/lib/openssl-1.0" \
+ CPPFLAGS="-I/usr/include/openssl-1.0" check
+
+log "Build and test using OpenSSL 3.0"
+OSSL3=$HOME/src/openssl/inst/usr/local
+LD_LIBRARY_PATH="$OSSL3/lib64" $MAKE CFLAGS="-O2 -Werror" \
+ LDFLAGS="-L$OSSL3/lib64" CPPFLAGS="-I$OSSL3/include" check
+
log "Build and test using -funsigned-char"
$MAKE CFLAGS="-O2 -Werror -funsigned-char" check