102 lines
3.5 KiB
C
102 lines
3.5 KiB
C
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||
|
|
||
|
#include "cryptenroll-recovery.h"
|
||
|
#include "json.h"
|
||
|
#include "locale-util.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_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;
|
||
|
}
|