summaryrefslogtreecommitdiff
path: root/src/cryptsetup
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-04-29 19:41:02 +0200
committerLennart Poettering <lennart@poettering.net>2020-05-19 17:28:40 +0200
commit0ba6f85ed3227ca15bde84890d4d9381c133f978 (patch)
tree12d79b4dedc46948c56f8918ec088c52e4206d93 /src/cryptsetup
parent2424fb7e7bdfe3d4158bbfe14a56e2f0159a69ec (diff)
downloadsystemd-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.c50
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))