| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #include "cryptenroll-recovery.h" |
| #include "glyph-util.h" |
| #include "json.h" |
| #include "memory-util.h" |
| #include "qrcode-util.h" |
| #include "recovery-key.h" |
| #include "terminal-util.h" |
| |
| int enroll_recovery( |
| struct crypt_device *cd, |
| const void *volume_key, |
| size_t volume_key_size) { |
| |
| _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; |
| _cleanup_(erase_and_freep) char *password = NULL; |
| _cleanup_free_ char *keyslot_as_string = NULL; |
| int keyslot, r, q; |
| const char *node; |
| |
| assert_se(cd); |
| assert_se(volume_key); |
| assert_se(volume_key_size > 0); |
| |
| assert_se(node = crypt_get_device_name(cd)); |
| |
| r = make_recovery_key(&password); |
| if (r < 0) |
| return log_error_errno(r, "Failed to generate recovery key: %m"); |
| |
| r = cryptsetup_set_minimal_pbkdf(cd); |
| if (r < 0) |
| return log_error_errno(r, "Failed to set minimal PBKDF: %m"); |
| |
| keyslot = crypt_keyslot_add_by_volume_key( |
| cd, |
| CRYPT_ANY_SLOT, |
| volume_key, |
| volume_key_size, |
| password, |
| strlen(password)); |
| if (keyslot < 0) |
| return log_error_errno(keyslot, "Failed to add new recovery key to %s: %m", node); |
| |
| fflush(stdout); |
| fprintf(stderr, |
| "A secret recovery key has been generated for this volume:\n\n" |
| " %s%s%s", |
| emoji_enabled() ? special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY) : "", |
| emoji_enabled() ? " " : "", |
| ansi_highlight()); |
| fflush(stderr); |
| |
| fputs(password, stdout); |
| fflush(stdout); |
| |
| fputs(ansi_normal(), stderr); |
| fflush(stderr); |
| |
| fputc('\n', stdout); |
| fflush(stdout); |
| |
| fputs("\nPlease save this secret recovery key at a secure location. It may be used to\n" |
| "regain access to the volume if the other configured access credentials have\n" |
| "been lost or forgotten. The recovery key may be entered in place of a password\n" |
| "whenever authentication is requested.\n", stderr); |
| fflush(stderr); |
| |
| (void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password); |
| |
| if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) { |
| r = log_oom(); |
| goto rollback; |
| } |
| |
| r = json_build(&v, |
| JSON_BUILD_OBJECT( |
| JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-recovery")), |
| JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))))); |
| if (r < 0) { |
| log_error_errno(r, "Failed to prepare recovery key JSON token object: %m"); |
| goto rollback; |
| } |
| |
| r = cryptsetup_add_token_json(cd, v); |
| if (r < 0) { |
| log_error_errno(r, "Failed to add recovery JSON token to LUKS2 header: %m"); |
| goto rollback; |
| } |
| |
| log_info("New recovery key enrolled as key slot %i.", keyslot); |
| return keyslot; |
| |
| rollback: |
| q = crypt_keyslot_destroy(cd, keyslot); |
| if (q < 0) |
| log_debug_errno(q, "Unable to remove key slot we just added again, can't rollback, sorry: %m"); |
| |
| return r; |
| } |