1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-21 22:04:01 +03:00

tree-wide: Introduce --certificate-source= option

This allows loading the X.509 certificate from an OpenSSL provider
instead of a file system path. This allows loading certficates directly
from hardware tokens instead of having to export them to a file on
disk first.
This commit is contained in:
Daan De Meyer 2024-11-06 18:08:26 +01:00
parent 5619a61829
commit a1d46e3078
12 changed files with 336 additions and 61 deletions

View File

@ -529,8 +529,9 @@
<varlistentry>
<term><option>--secure-boot-auto-enroll=yes|no</option></term>
<term><option>--private-key=<replaceable>PATH/URI</replaceable></option></term>
<term><option>--private-key-source=<replaceable>TYPE[:NAME]</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>Configure the ESP for secure boot auto-enrollment when invoking the
<command>install</command> command. Takes a boolean argument. Disabled by default. Enabling this
@ -542,9 +543,12 @@
<para>When specifying this option, a certificate and private key have to be provided as well using
the <option>--certificate=</option> and <option>--private-key=</option> options. The
<option>--certificate=</option> option takes a path to a PEM encoded X.509 certificate. 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
<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> which
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>. The specified OpenSSL
signing engine or provider will be used to sign the EFI signature lists.</para>

View File

@ -188,8 +188,9 @@
<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>
<term><option>--private-key-source=<replaceable>TYPE</replaceable>[:<replaceable>NAME</replaceable>]</option></term>
<term><option>--certificate=<replaceable>PATH/URI</replaceable></option></term>
<term><option>--certificate-source=<replaceable>TYPE</replaceable>[:<replaceable>NAME</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
@ -197,6 +198,11 @@
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>
<para>The <option>--certificate=</option> option also takes a path or a URI that will be passed to
the OpenSSL provider, as specified by <option>--certificate-source=</option> as a
<literal>type:name</literal> tuple, such as <literal>provider:pkcs11</literal>. Note that unlike
<option>--private-key-source=</option> this option only supports providers and not engines.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>

View File

@ -348,9 +348,9 @@
<varlistentry>
<term><option>--private-key=</option></term>
<listitem><para>Takes a file system path. 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 a file system path or an engine or provider specific designation. Configures
the signing key 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="v252"/></listitem>
</varlistentry>
@ -361,7 +361,7 @@
<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
Configures how to load the private key 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>
@ -370,13 +370,24 @@
<varlistentry>
<term><option>--certificate=</option></term>
<listitem><para>Takes a file system path. Configures the PEM encoded X.509 certificate to use when
creating verity signature partitions with the <varname>Verity=signature</varname> setting in
partition files.</para>
<listitem><para>Takes a file system path or a provider specific designation. Configures the PEM
encoded X.509 certificate 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="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--certificate-source=</option></term>
<listitem><para>Takes one of <literal>file</literal>, or <literal>provider</literal>. In the latter
case, it is followed by the name of a provider, separated by colon, that will be passed to OpenSSL's
"provider" logic. Configures how to load the X.509 certificate 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="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--tpm2-device=</option></term>
<term><option>--tpm2-pcrs=</option></term>

View File

@ -85,11 +85,16 @@
<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 Secure Boot private key and certificate for use with the
<command>sign</command>. The <option>--certificate=</option> option takes a path to a PEM encoded
X.509 certificate. 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
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>. The specified OpenSSL
signing engine or provider will be used to sign the PE binary.</para>

View File

@ -956,7 +956,17 @@ int verb_install(int argc, char *argv[], void *userdata) {
graceful = !install && arg_graceful; /* support graceful mode for updates */
if (arg_secure_boot_auto_enroll) {
r = openssl_load_x509_certificate(arg_certificate, &certificate);
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);

View File

@ -64,6 +64,8 @@ ImagePolicy *arg_image_policy = NULL;
bool arg_varlink = false;
bool arg_secure_boot_auto_enroll = false;
char *arg_certificate = NULL;
CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE;
char *arg_certificate_source = NULL;
char *arg_private_key = NULL;
KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
char *arg_private_key_source = NULL;
@ -77,6 +79,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
@ -295,9 +298,14 @@ static int help(int argc, char *argv[], void *userdata) {
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used when setting\n"
" up secure boot auto-enrollment\n"
" --certificate=PATH\n"
" PEM certificate to use when setting up secure boot\n"
" auto-enrollment\n"
" --certificate=PATH|URI\n"
" PEM certificate to use when setting up Secure Boot\n"
" auto-enrollment, or a provider specific designation\n"
" 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,
@ -332,6 +340,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PRINT_STUB_PATH,
ARG_SECURE_BOOT_AUTO_ENROLL,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
};
@ -366,6 +375,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "dry-run", no_argument, NULL, ARG_DRY_RUN },
{ "secure-boot-auto-enroll", required_argument, NULL, ARG_SECURE_BOOT_AUTO_ENROLL },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{}
@ -526,12 +536,20 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
case ARG_CERTIFICATE: {
r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_certificate);
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 ARG_PRIVATE_KEY: {
r = free_and_strdup_warn(&arg_private_key, optarg);

View File

@ -41,6 +41,8 @@ extern ImagePolicy *arg_image_policy;
extern bool arg_varlink;
extern bool arg_secure_boot_auto_enroll;
extern char *arg_certificate;
extern CertificateSourceType arg_certificate_source_type;
extern char *arg_certificate_source;
extern char *arg_private_key;
extern KeySourceType arg_private_key_source_type;
extern char *arg_private_key_source;

View File

@ -38,6 +38,8 @@ 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 char *arg_certificate_source = NULL;
static CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE;
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO|SD_JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
static bool arg_current = false;
@ -50,6 +52,7 @@ 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_certificate_source, freep);
STATIC_DESTRUCTOR_REGISTER(arg_phase, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_append, freep);
@ -87,7 +90,13 @@ static int help(int argc, char *argv[], void *userdata) {
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used for signing\n"
" --public-key=KEY Public key (PEM) to validate against\n"
" --certificate=PATH PEM certificate to use when signing with a URI\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"
" --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"
@ -156,6 +165,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PRIVATE_KEY_SOURCE,
ARG_PUBLIC_KEY,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_TPM2_DEVICE,
ARG_JSON,
ARG_PHASE,
@ -186,6 +196,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{ "public-key", required_argument, NULL, ARG_PUBLIC_KEY },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE },
{ "json", required_argument, NULL, ARG_JSON },
{ "phase", required_argument, NULL, ARG_PHASE },
{ "append", required_argument, NULL, ARG_APPEND },
@ -265,10 +276,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CERTIFICATE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &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 ARG_TPM2_DEVICE: {
@ -841,7 +860,17 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
/* This must be done before openssl_load_private_key() otherwise it will get stuck */
if (arg_certificate) {
r = openssl_load_x509_certificate(arg_certificate, &certificate);
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);
}

View File

@ -154,6 +154,8 @@ 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 CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE;
static char *arg_certificate_source = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_seal_key_handle = 0;
static char *arg_tpm2_device_key = NULL;
@ -186,6 +188,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
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_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
@ -7808,8 +7811,14 @@ static int help(void) {
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used when generating\n"
" verity roothash signatures\n"
" --certificate=PATH PEM certificate to use when generating verity\n"
" roothash signatures\n"
" --certificate=PATH|URI\n"
" PEM certificate to use when generating verity roothash\n"
" signatures, or a provider specific designation if\n"
" --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"
"\n%3$sEncryption:%4$s\n"
" --key-file=PATH Key to use when encrypting partitions\n"
" --tpm2-device=PATH Path to TPM2 device node to use\n"
@ -7878,6 +7887,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_TPM2_DEVICE,
ARG_TPM2_DEVICE_KEY,
ARG_TPM2_SEAL_KEY_HANDLE,
@ -7922,6 +7932,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
{ "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 },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-device-key", required_argument, NULL, ARG_TPM2_DEVICE_KEY },
{ "tpm2-seal-key-handle", required_argument, NULL, ARG_TPM2_SEAL_KEY_HANDLE },
@ -8130,12 +8141,20 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
return r;
break;
case ARG_CERTIFICATE: {
r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_certificate);
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 ARG_TPM2_DEVICE: {
_cleanup_free_ char *device = NULL;
@ -8468,7 +8487,17 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
}
if (arg_certificate) {
r = openssl_load_x509_certificate(arg_certificate, &certificate);
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);
}

View File

@ -21,12 +21,15 @@
static PagerFlags arg_pager_flags = 0;
static char *arg_output = NULL;
static char *arg_certificate = NULL;
static CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE;
static char *arg_certificate_source = 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_DESTRUCTOR_REGISTER(arg_output, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
@ -42,13 +45,19 @@ 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 private key\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"
" --no-pager Do not pipe output into a pager\n"
" --output Where to write the signed PE binary\n"
" --certificate=PATH PEM certificate to use when signing with a URI\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"
" --private-key=KEY Private key (PEM) to sign with\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use KEY for --private-key=. Allows\n"
@ -70,6 +79,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_PAGER,
ARG_OUTPUT,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
};
@ -80,6 +90,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "output", required_argument, NULL, ARG_OUTPUT },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{}
@ -112,10 +123,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CERTIFICATE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &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 ARG_PRIVATE_KEY:
@ -168,7 +187,17 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
if (!arg_output)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No output specified, use --output=");
r = openssl_load_x509_certificate(arg_certificate, &certificate);
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);
@ -470,14 +499,33 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
}
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)

View File

@ -1482,6 +1482,80 @@ static int openssl_ask_password_ui_new(const AskPasswordRequest *request, OpenSS
*ret = TAKE_PTR(ui);
return 0;
}
static int load_x509_certificate_from_file(const char *path, X509 **ret) {
_cleanup_free_ char *rawcert = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
_cleanup_(BIO_freep) BIO *cb = NULL;
size_t rawcertsz;
int r;
assert(path);
assert(ret);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawcert, &rawcertsz);
if (r < 0)
return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
cb = BIO_new_mem_buf(rawcert, rawcertsz);
if (!cb)
return log_oom_debug();
cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
if (!cert)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
ERR_error_string(ERR_get_error(), NULL));
if (ret)
*ret = TAKE_PTR(cert);
return 0;
}
static int load_x509_certificate_from_provider(const char *provider, const char *certificate_uri, X509 **ret) {
assert(provider);
assert(certificate_uri);
assert(ret);
#if OPENSSL_VERSION_MAJOR >= 3
/* Load the provider so that this can work without any custom written configuration in /etc/.
* Also load the 'default' as that seems to be the recommendation. */
if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
return log_openssl_errors("Failed to load OpenSSL provider '%s'", provider);
if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
return log_openssl_errors("Failed to load OpenSSL provider 'default'");
_cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
certificate_uri,
/*ui_method=*/ NULL,
/*ui_method=*/ NULL,
/* post_process= */ NULL,
/* post_process_data= */ NULL);
if (!store)
return log_openssl_errors("Failed to open OpenSSL store via '%s'", certificate_uri);
if (OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) == 0)
return log_openssl_errors("Failed to filter store by X.509 certificates");
_cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = OSSL_STORE_load(store);
if (!info)
return log_openssl_errors("Failed to load OpenSSL store via '%s'", certificate_uri);
_cleanup_(X509_freep) X509 *cert = OSSL_STORE_INFO_get1_CERT(info);
if (!cert)
return log_openssl_errors("Failed to load certificate via '%s'", certificate_uri);
*ret = TAKE_PTR(cert);
return 0;
#else
return -EOPNOTSUPP;
#endif
}
#endif
OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
@ -1517,36 +1591,33 @@ int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
#endif
}
int openssl_load_x509_certificate(const char *path, X509 **ret) {
int openssl_load_x509_certificate(
CertificateSourceType certificate_source_type,
const char *certificate_source,
const char *certificate,
X509 **ret) {
#if HAVE_OPENSSL
_cleanup_free_ char *rawcert = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
_cleanup_(BIO_freep) BIO *cb = NULL;
size_t rawcertsz;
int r;
assert(path);
assert(ret);
assert(certificate);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawcert, &rawcertsz);
switch (certificate_source_type) {
case OPENSSL_CERTIFICATE_SOURCE_FILE:
r = load_x509_certificate_from_file(certificate, ret);
break;
case OPENSSL_CERTIFICATE_SOURCE_PROVIDER:
r = load_x509_certificate_from_provider(certificate_source, certificate, ret);
break;
default:
assert_not_reached();
}
if (r < 0)
return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
cb = BIO_new_mem_buf(rawcert, rawcertsz);
if (!cb)
return log_oom_debug();
cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
if (!cert)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
ERR_error_string(ERR_get_error(), NULL));
if (ret)
*ret = TAKE_PTR(cert);
return log_debug_errno(
r,
"Failed to load certificate '%s' from OpenSSL certificate source %s: %m",
certificate,
certificate_source);
return 0;
#else
@ -1606,6 +1677,35 @@ int openssl_load_private_key(
#endif
}
int parse_openssl_certificate_source_argument(
const char *argument,
char **certificate_source,
CertificateSourceType *certificate_source_type) {
CertificateSourceType type;
const char *e = NULL;
int r;
assert(argument);
assert(certificate_source);
assert(certificate_source_type);
if (streq(argument, "file"))
type = OPENSSL_CERTIFICATE_SOURCE_FILE;
else if ((e = startswith(argument, "provider:")))
type = OPENSSL_CERTIFICATE_SOURCE_PROVIDER;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid certificate source '%s'", argument);
r = free_and_strdup_warn(certificate_source, e);
if (r < 0)
return r;
*certificate_source_type = type;
return 0;
}
int parse_openssl_key_source_argument(
const char *argument,
char **private_key_source,

View File

@ -6,6 +6,13 @@
#include "macro.h"
#include "sha256.h"
typedef enum CertificateSourceType {
OPENSSL_CERTIFICATE_SOURCE_FILE,
OPENSSL_CERTIFICATE_SOURCE_PROVIDER,
_OPENSSL_CERTIFICATE_SOURCE_MAX,
_OPENSSL_CERTIFICATE_SOURCE_INVALID = -EINVAL,
} CertificateSourceType;
typedef enum KeySourceType {
OPENSSL_KEY_SOURCE_FILE,
OPENSSL_KEY_SOURCE_ENGINE,
@ -16,6 +23,8 @@ typedef enum KeySourceType {
typedef struct OpenSSLAskPasswordUI OpenSSLAskPasswordUI;
int parse_openssl_certificate_source_argument(const char *argument, char **certificate_source, CertificateSourceType *certificate_source_type);
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
@ -182,7 +191,11 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OpenSSLAskPasswordUI*, openssl_ask_password_ui_
int x509_fingerprint(X509 *cert, uint8_t buffer[static X509_FINGERPRINT_SIZE]);
int openssl_load_x509_certificate(const char *path, X509 **ret);
int openssl_load_x509_certificate(
CertificateSourceType certificate_source_type,
const char *certificate_source,
const char *certificate,
X509 **ret);
int openssl_load_private_key(
KeySourceType private_key_source_type,