From: Daan De Meyer Date: Mon, 1 Dec 2025 21:21:45 +0000 (+0100) Subject: keyutil: Add extract-certificate X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42b6f87a42061ae3d445a748e68c94cf8761059d;p=thirdparty%2Fsystemd.git keyutil: Add extract-certificate Useful to extract a certificate from a hardware token to a file, for example in mkosi to ship the certificate from a hardware token in /usr/lib/verity.d in an image --- diff --git a/man/systemd-keyutil.xml b/man/systemd-keyutil.xml index 47ab28a055e..c9e8cd5e8c2 100644 --- a/man/systemd-keyutil.xml +++ b/man/systemd-keyutil.xml @@ -65,6 +65,17 @@ + + extract-certificate + + This command prints the X.509 certificate in PEM format extracted from the + certificate given with . This is useful when loading a certificate + from an OpenSSL provider (e.g. a hardware token) and wanting to output a standalone PEM certificate + that can be used without the provider. + + + + pkcs7 diff --git a/src/keyutil/keyutil.c b/src/keyutil/keyutil.c index 0e4e5006c72..f26b235d39a 100644 --- a/src/keyutil/keyutil.c +++ b/src/keyutil/keyutil.c @@ -49,6 +49,7 @@ static int help(int argc, char *argv[], void *userdata) { "\n%3$sCommands:%4$s\n" " validate Load and validate the given certificate and private key\n" " extract-public Extract a public key\n" + " extract-certificate Extract a certificate\n" " pkcs7 Generate a PKCS#7 signature\n" "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" @@ -314,6 +315,33 @@ static int verb_extract_public(int argc, char *argv[], void *userdata) { return 0; } +static int verb_extract_certificate(int argc, char *argv[], void *userdata) { + _cleanup_(X509_freep) X509 *certificate = NULL; + int r; + + if (!arg_certificate) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--certificate= must be specified."); + + 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 (PEM_write_X509(stdout, certificate) == 0) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write certificate to stdout."); + + return 0; +} + static int verb_pkcs7(int argc, char *argv[], void *userdata) { _cleanup_(X509_freep) X509 *certificate = NULL; _cleanup_free_ char *pkcs1 = NULL; @@ -399,11 +427,12 @@ static int verb_pkcs7(int argc, char *argv[], void *userdata) { 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 }, - { "extract-public", VERB_ANY, 1, 0, verb_extract_public }, - { "public", VERB_ANY, 1, 0, verb_extract_public }, /* Deprecated but kept for backwards compat. */ - { "pkcs7", VERB_ANY, VERB_ANY, 0, verb_pkcs7 }, + { "help", VERB_ANY, VERB_ANY, 0, help }, + { "validate", VERB_ANY, 1, 0, verb_validate }, + { "extract-public", VERB_ANY, 1, 0, verb_extract_public }, + { "public", VERB_ANY, 1, 0, verb_extract_public }, /* Deprecated but kept for backwards compat. */ + { "extract-certificate", VERB_ANY, 1, 0, verb_extract_certificate }, + { "pkcs7", VERB_ANY, VERB_ANY, 0, verb_pkcs7 }, {} }; int r; diff --git a/test/units/TEST-74-AUX-UTILS.keyutil.sh b/test/units/TEST-74-AUX-UTILS.keyutil.sh index 7cc9fd05f9f..5e36392d270 100755 --- a/test/units/TEST-74-AUX-UTILS.keyutil.sh +++ b/test/units/TEST-74-AUX-UTILS.keyutil.sh @@ -47,6 +47,13 @@ testcase_extract_public() { (! /usr/lib/systemd/systemd-keyutil extract-public) } +testcase_extract_certificate() { + CERT="$(/usr/lib/systemd/systemd-keyutil extract-certificate --certificate /tmp/test.crt)" + assert_eq "$CERT" "$(cat /tmp/test.crt)" + + (! /usr/lib/systemd/systemd-keyutil extract-certificate) +} + verify_pkcs7() { # Verify using internal certificate openssl smime -verify -binary -inform der -in /tmp/payload.p7s -content /tmp/payload -noverify >/dev/null