diff options
author | Lennart Poettering <lennart@poettering.net> | 2020-04-29 19:41:02 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2020-05-19 17:28:40 +0200 |
commit | 0ba6f85ed3227ca15bde84890d4d9381c133f978 (patch) | |
tree | 12d79b4dedc46948c56f8918ec088c52e4206d93 /src/cryptsetup | |
parent | 2424fb7e7bdfe3d4158bbfe14a56e2f0159a69ec (diff) | |
download | systemd-0ba6f85ed3227ca15bde84890d4d9381c133f978.tar.gz |
cryptsetup: optionally, see if empty password works for unlocking the file system
This adds a new switch try-empty-password. If set and none of PKCS#11 or
key files work, it is attempted to unlock the volume with an empty
password, before the user is asked for a password.
Usecase: an installer generates an OS image on one system, which is the
booted up for the first time in a possibly different system. The image
is encrypted using a random volume key, but an empty password. A tool
that runs on first boot then queries the user for a password to set or
enrols the volume in the TPM, removing the empty password. (Of course, in
such a scenario it is important to never reuse the installer image on
multiple systems as they all will have the same volume key, but that's a
different question.)
Diffstat (limited to 'src/cryptsetup')
-rw-r--r-- | src/cryptsetup/cryptsetup.c | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 617304c280..f07fd986d9 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -46,6 +46,7 @@ static int arg_key_slot = CRYPT_ANY_SLOT; static unsigned arg_keyfile_size = 0; static uint64_t arg_keyfile_offset = 0; static bool arg_keyfile_erase = false; +static bool arg_try_empty_password = false; static char *arg_hash = NULL; static char *arg_header = NULL; static unsigned arg_tries = 3; @@ -262,7 +263,20 @@ static int parse_one_option(const char *option) { if (r < 0) return log_oom(); - } else if (!streq(option, "x-initrd.attach")) + } else if ((val = startswith(option, "try-empty-password="))) { + + r = parse_boolean(val); + if (r < 0) { + log_error_errno(r, "Failed to parse %s, ignoring: %m", option); + return 0; + } + + arg_try_empty_password = r; + + } else if (streq(option, "try-empty-password")) + arg_try_empty_password = true; + + else if (!streq(option, "x-initrd.attach")) log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option); return 0; @@ -939,12 +953,36 @@ static int run(int argc, char *argv[]) { for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { _cleanup_strv_free_erase_ char **passwords = NULL; + /* When we were able to acquire multiple keys, let's always process them in this order: + * + * 1. A key acquired via PKCS#11 token + * 2. The discovered key: i.e. key_data + key_data_size + * 3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size + * 4. The empty password, in case arg_try_empty_password is set + * 5. We enquire the user for a password + */ + if (!key_file && !key_data && !arg_pkcs11_uri) { - r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); - if (r == -EAGAIN) - continue; - if (r < 0) - return r; + + if (arg_try_empty_password) { + /* Hmm, let's try an empty password now, but only once */ + arg_try_empty_password = false; + + key_data = strdup(""); + if (!key_data) + return log_oom(); + + key_data_size = 0; + } else { + /* Ask the user for a passphrase only as last resort, if we have + * nothing else to check for */ + + r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); + if (r == -EAGAIN) + continue; + if (r < 0) + return r; + } } if (streq_ptr(arg_type, CRYPT_TCRYPT)) |