Merge pull request #31274 from bluca/measure_engine

repart/measure/ukify: add support for OpenSSL engines/providers
This commit is contained in:
Lennart Poettering 2024-03-01 23:41:25 +01:00 committed by GitHub
commit 5db99d6651
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 256 additions and 106 deletions

View file

@ -129,14 +129,6 @@ All tools:
* `$SYSTEMD_VERITY_SHARING=0` — if set, sharing dm-verity devices by
using a stable `<ROOTHASH>-verity` device mapper name will be disabled.
* `$SYSTEMD_OPENSSL_KEY_LOADER`— when using OpenSSL to load a key via an engine
or a provider, can be used to force the usage of one or the other interface.
Set to 'engine' to force the usage of the old engine API, and to 'provider'
force the usage of the new provider API. If unset, the provider will be tried
first and the engine as a fallback if that fails. Providers are the new OpenSSL
3 API, but there are very few if any in a production-ready state, so engines
are still needed.
`systemctl`:
* `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID 1's private D-Bus

View file

@ -158,6 +158,7 @@
<varlistentry>
<term><option>--private-key=<replaceable>PATH</replaceable></option></term>
<term><option>--public-key=<replaceable>PATH</replaceable></option></term>
<term><option>--certificate=<replaceable>PATH</replaceable></option></term>
<listitem><para>These switches take paths to a pair of PEM encoded RSA key files, for use with
the <command>sign</command> command.</para>
@ -172,9 +173,26 @@
<para>If the <option>--public-key=</option> is not specified but <option>--private-key=</option> is
specified the public key is automatically derived from the private key.</para>
<para><option>--certificate=</option> can be used to specify an X.509 certificate as an alternative
to <option>--public-key=</option> since v256.</para>
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--private-key=<replaceable>PATH/URI</replaceable></option></term>
<term><option>--private-key-source=<replaceable>TYPE[:NAME]</replaceable></option></term>
<term><option>--certificate=<replaceable>PATH</replaceable></option></term>
<listitem><para>As an alternative to <option>--public-key=</option> for the
<command>sign</command> command, these switches can be used to sign with an hardware token. The
private key option can take a path or a URI that will be passed to the OpenSSL engine or
provider, as specified by <option>--private-key-source=</option> as a type:name tuple, such as
engine:pkcs11. The specified OpenSSL signing engine or provider will be used to sign.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--tpm2-device=</option><replaceable>PATH</replaceable></term>

View file

@ -355,11 +355,13 @@
</varlistentry>
<varlistentry>
<term><option>--private-key-uri=</option></term>
<term><option>--private-key-source=</option></term>
<listitem><para>Takes a URI-like string referring to a private key, that will be passed to OpenSSL's
"engine" or "provider" logic. Configures the signing key to use when creating verity signature
partitions with the <varname>Verity=signature</varname> setting in partition files.</para>
<listitem><para>Takes one of <literal>file</literal>, <literal>engine</literal> or
<literal>provider</literal>. In the latter two cases, it is followed by the name of a provider or
engine, separated by colon, that will be passed to OpenSSL's "engine" or "provider" logic.
Configures the signing mechanism to use when creating verity signature partitions with the
<varname>Verity=signature</varname> setting in partition files.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
@ -662,7 +664,7 @@ VERSION_ID=38
IMAGE_ID=my-foo
IMAGE_VERSION=7
EOF
systemd-repart --make-ddi=sysext --private-key-uri="pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=0123456789abcdef;token=Some%20Cert" --certificate=cert.crt -s tree/ /var/lib/extensions/my-foo.sysext.raw
systemd-repart --make-ddi=sysext --private-key-source=engine:pkcs11 --private-key="pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=0123456789abcdef;token=Some%20Cert" --certificate=cert.crt -s tree/ /var/lib/extensions/my-foo.sysext.raw
systemd-sysext refresh</programlisting>
<para>The DDI generated that way may be applied to the system with

View file

@ -99,7 +99,10 @@
the n-th boot phase path set will be signed by the n-th key. This can be used to build different trust
policies for different phases of the boot. In the config file, <varname>PCRPrivateKey=</varname>,
<varname>PCRPublicKey=</varname>, and <varname>Phases=</varname> are grouped into separate sections,
describing separate boot phases.</para>
describing separate boot phases. If <varname>SigningEngine=</varname>/<option>--signing-engine=</option>
is specified, then the private keys arguments will be passed verbatim to OpenSSL as URIs, and the public
key arguments will be loaded as X.509 certificates, so that signing can be perfomed with an OpenSSL
engine.</para>
<para>If a SecureBoot signing key is provided via the
<varname>SecureBootPrivateKey=</varname>/<option>--secureboot-private-key=</option> option, the resulting

View file

@ -30,7 +30,10 @@ static char *arg_sections[_UNIFIED_SECTION_MAX] = {};
static char **arg_banks = NULL;
static char *arg_tpm2_device = NULL;
static char *arg_private_key = NULL;
static KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
static char *arg_private_key_source = NULL;
static char *arg_public_key = NULL;
static char *arg_certificate = NULL;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO|JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
static bool arg_current = false;
@ -40,7 +43,9 @@ static char *arg_append = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
STATIC_DESTRUCTOR_REGISTER(arg_public_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
STATIC_DESTRUCTOR_REGISTER(arg_phase, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_append, freep);
@ -74,7 +79,11 @@ static int help(int argc, char *argv[], void *userdata) {
" --bank=DIGEST Select TPM bank (SHA1, SHA256, SHA384, SHA512)\n"
" --tpm2-device=PATH Use specified TPM2 device\n"
" --private-key=KEY Private key (PEM) to sign with\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use the --private-key=. Allows to use\n"
" an OpenSSL engine/provider when signing\n"
" --public-key=KEY Public key (PEM) to validate against\n"
" --certificate=PATH PEM certificate to use when signing with a URI\n"
" --json=MODE Output as JSON\n"
" -j Same as --json=pretty on tty, --json=short otherwise\n"
" --append=PATH Load specified JSON signature, and append new signature to it\n"
@ -133,7 +142,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PCRPKEY = _ARG_SECTION_LAST,
ARG_BANK,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
ARG_PUBLIC_KEY,
ARG_CERTIFICATE,
ARG_TPM2_DEVICE,
ARG_JSON,
ARG_PHASE,
@ -141,26 +152,28 @@ static int parse_argv(int argc, char *argv[]) {
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "version", no_argument, NULL, ARG_VERSION },
{ "linux", required_argument, NULL, ARG_LINUX },
{ "osrel", required_argument, NULL, ARG_OSREL },
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
{ "initrd", required_argument, NULL, ARG_INITRD },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "uname", required_argument, NULL, ARG_UNAME },
{ "sbat", required_argument, NULL, ARG_SBAT },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "public-key", required_argument, NULL, ARG_PUBLIC_KEY },
{ "json", required_argument, NULL, ARG_JSON },
{ "phase", required_argument, NULL, ARG_PHASE },
{ "append", required_argument, NULL, ARG_APPEND },
{ "help", no_argument, NULL, 'h' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "version", no_argument, NULL, ARG_VERSION },
{ "linux", required_argument, NULL, ARG_LINUX },
{ "osrel", required_argument, NULL, ARG_OSREL },
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
{ "initrd", required_argument, NULL, ARG_INITRD },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "uname", required_argument, NULL, ARG_UNAME },
{ "sbat", required_argument, NULL, ARG_SBAT },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{ "public-key", required_argument, NULL, ARG_PUBLIC_KEY },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "json", required_argument, NULL, ARG_JSON },
{ "phase", required_argument, NULL, ARG_PHASE },
{ "append", required_argument, NULL, ARG_APPEND },
{}
};
@ -213,7 +226,17 @@ static int parse_argv(int argc, char *argv[]) {
}
case ARG_PRIVATE_KEY:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_private_key);
r = free_and_strdup_warn(&arg_private_key, optarg);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
optarg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
return r;
@ -226,6 +249,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CERTIFICATE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_certificate);
if (r < 0)
return r;
break;
case ARG_TPM2_DEVICE: {
_cleanup_free_ char *device = NULL;
@ -281,6 +311,12 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached();
}
if (arg_public_key && arg_certificate)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Both --public-key= and --certificate= specified, refusing.");
if (arg_private_key_source && !arg_certificate)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "When using --private-key-source=, --certificate= must be specified.");
if (strv_isempty(arg_banks)) {
/* If no banks are specifically selected, pick all known banks */
arg_banks = strv_new("SHA1", "SHA256", "SHA384", "SHA512");
@ -731,7 +767,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL;
_cleanup_fclose_ FILE *privkeyf = NULL;
_cleanup_(X509_freep) X509 *certificate = NULL;
size_t n;
int r;
@ -759,13 +795,57 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
/* When signing we only support JSON output */
arg_json_format_flags &= ~JSON_FORMAT_OFF;
privkeyf = fopen(arg_private_key, "re");
if (!privkeyf)
return log_error_errno(errno, "Failed to open private key file '%s': %m", arg_private_key);
/* This must be done before openssl_load_key_from_token() otherwise it will get stuck */
if (arg_certificate) {
_cleanup_(BIO_freep) BIO *cb = NULL;
_cleanup_free_ char *crt = NULL;
privkey = PEM_read_PrivateKey(privkeyf, NULL, NULL, NULL);
if (!privkey)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse private key '%s'.", arg_private_key);
r = read_full_file_full(
AT_FDCWD, arg_certificate, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
/* bind_name= */ NULL,
&crt, &n);
if (r < 0)
return log_error_errno(r, "Failed to read certificate file '%s': %m", arg_certificate);
cb = BIO_new_mem_buf(crt, n);
if (!cb)
return log_oom();
certificate = PEM_read_bio_X509(cb, NULL, NULL, NULL);
if (!certificate)
return log_error_errno(
SYNTHETIC_ERRNO(EBADMSG),
"Failed to parse X.509 certificate: %s",
ERR_error_string(ERR_get_error(), NULL));
}
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
_cleanup_fclose_ FILE *privkeyf = NULL;
_cleanup_free_ char *resolved_pkey = NULL;
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &resolved_pkey);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
privkeyf = fopen(resolved_pkey, "re");
if (!privkeyf)
return log_error_errno(errno, "Failed to open private key file '%s': %m", resolved_pkey);
privkey = PEM_read_PrivateKey(privkeyf, NULL, NULL, NULL);
if (!privkey)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse private key '%s'.", resolved_pkey);
} else if (arg_private_key_source &&
IN_SET(arg_private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER)) {
r = openssl_load_key_from_token(
arg_private_key_source_type, arg_private_key_source, arg_private_key, &privkey);
if (r < 0)
return log_error_errno(
r,
"Failed to load key '%s' from OpenSSL key source %s: %m",
arg_private_key,
arg_private_key_source);
}
if (arg_public_key) {
_cleanup_fclose_ FILE *pubkeyf = NULL;
@ -777,6 +857,13 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
pubkey = PEM_read_PUBKEY(pubkeyf, NULL, NULL, NULL);
if (!pubkey)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse public key '%s'.", arg_public_key);
} else if (certificate) {
pubkey = X509_get_pubkey(certificate);
if (!pubkey)
return log_error_errno(
SYNTHETIC_ERRNO(EIO),
"Failed to extract public key from certificate %s.",
arg_certificate);
} else {
_cleanup_(memstream_done) MemStream m = {};
FILE *tf;

View file

@ -146,6 +146,8 @@ static bool arg_legend = true;
static void *arg_key = NULL;
static size_t arg_key_size = 0;
static EVP_PKEY *arg_private_key = NULL;
static KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
static char *arg_private_key_source = NULL;
static X509 *arg_certificate = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_seal_key_handle = 0;
@ -177,6 +179,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep);
@ -6806,8 +6809,14 @@ static int help(void) {
" Specify disk image dissection policy\n"
" --definitions=DIR Find partition definitions in specified directory\n"
" --key-file=PATH Key to use when encrypting partitions\n"
" --private-key=PATH Private key to use when generating verity roothash\n"
" signatures\n"
" --private-key=PATH|URI\n"
" Private key to use when generating verity roothash\n"
" signatures, or an engine or provider specific\n"
" designation if --private-key-source= is used.\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use the --private-key=. Allows to use\n"
" an OpenSSL engine/provider when generating verity\n"
" roothash signatures\n"
" --certificate=PATH PEM certificate to use when generating verity\n"
" roothash signatures\n"
" --tpm2-device=PATH Path to TPM2 device node to use\n"
@ -6857,7 +6866,7 @@ static int help(void) {
}
static int parse_argv(int argc, char *argv[]) {
_cleanup_free_ char *private_key = NULL, *private_key_uri = NULL;
_cleanup_free_ char *private_key = NULL;
enum {
ARG_VERSION = 0x100,
@ -6878,7 +6887,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_JSON,
ARG_KEY_FILE,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_URI,
ARG_PRIVATE_KEY_SOURCE,
ARG_CERTIFICATE,
ARG_TPM2_DEVICE,
ARG_TPM2_DEVICE_KEY,
@ -6921,7 +6930,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "json", required_argument, NULL, ARG_JSON },
{ "key-file", required_argument, NULL, ARG_KEY_FILE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-uri", required_argument, NULL, ARG_PRIVATE_KEY_URI },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-device-key", required_argument, NULL, ARG_TPM2_DEVICE_KEY },
@ -7115,12 +7124,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_PRIVATE_KEY_URI: {
r = free_and_strdup_warn(&private_key_uri, optarg);
case ARG_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
optarg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
return r;
break;
}
case ARG_CERTIFICATE: {
_cleanup_free_ char *cert = NULL;
@ -7465,12 +7476,7 @@ static int parse_argv(int argc, char *argv[]) {
*p = gpt_partition_type_override_architecture(*p, arg_architecture);
}
if (private_key && private_key_uri)
return log_error_errno(
SYNTHETIC_ERRNO(EINVAL),
"Cannot specify both --private-key= and --private-key-uri=.");
if (private_key) {
if (private_key && arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
_cleanup_(erase_and_freep) char *k = NULL;
size_t n = 0;
@ -7485,16 +7491,22 @@ static int parse_argv(int argc, char *argv[]) {
r = parse_private_key(k, n, &arg_private_key);
if (r < 0)
return r;
} else if (private_key_uri) {
} else if (private_key &&
IN_SET(arg_private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER)) {
/* This must happen after parse_x509_certificate() is called above, otherwise
* signing later will get stuck as the parsed private key won't have the
* certificate, so this block cannot be inline in ARG_PRIVATE_KEY. */
r = openssl_load_key_from_token(private_key_uri, &arg_private_key);
r = openssl_load_key_from_token(
arg_private_key_source_type,
arg_private_key_source,
private_key,
&arg_private_key);
if (r < 0)
return log_error_errno(
r,
"Failed to load key '%s' from OpenSSL provider: %m",
private_key);
"Failed to load key '%s' from OpenSSL private key source %s: %m",
private_key,
arg_private_key_source);
}
return 1;

View file

@ -1366,38 +1366,25 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
return 0;
}
int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret) {
_cleanup_free_ char *provider = NULL;
const char *colon, *e;
int r;
int openssl_load_key_from_token(
KeySourceType private_key_source_type,
const char *private_key_source,
const char *private_key,
EVP_PKEY **ret) {
assert(private_key_uri);
assert(IN_SET(private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER));
assert(private_key_source);
assert(private_key);
colon = strchr(private_key_uri, ':');
if (!colon)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid URI '%s'", private_key_uri);
switch (private_key_source_type) {
provider = strndup(private_key_uri, colon - private_key_uri);
if (!provider)
return log_oom_debug();
e = secure_getenv("SYSTEMD_OPENSSL_KEY_LOADER");
if (e) {
if (streq(e, "provider"))
r = load_key_from_provider(provider, private_key_uri, ret);
else if (streq(e, "engine"))
r = load_key_from_engine(provider, private_key_uri, ret);
else
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid value for SYSTEMD_OPENSSL_KEY_LOADER: %s", e);
} else {
r = load_key_from_provider(provider, private_key_uri, ret);
if (r < 0) {
log_debug_errno(r, "Failed to load key from provider '%s', falling back to engine", provider);
r = load_key_from_engine(provider, private_key_uri, ret);
}
case OPENSSL_KEY_SOURCE_ENGINE:
return load_key_from_engine(private_key_source, private_key, ret);
case OPENSSL_KEY_SOURCE_PROVIDER:
return load_key_from_provider(private_key_source, private_key, ret);
default:
assert_not_reached();
}
return r;
}
#endif
@ -1418,3 +1405,34 @@ int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate X509 fingerprint: %m");
#endif
}
int parse_openssl_key_source_argument(
const char *argument,
char **private_key_source,
KeySourceType *private_key_source_type) {
KeySourceType type;
const char *e = NULL;
int r;
assert(argument);
assert(private_key_source);
assert(private_key_source_type);
if (streq(argument, "file"))
type = OPENSSL_KEY_SOURCE_FILE;
else if ((e = startswith(argument, "engine:")))
type = OPENSSL_KEY_SOURCE_ENGINE;
else if ((e = startswith(argument, "provider:")))
type = OPENSSL_KEY_SOURCE_PROVIDER;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid private key source '%s'", argument);
r = free_and_strdup_warn(private_key_source, e);
if (r < 0)
return r;
*private_key_source_type = type;
return 0;
}

View file

@ -5,6 +5,16 @@
#include "macro.h"
#include "sha256.h"
typedef enum KeySourceType {
OPENSSL_KEY_SOURCE_FILE,
OPENSSL_KEY_SOURCE_ENGINE,
OPENSSL_KEY_SOURCE_PROVIDER,
_OPENSSL_KEY_SOURCE_MAX,
_OPENSSL_KEY_SOURCE_INVALID = -EINVAL,
} KeySourceType;
int parse_openssl_key_source_argument(const char *argument, char **private_key_source, KeySourceType *private_key_source_type);
#define X509_FINGERPRINT_SIZE SHA256_DIGEST_SIZE
#if HAVE_OPENSSL
@ -123,7 +133,7 @@ int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_s
int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_t size, void **ret, size_t *ret_size);
int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret);
int openssl_load_key_from_token(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, EVP_PKEY **ret);
#else
@ -140,7 +150,12 @@ static inline void *EVP_PKEY_free(EVP_PKEY *p) {
return NULL;
}
static inline int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret) {
static inline int openssl_load_key_from_token(
KeySourceType private_key_source_type,
const char *private_key_source,
const char *private_key,
EVP_PKEY **ret) {
return -EOPNOTSUPP;
}

View file

@ -120,7 +120,7 @@ def test_apply_config(tmp_path):
assert ns.sign_kernel is False
assert ns._groups == ['NAME']
assert ns.pcr_private_keys == [pathlib.Path('some/path7')]
assert ns.pcr_private_keys == ['some/path7']
assert ns.pcr_public_keys == [pathlib.Path('some/path8')]
assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']]
@ -143,7 +143,7 @@ def test_apply_config(tmp_path):
assert ns.sign_kernel is False
assert ns._groups == ['NAME']
assert ns.pcr_private_keys == [pathlib.Path('some/path7')]
assert ns.pcr_private_keys == ['some/path7']
assert ns.pcr_public_keys == [pathlib.Path('some/path8')]
assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']]
@ -189,7 +189,7 @@ def test_parse_args_many_deprecated():
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
assert opts.pcr_private_keys == [pathlib.Path('PKEY1')]
assert opts.pcr_private_keys == ['PKEY1']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2')]
assert opts.pcr_banks == ['SHA1', 'SHA256']
assert opts.signing_engine == 'ENGINE'
@ -235,7 +235,7 @@ def test_parse_args_many():
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
assert opts.pcr_private_keys == [pathlib.Path('PKEY1')]
assert opts.pcr_private_keys == ['PKEY1']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2')]
assert opts.pcr_banks == ['SHA1', 'SHA256']
assert opts.signing_engine == 'ENGINE'
@ -342,8 +342,7 @@ def test_config_priority(tmp_path):
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
assert opts.pcr_private_keys == [pathlib.Path('PKEY1'),
pathlib.Path('some/path7')]
assert opts.pcr_private_keys == ['PKEY1', 'some/path7']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2'),
pathlib.Path('some/path8')]
assert opts.pcr_banks == ['SHA1', 'SHA256']

View file

@ -449,7 +449,7 @@ def check_cert_and_keys_nonexistent(opts):
*((priv_key, pub_key)
for priv_key, pub_key, _ in key_path_groups(opts)))
for path in paths:
if path and path.exists():
if path and pathlib.Path(path).exists():
raise ValueError(f'{path} is present')
@ -539,7 +539,11 @@ def call_systemd_measure(uki, linux, opts):
for priv_key, pub_key, group in key_path_groups(opts):
extra = [f'--private-key={priv_key}']
if pub_key:
if opts.signing_engine is not None:
assert pub_key
extra += [f'--private-key-source=engine:{opts.signing_engine}']
extra += [f'--certificate={pub_key}']
elif pub_key:
extra += [f'--public-key={pub_key}']
extra += [f'--phase={phase_path}' for phase_path in group or ()]
@ -728,11 +732,13 @@ def sbsign_sign(sbsign_tool, input_f, output_f, opts=None):
sbsign_tool,
'--key', opts.sb_key,
'--cert', opts.sb_cert,
input_f,
'--output', output_f,
]
if opts.signing_engine is not None:
sign_invocation += ['--engine', opts.signing_engine]
sign_invocation += [
input_f,
'--output', output_f,
]
signer_sign(sign_invocation)
def find_pesign(opts=None):
@ -820,7 +826,7 @@ def make_uki(opts):
pcrpkey = opts.pcr_public_keys[0]
elif opts.pcr_private_keys and len(opts.pcr_private_keys) == 1:
from cryptography.hazmat.primitives import serialization
privkey = serialization.load_pem_private_key(opts.pcr_private_keys[0].read_bytes(), password=None)
privkey = serialization.load_pem_private_key(pathlib.Path(opts.pcr_private_keys[0]).read_bytes(), password=None)
pcrpkey = privkey.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
@ -1002,7 +1008,7 @@ def generate_keys(opts):
print(f'Writing private key for PCR signing to {priv_key}')
with temporary_umask(0o077):
priv_key.write_bytes(priv_key_pem)
pathlib.Path(priv_key).write_bytes(priv_key_pem)
if pub_key:
print(f'Writing public key for PCR signing to {pub_key}')
pub_key.write_bytes(pub_key_pem)
@ -1405,10 +1411,8 @@ CONFIG_ITEMS = [
ConfigItem(
'--pcr-private-key',
dest = 'pcr_private_keys',
metavar = 'PATH',
type = pathlib.Path,
action = 'append',
help = 'private part of the keypair for signing PCR signatures',
help = 'private part of the keypair or engine-specific designation for signing PCR signatures',
config_key = 'PCRSignature:/PCRPrivateKey',
config_push = ConfigItem.config_set_group,
),
@ -1418,7 +1422,7 @@ CONFIG_ITEMS = [
metavar = 'PATH',
type = pathlib.Path,
action = 'append',
help = 'public part of the keypair for signing PCR signatures',
help = 'public part of the keypair or engine-specific designation for signing PCR signatures',
config_key = 'PCRSignature:/PCRPublicKey',
config_push = ConfigItem.config_set_group,
),