Skip to content

Commit 7407f68

Browse files
committed
cryptsetup: automatically load luks keys off disk
Let's make loading of keys a bit more automatic and define a common place where key files can be placed. Specifically, whenever a volume of name "foo" is attempted, search for a key file in /etc/cryptsetup-keys.d/foo.key and /run/cryptsetup-keys.d/foo.key, unless a key file is declared explicitly. With this scheme we have a simple discovery in place that should make it more straightfoward wher to place keys, and requires no explicit configuration to be used.
1 parent 23769fb commit 7407f68

File tree

3 files changed

+102
-28
lines changed

3 files changed

+102
-28
lines changed

src/cryptsetup/cryptsetup-pkcs11.c

+20-6
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ struct pkcs11_callback_data {
2727
size_t encrypted_key_size;
2828
void *decrypted_key;
2929
size_t decrypted_key_size;
30+
bool free_encrypted_key;
3031
};
3132

3233
static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
3334
free(data->decrypted_key);
34-
free(data->encrypted_key);
35+
36+
if (data->free_encrypted_key)
37+
free(data->encrypted_key);
3538
}
3639

3740
static int pkcs11_callback(
@@ -94,9 +97,11 @@ static int pkcs11_callback(
9497
int decrypt_pkcs11_key(
9598
const char *friendly_name,
9699
const char *pkcs11_uri,
97-
const char *key_file,
100+
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
98101
size_t key_file_size,
99102
uint64_t key_file_offset,
103+
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
104+
size_t key_data_size,
100105
usec_t until,
101106
void **ret_decrypted_key,
102107
size_t *ret_decrypted_key_size) {
@@ -109,15 +114,24 @@ int decrypt_pkcs11_key(
109114

110115
assert(friendly_name);
111116
assert(pkcs11_uri);
112-
assert(key_file);
117+
assert(key_file || key_data);
113118
assert(ret_decrypted_key);
114119
assert(ret_decrypted_key_size);
115120

116121
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
117122

118-
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
119-
if (r < 0)
120-
return r;
123+
if (key_data) {
124+
data.encrypted_key = (void*) key_data;
125+
data.encrypted_key_size = key_data_size;
126+
127+
data.free_encrypted_key = false;
128+
} else {
129+
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
130+
if (r < 0)
131+
return r;
132+
133+
data.free_encrypted_key = true;
134+
}
121135

122136
r = pkcs11_find_token(pkcs11_uri, pkcs11_callback, &data);
123137
if (r < 0)

src/cryptsetup/cryptsetup-pkcs11.h

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ int decrypt_pkcs11_key(
1414
const char *key_file,
1515
size_t key_file_size,
1616
uint64_t key_file_offset,
17+
const void *key_data,
18+
size_t key_data_size,
1719
usec_t until,
1820
void **ret_decrypted_key,
1921
size_t *ret_decrypted_key_size);
@@ -26,6 +28,8 @@ static inline int decrypt_pkcs11_key(
2628
const char *key_file,
2729
size_t key_file_size,
2830
uint64_t key_file_offset,
31+
const void *key_data,
32+
size_t key_data_size,
2933
usec_t until,
3034
void **ret_decrypted_key,
3135
size_t *ret_decrypted_key_size) {

src/cryptsetup/cryptsetup.c

+78-22
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "ask-password-api.h"
1414
#include "crypt-util.h"
1515
#include "cryptsetup-pkcs11.h"
16+
#include "cryptsetup-util.h"
1617
#include "device-util.h"
1718
#include "escape.h"
1819
#include "fileio.h"
@@ -21,6 +22,7 @@
2122
#include "hexdecoct.h"
2223
#include "log.h"
2324
#include "main-func.h"
25+
#include "memory-util.h"
2426
#include "mount-util.h"
2527
#include "nulstr-util.h"
2628
#include "parse-util.h"
@@ -458,6 +460,8 @@ static int attach_tcrypt(
458460
struct crypt_device *cd,
459461
const char *name,
460462
const char *key_file,
463+
const void *key_data,
464+
size_t key_data_size,
461465
char **passwords,
462466
uint32_t flags) {
463467

@@ -471,7 +475,7 @@ static int attach_tcrypt(
471475

472476
assert(cd);
473477
assert(name);
474-
assert(key_file || (passwords && passwords[0]));
478+
assert(key_file || key_data || !strv_isempty(passwords));
475479

476480
if (arg_pkcs11_uri)
477481
/* Ask for a regular password */
@@ -487,23 +491,36 @@ static int attach_tcrypt(
487491
if (arg_tcrypt_veracrypt)
488492
params.flags |= CRYPT_TCRYPT_VERA_MODES;
489493

490-
if (key_file) {
491-
r = read_one_line_file(key_file, &passphrase);
492-
if (r < 0) {
493-
log_error_errno(r, "Failed to read password file '%s': %m", key_file);
494-
return -EAGAIN; /* log with the actual error, but return EAGAIN */
495-
}
494+
if (key_data) {
495+
params.passphrase = key_data;
496+
params.passphrase_size = key_data_size;
497+
} else {
498+
if (key_file) {
499+
r = read_one_line_file(key_file, &passphrase);
500+
if (r < 0) {
501+
log_error_errno(r, "Failed to read password file '%s': %m", key_file);
502+
return -EAGAIN; /* log with the actual error, but return EAGAIN */
503+
}
496504

497-
params.passphrase = passphrase;
498-
} else
499-
params.passphrase = passwords[0];
500-
params.passphrase_size = strlen(params.passphrase);
505+
params.passphrase = passphrase;
506+
} else
507+
params.passphrase = passwords[0];
508+
509+
params.passphrase_size = strlen(params.passphrase);
510+
}
501511

502512
r = crypt_load(cd, CRYPT_TCRYPT, &params);
503513
if (r < 0) {
504-
if (key_file && r == -EPERM) {
505-
log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
506-
return -EAGAIN; /* log the actual error, but return EAGAIN */
514+
if (r == -EPERM) {
515+
if (key_data) {
516+
log_error_errno(r, "Failed to activate using discovered key. (Key not correct?)");
517+
return -EAGAIN; /* log the actual error, but return EAGAIN */
518+
}
519+
520+
if (key_file) {
521+
log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
522+
return -EAGAIN; /* log the actual error, but return EAGAIN */
523+
}
507524
}
508525

509526
return log_error_errno(r, "Failed to load tcrypt superblock on device %s: %m", crypt_get_device_name(cd));
@@ -520,6 +537,8 @@ static int attach_luks_or_plain(
520537
struct crypt_device *cd,
521538
const char *name,
522539
const char *key_file,
540+
const void *key_data,
541+
size_t key_data_size,
523542
char **passwords,
524543
uint32_t flags,
525544
usec_t until) {
@@ -589,7 +608,7 @@ static int attach_luks_or_plain(
589608
_cleanup_free_ char *friendly = NULL;
590609
size_t decrypted_key_size = 0;
591610

592-
if (!key_file)
611+
if (!key_file && !key_data)
593612
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
594613

595614
friendly = friendly_disk_name(crypt_get_device_name(cd), name);
@@ -602,8 +621,8 @@ static int attach_luks_or_plain(
602621
r = decrypt_pkcs11_key(
603622
friendly,
604623
arg_pkcs11_uri,
605-
key_file,
606-
arg_keyfile_size, arg_keyfile_offset,
624+
key_file, arg_keyfile_size, arg_keyfile_offset,
625+
key_data, key_data_size,
607626
until,
608627
&decrypted_key, &decrypted_key_size);
609628
if (r >= 0)
@@ -686,6 +705,18 @@ static int attach_luks_or_plain(
686705
if (r < 0)
687706
return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m");
688707

708+
} else if (key_data) {
709+
if (pass_volume_key)
710+
r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags);
711+
else
712+
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags);
713+
if (r == -EPERM) {
714+
log_error_errno(r, "Failed to activate. (Key incorrect?)");
715+
return -EAGAIN; /* Log actual error, but return EAGAIN */
716+
}
717+
if (r < 0)
718+
return log_error_errno(r, "Failed to activate: %m");
719+
689720
} else if (key_file) {
690721
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
691722
if (r == -EPERM) {
@@ -805,12 +836,17 @@ static int run(int argc, char *argv[]) {
805836
crypt_status_info status;
806837
_cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
807838
const char *key_file = NULL;
839+
_cleanup_(erase_and_freep) void *key_data = NULL;
840+
size_t key_data_size = 0;
808841

809842
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
810843

811844
if (argc < 4)
812845
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
813846

847+
if (!filename_is_valid(argv[2]))
848+
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
849+
814850
if (argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none")) {
815851
if (path_is_absolute(argv[4]))
816852
key_file = argv[4];
@@ -827,7 +863,22 @@ static int run(int argc, char *argv[]) {
827863
/* A delicious drop of snake oil */
828864
(void) mlockall(MCL_FUTURE);
829865

830-
if (key_file && arg_keyfile_erase)
866+
if (!key_file) {
867+
const char *fn;
868+
869+
/* If a key file is not explicitly specified, search for a key in a well defined
870+
* search path, and load it. */
871+
872+
fn = strjoina(argv[2], ".key");
873+
r = load_key_file(fn,
874+
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
875+
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
876+
&key_data, &key_data_size);
877+
if (r < 0)
878+
return r;
879+
if (r > 0)
880+
log_debug("Automatically discovered key for volume '%s'.", argv[2]);
881+
} else if (arg_keyfile_erase)
831882
destroy_key_file = key_file; /* let's get this baby erased when we leave */
832883

833884
if (arg_header) {
@@ -876,7 +927,7 @@ static int run(int argc, char *argv[]) {
876927
}
877928

878929
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
879-
if (!key_file) {
930+
if (!key_file && !key_data) {
880931
r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
881932
if (r >= 0) {
882933
log_debug("Volume %s activated with LUKS token id %i.", argv[2], r);
@@ -890,7 +941,7 @@ static int run(int argc, char *argv[]) {
890941
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
891942
_cleanup_strv_free_erase_ char **passwords = NULL;
892943

893-
if (!key_file && !arg_pkcs11_uri) {
944+
if (!key_file && !key_data && !arg_pkcs11_uri) {
894945
r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
895946
if (r == -EAGAIN)
896947
continue;
@@ -899,16 +950,18 @@ static int run(int argc, char *argv[]) {
899950
}
900951

901952
if (streq_ptr(arg_type, CRYPT_TCRYPT))
902-
r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
953+
r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
903954
else
904-
r = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags, until);
955+
r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
905956
if (r >= 0)
906957
break;
907958
if (r != -EAGAIN)
908959
return r;
909960

910961
/* Passphrase not correct? Let's try again! */
911962
key_file = NULL;
963+
key_data = erase_and_free(key_data);
964+
key_data_size = 0;
912965
arg_pkcs11_uri = NULL;
913966
}
914967

@@ -917,6 +970,9 @@ static int run(int argc, char *argv[]) {
917970

918971
} else if (streq(argv[1], "detach")) {
919972

973+
if (!filename_is_valid(argv[2]))
974+
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
975+
920976
r = crypt_init_by_name(&cd, argv[2]);
921977
if (r == -ENODEV) {
922978
log_info("Volume %s already inactive.", argv[2]);

0 commit comments

Comments
 (0)