From 2e4beb875bcb24e7d7d4339cc202b0b3f2953f71 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 27 May 2019 09:27:54 +0200 Subject: [PATCH 1/3] cryptsetup: Do not fallback to PLAIN mapping if LUKS data device set fails. If crypt_load() for LUKS succeeds, we know that it is a LUKS device. Failure of data device setting should fail in this case; remapping as a PLAIN device late could mean data corruption. (If a user wants to map PLAIN device over a device with LUKS header, it should be said explicitly with "plain" argument type.) Also, if there is no explicit PLAIN type requested and crypt device is already initialized (crypt_data_type() is set), do not run the initialization again. --- src/cryptsetup/cryptsetup.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 864d6ff472..bf523fe50d 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -502,11 +502,14 @@ static int attach_luks_or_plain(struct crypt_device *cd, if (r < 0) return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); - if (data_device) + if (data_device) { r = crypt_set_data_device(cd, data_device); + if (r < 0) + return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device); + } } - if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) { + if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) { struct crypt_params_plain params = { .offset = arg_offset, .skip = arg_skip, @@ -547,12 +550,12 @@ static int attach_luks_or_plain(struct crypt_device *cd, /* In contrast to what the name crypt_setup() might suggest this doesn't actually format * anything, it just configures encryption parameters when used for plain mode. */ r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, ¶ms); + if (r < 0) + return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); /* hash == NULL implies the user passed "plain" */ pass_volume_key = (params.hash == NULL); } - if (r < 0) - return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); log_info("Set cipher %s, mode %s, key size %i bits for device %s.", crypt_get_cipher(cd), From ea9a9d49e4af31c49e5c216e7e5e2f533e727579 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 27 May 2019 09:43:03 +0200 Subject: [PATCH 2/3] cryptsetup: call crypt_load() for LUKS only once The crypt_load() for LUKS2 can read a quite big area of disk (metadata area size is configurable and can increase up to megabytes). This initialization is not needed to be repeated, just use the existing context. (This patch is also required for the following change.) --- src/cryptsetup/cryptsetup.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index bf523fe50d..1f891764b6 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -487,7 +487,6 @@ static int attach_tcrypt( static int attach_luks_or_plain(struct crypt_device *cd, const char *name, const char *key_file, - const char *data_device, char **passwords, uint32_t flags) { int r = 0; @@ -497,18 +496,6 @@ static int attach_luks_or_plain(struct crypt_device *cd, assert(name); assert(key_file || passwords); - if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) { - r = crypt_load(cd, CRYPT_LUKS, NULL); - if (r < 0) - return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); - - if (data_device) { - r = crypt_set_data_device(cd, data_device); - if (r < 0) - return log_error_errno(r, "Failed to set LUKS data device %s: %m", data_device); - } - } - if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) { struct crypt_params_plain params = { .offset = arg_offset, @@ -718,6 +705,18 @@ static int run(int argc, char *argv[]) { log_warning("Key file %s is world-readable. This is not a good idea!", key_file); } + if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) { + r = crypt_load(cd, CRYPT_LUKS, NULL); + if (r < 0) + return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); + + if (arg_header) { + r = crypt_set_data_device(cd, argv[3]); + if (r < 0) + return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]); + } + } + for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { _cleanup_strv_free_erase_ char **passwords = NULL; @@ -735,7 +734,6 @@ static int run(int argc, char *argv[]) { r = attach_luks_or_plain(cd, argv[2], key_file, - arg_header ? argv[3] : NULL, passwords, flags); if (r >= 0) From 894bb3ca4c730cc9e9d46ef5004ba4ca5e201d8d Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 27 May 2019 09:44:14 +0200 Subject: [PATCH 3/3] cryptsetup: Add LUKS2 token support. LUKS2 supports so-called tokens. The libcryptsetup internally support keyring token (it tries to open device using specified keyring entry). Only if all token fails (or are not available), it uses a passphrase. This patch aligns the functionality with the cryptsetup utility (cryptsetup luksOpen tries tokens first) but does not replace the systemd native ask-password function (can be used the same in combination with this patch). --- src/cryptsetup/cryptsetup.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 1f891764b6..af95b41816 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -715,6 +715,18 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]); } +#ifdef CRYPT_ANY_TOKEN + /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */ + if (!key_file) { + r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags); + if (r >= 0) { + log_debug("Volume %s activated with LUKS token id %i.", argv[2], r); + return 0; + } + + log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd)); + } +#endif } for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {