diff options
author | Colin Cross <ccross@android.com> | 2022-01-05 18:29:22 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-01-05 18:29:22 +0000 |
commit | 2fc32129e94a96eac3511406796cc37d078d696f (patch) | |
tree | 200c870b269156ade8fbd2924548ddda83f21a07 | |
parent | c829e950b7fdb0bb77c75ebc3d52151ea22ab239 (diff) | |
parent | 456606b97ff7db5059d240faeccc5b261a4f6d2a (diff) | |
download | fsverity-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-- | METADATA | 6 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | include/libfsverity.h | 44 | ||||
-rw-r--r-- | lib/lib_private.h | 5 | ||||
-rw-r--r-- | lib/sign_digest.c | 96 | ||||
-rw-r--r-- | lib/utils.c | 34 | ||||
-rw-r--r-- | man/fsverity.1.md | 28 | ||||
-rw-r--r-- | programs/cmd_sign.c | 48 | ||||
-rw-r--r-- | programs/fsverity.c | 5 | ||||
-rw-r--r-- | programs/fsverity.h | 3 | ||||
-rwxr-xr-x | scripts/run-tests.sh | 9 |
11 files changed, 211 insertions, 75 deletions
@@ -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 } } @@ -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 |