diff options
-rw-r--r-- | man/rules/meson.build | 1 | ||||
-rw-r--r-- | man/systemd-keyutil.xml | 105 | ||||
-rw-r--r-- | man/systemd-measure.xml | 10 | ||||
-rw-r--r-- | man/systemd-sbsign.xml | 16 | ||||
-rw-r--r-- | meson.build | 3 | ||||
-rw-r--r-- | src/keyutil/keyutil.c | 292 | ||||
-rw-r--r-- | src/keyutil/meson.build | 12 | ||||
-rw-r--r-- | src/measure/measure.c | 89 | ||||
-rw-r--r-- | src/sbsign/sbsign.c | 54 | ||||
-rwxr-xr-x | src/ukify/ukify.py | 12 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.keyutil.sh | 50 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.sbsign.sh | 4 |
12 files changed, 468 insertions, 180 deletions
diff --git a/man/rules/meson.build b/man/rules/meson.build index 7d2c62f574..e76cb0223b 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -992,6 +992,7 @@ manpages = [ 'systemd-journald@.service', 'systemd-journald@.socket'], ''], + ['systemd-keyutil', '1', [], ''], ['systemd-localed.service', '8', ['systemd-localed'], 'ENABLE_LOCALED'], ['systemd-logind.service', '8', ['systemd-logind'], 'ENABLE_LOGIND'], ['systemd-machine-id-commit.service', '8', [], ''], diff --git a/man/systemd-keyutil.xml b/man/systemd-keyutil.xml new file mode 100644 index 0000000000..99d4d903b4 --- /dev/null +++ b/man/systemd-keyutil.xml @@ -0,0 +1,105 @@ +<?xml version='1.0'?> <!--*-nxml-*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" + "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> +<!-- SPDX-License-Identifier: LGPL-2.1-or-later --> + +<refentry id="systemd-keyutil" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <refentryinfo> + <title>systemd-keyutil</title> + <productname>systemd</productname> + </refentryinfo> + + <refmeta> + <refentrytitle>systemd-keyutil</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd-keyutil</refname> + <refpurpose>Perform various operations on private keys and X.509 certificates</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>systemd-keyutil</command> + <arg choice="opt" rep="repeat">OPTIONS</arg> + <arg choice="req">COMMAND</arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><command>systemd-keyutil</command> can be used to perform various operations on private keys and + X.509 certificates.</para> + </refsect1> + + <refsect1> + <title>Commands</title> + + <variablelist> + <varlistentry> + <term><option>validate</option></term> + + <listitem><para>Checks that we can load the private key and certificate specified with + <option>--private-key=</option> and <option>--certificate=</option> respectively.</para> + + <para>As a side effect, if the private key is loaded from a PIN-protected hardware token, this + command can be used to cache the PIN in the kernel keyring. The + <varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC</varname> and + <varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TYPE</varname> environment variables can be used to control + how long and in which kernel keyring the PIN is cached.</para> + + <xi:include href="version-info.xml" xpointer="v257"/> + </listitem> + </varlistentry> + + <varlistentry> + <term><command>public</command></term> + + <listitem><para>This commands prints the public key in PEM format extracted from either the + certificate given with <option>--certificate=</option> or the private key given with + <option>--private-key=</option>.</para> + + <xi:include href="version-info.xml" xpointer="v257"/></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Options</title> + <para>The following options are understood:</para> + + <variablelist> + <varlistentry> + <term><option>--private-key=<replaceable>PATH/URI</replaceable></option></term> + <term><option>--private-key-source=<replaceable>TYPE</replaceable>[:<replaceable>NAME</replaceable>]</option></term> + <term><option>--certificate=<replaceable>PATH</replaceable></option></term> + <term><option>--certificate-source=<replaceable>TYPE</replaceable>[:<replaceable>NAME</replaceable>]</option></term> + + <listitem><para>Set the private key and certificate to use. The <option>--certificate=</option> + option takes a path to a PEM encoded X.509 certificate or a URI that's passed to the OpenSSL provider + configured with <option>--certificate-source</option>. The <option>--certificate-source</option> + takes one of <literal>file</literal> or <literal>provider</literal>, with the latter being followed + by a specific provider identifier, separated with a colon, e.g. <literal>provider:pkcs11</literal>. + The <option>--private-key=</option> 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 + <literal>type:name</literal> tuple, such as <literal>engine:pkcs11</literal></para>. + + <xi:include href="version-info.xml" xpointer="v257"/></listitem> + </varlistentry> + + <xi:include href="standard-options.xml" xpointer="help"/> + <xi:include href="standard-options.xml" xpointer="version"/> + </variablelist> + </refsect1> + + <refsect1> + <title>See Also</title> + <para><simplelist type="inline"> + <member><citerefentry><refentrytitle>systemd-sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> + <member><citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> + </simplelist></para> + </refsect1> +</refentry> diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml index 5ca373f181..c7e5a5e9e2 100644 --- a/man/systemd-measure.xml +++ b/man/systemd-measure.xml @@ -104,16 +104,6 @@ <xi:include href="version-info.xml" xpointer="v252"/></listitem> </varlistentry> - - <varlistentry> - <term><command>pcrpkey</command></term> - - <listitem><para>This commands prints the public key either given with <option>--public-key=</option>, - or extracted from the certificate given with <option>--certificate=</option> or the private key given - with <option>--private-key=</option>.</para> - - <xi:include href="version-info.xml" xpointer="v257"/></listitem> - </varlistentry> </variablelist> </refsect1> diff --git a/man/systemd-sbsign.xml b/man/systemd-sbsign.xml index 1248377845..57b685f8c3 100644 --- a/man/systemd-sbsign.xml +++ b/man/systemd-sbsign.xml @@ -49,22 +49,6 @@ <xi:include href="version-info.xml" xpointer="v257"/> </listitem> </varlistentry> - - <varlistentry> - <term><option>validate-key</option></term> - - <listitem><para>Checks that we can load the private key specified with - <option>--private-key=</option>. </para> - - <para>As a side effect, if the private key is loaded from a PIN-protected hardware token, this - command can be used to cache the PIN in the kernel keyring. The - <varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC</varname> and - <varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TYPE</varname> environment variables can be used to control - how long and in which kernel keyring the PIN is cached.</para> - - <xi:include href="version-info.xml" xpointer="v257"/> - </listitem> - </varlistentry> </variablelist> </refsect1> diff --git a/meson.build b/meson.build index 6b62dfa052..fbab9300c5 100644 --- a/meson.build +++ b/meson.build @@ -2377,6 +2377,7 @@ subdir('src/integritysetup') subdir('src/journal') subdir('src/journal-remote') subdir('src/kernel-install') +subdir('src/keyutil') subdir('src/locale') subdir('src/login') subdir('src/machine') @@ -2698,7 +2699,7 @@ endif mkosi_depends = public_programs -foreach executable : ['systemd-journal-remote', 'systemd-measure'] +foreach executable : ['systemd-journal-remote', 'systemd-measure', 'systemd-sbsign', 'systemd-keyutil'] if executable in executables_by_name mkosi_depends += [executables_by_name[executable]] endif diff --git a/src/keyutil/keyutil.c b/src/keyutil/keyutil.c new file mode 100644 index 0000000000..70176c76c7 --- /dev/null +++ b/src/keyutil/keyutil.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <getopt.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "ask-password-api.h" +#include "build.h" +#include "fd-util.h" +#include "main-func.h" +#include "memstream-util.h" +#include "openssl-util.h" +#include "parse-argument.h" +#include "pretty-print.h" +#include "verbs.h" + +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_certificate = NULL; +static char *arg_certificate_source = NULL; +static CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE; + +STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep); +STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep); +STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep); +STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep); + +static int help(int argc, char *argv[], void *userdata) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-keyutil", "1", &link); + if (r < 0) + return log_oom(); + + printf("%1$s [OPTIONS...] COMMAND ...\n" + "\n%5$sPerform various operations on private keys and certificates.%6$s\n" + "\n%3$sCommands:%4$s\n" + " validate Load and validate the given certificate and private key\n" + " public Extract a public key\n" + "\n%3$sOptions:%4$s\n" + " -h --help Show this help\n" + " --version Print version\n" + " --private-key=KEY Private key in PEM format\n" + " --private-key-source=file|provider:PROVIDER|engine:ENGINE\n" + " Specify how to use KEY for --private-key=. Allows\n" + " an OpenSSL engine/provider to be used for signing\n" + " --certificate=PATH|URI\n" + " PEM certificate to use for signing, or a provider\n" + " specific designation if --certificate-source= is used\n" + " --certificate-source=file|provider:PROVIDER\n" + " Specify how to interpret the certificate from\n" + " --certificate=. Allows the certificate to be loaded\n" + " from an OpenSSL provider\n" + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_PRIVATE_KEY, + ARG_PRIVATE_KEY_SOURCE, + ARG_CERTIFICATE, + ARG_CERTIFICATE_SOURCE, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "private-key", required_argument, NULL, ARG_PRIVATE_KEY }, + { "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE }, + { "certificate", required_argument, NULL, ARG_CERTIFICATE }, + { "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + switch (c) { + + case 'h': + help(0, NULL, NULL); + return 0; + + case ARG_VERSION: + return version(); + + case 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; + + break; + + case ARG_CERTIFICATE: + r = free_and_strdup_warn(&arg_certificate, optarg); + if (r < 0) + return r; + break; + + case ARG_CERTIFICATE_SOURCE: + r = parse_openssl_certificate_source_argument( + optarg, + &arg_certificate_source, + &arg_certificate_source_type); + if (r < 0) + return r; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached(); + } + + if (arg_private_key_source && !arg_certificate) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "When using --private-key-source=, --certificate= must be specified."); + + return 1; +} + +static int verb_validate(int argc, char *argv[], void *userdata) { + _cleanup_(X509_freep) X509 *certificate = NULL; + _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL; + _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL; + int r; + + if (!arg_certificate) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No certificate specified, use --certificate="); + + if (!arg_private_key) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No private key specified, use --private-key=."); + + if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) { + r = parse_path_argument(arg_certificate, /*suppress_root=*/ false, &arg_certificate); + if (r < 0) + return r; + } + + r = openssl_load_x509_certificate( + arg_certificate_source_type, + arg_certificate_source, + arg_certificate, + &certificate); + if (r < 0) + return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate); + + if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) { + r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key); + if (r < 0) + return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key); + } + + r = openssl_load_private_key( + arg_private_key_source_type, + arg_private_key_source, + arg_private_key, + &(AskPasswordRequest) { + .id = "keyutil-private-key-pin", + .keyring = arg_private_key, + .credential = "keyutil.private-key-pin", + }, + &private_key, + &ui); + if (r < 0) + return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key); + + puts("OK"); + return 0; +} + +static int verb_public(int argc, char *argv[], void *userdata) { + _cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL; + int r; + + if (arg_certificate) { + _cleanup_(X509_freep) X509 *certificate = NULL; + + if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) { + r = parse_path_argument(arg_certificate, /*suppress_root=*/ false, &arg_certificate); + if (r < 0) + return r; + } + + r = openssl_load_x509_certificate( + arg_certificate_source_type, + arg_certificate_source, + arg_certificate, + &certificate); + if (r < 0) + return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate); + + public_key = X509_get_pubkey(certificate); + if (!public_key) + return log_error_errno( + SYNTHETIC_ERRNO(EIO), + "Failed to extract public key from certificate %s.", + arg_certificate); + + } else if (arg_private_key) { + _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL; + _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL; + + if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) { + r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key); + if (r < 0) + return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key); + } + + r = openssl_load_private_key( + arg_private_key_source_type, + arg_private_key_source, + arg_private_key, + &(AskPasswordRequest) { + .id = "keyutil-private-key-pin", + .keyring = arg_private_key, + .credential = "keyutil.private-key-pin", + }, + &private_key, + &ui); + if (r < 0) + return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key); + + _cleanup_(memstream_done) MemStream m = {}; + FILE *tf = memstream_init(&m); + if (!tf) + return log_oom(); + + if (i2d_PUBKEY_fp(tf, private_key) != 1) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to extract public key from private key file '%s'.", arg_private_key); + + fflush(tf); + rewind(tf); + + if (!d2i_PUBKEY_fp(tf, &public_key)) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to parse extracted public key of private key file '%s'.", arg_private_key); + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "One of --certificate=, or --private-key= must be specified"); + + if (PEM_write_PUBKEY(stdout, public_key) == 0) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write public key to stdout"); + + return 0; +} + +static int run(int argc, char *argv[]) { + static const Verb verbs[] = { + { "help", VERB_ANY, VERB_ANY, 0, help }, + { "validate", VERB_ANY, 1, 0, verb_validate }, + { "public", VERB_ANY, 1, 0, verb_public }, + {} + }; + int r; + + log_setup(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + return dispatch_verb(argc, argv, verbs, NULL); +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/keyutil/meson.build b/src/keyutil/meson.build new file mode 100644 index 0000000000..956f603989 --- /dev/null +++ b/src/keyutil/meson.build @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +executables += [ + libexec_template + { + 'name' : 'systemd-keyutil', + 'conditions' : [ + 'HAVE_OPENSSL', + ], + 'sources' : files('keyutil.c'), + 'dependencies' : libopenssl, + }, +] diff --git a/src/measure/measure.c b/src/measure/measure.c index ac294d28b3..979426c18f 100644 --- a/src/measure/measure.c +++ b/src/measure/measure.c @@ -77,7 +77,6 @@ static int help(int argc, char *argv[], void *userdata) { " status Show current PCR values\n" " calculate Calculate expected PCR values\n" " sign Calculate and sign expected PCR values\n" - " pcrpkey Extract the PCR public key\n" "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" " --version Print version\n" @@ -1174,100 +1173,12 @@ static int verb_status(int argc, char *argv[], void *userdata) { return 0; } -static int verb_pcrpkey(int argc, char *argv[], void *userdata) { - _cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL; - int r; - - if (arg_public_key) { - _cleanup_fclose_ FILE *public_keyf = NULL; - - public_keyf = fopen(arg_public_key, "re"); - if (!public_keyf) - return log_error_errno(errno, "Failed to open public key file '%s': %m", arg_public_key); - - public_key = PEM_read_PUBKEY(public_keyf, NULL, NULL, NULL); - if (!public_key) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse public key '%s'.", arg_public_key); - - } else if (arg_certificate) { - _cleanup_(X509_freep) X509 *certificate = NULL; - - if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) { - r = parse_path_argument(arg_certificate, /*suppress_root=*/ false, &arg_certificate); - if (r < 0) - return r; - } - - r = openssl_load_x509_certificate( - arg_certificate_source_type, - arg_certificate_source, - arg_certificate, - &certificate); - if (r < 0) - return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate); - - public_key = X509_get_pubkey(certificate); - if (!public_key) - return log_error_errno( - SYNTHETIC_ERRNO(EIO), - "Failed to extract public key from certificate %s.", - arg_certificate); - - } else if (arg_private_key) { - _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL; - _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL; - - if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) { - r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key); - if (r < 0) - return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key); - } - - r = openssl_load_private_key( - arg_private_key_source_type, - arg_private_key_source, - arg_private_key, - &(AskPasswordRequest) { - .id = "measure-private-key-pin", - .keyring = arg_private_key, - .credential = "measure.private-key-pin", - }, - &private_key, - &ui); - if (r < 0) - return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key); - - _cleanup_(memstream_done) MemStream m = {}; - FILE *tf = memstream_init(&m); - if (!tf) - return log_oom(); - - if (i2d_PUBKEY_fp(tf, private_key) != 1) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to extract public key from private key file '%s'.", arg_private_key); - - fflush(tf); - rewind(tf); - - if (!d2i_PUBKEY_fp(tf, &public_key)) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to parse extracted public key of private key file '%s'.", arg_private_key); - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "One of --public-key=, --certificate=, or --private-key= must be specified"); - - if (PEM_write_PUBKEY(stdout, public_key) == 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write public key to stdout"); - - return 0; -} - static int measure_main(int argc, char *argv[]) { static const Verb verbs[] = { { "help", VERB_ANY, VERB_ANY, 0, help }, { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status }, { "calculate", VERB_ANY, 1, 0, verb_calculate }, { "sign", VERB_ANY, 1, 0, verb_sign }, - { "pcrpkey", VERB_ANY, 1, 0, verb_pcrpkey }, {} }; diff --git a/src/sbsign/sbsign.c b/src/sbsign/sbsign.c index d65f28b4c4..81970a7302 100644 --- a/src/sbsign/sbsign.c +++ b/src/sbsign/sbsign.c @@ -45,7 +45,6 @@ static int help(int argc, char *argv[], void *userdata) { "\n%5$sSign binaries for EFI Secure Boot%6$s\n" "\n%3$sCommands:%4$s\n" " sign EXEFILE Sign the given binary for EFI Secure Boot\n" - " validate-key Load and validate the given certificate and private key\n" "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" " --version Print version\n" @@ -498,63 +497,10 @@ static int verb_sign(int argc, char *argv[], void *userdata) { return 0; } -static int verb_validate_key(int argc, char *argv[], void *userdata) { - _cleanup_(X509_freep) X509 *certificate = NULL; - _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL; - _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL; - int r; - - if (!arg_certificate) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "No certificate specified, use --certificate="); - - if (!arg_private_key) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "No private key specified, use --private-key=."); - - if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) { - r = parse_path_argument(arg_certificate, /*suppress_root=*/ false, &arg_certificate); - if (r < 0) - return r; - } - - r = openssl_load_x509_certificate( - arg_certificate_source_type, - arg_certificate_source, - arg_certificate, - &certificate); - if (r < 0) - return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate); - - if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) { - r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key); - if (r < 0) - return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key); - } - - r = openssl_load_private_key( - arg_private_key_source_type, - arg_private_key_source, - arg_private_key, - &(AskPasswordRequest) { - .id = "sbsign-private-key-pin", - .keyring = arg_private_key, - .credential = "sbsign.private-key-pin", - }, - &private_key, - &ui); - if (r < 0) - return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key); - - puts("OK"); - return 0; -} - static int run(int argc, char *argv[]) { static const Verb verbs[] = { { "help", VERB_ANY, VERB_ANY, 0, help }, { "sign", 2, 2, 0, verb_sign }, - { "validate-key", VERB_ANY, 1, 0, verb_validate_key }, {} }; int r; diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index 355e3f99f4..ae3e1d03b4 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -1017,8 +1017,8 @@ def make_uki(opts: UkifyConfig) -> None: pcrpkey: Union[bytes, Path, None] = opts.pcrpkey if pcrpkey is None: - measure_tool = find_tool('systemd-measure', '/usr/lib/systemd/systemd-measure') - cmd = [measure_tool, 'pcrpkey'] + measure_tool = find_tool('systemd-keyutil', '/usr/lib/systemd/systemd-keyutil') + cmd = [measure_tool, 'public'] if opts.pcr_public_keys and len(opts.pcr_public_keys) == 1: # If we're using an engine or provider, the public key will be an X.509 certificate. @@ -1026,11 +1026,11 @@ def make_uki(opts: UkifyConfig) -> None: cmd += ['--certificate', opts.pcr_public_keys[0]] if opts.certificate_provider: cmd += ['--certificate-source', f'provider:{opts.certificate_provider}'] - else: - cmd += ['--public-key', opts.pcr_public_keys[0]] - print('+', shell_join(cmd)) - pcrpkey = subprocess.check_output(cmd) + print('+', shell_join(cmd)) + pcrpkey = subprocess.check_output(cmd) + else: + pcrpkey = Path(opts.pcr_public_keys[0]) elif opts.pcr_private_keys and len(opts.pcr_private_keys) == 1: cmd += ['--private-key', Path(opts.pcr_private_keys[0])] diff --git a/test/units/TEST-74-AUX-UTILS.keyutil.sh b/test/units/TEST-74-AUX-UTILS.keyutil.sh new file mode 100755 index 0000000000..bbbbf9fd67 --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.keyutil.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +if ! command -v /usr/lib/systemd/systemd-keyutil >/dev/null; then + echo "systemd-keyutil not found, skipping." + exit 0 +fi + +cat >/tmp/openssl.conf <<EOF +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = DE +ST = Test State +L = Test Locality +O = Org Name +OU = Org Unit Name +CN = Common Name +emailAddress = test@email.com +EOF + +openssl req -config /tmp/openssl.conf -subj="/CN=waldo" \ + -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ + -keyout /tmp/test.key -out /tmp/test.crt + +testcase_validate() { + /usr/lib/systemd/systemd-keyutil validate --certificate /tmp/test.crt --private-key /tmp/test.key +} + +testcase_public() { + PUBLIC="$(/usr/lib/systemd/systemd-keyutil public --certificate /tmp/test.crt)" + assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)" + + PUBLIC="$(/usr/lib/systemd/systemd-keyutil public --private-key /tmp/test.key)" + assert_eq "$PUBLIC" "$(openssl x509 -in /tmp/test.crt -pubkey -noout)" + + (! /usr/lib/systemd/systemd-keyutil public) +} + +run_testcases diff --git a/test/units/TEST-74-AUX-UTILS.sbsign.sh b/test/units/TEST-74-AUX-UTILS.sbsign.sh index 891a2ae8af..fc186517d1 100755 --- a/test/units/TEST-74-AUX-UTILS.sbsign.sh +++ b/test/units/TEST-74-AUX-UTILS.sbsign.sh @@ -53,8 +53,4 @@ testcase_sign_systemd_boot() { sbverify --cert /tmp/sb.crt /tmp/sdboot } -testcase_validate_key() { - /usr/lib/systemd/systemd-sbsign validate-key --certificate /tmp/sb.crt --private-key /tmp/sb.key -} - run_testcases |