From 9569d721829bc2655b672c15756d31867741eda4 Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Tue, 8 Sep 2026 11:58:41 +0200 Subject: [PATCH] cryptenroll-varlink: Add method to generate a recovery-key We want users to use a recovery-key generated by systemd. Therefore expose a method that let's clients generate a key that can be given to the Enroll method. This way the key can be displayed before enrolling it. --- src/cryptenroll/cryptenroll-varlink.c | 36 +++++++++++++++++++-- src/shared/varlink-io.systemd.CryptEnroll.c | 9 +++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/cryptenroll/cryptenroll-varlink.c b/src/cryptenroll/cryptenroll-varlink.c index 366845569e..d744d2cf74 100644 --- a/src/cryptenroll/cryptenroll-varlink.c +++ b/src/cryptenroll/cryptenroll-varlink.c @@ -15,6 +15,7 @@ #include "json-util.h" #include "libfido2-util.h" #include "path-util.h" +#include "recovery-key.h" #include "string-util.h" #include "varlink-io.systemd.CryptEnroll.h" #include "varlink-util.h" @@ -467,6 +468,36 @@ static int vl_method_list_slots( return sd_varlink_reply(link, NULL); } +static int vl_method_make_recovery_key( + sd_varlink *link, + sd_json_variant *parameters, + sd_varlink_method_flags_t flags, + void *userdata) { + + _cleanup_(erase_and_freep) char *recovery_key = NULL; + _cleanup_(sd_json_variant_unrefp) sd_json_variant *rk = NULL; + int r; + + assert(link); + assert(parameters); + + r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); + if (r != 0) + return r; + + r = make_recovery_key(&recovery_key); + if (r < 0) + return r; + + r = sd_json_variant_new_string(&rk, recovery_key); + if (r < 0) + return r; + + sd_json_variant_sensitive(rk); + + return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("recoveryKey", rk)); +} + int cryptenroll_varlink_server(void) { _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL; _cleanup_hashmap_free_ Hashmap *polkit_registry = NULL; @@ -485,8 +516,9 @@ int cryptenroll_varlink_server(void) { r = sd_varlink_server_bind_method_many( varlink_server, - "io.systemd.CryptEnroll.Enroll", vl_method_enroll, - "io.systemd.CryptEnroll.ListSlots", vl_method_list_slots); + "io.systemd.CryptEnroll.Enroll", vl_method_enroll, + "io.systemd.CryptEnroll.ListSlots", vl_method_list_slots, + "io.systemd.CryptEnroll.MakeRecoveryKey", vl_method_make_recovery_key); if (r < 0) return log_error_errno(r, "Failed to bind Varlink methods: %m"); diff --git a/src/shared/varlink-io.systemd.CryptEnroll.c b/src/shared/varlink-io.systemd.CryptEnroll.c index 5ff9110437..391861b0e8 100644 --- a/src/shared/varlink-io.systemd.CryptEnroll.c +++ b/src/shared/varlink-io.systemd.CryptEnroll.c @@ -42,7 +42,7 @@ static SD_VARLINK_DEFINE_METHOD_FULL( SD_VARLINK_FIELD_COMMENT("The passphrase to enroll, when mechanism is 'password'. Contains key material."), SD_VARLINK_DEFINE_INPUT(password, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), - SD_VARLINK_FIELD_COMMENT("A recovery key to enroll, when mechanism is 'recovery'. The key must be in the normalized form and have high entropy. Contains key material."), + SD_VARLINK_FIELD_COMMENT("A recovery key to enroll, when mechanism is 'recovery'. The key must be in the normalized form and have high entropy. Use MakeRecoveryKey() to generate the recovery key. Contains key material."), SD_VARLINK_DEFINE_INPUT(recoveryKey, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Path to the FIDO2 device to enroll, when mechanism is 'fido2'. Leave empty to automatically discover a suitable device."), @@ -82,6 +82,11 @@ static SD_VARLINK_DEFINE_METHOD_FULL( SD_VARLINK_FIELD_COMMENT("The type of the keyslot."), SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(type, EnrollMechanism, SD_VARLINK_NULLABLE)); +static SD_VARLINK_DEFINE_METHOD( + MakeRecoveryKey, + SD_VARLINK_FIELD_COMMENT("The generated recovery key."), + SD_VARLINK_DEFINE_OUTPUT(recoveryKey, SD_VARLINK_STRING, 0)); + static SD_VARLINK_DEFINE_ERROR(VolumeUnderForeignManagement); static SD_VARLINK_DEFINE_ERROR(PasswordRequired); static SD_VARLINK_DEFINE_ERROR(PasswordIncorrect); @@ -98,6 +103,8 @@ SD_VARLINK_DEFINE_INTERFACE( &vl_method_Enroll, SD_VARLINK_SYMBOL_COMMENT("Enumerate the keyslots currently enrolled in a LUKS2 volume, one per reply. Must be called with the 'more' flag."), &vl_method_ListSlots, + SD_VARLINK_SYMBOL_COMMENT("Generate a recovery key that can be enrolled using the 'recovery' mechanism in Enroll()."), + &vl_method_MakeRecoveryKey, SD_VARLINK_SYMBOL_COMMENT("The volume is managed by another subsystem (e.g. systemd-homed) and may not be enrolled into directly."), &vl_error_VolumeUnderForeignManagement, SD_VARLINK_SYMBOL_COMMENT("A password is required to unlock the volume, but none was provided."),