diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 48eeaa508c..30c987f834 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -738,9 +738,13 @@ Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as
`systemd-ask-password`:
-* `$SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC` - takes a timespan or `default`,
- which controls the expiration time of keys stored in the kernel keyring by
- `systemd-ask-password`. If unset or set to `default`, the default expiration
- of 150 seconds is used. If set to `0`, keys are not cached in the kernel
- keyring. If set to `infinity`, keys are cached without an expiration time in
- the kernel keyring.
+* `$SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC` - takes a timespan, which controls
+ the expiration time of keys stored in the kernel keyring by `systemd-ask-password`.
+ If unset, the default expiration of 150 seconds is used. If set to `0`, keys are
+ not cached in the kernel keyring. If set to `infinity`, keys are cached without an
+ expiration time in the kernel keyring.
+
+* `SYSTEMD_ASK_PASSWORD_KEYRING_TYPE` - takes a keyring ID or one of `thread`,
+ `process`, `session`, `user`, `user-session`, or `group`. Controls the kernel
+ keyring in which `systemd-ask-password` caches the queried password. Defaults
+ to `user`.
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 6fa279aa35..eab18f7575 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -526,6 +526,31 @@
+
+
+
+
+
+
+ Configure the ESP for secure boot auto-enrollment when invoking the
+ install command. Takes a boolean argument. Disabled by default. Enabling this
+ option will make bootctl populate the ESP with signed PK,
+ KEK and db signature databases, each containing the given
+ certificate in DER format as their only entry. These secure boot signature
+ databases will be picked up and enrolled by systemd-boot if secure boot is in
+ setup mode and secure boot auto-enrollment is enabled.
+
+ When specifying this option, a certificate and private key have to be provided as well using
+ the and options. The
+ option takes a path to a PEM encoded X.509 certificate. The
+ option can take a path or a URI that will be passed to the OpenSSL
+ engine or provider, as specified by as a
+ type:name tuple, such as engine:pkcs11. The specified OpenSSL
+ signing engine or provider will be used to sign the EFI signature lists.
+
+
+
+
diff --git a/src/basic/efivars.c b/src/basic/efivars.c
index 0ff07fa113..5e04c32212 100644
--- a/src/basic/efivars.c
+++ b/src/basic/efivars.c
@@ -330,7 +330,7 @@ bool is_efi_secure_boot(void) {
int r;
if (cache < 0) {
- r = read_flag(EFI_GLOBAL_VARIABLE(SecureBoot));
+ r = read_flag(EFI_GLOBAL_VARIABLE_STR("SecureBoot"));
if (r == -ENOENT)
cache = false;
else if (r < 0)
@@ -348,7 +348,7 @@ SecureBootMode efi_get_secure_boot_mode(void) {
if (cache != _SECURE_BOOT_INVALID)
return cache;
- int secure = read_flag(EFI_GLOBAL_VARIABLE(SecureBoot));
+ int secure = read_flag(EFI_GLOBAL_VARIABLE_STR("SecureBoot"));
if (secure < 0) {
if (secure != -ENOENT)
log_debug_errno(secure, "Error reading SecureBoot EFI variable, assuming not in SecureBoot mode: %m");
@@ -358,9 +358,9 @@ SecureBootMode efi_get_secure_boot_mode(void) {
/* We can assume false for all these if they are abscent (AuditMode and
* DeployedMode may not exist on older firmware). */
- int audit = read_flag(EFI_GLOBAL_VARIABLE(AuditMode));
- int deployed = read_flag(EFI_GLOBAL_VARIABLE(DeployedMode));
- int setup = read_flag(EFI_GLOBAL_VARIABLE(SetupMode));
+ int audit = read_flag(EFI_GLOBAL_VARIABLE_STR("AuditMode"));
+ int deployed = read_flag(EFI_GLOBAL_VARIABLE_STR("DeployedMode"));
+ int setup = read_flag(EFI_GLOBAL_VARIABLE_STR("SetupMode"));
log_debug("Secure boot variables: SecureBoot=%d AuditMode=%d DeployedMode=%d SetupMode=%d",
secure, audit, deployed, setup);
@@ -381,13 +381,13 @@ static int read_efi_options_variable(char **ret) {
/* Let's be helpful with the returned error and check if the variable exists at all. If it
* does, let's return a recognizable error (EPERM), and if not ENODATA. */
- if (access(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), F_OK) < 0)
+ if (access(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions")), F_OK) < 0)
return errno == ENOENT ? -ENODATA : -errno;
return -EPERM;
}
- r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(SystemdOptions), ret);
+ r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions"), ret);
if (r == -ENOENT)
return -ENODATA;
return r;
@@ -401,7 +401,7 @@ int cache_efi_options_variable(void) {
if (r < 0)
return r;
- return write_string_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), line,
+ return write_string_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions")), line,
WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755);
}
@@ -418,7 +418,7 @@ int systemd_efi_options_variable(char **ret) {
if (e)
return strdup_to(ret, e);
- r = read_one_line_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), ret);
+ r = read_one_line_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions")), ret);
if (r == -ENOENT)
return -ENODATA;
return r;
@@ -432,12 +432,12 @@ int systemd_efi_options_efivarfs_if_newer(char **ret) {
struct stat a = {}, b;
int r;
- if (stat(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), &a) < 0 && errno != ENOENT)
+ if (stat(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions")), &a) < 0 && errno != ENOENT)
return log_debug_errno(errno, "Failed to stat EFI variable SystemdOptions: %m");
- if (stat(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), &b) < 0) {
+ if (stat(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions")), &b) < 0) {
if (errno != ENOENT)
- log_debug_errno(errno, "Failed to stat "EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions))": %m");
+ log_debug_errno(errno, "Failed to stat "EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions"))": %m");
} else if (compare_stat_mtime(&a, &b) > 0)
log_debug("Variable SystemdOptions in evifarfs is newer than in cache.");
else {
diff --git a/src/basic/efivars.h b/src/basic/efivars.h
index fe2be3107a..f9167a2ee6 100644
--- a/src/basic/efivars.h
+++ b/src/basic/efivars.h
@@ -23,9 +23,10 @@
#define EFI_VENDOR_SYSTEMD SD_ID128_MAKE(8c,f2,64,4b,4b,0b,42,8f,93,87,6d,87,60,50,dc,67)
#define EFI_VENDOR_SYSTEMD_STR SD_ID128_MAKE_UUID_STR(8c,f2,64,4b,4b,0b,42,8f,93,87,6d,87,60,50,dc,67)
-#define EFI_VARIABLE_NON_VOLATILE UINT32_C(0x00000001)
-#define EFI_VARIABLE_BOOTSERVICE_ACCESS UINT32_C(0x00000002)
-#define EFI_VARIABLE_RUNTIME_ACCESS UINT32_C(0x00000004)
+#define EFI_VARIABLE_NON_VOLATILE UINT32_C(0x00000001)
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS UINT32_C(0x00000002)
+#define EFI_VARIABLE_RUNTIME_ACCESS UINT32_C(0x00000004)
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS UINT32_C(0x00000020)
/* Note that the - naming scheme is an efivarfs convention, i.e. part of the Linux
* API file system implementation for EFI. EFI itself processes UIDS in binary form.
@@ -37,10 +38,6 @@
#define EFI_LOADER_VARIABLE_STR(name) EFI_VENDOR_VARIABLE_STR(EFI_VENDOR_LOADER_STR, name)
#define EFI_SYSTEMD_VARIABLE_STR(name) EFI_VENDOR_VARIABLE_STR(EFI_VENDOR_SYSTEMD_STR, name)
-#define EFI_GLOBAL_VARIABLE(name) EFI_GLOBAL_VARIABLE_STR(STRINGIFY(name))
-#define EFI_LOADER_VARIABLE(name) EFI_LOADER_VARIABLE_STR(STRINGIFY(name))
-#define EFI_SYSTEMD_VARIABLE(name) EFI_SYSTEMD_VARIABLE_STR(STRINGIFY(name))
-
#define EFIVAR_PATH(variable) "/sys/firmware/efi/efivars/" variable
#define EFIVAR_CACHE_PATH(variable) "/run/systemd/efivars/" variable
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 0d904e53af..2a9da59881 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -504,6 +504,10 @@ size_t char16_strlen(const char16_t *s) {
return n;
}
+size_t char16_strsize(const char16_t *s) {
+ return s ? (char16_strlen(s) + 1) * sizeof(*s) : 0;
+}
+
/* expected size used to encode one unicode char */
static int utf8_unichar_to_encoded_len(char32_t unichar) {
diff --git a/src/basic/utf8.h b/src/basic/utf8.h
index 8a5e884a0a..221bc46a2d 100644
--- a/src/basic/utf8.h
+++ b/src/basic/utf8.h
@@ -42,6 +42,7 @@ char* utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
char16_t *utf8_to_utf16(const char *s, size_t length);
size_t char16_strlen(const char16_t *s); /* returns the number of 16-bit words in the string (not bytes!) */
+size_t char16_strsize(const char16_t *s);
int utf8_encoded_valid_unichar(const char *str, size_t length);
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
diff --git a/src/boot/bless-boot-generator.c b/src/boot/bless-boot-generator.c
index cf645e2416..2c3d54173d 100644
--- a/src/boot/bless-boot-generator.c
+++ b/src/boot/bless-boot-generator.c
@@ -33,7 +33,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
return 0;
}
- if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderBootCountPath)), F_OK) < 0) {
+ if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderBootCountPath")), F_OK) < 0) {
if (errno == ENOENT) {
log_debug_errno(errno, "Skipping generator, not booted with boot counting in effect.");
return 0;
diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c
index 4853aaefe9..61b882c505 100644
--- a/src/boot/bless-boot.c
+++ b/src/boot/bless-boot.c
@@ -219,7 +219,7 @@ static int acquire_boot_count_path(
uint64_t left, done;
int r;
- r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
+ r = efi_get_variable_path(EFI_LOADER_VARIABLE_STR("LoaderBootCountPath"), &path);
if (r == -ENOENT)
return -EUNATCH; /* in this case, let the caller print a message */
if (r < 0)
diff --git a/src/boot/bootctl-install.c b/src/boot/bootctl-install.c
index 0612791e07..a9e2eea486 100644
--- a/src/boot/bootctl-install.c
+++ b/src/boot/bootctl-install.c
@@ -8,14 +8,17 @@
#include "copy.h"
#include "dirent-util.h"
#include "efi-api.h"
+#include "efi-fundamental.h"
#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "glyph-util.h"
#include "id128-util.h"
+#include "io-util.h"
#include "kernel-config.h"
#include "os-util.h"
+#include "parse-argument.h"
#include "path-util.h"
#include "rm-rf.h"
#include "stat-util.h"
@@ -295,6 +298,8 @@ static const char *const esp_subdirs[] = {
"EFI/systemd",
"EFI/BOOT",
"loader",
+ "loader/keys",
+ "loader/keys/auto",
NULL
};
@@ -569,6 +574,164 @@ static int install_entry_token(void) {
return 0;
}
+#if HAVE_OPENSSL
+static int efi_timestamp(EFI_TIME *ret) {
+ uint64_t epoch = UINT64_MAX;
+ struct tm tm = {};
+ int r;
+
+ assert(ret);
+
+ r = secure_getenv_uint64("SOURCE_DATE_EPOCH", &epoch);
+ if (r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SOURCE_DATE_EPOCH, ignoring: %m");
+
+ r = localtime_or_gmtime_usec(epoch != UINT64_MAX ? epoch : now(CLOCK_REALTIME), /*utc=*/ true, &tm);
+ if (r < 0)
+ return log_error_errno(r, "Failed to convert timestamp to calendar time: %m");
+
+ *ret = (EFI_TIME) {
+ .Year = 1900 + tm.tm_year,
+ /* tm_mon starts at 0, EFI_TIME months start at 1. */
+ .Month = tm.tm_mon + 1,
+ .Day = tm.tm_mday,
+ .Hour = tm.tm_hour,
+ .Minute = tm.tm_min,
+ .Second = tm.tm_sec,
+ };
+
+ return 0;
+}
+#endif
+
+static int install_secure_boot_auto_enroll(const char *esp, X509 *certificate, EVP_PKEY *private_key) {
+#if HAVE_OPENSSL
+ int r;
+
+ _cleanup_free_ uint8_t *dercert = NULL;
+ int dercertsz;
+ dercertsz = i2d_X509(certificate, &dercert);
+ if (dercertsz < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert X.509 certificate to DER: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ _cleanup_close_ int keys_fd = chase_and_open("loader/keys/auto", esp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY, NULL);
+ if (keys_fd < 0)
+ return log_error_errno(keys_fd, "Failed to chase loader/keys/auto in the ESP: %m");
+
+ uint32_t siglistsz = offsetof(EFI_SIGNATURE_LIST, Signatures) + offsetof(EFI_SIGNATURE_DATA, SignatureData) + dercertsz;
+ /* We use malloc0() to zero-initialize the SignatureOwner field of Signatures[0]. */
+ _cleanup_free_ EFI_SIGNATURE_LIST *siglist = malloc0(siglistsz);
+ if (!siglist)
+ return log_oom();
+
+ *siglist = (EFI_SIGNATURE_LIST) {
+ .SignatureType = EFI_CERT_X509_GUID,
+ .SignatureListSize = siglistsz,
+ .SignatureSize = offsetof(EFI_SIGNATURE_DATA, SignatureData) + dercertsz,
+ };
+
+ memcpy(siglist->Signatures[0].SignatureData, dercert, dercertsz);
+
+ EFI_TIME timestamp;
+ r = efi_timestamp(×tamp);
+ if (r < 0)
+ return r;
+
+ uint32_t attrs =
+ EFI_VARIABLE_NON_VOLATILE|
+ EFI_VARIABLE_BOOTSERVICE_ACCESS|
+ EFI_VARIABLE_RUNTIME_ACCESS|
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+ FOREACH_STRING(db, "PK", "KEK", "db") {
+ _cleanup_(BIO_freep) BIO *bio = NULL;
+
+ bio = BIO_new(BIO_s_mem());
+ if (!bio)
+ return log_oom();
+
+ _cleanup_free_ char16_t *db16 = utf8_to_utf16(db, SIZE_MAX);
+ if (!db16)
+ return log_oom();
+
+ /* Don't count the trailing NUL terminator. */
+ if (BIO_write(bio, db16, char16_strsize(db16) - sizeof(char16_t)) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write variable name to bio");
+
+ EFI_GUID *guid = STR_IN_SET(db, "PK", "KEK") ? &(EFI_GUID) EFI_GLOBAL_VARIABLE : &(EFI_GUID) EFI_IMAGE_SECURITY_DATABASE_GUID;
+
+ if (BIO_write(bio, guid, sizeof(*guid)) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write variable GUID to bio");
+
+ if (BIO_write(bio, &attrs, sizeof(attrs)) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write variable attributes to bio");
+
+ if (BIO_write(bio, ×tamp, sizeof(timestamp)) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write timestamp to bio");
+
+ if (BIO_write(bio, siglist, siglistsz) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write signature list to bio");
+
+ _cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
+ p7 = PKCS7_sign(certificate, private_key, /*certs=*/ NULL, bio, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY|PKCS7_NOSMIMECAP);
+ if (!p7)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ _cleanup_free_ uint8_t *sig = NULL;
+ int sigsz = i2d_PKCS7_SIGNED(p7->d.sign, &sig);
+ if (sigsz < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ size_t authsz = offsetof(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo.CertData) + sigsz;
+ _cleanup_free_ EFI_VARIABLE_AUTHENTICATION_2 *auth = malloc(authsz);
+ if (!auth)
+ return log_oom();
+
+ *auth = (EFI_VARIABLE_AUTHENTICATION_2) {
+ .TimeStamp = timestamp,
+ .AuthInfo = {
+ .Hdr = {
+ .dwLength = offsetof(WIN_CERTIFICATE_UEFI_GUID, CertData) + sigsz,
+ .wRevision = 0x0200,
+ .wCertificateType = 0x0EF1, /* WIN_CERT_TYPE_EFI_GUID */
+ },
+ .CertType = EFI_CERT_TYPE_PKCS7_GUID,
+ }
+ };
+
+ memcpy(auth->AuthInfo.CertData, sig, sigsz);
+
+ _cleanup_free_ char *filename = strjoin(db, ".auth");
+ if (!filename)
+ return log_oom();
+
+ _cleanup_close_ int fd = openat(keys_fd, filename, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to open secure boot auto-enrollment file for writing: %m");
+
+ r = loop_write(fd, auth, authsz);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write authentication descriptor to secure boot auto-enrollment file: %m");
+
+ r = loop_write(fd, siglist, siglistsz);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write signature list to secure boot auto-enrollment file: %m");
+
+ if (fsync(fd) < 0 || fsync(keys_fd) < 0)
+ return log_error_errno(errno, "Failed to sync secure boot auto-enrollment file: %m");
+
+ log_info("Secure boot auto-enrollment file %s/loader/keys/auto/%s successfully written.", esp, filename);
+ }
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot set up secure boot auto-enrollment.");
+#endif
+}
+
static bool same_entry(uint16_t id, sd_id128_t uuid, const char *path) {
_cleanup_free_ char *opath = NULL;
sd_id128_t ouuid;
@@ -778,6 +941,9 @@ static int are_we_installed(const char *esp_path) {
}
int verb_install(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;
sd_id128_t uuid = SD_ID128_NULL;
uint64_t pstart = 0, psize = 0;
uint32_t part = 0;
@@ -789,6 +955,26 @@ int verb_install(int argc, char *argv[], void *userdata) {
install = streq(argv[0], "install");
graceful = !install && arg_graceful; /* support graceful mode for updates */
+ if (arg_secure_boot_auto_enroll) {
+ r = openssl_load_x509_certificate(arg_certificate, &certificate);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
+
+ r = openssl_load_private_key(
+ arg_private_key_source_type,
+ arg_private_key_source,
+ arg_private_key,
+ &(AskPasswordRequest) {
+ .id = "bootctl-private-key-pin",
+ .keyring = arg_private_key,
+ .credential = "bootctl.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);
+ }
+
r = acquire_esp(/* unprivileged_mode= */ false, graceful, &part, &pstart, &psize, &uuid, NULL);
if (graceful && r == -ENOKEY)
return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */
@@ -852,6 +1038,12 @@ int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
}
+
+ if (arg_secure_boot_auto_enroll) {
+ r = install_secure_boot_auto_enroll(arg_esp_path, certificate, private_key);
+ if (r < 0)
+ return r;
+ }
}
r = install_loader_specification(arg_dollar_boot_path());
@@ -1015,13 +1207,13 @@ static int remove_loader_variables(void) {
/* Remove all persistent loader variables we define */
FOREACH_STRING(var,
- EFI_LOADER_VARIABLE(LoaderConfigConsoleMode),
- EFI_LOADER_VARIABLE(LoaderConfigTimeout),
- EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot),
- EFI_LOADER_VARIABLE(LoaderEntryDefault),
- EFI_LOADER_VARIABLE(LoaderEntryLastBooted),
- EFI_LOADER_VARIABLE(LoaderEntryOneShot),
- EFI_LOADER_VARIABLE(LoaderSystemToken)) {
+ EFI_LOADER_VARIABLE_STR("LoaderConfigConsoleMode"),
+ EFI_LOADER_VARIABLE_STR("LoaderConfigTimeout"),
+ EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot"),
+ EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"),
+ EFI_LOADER_VARIABLE_STR("LoaderEntryLastBooted"),
+ EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"),
+ EFI_LOADER_VARIABLE_STR("LoaderSystemToken")) {
int q;
@@ -1069,6 +1261,16 @@ int verb_remove(int argc, char *argv[], void *userdata) {
if (q < 0 && r >= 0)
r = q;
+ FOREACH_STRING(db, "PK.auth", "KEK.auth", "db.auth") {
+ _cleanup_free_ char *p = path_join("/loader/keys/auto", db);
+ if (!p)
+ return log_oom();
+
+ q = remove_file(arg_esp_path, p);
+ if (q < 0 && r >= 0)
+ r = q;
+ }
+
q = remove_subdirs(arg_esp_path, esp_subdirs);
if (q < 0 && r >= 0)
r = q;
diff --git a/src/boot/bootctl-random-seed.c b/src/boot/bootctl-random-seed.c
index cfe10c4115..93cb4f9493 100644
--- a/src/boot/bootctl-random-seed.c
+++ b/src/boot/bootctl-random-seed.c
@@ -79,7 +79,7 @@ static int set_system_token(void) {
return 0;
}
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), NULL, NULL, &token_size);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderSystemToken"), NULL, NULL, &token_size);
if (r == -ENODATA)
log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
else if (r < 0) {
@@ -103,7 +103,7 @@ static int set_system_token(void) {
* and possibly get identification information or too much insight into the kernel's entropy pool
* state. */
WITH_UMASK(0077) {
- r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sizeof(buffer));
+ r = efi_set_variable(EFI_LOADER_VARIABLE_STR("LoaderSystemToken"), buffer, sizeof(buffer));
if (r < 0) {
if (!arg_graceful)
return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
diff --git a/src/boot/bootctl-set-efivar.c b/src/boot/bootctl-set-efivar.c
index 10867b2257..f23fcc713e 100644
--- a/src/boot/bootctl-set-efivar.c
+++ b/src/boot/bootctl-set-efivar.c
@@ -74,17 +74,17 @@ static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target
assert(ret_target_size);
if (streq(arg1, "@current")) {
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntrySelected), NULL, (void *) ret_target, ret_target_size);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), NULL, (void *) ret_target, ret_target_size);
if (r < 0)
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
} else if (streq(arg1, "@oneshot")) {
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot), NULL, (void *) ret_target, ret_target_size);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), NULL, (void *) ret_target, ret_target_size);
if (r < 0)
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
} else if (streq(arg1, "@default")) {
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryDefault), NULL, (void *) ret_target, ret_target_size);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), NULL, (void *) ret_target, ret_target_size);
if (r < 0)
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
@@ -114,7 +114,7 @@ int verb_set_efivar(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Not booted with UEFI.");
- if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderInfo)), F_OK) < 0) {
+ if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderInfo")), F_OK) < 0) {
if (errno == ENOENT) {
log_error_errno(errno, "Not booted with a supported boot loader.");
return -EOPNOTSUPP;
@@ -137,16 +137,16 @@ int verb_set_efivar(int argc, char *argv[], void *userdata) {
int (* arg_parser)(const char *, char16_t **, size_t *);
if (streq(argv[0], "set-default")) {
- variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
+ variable = EFI_LOADER_VARIABLE_STR("LoaderEntryDefault");
arg_parser = parse_loader_entry_target_arg;
} else if (streq(argv[0], "set-oneshot")) {
- variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
+ variable = EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot");
arg_parser = parse_loader_entry_target_arg;
} else if (streq(argv[0], "set-timeout")) {
- variable = EFI_LOADER_VARIABLE(LoaderConfigTimeout);
+ variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeout");
arg_parser = parse_timeout;
} else if (streq(argv[0], "set-timeout-oneshot")) {
- variable = EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot);
+ variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot");
arg_parser = parse_timeout;
} else
assert_not_reached();
diff --git a/src/boot/bootctl-status.c b/src/boot/bootctl-status.c
index c548ddcee5..229c1ad535 100644
--- a/src/boot/bootctl-status.c
+++ b/src/boot/bootctl-status.c
@@ -413,17 +413,17 @@ int verb_status(int argc, char *argv[], void *userdata) {
uint64_t loader_features = 0, stub_features = 0;
int have;
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(StubInfo), &stub);
- (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
- (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(StubImageIdentifier), &stub_path);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderFirmwareType"), &fw_type);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderFirmwareInfo"), &fw_info);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderInfo"), &loader);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("StubInfo"), &stub);
+ (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE_STR("LoaderImageIdentifier"), &loader_path);
+ (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE_STR("StubImageIdentifier"), &stub_path);
(void) efi_loader_get_features(&loader_features);
(void) efi_stub_get_features(&stub_features);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntrySelected), ¤t_entry);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &oneshot_entry);
- (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryDefault), &default_entry);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), ¤t_entry);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), &oneshot_entry);
+ (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), &default_entry);
SecureBootMode secure = efi_get_secure_boot_mode();
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
@@ -525,7 +525,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
}
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
- have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
+ have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderSystemToken")), F_OK) >= 0;
printf(" System Token: %s\n", have ? "set" : "not set");
if (arg_esp_path) {
diff --git a/src/boot/bootctl-systemd-efi-options.c b/src/boot/bootctl-systemd-efi-options.c
index 7f8308fc3d..d626d87abc 100644
--- a/src/boot/bootctl-systemd-efi-options.c
+++ b/src/boot/bootctl-systemd-efi-options.c
@@ -34,7 +34,7 @@ int verb_systemd_efi_options(int argc, char *argv[], void *userdata) {
log_notice("Note: SystemdOptions EFI variable has been modified since boot. New value: %s",
new);
} else {
- r = efi_set_variable_string(EFI_SYSTEMD_VARIABLE(SystemdOptions), argv[1]);
+ r = efi_set_variable_string(EFI_SYSTEMD_VARIABLE_STR("SystemdOptions"), argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to set SystemdOptions EFI variable: %m");
}
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 176de8d55d..23a3d2f922 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -62,6 +62,11 @@ char *arg_efi_boot_option_description = NULL;
bool arg_dry_run = false;
ImagePolicy *arg_image_policy = NULL;
bool arg_varlink = false;
+bool arg_secure_boot_auto_enroll = false;
+char *arg_certificate = NULL;
+char *arg_private_key = NULL;
+KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
+char *arg_private_key_source = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -71,6 +76,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
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_private_key, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
int acquire_esp(
int unprivileged_mode,
@@ -149,7 +157,7 @@ static int print_loader_or_stub_path(void) {
if (r < 0)
return log_error_errno(r, "Unable to determine loader partition UUID: %m");
- r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &p);
+ r = efi_get_variable_path(EFI_LOADER_VARIABLE_STR("LoaderImageIdentifier"), &p);
if (r == -ENOENT)
return log_error_errno(r, "No loader EFI binary path passed.");
if (r < 0)
@@ -163,7 +171,7 @@ static int print_loader_or_stub_path(void) {
if (r < 0)
return log_error_errno(r, "Unable to determine stub partition UUID: %m");
- r = efi_get_variable_path(EFI_LOADER_VARIABLE(StubImageIdentifier), &p);
+ r = efi_get_variable_path(EFI_LOADER_VARIABLE_STR("StubImageIdentifier"), &p);
if (r == -ENOENT)
return log_error_errno(r, "No stub EFI binary path passed.");
if (r < 0)
@@ -277,6 +285,19 @@ static int help(int argc, char *argv[], void *userdata) {
" --efi-boot-option-description=DESCRIPTION\n"
" Description of the entry in the boot option list\n"
" --dry-run Dry run (unlink and cleanup)\n"
+ " --secure-boot-auto-enroll\n"
+ " Set up secure boot auto-enrollment\n"
+ " --private-key=PATH|URI\n"
+ " Private key to use when setting up secure boot\n"
+ " auto-enrollment 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 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"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -309,6 +330,10 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DRY_RUN,
ARG_PRINT_LOADER_PATH,
ARG_PRINT_STUB_PATH,
+ ARG_SECURE_BOOT_AUTO_ENROLL,
+ ARG_CERTIFICATE,
+ ARG_PRIVATE_KEY,
+ ARG_PRIVATE_KEY_SOURCE,
};
static const struct option options[] = {
@@ -339,6 +364,10 @@ static int parse_argv(int argc, char *argv[]) {
{ "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
{ "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
{ "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 },
+ { "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
+ { "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{}
};
@@ -491,6 +520,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_dry_run = true;
break;
+ case ARG_SECURE_BOOT_AUTO_ENROLL:
+ r = parse_boolean_argument("--secure-boot-auto-enroll=", optarg, &arg_secure_boot_auto_enroll);
+ if (r < 0)
+ return r;
+ break;
+
+ case ARG_CERTIFICATE: {
+ r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_certificate);
+ if (r < 0)
+ return r;
+ break;
+ }
+
+ 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 '?':
return -EINVAL;
@@ -517,6 +575,12 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_dry_run && argv[optind] && !STR_IN_SET(argv[optind], "unlink", "cleanup"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--dry is only supported with --unlink or --cleanup");
+ if (arg_secure_boot_auto_enroll && !arg_certificate)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Secure boot auto-enrollment requested but no certificate provided");
+
+ if (arg_secure_boot_auto_enroll && !arg_private_key)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Secure boot auto-enrollment requested but no private key provided");
+
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
if (r < 0)
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
diff --git a/src/boot/bootctl.h b/src/boot/bootctl.h
index 19eb93c2b1..8a67f5d8f8 100644
--- a/src/boot/bootctl.h
+++ b/src/boot/bootctl.h
@@ -6,6 +6,7 @@
#include "boot-entry.h"
#include "image-policy.h"
+#include "openssl-util.h"
#include "pager.h"
typedef enum InstallSource {
@@ -38,6 +39,11 @@ extern char *arg_efi_boot_option_description;
extern bool arg_dry_run;
extern ImagePolicy *arg_image_policy;
extern bool arg_varlink;
+extern bool arg_secure_boot_auto_enroll;
+extern char *arg_certificate;
+extern char *arg_private_key;
+extern KeySourceType arg_private_key_source_type;
+extern char *arg_private_key_source;
static inline const char* arg_dollar_boot_path(void) {
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
diff --git a/src/boot/measure.c b/src/boot/measure.c
index 3ad49e9d74..3c409f8bd9 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -6,6 +6,7 @@
#include "sd-json.h"
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "build.h"
#include "efi-loader.h"
#include "fd-util.h"
@@ -803,6 +804,7 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
static int verb_sign(int argc, char *argv[], void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL;
_cleanup_(X509_freep) X509 *certificate = NULL;
size_t n;
@@ -834,54 +836,31 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
/* 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;
-
- r = read_full_file_full(
- AT_FDCWD, arg_certificate, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_CONNECT_SOCKET,
- /* bind_name= */ NULL,
- &crt, &n);
+ r = openssl_load_x509_certificate(arg_certificate, &certificate);
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));
+ 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) {
- _cleanup_fclose_ FILE *privkeyf = NULL;
- _cleanup_free_ char *resolved_pkey = NULL;
+ if (arg_private_key) {
+ 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 = parse_path_argument(arg_private_key, /* suppress_root= */ false, &resolved_pkey);
+ 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",
+ },
+ &privkey,
+ &ui);
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);
+ return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
}
if (arg_public_key) {
@@ -1049,7 +1028,7 @@ static int validate_stub(void) {
log_warning("Warning: current kernel image does not support measuring itself, the command line or initrd system extension images.\n"
"The PCR measurements seen are unlikely to be valid.");
- r = compare_reported_pcr_nr(TPM2_PCR_KERNEL_BOOT, EFI_LOADER_VARIABLE(StubPcrKernelImage), "kernel image");
+ r = compare_reported_pcr_nr(TPM2_PCR_KERNEL_BOOT, EFI_LOADER_VARIABLE_STR("StubPcrKernelImage"), "kernel image");
if (r < 0)
return r;
diff --git a/src/boot/meson.build b/src/boot/meson.build
index 55b9bd6294..9c28c623d4 100644
--- a/src/boot/meson.build
+++ b/src/boot/meson.build
@@ -30,7 +30,7 @@ executables += [
],
'sources' : bootctl_sources,
'link_with' : boot_link_with,
- 'dependencies' : libblkid,
+ 'dependencies' : [libblkid, libopenssl],
},
libexec_template + {
'name' : 'systemd-bless-boot',
diff --git a/src/core/efi-random.c b/src/core/efi-random.c
index dffde57c91..f3af300825 100644
--- a/src/core/efi-random.c
+++ b/src/core/efi-random.c
@@ -16,7 +16,7 @@ void lock_down_efi_variables(void) {
_cleanup_close_ int fd = -EBADF;
int r;
- fd = open(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), O_RDONLY|O_CLOEXEC);
+ fd = open(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderSystemToken")), O_RDONLY|O_CLOEXEC);
if (fd < 0) {
if (errno != ENOENT)
log_warning_errno(errno, "Unable to open LoaderSystemToken EFI variable, ignoring: %m");
diff --git a/src/fundamental/efi-fundamental.h b/src/fundamental/efi-fundamental.h
index 2862932ec9..75cfd23b8c 100644
--- a/src/fundamental/efi-fundamental.h
+++ b/src/fundamental/efi-fundamental.h
@@ -10,4 +10,65 @@ typedef struct {
uint16_t Data3;
uint8_t Data4[8];
} EFI_GUID;
+
+typedef struct {
+ EFI_GUID SignatureOwner;
+ uint8_t SignatureData[];
+} EFI_SIGNATURE_DATA;
+
+typedef struct {
+ EFI_GUID SignatureType;
+ uint32_t SignatureListSize;
+ uint32_t SignatureHeaderSize;
+ uint32_t SignatureSize;
+ EFI_SIGNATURE_DATA Signatures[];
+} EFI_SIGNATURE_LIST;
+
+typedef struct {
+ uint32_t dwLength;
+ uint16_t wRevision;
+ uint16_t wCertificateType;
+ uint8_t bCertificate[];
+} WIN_CERTIFICATE;
+
+typedef struct {
+ WIN_CERTIFICATE Hdr;
+ EFI_GUID CertType;
+ uint8_t CertData[];
+} WIN_CERTIFICATE_UEFI_GUID;
+
+typedef struct {
+ uint16_t Year;
+ uint8_t Month;
+ uint8_t Day;
+ uint8_t Hour;
+ uint8_t Minute;
+ uint8_t Second;
+ uint8_t Pad1;
+ uint32_t Nanosecond;
+ int16_t TimeZone;
+ uint8_t Daylight;
+ uint8_t Pad2;
+} EFI_TIME;
+
+typedef struct {
+ EFI_TIME TimeStamp;
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+} EFI_VARIABLE_AUTHENTICATION_2;
+
+#define GUID_DEF(d1, d2, d3, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8) \
+ { d1, d2, d3, { d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8 } }
+
+#define MAKE_GUID_PTR(name) ((EFI_GUID *) &(const EFI_GUID) name##_GUID)
+
+#define EFI_GLOBAL_VARIABLE \
+ GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+ GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
+
+#define EFI_CERT_X509_GUID \
+ GUID_DEF(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
+#define EFI_CERT_TYPE_PKCS7_GUID \
+ GUID_DEF(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
+
#endif
diff --git a/src/hibernate-resume/hibernate-resume-config.c b/src/hibernate-resume/hibernate-resume-config.c
index edf7a70e7c..d93919956b 100644
--- a/src/hibernate-resume/hibernate-resume-config.c
+++ b/src/hibernate-resume/hibernate-resume-config.c
@@ -161,7 +161,7 @@ int get_efi_hibernate_location(EFIHibernateLocation **ret) {
if (!is_efi_boot())
goto skip;
- r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(HibernateLocation), &location_str);
+ r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE_STR("HibernateLocation"), &location_str);
if (r == -ENOENT) {
log_debug_errno(r, "EFI variable HibernateLocation is not set, skipping.");
goto skip;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 467c5f78a0..1b6e358b74 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -3286,12 +3286,12 @@ static int method_set_reboot_to_boot_loader_menu(
if (use_efi) {
if (x == UINT64_MAX)
- r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot), NULL, 0);
+ r = efi_set_variable(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot"), NULL, 0);
else {
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
xsprintf(buf, "%" PRIu64, DIV_ROUND_UP(x, USEC_PER_SEC)); /* second granularity */
- r = efi_set_variable_string(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot), buf);
+ r = efi_set_variable_string(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot"), buf);
}
if (r < 0)
return r;
@@ -3481,9 +3481,9 @@ static int method_set_reboot_to_boot_loader_entry(
if (use_efi) {
if (isempty(v))
/* Delete item */
- r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot), NULL, 0);
+ r = efi_set_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), NULL, 0);
else
- r = efi_set_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), v);
+ r = efi_set_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), v);
if (r < 0)
return r;
} else {
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 5427e0a69f..be5171d5e1 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -17,6 +17,7 @@
#include "sd-json.h"
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "blkid-util.h"
#include "blockdev-list.h"
#include "blockdev-util.h"
@@ -149,10 +150,10 @@ static PagerFlags arg_pager_flags = 0;
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 char *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_certificate = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_seal_key_handle = 0;
static char *arg_tpm2_device_key = NULL;
@@ -182,9 +183,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
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, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_certificate, 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);
@@ -429,6 +430,9 @@ typedef struct Context {
int backing_fd;
bool from_scratch;
+
+ X509 *certificate;
+ EVP_PKEY *private_key;
} Context;
static const char *empty_mode_table[_EMPTY_MODE_MAX] = {
@@ -709,9 +713,11 @@ static Partition* partition_unlink_and_free(Context *context, Partition *p) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Partition*, partition_free);
-static Context* context_new(sd_id128_t seed) {
+static Context* context_new(sd_id128_t seed, X509 *certificate, EVP_PKEY *private_key) {
Context *context;
+ /* Note: This function takes ownership of the certificate and private_key arguments. */
+
context = new(Context, 1);
if (!context)
return NULL;
@@ -721,6 +727,8 @@ static Context* context_new(sd_id128_t seed) {
.end = UINT64_MAX,
.total = UINT64_MAX,
.seed = seed,
+ .certificate = certificate,
+ .private_key = private_key,
};
return context;
@@ -755,6 +763,9 @@ static Context* context_free(Context *context) {
else
free(context->node);
+ X509_free(context->certificate);
+ EVP_PKEY_free(context->private_key);
+
return mfree(context);
}
@@ -4979,6 +4990,8 @@ static int partition_format_verity_hash(
static int sign_verity_roothash(
const struct iovec *roothash,
+ X509 *certificate,
+ EVP_PKEY *private_key,
struct iovec *ret_signature) {
#if HAVE_OPENSSL
@@ -4989,6 +5002,7 @@ static int sign_verity_roothash(
int sigsz;
assert(roothash);
+ assert(private_key);
assert(iovec_is_set(roothash));
assert(ret_signature);
@@ -5000,7 +5014,7 @@ static int sign_verity_roothash(
if (!rb)
return log_oom();
- p7 = PKCS7_sign(arg_certificate, arg_private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
+ p7 = PKCS7_sign(certificate, private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
if (!p7)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -5039,15 +5053,13 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
assert_se(hp = p->siblings[VERITY_HASH]);
assert(!hp->dropped);
- assert(arg_certificate);
-
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
- r = sign_verity_roothash(&hp->roothash, &sig);
+ r = sign_verity_roothash(&hp->roothash, context->certificate, context->private_key, &sig);
if (r < 0)
return r;
- r = x509_fingerprint(arg_certificate, fp);
+ r = x509_fingerprint(context->certificate, fp);
if (r < 0)
return log_error_errno(r, "Unable to calculate X509 certificate fingerprint: %m");
@@ -6040,60 +6052,6 @@ static int context_mkfs(Context *context) {
return 0;
}
-static int parse_x509_certificate(const char *certificate, size_t certificate_size, X509 **ret) {
-#if HAVE_OPENSSL
- _cleanup_(X509_freep) X509 *cert = NULL;
- _cleanup_(BIO_freep) BIO *cb = NULL;
-
- assert(certificate);
- assert(certificate_size > 0);
- assert(ret);
-
- cb = BIO_new_mem_buf(certificate, certificate_size);
- if (!cb)
- return log_oom();
-
- cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
- if (!cert)
- return log_error_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;
-#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot parse X509 certificate.");
-#endif
-}
-
-static int parse_private_key(const char *key, size_t key_size, EVP_PKEY **ret) {
-#if HAVE_OPENSSL
- _cleanup_(BIO_freep) BIO *kb = NULL;
- _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
-
- assert(key);
- assert(key_size > 0);
- assert(ret);
-
- kb = BIO_new_mem_buf(key, key_size);
- if (!kb)
- return log_oom();
-
- pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
- if (!pk)
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
-
- if (ret)
- *ret = TAKE_PTR(pk);
-
- return 0;
-#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot parse private key.");
-#endif
-}
-
static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *ret) {
struct {
sd_id128_t type_uuid;
@@ -7898,9 +7856,7 @@ static int help(void) {
return 0;
}
-static int parse_argv(int argc, char *argv[]) {
- _cleanup_free_ char *private_key = NULL;
-
+static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY **ret_private_key, OpenSSLAskPasswordUI **ret_ui) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
@@ -7989,11 +7945,17 @@ static int parse_argv(int argc, char *argv[]) {
{}
};
+ _cleanup_(X509_freep) X509 *certificate = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
bool auto_hash_pcr_values = true, auto_public_key_pcr_mask = true, auto_pcrlock = true;
int c, r;
assert(argc >= 0);
assert(argv);
+ assert(ret_certificate);
+ assert(ret_private_key);
+ assert(ret_ui);
while ((c = getopt_long(argc, argv, "hs:SCP", options, NULL)) >= 0)
@@ -8153,7 +8115,7 @@ static int parse_argv(int argc, char *argv[]) {
}
case ARG_PRIVATE_KEY: {
- r = free_and_strdup_warn(&private_key, optarg);
+ r = free_and_strdup_warn(&arg_private_key, optarg);
if (r < 0)
return r;
break;
@@ -8169,20 +8131,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CERTIFICATE: {
- _cleanup_free_ char *cert = NULL;
- size_t n = 0;
-
- r = read_full_file_full(
- AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_CONNECT_SOCKET,
- NULL,
- &cert, &n);
- if (r < 0)
- return log_error_errno(r, "Failed to read certificate file '%s': %m", optarg);
-
- X509_free(arg_certificate);
- arg_certificate = NULL;
- r = parse_x509_certificate(cert, n, &arg_certificate);
+ r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_certificate);
if (r < 0)
return r;
break;
@@ -8518,39 +8467,38 @@ static int parse_argv(int argc, char *argv[]) {
*p = gpt_partition_type_override_architecture(*p, arg_architecture);
}
- if (private_key && arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
- _cleanup_(erase_and_freep) char *k = NULL;
- size_t n = 0;
-
- r = read_full_file_full(
- AT_FDCWD, private_key, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
- NULL,
- &k, &n);
+ if (arg_certificate) {
+ r = openssl_load_x509_certificate(arg_certificate, &certificate);
if (r < 0)
- return log_error_errno(r, "Failed to read key file '%s': %m", private_key);
+ return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
+ }
- r = parse_private_key(k, n, &arg_private_key);
- if (r < 0)
- return r;
- } 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(
+ if (arg_private_key) {
+ 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 r;
+ }
+
+ r = openssl_load_private_key(
arg_private_key_source_type,
arg_private_key_source,
- private_key,
- &arg_private_key);
+ arg_private_key,
+ &(AskPasswordRequest) {
+ .id = "repart-private-key-pin",
+ .keyring = arg_private_key,
+ .credential = "repart.private-key-pin",
+ },
+ &private_key,
+ &ui);
if (r < 0)
- return log_error_errno(
- r,
- "Failed to load key '%s' from OpenSSL private key source %s: %m",
- private_key,
- arg_private_key_source);
+ return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
}
+ *ret_certificate = TAKE_PTR(certificate);
+ *ret_private_key = TAKE_PTR(private_key);
+ *ret_ui = TAKE_PTR(ui);
+
return 1;
}
@@ -8587,7 +8535,7 @@ static int parse_efi_variable_factory_reset(void) {
if (!in_initrd()) /* Never honour EFI variable factory reset request outside of the initrd */
return 0;
- r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(FactoryReset), &value);
+ r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE_STR("FactoryReset"), &value);
if (r < 0) {
if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
return 0;
@@ -8608,7 +8556,7 @@ static int parse_efi_variable_factory_reset(void) {
static int remove_efi_variable_factory_reset(void) {
int r;
- r = efi_set_variable(EFI_SYSTEMD_VARIABLE(FactoryReset), NULL, 0);
+ r = efi_set_variable(EFI_SYSTEMD_VARIABLE_STR("FactoryReset"), NULL, 0);
if (r < 0) {
if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
return 0;
@@ -8967,6 +8915,9 @@ static int determine_auto_size(Context *c) {
}
static int run(int argc, char *argv[]) {
+ _cleanup_(X509_freep) X509 *certificate = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
_cleanup_(context_freep) Context* context = NULL;
@@ -8975,7 +8926,7 @@ static int run(int argc, char *argv[]) {
log_setup();
- r = parse_argv(argc, argv);
+ r = parse_argv(argc, argv, &certificate, &private_key, &ui);
if (r <= 0)
return r;
@@ -9034,10 +8985,13 @@ static int run(int argc, char *argv[]) {
return log_oom();
}
- context = context_new(arg_seed);
+ context = context_new(arg_seed, certificate, private_key);
if (!context)
return log_oom();
+ TAKE_PTR(certificate);
+ TAKE_PTR(private_key);
+
r = context_read_seed(context, arg_root);
if (r < 0)
return r;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 0c3156cd27..2e49096f82 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -44,6 +44,7 @@
#include "random-util.h"
#include "signal-util.h"
#include "socket-util.h"
+#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
@@ -54,6 +55,17 @@
#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
+static const char* keyring_table[] = {
+ [-KEY_SPEC_THREAD_KEYRING] = "thread",
+ [-KEY_SPEC_PROCESS_KEYRING] = "process",
+ [-KEY_SPEC_SESSION_KEYRING] = "session",
+ [-KEY_SPEC_USER_KEYRING] = "user",
+ [-KEY_SPEC_USER_SESSION_KEYRING] = "user-session",
+ [-KEY_SPEC_GROUP_KEYRING] = "group",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(keyring, int);
+
static int lookup_key(const char *keyname, key_serial_t *ret) {
key_serial_t serial;
@@ -115,7 +127,7 @@ static int touch_ask_password_directory(AskPasswordFlags flags) {
}
static usec_t keyring_cache_timeout(void) {
- static usec_t saved_timeout = USEC_INFINITY;
+ static usec_t saved_timeout = KEYRING_TIMEOUT_USEC;
static bool saved_timeout_set = false;
int r;
@@ -123,9 +135,7 @@ static usec_t keyring_cache_timeout(void) {
return saved_timeout;
const char *e = secure_getenv("SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC");
- if (streq_ptr(e, "default"))
- saved_timeout = KEYRING_TIMEOUT_USEC;
- else if (e) {
+ if (e) {
r = parse_sec(e, &saved_timeout);
if (r < 0)
log_debug_errno(r, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC, ignoring: %s", e);
@@ -136,6 +146,38 @@ static usec_t keyring_cache_timeout(void) {
return saved_timeout;
}
+static key_serial_t keyring_cache_type(void) {
+ static key_serial_t saved_keyring = KEY_SPEC_USER_KEYRING;
+ static bool saved_keyring_set = false;
+ int r;
+
+ if (saved_keyring_set)
+ return saved_keyring;
+
+ const char *e = secure_getenv("SYSTEMD_ASK_PASSWORD_KEYRING_TYPE");
+ if (e) {
+ key_serial_t keyring;
+
+ r = safe_atoi32(e, &keyring);
+ if (r >= 0)
+ if (keyring < 0)
+ log_debug_errno(keyring, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TYPE, ignoring: %s", e);
+ else
+ saved_keyring = keyring;
+ else {
+ keyring = keyring_from_string(e);
+ if (keyring < 0)
+ log_debug_errno(keyring, "Invalid value in $SYSTEMD_ASK_PASSWORD_KEYRING_TYPE, ignoring: %s", e);
+ else
+ saved_keyring = -keyring;
+ }
+ }
+
+ saved_keyring_set = true;
+
+ return saved_keyring;
+}
+
static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
_cleanup_strv_free_erase_ char **l = NULL;
_cleanup_(erase_and_freep) char *p = NULL;
@@ -170,7 +212,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
* have multiple passwords. */
n = LESS_BY(n, (size_t) 1);
- serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
+ serial = add_key("user", keyname, p, n, keyring_cache_type());
if (serial == -1)
return -errno;
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index 4c0195a41e..584515a297 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -1382,19 +1382,19 @@ static int boot_load_efi_entry_pointers(BootConfig *config, bool skip_efivars) {
/* Loads the three "pointers" to boot loader entries from their EFI variables */
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &config->entry_oneshot);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), &config->entry_oneshot);
if (r == -ENOMEM)
return log_oom();
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\", ignoring: %m");
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryDefault), &config->entry_default);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), &config->entry_default);
if (r == -ENOMEM)
return log_oom();
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\", ignoring: %m");
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), &config->entry_selected);
if (r == -ENOMEM)
return log_oom();
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
@@ -1560,7 +1560,7 @@ int boot_config_augment_from_loader(
break;
}
- p = strdup(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderEntries)));
+ p = strdup(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderEntries")));
if (!p)
return log_oom();
diff --git a/src/shared/efi-api.c b/src/shared/efi-api.c
index 3b9954be9b..37720f896b 100644
--- a/src/shared/efi-api.c
+++ b/src/shared/efi-api.c
@@ -79,7 +79,7 @@ int efi_reboot_to_firmware_supported(void) {
if (!is_efi_boot())
goto not_supported;
- r = efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndicationsSupported), NULL, &v, &s);
+ r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("OsIndicationsSupported"), NULL, &v, &s);
if (r == -ENOENT)
goto not_supported; /* variable doesn't exist? it's not supported then */
if (r < 0)
@@ -115,7 +115,7 @@ static int get_os_indications(uint64_t *ret) {
return r;
/* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
- if (stat(EFIVAR_PATH(EFI_GLOBAL_VARIABLE(OsIndications)), &new_stat) < 0) {
+ if (stat(EFIVAR_PATH(EFI_GLOBAL_VARIABLE_STR("OsIndications")), &new_stat) < 0) {
if (errno != ENOENT)
return -errno;
@@ -129,7 +129,7 @@ static int get_os_indications(uint64_t *ret) {
return 0;
}
- r = efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndications), NULL, &v, &s);
+ r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("OsIndications"), NULL, &v, &s);
if (r == -ENOENT) {
/* Some firmware implementations that do support OsIndications and report that with
* OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
@@ -172,7 +172,7 @@ int efi_set_reboot_to_firmware(bool value) {
/* Avoid writing to efi vars store if we can due to firmware bugs. */
if (b != b_new)
- return efi_set_variable(EFI_GLOBAL_VARIABLE(OsIndications), &b_new, sizeof(uint64_t));
+ return efi_set_variable(EFI_GLOBAL_VARIABLE_STR("OsIndications"), &b_new, sizeof(uint64_t));
return 0;
}
@@ -399,7 +399,7 @@ int efi_get_boot_order(uint16_t **ret_order) {
if (!is_efi_boot())
return -EOPNOTSUPP;
- r = efi_get_variable(EFI_GLOBAL_VARIABLE(BootOrder), NULL, &buf, &l);
+ r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("BootOrder"), NULL, &buf, &l);
if (r < 0)
return r;
@@ -419,7 +419,7 @@ int efi_set_boot_order(const uint16_t *order, size_t n) {
if (!is_efi_boot())
return -EOPNOTSUPP;
- return efi_set_variable(EFI_GLOBAL_VARIABLE(BootOrder), order, n * sizeof(uint16_t));
+ return efi_set_variable(EFI_GLOBAL_VARIABLE_STR("BootOrder"), order, n * sizeof(uint16_t));
}
static int boot_id_hex(const char s[static 4]) {
diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c
index ae0b2b1fdc..3eddc49bf9 100644
--- a/src/shared/efi-loader.c
+++ b/src/shared/efi-loader.c
@@ -43,11 +43,11 @@ int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
if (!is_efi_boot())
return -EOPNOTSUPP;
- r = read_usec(EFI_LOADER_VARIABLE(LoaderTimeInitUSec), &x);
+ r = read_usec(EFI_LOADER_VARIABLE_STR("LoaderTimeInitUSec"), &x);
if (r < 0)
return log_debug_errno(r, "Failed to read LoaderTimeInitUSec: %m");
- r = read_usec(EFI_LOADER_VARIABLE(LoaderTimeExecUSec), &y);
+ r = read_usec(EFI_LOADER_VARIABLE_STR("LoaderTimeExecUSec"), &y);
if (r < 0)
return log_debug_errno(r, "Failed to read LoaderTimeExecUSec: %m");
@@ -69,11 +69,11 @@ static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
}
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
- return get_device_part_uuid(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), ret);
+ return get_device_part_uuid(EFI_LOADER_VARIABLE_STR("LoaderDevicePartUUID"), ret);
}
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
- return get_device_part_uuid(EFI_LOADER_VARIABLE(StubDevicePartUUID), ret);
+ return get_device_part_uuid(EFI_LOADER_VARIABLE_STR("StubDevicePartUUID"), ret);
}
int efi_loader_get_entries(char ***ret) {
@@ -87,7 +87,7 @@ int efi_loader_get_entries(char ***ret) {
if (!is_efi_boot())
return -EOPNOTSUPP;
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntries), NULL, (void**) &entries, &size);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntries"), NULL, (void**) &entries, &size);
if (r < 0)
return r;
@@ -148,12 +148,12 @@ int efi_loader_get_features(uint64_t *ret) {
return 0;
}
- r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderFeatures), NULL, &v, &s);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderFeatures"), NULL, &v, &s);
if (r == -ENOENT) {
_cleanup_free_ char *info = NULL;
/* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderInfo), &info);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderInfo"), &info);
if (r < 0) {
if (r != -ENOENT)
return r;
@@ -199,12 +199,12 @@ int efi_stub_get_features(uint64_t *ret) {
return 0;
}
- r = efi_get_variable(EFI_LOADER_VARIABLE(StubFeatures), NULL, &v, &s);
+ r = efi_get_variable(EFI_LOADER_VARIABLE_STR("StubFeatures"), NULL, &v, &s);
if (r == -ENOENT) {
_cleanup_free_ char *info = NULL;
/* The new (v252+) StubFeatures variable is not supported, let's see if it's systemd-stub at all */
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(StubInfo), &info);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("StubInfo"), &info);
if (r < 0) {
if (r != -ENOENT)
return r;
@@ -261,7 +261,7 @@ int efi_measured_uki(int log_level) {
if (!efi_has_tpm2())
return (cached = 0);
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(StubPcrKernelImage), &pcr_string);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("StubPcrKernelImage"), &pcr_string);
if (r == -ENOENT)
return (cached = 0);
if (r < 0)
@@ -291,7 +291,7 @@ int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
assert(ret);
/* stat() the EFI variable, to see if the mtime changed. If it did, we need to cache again. */
- if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot)), &new_stat) < 0)
+ if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot")), &new_stat) < 0)
return -errno;
if (stat_inode_unmodified(&new_stat, &cache_stat)) {
@@ -299,7 +299,7 @@ int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
return 0;
}
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot), &v);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot"), &v);
if (r < 0)
return r;
@@ -323,13 +323,13 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat
assert(cache_stat);
/* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
- if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderEntryOneShot)), &new_stat) < 0)
+ if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot")), &new_stat) < 0)
return -errno;
if (stat_inode_unmodified(&new_stat, cache_stat))
return 0;
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &v);
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), &v);
if (r < 0)
return r;
diff --git a/src/shared/hibernate-util.c b/src/shared/hibernate-util.c
index 7c21157580..1213fdc2c7 100644
--- a/src/shared/hibernate-util.c
+++ b/src/shared/hibernate-util.c
@@ -527,7 +527,7 @@ int clear_efi_hibernate_location_and_warn(void) {
if (!is_efi_boot())
return 0;
- r = efi_set_variable(EFI_SYSTEMD_VARIABLE(HibernateLocation), NULL, 0);
+ r = efi_set_variable(EFI_SYSTEMD_VARIABLE_STR("HibernateLocation"), NULL, 0);
if (r == -ENOENT)
return 0;
if (r < 0)
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
index 2ab89c7639..818f4a5f19 100644
--- a/src/shared/openssl-util.c
+++ b/src/shared/openssl-util.c
@@ -3,12 +3,15 @@
#include
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "fd-util.h"
+#include "fileio.h"
#include "hexdecoct.h"
#include "memory-util.h"
#include "openssl-util.h"
#include "random-util.h"
#include "string-util.h"
+#include "strv.h"
#if HAVE_OPENSSL
# include
@@ -1309,10 +1312,15 @@ int pkey_generate_volume_keys(
}
}
-static int load_key_from_provider(const char *provider, const char *private_key_uri, EVP_PKEY **ret) {
+static int load_key_from_provider(
+ const char *provider,
+ const char *private_key_uri,
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret) {
assert(provider);
assert(private_key_uri);
+ assert(ui);
assert(ret);
#if OPENSSL_VERSION_MAJOR >= 3
@@ -1325,8 +1333,8 @@ static int load_key_from_provider(const char *provider, const char *private_key_
_cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
private_key_uri,
- /* ui_method= */ NULL,
- /* ui_data= */ NULL,
+ ui->method,
+ &ui->request,
/* post_process= */ NULL,
/* post_process_data= */ NULL);
if (!store)
@@ -1348,10 +1356,10 @@ static int load_key_from_provider(const char *provider, const char *private_key_
#endif
}
-static int load_key_from_engine(const char *engine, const char *private_key_uri, EVP_PKEY **ret) {
-
+static int load_key_from_engine(const char *engine, const char *private_key_uri, OpenSSLAskPasswordUI *ui, EVP_PKEY **ret) {
assert(engine);
assert(private_key_uri);
+ assert(ui);
assert(ret);
#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
@@ -1363,11 +1371,13 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
if (ENGINE_init(e) == 0)
return log_openssl_errors("Failed to initialize signing engine '%s'", engine);
- _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(
- e,
- private_key_uri,
- /* ui_method= */ NULL,
- /* callback_data= */ NULL);
+ if (ENGINE_ctrl(e, ENGINE_CTRL_SET_USER_INTERFACE, /*i=*/ 0, ui->method, /*f=*/ NULL) <= 0)
+ return log_openssl_errors("Failed to set engine user interface");
+
+ if (ENGINE_ctrl(e, ENGINE_CTRL_SET_CALLBACK_DATA, /*i=*/ 0, &ui->request, /*f=*/ NULL) <= 0)
+ return log_openssl_errors("Failed to set engine user interface data");
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(e, private_key_uri, ui->method, &ui->request);
if (!private_key)
return log_openssl_errors("Failed to load private key from '%s'", private_key_uri);
REENABLE_WARNING;
@@ -1384,24 +1394,88 @@ int openssl_load_key_from_token(
KeySourceType private_key_source_type,
const char *private_key_source,
const char *private_key,
- EVP_PKEY **ret) {
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret_private_key) {
assert(IN_SET(private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER));
assert(private_key_source);
+ assert(ui);
assert(private_key);
switch (private_key_source_type) {
case OPENSSL_KEY_SOURCE_ENGINE:
- return load_key_from_engine(private_key_source, private_key, ret);
+ return load_key_from_engine(private_key_source, private_key, ui, ret_private_key);
case OPENSSL_KEY_SOURCE_PROVIDER:
- return load_key_from_provider(private_key_source, private_key, ret);
+ return load_key_from_provider(private_key_source, private_key, ui, ret_private_key);
default:
assert_not_reached();
}
}
+
+static int openssl_ask_password_ui_read(UI *ui, UI_STRING *uis) {
+ int r;
+
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT: {
+ /* If no ask password request was configured use the default openssl UI. */
+ AskPasswordRequest *req = UI_get0_user_data(ui);
+ if (!req)
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+
+ req->message = UI_get0_output_string(uis);
+
+ _cleanup_(strv_freep) char **l = NULL;
+ r = ask_password_auto(req, /*until=*/ 0, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &l);
+ if (r < 0) {
+ log_error_errno(r, "Failed to query for PIN: %m");
+ return 0;
+ }
+
+ if (strv_length(l) != 1) {
+ log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected only a single password/pin.");
+ return 0;
+ }
+
+ if (UI_set_result(ui, uis, *l) != 0) {
+ log_openssl_errors("Failed to set user interface result");
+ return 0;
+ }
+
+ return 1;
+ }
+ default:
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+ }
+}
#endif
+int openssl_ask_password_ui_new(OpenSSLAskPasswordUI **ret) {
+#if HAVE_OPENSSL
+ assert(ret);
+
+ _cleanup_(UI_destroy_methodp) UI_METHOD *method = UI_create_method("systemd-ask-password");
+ if (!method)
+ return log_openssl_errors("Failed to initialize openssl user interface");
+
+ if (UI_method_set_reader(method, openssl_ask_password_ui_read) != 0)
+ return log_openssl_errors("Failed to set openssl user interface reader");
+
+ OpenSSLAskPasswordUI *ui = new(OpenSSLAskPasswordUI, 1);
+ if (!ui)
+ return log_oom_debug();
+
+ *ui = (OpenSSLAskPasswordUI) {
+ .method = TAKE_PTR(method),
+ };
+
+ *ret = TAKE_PTR(ui);
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot create ask-password user interface.");
+#endif
+}
+
int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
#if HAVE_OPENSSL
_cleanup_free_ uint8_t *der = NULL;
@@ -1420,6 +1494,126 @@ int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
#endif
}
+int openssl_load_x509_certificate(const char *path, 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);
+
+ 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;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load X509 certificate.");
+#endif
+}
+
+static int openssl_load_private_key_from_file(const char *path, EVP_PKEY **ret) {
+#if HAVE_OPENSSL
+ _cleanup_(erase_and_freep) char *rawkey = NULL;
+ _cleanup_(BIO_freep) BIO *kb = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
+ size_t rawkeysz;
+ int r;
+
+ assert(path);
+ assert(ret);
+
+ r = read_full_file_full(
+ AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
+ READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+ NULL,
+ &rawkey, &rawkeysz);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to read key file '%s': %m", path);
+
+ kb = BIO_new_mem_buf(rawkey, rawkeysz);
+ if (!kb)
+ return log_oom_debug();
+
+ pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
+ if (!pk)
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ if (ret)
+ *ret = TAKE_PTR(pk);
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load private key.");
+#endif
+}
+
+int openssl_load_private_key(
+ KeySourceType private_key_source_type,
+ const char *private_key_source,
+ const char *private_key,
+ const AskPasswordRequest *request,
+ EVP_PKEY **ret_private_key,
+ OpenSSLAskPasswordUI **ret_user_interface) {
+
+ int r;
+
+ assert(private_key);
+ assert(request);
+
+ if (private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
+ r = openssl_load_private_key_from_file(private_key, ret_private_key);
+ if (r < 0)
+ return r;
+
+ *ret_user_interface = NULL;
+ } else {
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ r = openssl_ask_password_ui_new(&ui);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to allocate ask-password user interface: %m");
+
+ ui->request = *request;
+
+ r = openssl_load_key_from_token(
+ private_key_source_type,
+ private_key_source,
+ private_key,
+ ui,
+ ret_private_key);
+ if (r < 0)
+ return log_debug_errno(
+ r,
+ "Failed to load key '%s' from OpenSSL private key source %s: %m",
+ private_key,
+ private_key_source);
+
+ *ret_user_interface = TAKE_PTR(ui);
+ }
+
+ return 0;
+}
+
int parse_openssl_key_source_argument(
const char *argument,
char **private_key_source,
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
index 1a89fcc2bd..c9acd40f22 100644
--- a/src/shared/openssl-util.h
+++ b/src/shared/openssl-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "ask-password-api.h"
#include "iovec-util.h"
#include "macro.h"
#include "sha256.h"
@@ -13,6 +14,8 @@ typedef enum KeySourceType {
_OPENSSL_KEY_SOURCE_INVALID = -EINVAL,
} KeySourceType;
+typedef struct OpenSSLAskPasswordUI OpenSSLAskPasswordUI;
+
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
@@ -26,6 +29,7 @@ int parse_openssl_key_source_argument(const char *argument, char **private_key_s
# include
# include
# include
+# include
# include
# ifndef OPENSSL_VERSION_MAJOR
/* OPENSSL_VERSION_MAJOR macro was added in OpenSSL 3. Thus, if it doesn't exist, we must be before OpenSSL 3. */
@@ -130,12 +134,13 @@ 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(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, EVP_PKEY **ret);
+int openssl_load_key_from_token(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, OpenSSLAskPasswordUI *ui, EVP_PKEY **ret_private_key);
#else
typedef struct X509 X509;
typedef struct EVP_PKEY EVP_PKEY;
+typedef struct UI_METHOD UI_METHOD;
static inline void *X509_free(X509 *p) {
assert(p == NULL);
@@ -147,11 +152,17 @@ static inline void *EVP_PKEY_free(EVP_PKEY *p) {
return NULL;
}
+static inline void* UI_destroy_method(UI_METHOD *p) {
+ assert(p == NULL);
+ return NULL;
+}
+
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) {
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret_private_key) {
return -EOPNOTSUPP;
}
@@ -160,9 +171,37 @@ static inline int openssl_load_key_from_token(
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY*, EVP_PKEY_free, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UI_METHOD*, UI_destroy_method, NULL);
+
+struct OpenSSLAskPasswordUI {
+ AskPasswordRequest request;
+ UI_METHOD *method;
+};
+
+int openssl_ask_password_ui_new(OpenSSLAskPasswordUI **ret);
+
+static inline OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
+ if (!ui)
+ return NULL;
+
+ UI_destroy_method(ui->method);
+ return mfree(ui);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OpenSSLAskPasswordUI*, openssl_ask_password_ui_free, NULL);
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_private_key(
+ KeySourceType private_key_source_type,
+ const char *private_key_source,
+ const char *private_key,
+ const AskPasswordRequest *request,
+ EVP_PKEY **ret_private_key,
+ OpenSSLAskPasswordUI **ret_user_interface);
+
#if PREFER_OPENSSL
/* The openssl definition */
typedef const EVP_MD* hash_md_t;
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 3f113fff74..181bb4ccef 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -114,7 +114,7 @@ static int write_efi_hibernate_location(const HibernationDevice *hibernation_dev
if (r < 0)
return log_full_errno(log_level, r, "Failed to format JSON object: %m");
- r = efi_set_variable_string(EFI_SYSTEMD_VARIABLE(HibernateLocation), formatted);
+ r = efi_set_variable_string(EFI_SYSTEMD_VARIABLE_STR("HibernateLocation"), formatted);
if (r < 0)
return log_full_errno(log_level, r, "Failed to set EFI variable HibernateLocation: %m");
diff --git a/test/TEST-74-AUX-UTILS/test.sh b/test/TEST-74-AUX-UTILS/test.sh
index b10965040a..e90c55c28d 100755
--- a/test/TEST-74-AUX-UTILS/test.sh
+++ b/test/TEST-74-AUX-UTILS/test.sh
@@ -38,6 +38,7 @@ test_append_files() {
instmods vmw_vsock_vmci_transport
inst_binary gcc
generate_module_dependencies
+ inst_binary openssl
}
do_test "$@"
diff --git a/test/units/TEST-74-AUX-UTILS.bootctl.sh b/test/units/TEST-74-AUX-UTILS.bootctl.sh
index 1767f1fc89..46fd5d1f2d 100755
--- a/test/units/TEST-74-AUX-UTILS.bootctl.sh
+++ b/test/units/TEST-74-AUX-UTILS.bootctl.sh
@@ -276,4 +276,31 @@ testcase_bootctl_varlink() {
SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.SetRebootToFirmware '{"state":false}' --graceful=io.systemd.BootControl.RebootToFirmwareNotSupported
}
+testcase_bootctl_secure_boot_auto_enroll() {
+ cat >/tmp/openssl.conf <