summaryrefslogtreecommitdiffstats
path: root/src/cryptsetup
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cryptsetup/cryptsetup-generator.c25
-rw-r--r--src/cryptsetup/cryptsetup-pkcs11.c6
-rw-r--r--src/cryptsetup/cryptsetup-pkcs11.h4
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c12
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c6
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c65
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-fido2.c4
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c4
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c44
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h19
-rw-r--r--src/cryptsetup/cryptsetup.c288
-rw-r--r--src/cryptsetup/meson.build4
-rw-r--r--src/shared/cryptsetup-tpm2.c (renamed from src/cryptsetup/cryptsetup-tpm2.c)150
-rw-r--r--src/shared/cryptsetup-tpm2.h (renamed from src/cryptsetup/cryptsetup-tpm2.h)78
14 files changed, 393 insertions, 316 deletions
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 904e4cd..4db25d3 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -229,7 +229,8 @@ static int generate_device_umount(const char *name,
static int print_dependencies(FILE *f, const char* device_path, const char* timeout_value, bool canfail) {
int r;
- assert(!canfail || timeout_value);
+ assert(f);
+ assert(device_path);
if (STR_IN_SET(device_path, "-", "none"))
/* None, nothing to do */
@@ -263,11 +264,13 @@ static int print_dependencies(FILE *f, const char* device_path, const char* time
fprintf(f, "After=%1$s\n", unit);
if (canfail) {
fprintf(f, "Wants=%1$s\n", unit);
- r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
- "# Automatically generated by systemd-cryptsetup-generator \n\n"
- "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
- if (r < 0)
- return log_error_errno(r, "Failed to write device drop-in: %m");
+ if (timeout_value) {
+ r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
+ "# Automatically generated by systemd-cryptsetup-generator \n\n"
+ "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
+ }
} else
fprintf(f, "Requires=%1$s\n", unit);
} else {
@@ -276,7 +279,7 @@ static int print_dependencies(FILE *f, const char* device_path, const char* time
if (!escaped_path)
return log_oom();
- fprintf(f, "RequiresMountsFor=%s\n", escaped_path);
+ fprintf(f, "%s=%s\n", canfail ? "WantsMountsFor" : "RequiresMountsFor", escaped_path);
}
return 0;
@@ -486,7 +489,7 @@ static int create_disk(
if (key_file && !keydev) {
r = print_dependencies(f, key_file,
keyfile_timeout_value,
- /* canfail= */ keyfile_can_timeout > 0);
+ /* canfail= */ keyfile_can_timeout > 0 || nofail);
if (r < 0)
return r;
}
@@ -494,8 +497,8 @@ static int create_disk(
/* Check if a header option was specified */
if (detached_header > 0 && !headerdev) {
r = print_dependencies(f, header_path,
- NULL,
- /* canfail= */ false); /* header is always necessary */
+ /* timeout_value= */ NULL,
+ /* canfail= */ nofail);
if (r < 0)
return r;
}
@@ -578,6 +581,8 @@ static crypto_device* crypt_device_free(crypto_device *d) {
free(d->uuid);
free(d->keyfile);
free(d->keydev);
+ free(d->headerdev);
+ free(d->datadev);
free(d->name);
free(d->options);
return mfree(d);
diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c
index f991389..4b2b5bb 100644
--- a/src/cryptsetup/cryptsetup-pkcs11.c
+++ b/src/cryptsetup/cryptsetup-pkcs11.c
@@ -34,14 +34,14 @@ int decrypt_pkcs11_key(
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
size_t key_data_size,
usec_t until,
- bool headless,
+ AskPasswordFlags askpw_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
_cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
.friendly_name = friendly_name,
+ .askpw_flags = askpw_flags,
.until = until,
- .headless = headless,
};
int r;
@@ -154,7 +154,7 @@ int find_pkcs11_auto_data(
assert(!key);
assert(key_size == 0);
- r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size);
+ r = unbase64mem(json_variant_string(w), &key, &key_size);
if (r < 0)
return log_error_errno(r, "Failed to decode base64 encoded key.");
}
diff --git a/src/cryptsetup/cryptsetup-pkcs11.h b/src/cryptsetup/cryptsetup-pkcs11.h
index 256c09a..22e6992 100644
--- a/src/cryptsetup/cryptsetup-pkcs11.h
+++ b/src/cryptsetup/cryptsetup-pkcs11.h
@@ -19,7 +19,7 @@ int decrypt_pkcs11_key(
const void *key_data,
size_t key_data_size,
usec_t until,
- bool headless,
+ AskPasswordFlags askpw_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
@@ -42,7 +42,7 @@ static inline int decrypt_pkcs11_key(
const void *key_data,
size_t key_data_size,
usec_t until,
- bool headless,
+ AskPasswordFlags askpw_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c
index fdb3b17..1efb7c5 100644
--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c
+++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c
@@ -18,7 +18,7 @@
/* for libcryptsetup debug purpose */
_public_ const char *cryptsetup_token_version(void) {
- return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
+ return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" PROJECT_VERSION_FULL " (" GIT_VERSION ")";
}
_public_ int cryptsetup_token_open_pin(
@@ -34,7 +34,7 @@ _public_ int cryptsetup_token_open_pin(
const char *json;
_cleanup_(erase_and_freep) char *pin_string = NULL;
- assert(!pin || pin_size);
+ assert(pin || pin_size == 0);
assert(token >= 0);
/* This must not fail at this moment (internal error) */
@@ -87,7 +87,7 @@ _public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
*/
_public_ void cryptsetup_token_dump(
struct crypt_device *cd /* is always LUKS2 context */,
- const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
+ const char *json /* validated 'systemd-fido2' token if cryptsetup_token_validate is defined */) {
int r;
Fido2EnrollFlags required;
@@ -154,7 +154,7 @@ _public_ void cryptsetup_token_dump(
*/
_public_ int cryptsetup_token_validate(
struct crypt_device *cd, /* is always LUKS2 context */
- const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-tpm2' */) {
+ const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-fido2' */) {
int r;
JsonVariant *w;
@@ -172,7 +172,7 @@ _public_ int cryptsetup_token_validate(
return 1;
}
- r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ r = unbase64mem(json_variant_string(w), NULL, NULL);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'fido2-credential' field: %m");
@@ -182,7 +182,7 @@ _public_ int cryptsetup_token_validate(
return 1;
}
- r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ r = unbase64mem(json_variant_string(w), NULL, NULL);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded salt: %m.");
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c
index 2ac8a27..a9898ba 100644
--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c
+++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-pkcs11.c
@@ -18,7 +18,7 @@
/* for libcryptsetup debug purpose */
_public_ const char *cryptsetup_token_version(void) {
- return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
+ return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" PROJECT_VERSION_FULL " (" GIT_VERSION ")";
}
_public_ int cryptsetup_token_open_pin(
@@ -33,7 +33,7 @@ _public_ int cryptsetup_token_open_pin(
const char *json;
int r;
- assert(!pin || pin_size);
+ assert(pin || pin_size == 0);
assert(token >= 0);
/* This must not fail at this moment (internal error) */
@@ -136,7 +136,7 @@ _public_ int cryptsetup_token_validate(
return 1;
}
- r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ r = unbase64mem(json_variant_string(w), NULL, NULL);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
index 6fee831..8b4754a 100644
--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
@@ -20,7 +20,7 @@
/* for libcryptsetup debug purpose */
_public_ const char *cryptsetup_token_version(void) {
- return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
+ return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" PROJECT_VERSION_FULL " (" GIT_VERSION ")";
}
static int log_debug_open_error(struct crypt_device *cd, int r) {
@@ -42,9 +42,8 @@ _public_ int cryptsetup_token_open_pin(
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
_cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL;
- _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL, *salt = NULL, *srk_buf = NULL;
- size_t blob_size, policy_hash_size, decrypted_key_size, pubkey_size, salt_size = 0, srk_buf_size = 0;
- _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {};
+ _cleanup_(iovec_done_erase) struct iovec decrypted_key = {};
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
systemd_tpm2_plugin_params params = {
@@ -57,7 +56,7 @@ _public_ int cryptsetup_token_open_pin(
int r;
assert(token >= 0);
- assert(!pin || pin_size > 0);
+ assert(pin || pin_size == 0);
assert(ret_password);
assert(ret_password_len);
@@ -79,21 +78,17 @@ _public_ int cryptsetup_token_open_pin(
r = tpm2_parse_luks2_json(
v,
- NULL,
+ /* ret_keyslot= */ NULL,
&hash_pcr_mask,
&pcr_bank,
&pubkey,
- &pubkey_size,
&pubkey_pcr_mask,
&primary_alg,
&blob,
- &blob_size,
&policy_hash,
- &policy_hash_size,
&salt,
- &salt_size,
- &srk_buf,
- &srk_buf_size,
+ &srk,
+ &pcrlock_nv,
&flags);
if (r < 0)
return log_debug_open_error(cd, r);
@@ -105,28 +100,24 @@ _public_ int cryptsetup_token_open_pin(
params.device,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ &pubkey,
pubkey_pcr_mask,
params.signature_path,
pin_string,
params.pcrlock_path,
primary_alg,
- blob,
- blob_size,
- policy_hash,
- policy_hash_size,
- salt,
- salt_size,
- srk_buf,
- srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
flags,
- &decrypted_key,
- &decrypted_key_size);
+ &decrypted_key);
if (r < 0)
return log_debug_open_error(cd, r);
/* Before using this key as passphrase we base64 encode it, for compat with homed */
- base64_encoded_size = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
+ base64_encoded_size = base64mem(decrypted_key.iov_base, decrypted_key.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
return log_debug_open_error(cd, base64_encoded_size);
@@ -177,9 +168,8 @@ _public_ void cryptsetup_token_dump(
const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
_cleanup_free_ char *hash_pcrs_str = NULL, *pubkey_pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL, *pubkey_str = NULL;
- _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL, *salt = NULL, *srk_buf = NULL;
+ _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {};
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- size_t blob_size, policy_hash_size, pubkey_size, salt_size = 0, srk_buf_size = 0;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags flags = 0;
@@ -197,17 +187,13 @@ _public_ void cryptsetup_token_dump(
&hash_pcr_mask,
&pcr_bank,
&pubkey,
- &pubkey_size,
&pubkey_pcr_mask,
&primary_alg,
&blob,
- &blob_size,
&policy_hash,
- &policy_hash_size,
&salt,
- &salt_size,
- &srk_buf,
- &srk_buf_size,
+ &srk,
+ &pcrlock_nv,
&flags);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m");
@@ -220,15 +206,15 @@ _public_ void cryptsetup_token_dump(
if (!pubkey_pcrs_str)
return (void) crypt_log_debug_errno(cd, ENOMEM, "Cannot format PCR hash mask: %m");
- r = crypt_dump_buffer_to_hex_string(blob, blob_size, &blob_str);
+ r = crypt_dump_buffer_to_hex_string(blob.iov_base, blob.iov_len, &blob_str);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Cannot dump " TOKEN_NAME " content: %m");
- r = crypt_dump_buffer_to_hex_string(pubkey, pubkey_size, &pubkey_str);
+ r = crypt_dump_buffer_to_hex_string(pubkey.iov_base, pubkey.iov_len, &pubkey_str);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Cannot dump " TOKEN_NAME " content: %m");
- r = crypt_dump_buffer_to_hex_string(policy_hash, policy_hash_size, &policy_hash_str);
+ r = crypt_dump_buffer_to_hex_string(policy_hash.iov_base, policy_hash.iov_len, &policy_hash_str);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Cannot dump " TOKEN_NAME " content: %m");
@@ -241,8 +227,9 @@ _public_ void cryptsetup_token_dump(
crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN));
crypt_log(cd, "\ttpm2-pcrlock: %s\n", true_false(flags & TPM2_FLAGS_USE_PCRLOCK));
- crypt_log(cd, "\ttpm2-salt: %s\n", true_false(salt));
- crypt_log(cd, "\ttpm2-srk: %s\n", true_false(srk_buf));
+ crypt_log(cd, "\ttpm2-salt: %s\n", true_false(iovec_is_set(&salt)));
+ crypt_log(cd, "\ttpm2-srk: %s\n", true_false(iovec_is_set(&srk)));
+ crypt_log(cd, "\ttpm2-pcrlock-nv: %s\n", true_false(iovec_is_set(&pcrlock_nv)));
}
/*
@@ -326,7 +313,7 @@ _public_ int cryptsetup_token_validate(
return 1;
}
- r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ r = unbase64mem(json_variant_string(w), NULL, NULL);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-blob' field: %m");
@@ -336,7 +323,7 @@ _public_ int cryptsetup_token_validate(
return 1;
}
- r = unhexmem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ r = unhexmem(json_variant_string(w), NULL, NULL);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-policy-hash' field: %m");
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-fido2.c b/src/cryptsetup/cryptsetup-tokens/luks2-fido2.c
index a1c85e6..5b38613 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-fido2.c
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-fido2.c
@@ -104,7 +104,7 @@ int parse_luks2_fido2_data(
if (!w)
return -EINVAL;
- r = unbase64mem(json_variant_string(w), SIZE_MAX, &cid, &cid_size);
+ r = unbase64mem(json_variant_string(w), &cid, &cid_size);
if (r < 0)
return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-credentials' field: %m");
@@ -112,7 +112,7 @@ int parse_luks2_fido2_data(
if (!w)
return -EINVAL;
- r = unbase64mem(json_variant_string(w), SIZE_MAX, &salt, &salt_size);
+ r = unbase64mem(json_variant_string(w), &salt, &salt_size);
if (r < 0)
return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-salt' field: %m");
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
index 178fc7a..ac5100f 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
@@ -157,7 +157,7 @@ static int acquire_luks2_key_systemd(
assert(params);
data.friendly_name = params->friendly_name;
- data.headless = params->headless;
+ data.askpw_credential = params->askpw_credential;
data.askpw_flags = params->askpw_flags;
data.until = params->until;
@@ -260,7 +260,7 @@ int parse_luks2_pkcs11_data(
if (!w)
return -EINVAL;
- r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size);
+ r = unbase64mem(json_variant_string(w), &key, &key_size);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
index 846679f..08f901c 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
@@ -17,33 +17,27 @@ int acquire_luks2_key(
const char *device,
uint32_t hash_pcr_mask,
uint16_t pcr_bank,
- const void *pubkey,
- size_t pubkey_size,
+ const struct iovec *pubkey,
uint32_t pubkey_pcr_mask,
const char *signature_path,
const char *pin,
const char *pcrlock_path,
uint16_t primary_alg,
- const void *key_data,
- size_t key_data_size,
- const void *policy_hash,
- size_t policy_hash_size,
- const void *salt,
- size_t salt_size,
- const void *srk_buf,
- size_t srk_buf_size,
+ const struct iovec *blob,
+ const struct iovec *policy_hash,
+ const struct iovec *salt,
+ const struct iovec *srk,
+ const struct iovec *pcrlock_nv,
TPM2Flags flags,
- void **ret_decrypted_key,
- size_t *ret_decrypted_key_size) {
+ struct iovec *ret_decrypted_key) {
_cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL;
_cleanup_free_ char *auto_device = NULL;
_cleanup_(erase_and_freep) char *b64_salted_pin = NULL;
int r;
- assert(salt || salt_size == 0);
+ assert(iovec_is_valid(salt));
assert(ret_decrypted_key);
- assert(ret_decrypted_key_size);
if (!device) {
r = tpm2_find_device_auto(&auto_device);
@@ -58,10 +52,10 @@ int acquire_luks2_key(
if ((flags & TPM2_FLAGS_USE_PIN) && !pin)
return -ENOANO;
- if (pin && salt_size > 0) {
+ if (pin && iovec_is_set(salt)) {
uint8_t salted_pin[SHA256_DIGEST_SIZE] = {};
CLEANUP_ERASE(salted_pin);
- r = tpm2_util_pbkdf2_hmac_sha256(pin, strlen(pin), salt, salt_size, salted_pin);
+ r = tpm2_util_pbkdf2_hmac_sha256(pin, strlen(pin), salt->iov_base, salt->iov_len, salted_pin);
if (r < 0)
return log_error_errno(r, "Failed to perform PBKDF2: %m");
@@ -82,6 +76,14 @@ int acquire_luks2_key(
r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy);
if (r < 0)
return r;
+ if (r == 0) {
+ /* Not found? Then search among passed credentials */
+ r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume.");
+ }
}
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
@@ -92,16 +94,16 @@ int acquire_luks2_key(
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ pubkey,
pubkey_pcr_mask,
signature_json,
pin,
FLAGS_SET(flags, TPM2_FLAGS_USE_PCRLOCK) ? &pcrlock_policy : NULL,
primary_alg,
- key_data, key_data_size,
- policy_hash, policy_hash_size,
- srk_buf, srk_buf_size,
- ret_decrypted_key, ret_decrypted_key_size);
+ blob,
+ policy_hash,
+ srk,
+ ret_decrypted_key);
if (r < 0)
return log_error_errno(r, "Failed to unseal secret using TPM2: %m");
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
index 8408bab..c3a01df 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
@@ -10,21 +10,16 @@ int acquire_luks2_key(
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
- const void *pubkey,
- size_t pubkey_size,
+ const struct iovec *pubkey,
uint32_t pubkey_pcr_mask,
const char *signature_path,
const char *pin,
const char *pcrlock_path,
uint16_t primary_alg,
- const void *key_data,
- size_t key_data_size,
- const void *policy_hash,
- size_t policy_hash_size,
- const void *salt,
- size_t salt_size,
- const void *srk_buf,
- size_t srk_buf_size,
+ const struct iovec *key_data,
+ const struct iovec *policy_hash,
+ const struct iovec *salt,
+ const struct iovec *srk,
+ const struct iovec *pcrlock_nv,
TPM2Flags flags,
- void **ret_decrypted_key,
- size_t *ret_decrypted_key_size);
+ struct iovec *decrypted_key);
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 1822beb..85897ae 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -101,10 +101,12 @@ static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
static char *arg_tpm2_signature = NULL;
static bool arg_tpm2_pin = false;
static char *arg_tpm2_pcrlock = NULL;
-static bool arg_headless = false;
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
static unsigned arg_tpm2_measure_pcr = UINT_MAX; /* This and the following field is about measuring the unlocked volume key to the local TPM */
static char **arg_tpm2_measure_banks = NULL;
+static char *arg_link_keyring = NULL;
+static char *arg_link_key_type = NULL;
+static char *arg_link_key_description = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
@@ -118,6 +120,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_banks, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_pcrlock, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
[PASSPHRASE_REGULAR] = "passphrase",
@@ -338,7 +343,7 @@ static int parse_one_option(const char *option) {
arg_pkcs11_uri_auto = true;
} else {
if (!pkcs11_uri_valid(val))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing.");
r = free_and_strdup(&arg_pkcs11_uri, val);
if (r < 0)
@@ -368,7 +373,7 @@ static int parse_one_option(const char *option) {
_cleanup_free_ void *cid = NULL;
size_t cid_size;
- r = unbase64mem(val, SIZE_MAX, &cid, &cid_size);
+ r = unbase64mem(val, &cid, &cid_size);
if (r < 0)
return log_error_errno(r, "Failed to decode FIDO2 CID data: %m");
@@ -498,9 +503,9 @@ static int parse_one_option(const char *option) {
return 0;
}
- arg_headless = r;
+ SET_FLAG(arg_ask_password_flags, ASK_PASSWORD_HEADLESS, r);
} else if (streq(option, "headless"))
- arg_headless = true;
+ arg_ask_password_flags |= ASK_PASSWORD_HEADLESS;
else if ((val = startswith(option, "token-timeout="))) {
@@ -508,6 +513,56 @@ static int parse_one_option(const char *option) {
if (r < 0)
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
+ } else if ((val = startswith(option, "link-volume-key="))) {
+#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
+ const char *sep, *c;
+ _cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
+
+ /* Stick with cryptsetup --link-vk-to-keyring format
+ * <keyring_description>::%<key_type>:<key_description>,
+ * where %<key_type> is optional and defaults to 'user'.
+ */
+ if (!(sep = strstr(val, "::")))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %s", val);
+
+ /* cryptsetup (cli) supports <keyring_description> passed in various formats:
+ * - well-known keyrings prefixed with '@' (@u user, @s session, etc)
+ * - text descriptions prefixed with "%:" or "%keyring:".
+ * - text description with no prefix.
+ * - numeric keyring id (ignored in current patch set). */
+ if (IN_SET(*val, '@', '%'))
+ keyring = strndup(val, sep - val);
+ else
+ /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */
+ keyring = strnappend("%:", val, sep - val);
+ if (!keyring)
+ return log_oom();
+
+ sep += 2;
+
+ /* %<key_type> is optional (and defaults to 'user') */
+ if (*sep == '%') {
+ /* must be separated by colon */
+ if (!(c = strchr(sep, ':')))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %s", val);
+
+ key_type = strndup(sep + 1, c - sep - 1);
+ if (!key_type)
+ return log_oom();
+
+ sep = c + 1;
+ }
+
+ key_description = strdup(sep);
+ if (!key_description)
+ return log_oom();
+
+ free_and_replace(arg_link_keyring, keyring);
+ free_and_replace(arg_link_key_type, key_type);
+ free_and_replace(arg_link_key_description, key_description);
+#else
+ log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
+#endif
} else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
@@ -742,17 +797,16 @@ static int get_password(
PassphraseType passphrase_type,
char ***ret) {
- _cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL;
+ _cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL, *id = NULL;
_cleanup_strv_free_erase_ char **passwords = NULL;
- char *id;
- int r = 0;
AskPasswordFlags flags = arg_ask_password_flags | ASK_PASSWORD_PUSH_CACHE;
+ int r;
assert(vol);
assert(src);
assert(ret);
- if (arg_headless)
+ if (FLAGS_SET(arg_ask_password_flags, ASK_PASSWORD_HEADLESS))
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Password querying disabled via 'headless' option.");
friendly = friendly_disk_name(src, vol);
@@ -766,11 +820,23 @@ static int get_password(
if (!disk_path)
return log_oom();
- id = strjoina("cryptsetup:", disk_path);
+ id = strjoin("cryptsetup:", disk_path);
+ if (!id)
+ return log_oom();
+
+ AskPasswordRequest req = {
+ .message = text,
+ .icon = "drive-harddisk",
+ .id = id,
+ .keyring = "cryptsetup",
+ .credential = "cryptsetup.passphrase",
+ };
- r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until,
- flags | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
- &passwords);
+ r = ask_password_auto(
+ &req,
+ until,
+ flags | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
+ &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
@@ -779,12 +845,19 @@ static int get_password(
assert(strv_length(passwords) == 1);
+ text = mfree(text);
if (asprintf(&text, "Please enter %s for disk %s (verification):", passphrase_type_to_string(passphrase_type), friendly) < 0)
return log_oom();
- id = strjoina("cryptsetup-verification:", disk_path);
+ free(id);
+ id = strjoin("cryptsetup-verification:", disk_path);
+ if (!id)
+ return log_oom();
- r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, flags, &passwords2);
+ req.message = text;
+ req.id = id;
+
+ r = ask_password_auto(&req, until, flags, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query verification password: %m");
@@ -1192,12 +1265,11 @@ static int crypt_activate_by_token_pin_ask_password(
const char *name,
const char *type,
usec_t until,
- bool headless,
void *userdata,
uint32_t activation_flags,
const char *message,
- const char *key_name,
- const char *credential_name) {
+ const char *keyring,
+ const char *credential) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
AskPasswordFlags flags = arg_ask_password_flags | ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
@@ -1222,12 +1294,20 @@ static int crypt_activate_by_token_pin_ask_password(
return r;
}
- if (headless)
+ if (FLAGS_SET(arg_ask_password_flags, ASK_PASSWORD_HEADLESS))
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
for (;;) {
pins = strv_free_erase(pins);
- r = ask_password_auto(message, "drive-harddisk", /* id= */ NULL, key_name, credential_name, until, flags, &pins);
+
+ AskPasswordRequest req = {
+ .message = message,
+ .icon = "drive-harddisk",
+ .keyring = keyring,
+ .credential = credential,
+ };
+
+ r = ask_password_auto(&req, until, flags, &pins);
if (r < 0)
return r;
@@ -1251,7 +1331,6 @@ static int attach_luks2_by_fido2_via_plugin(
struct crypt_device *cd,
const char *name,
usec_t until,
- bool headless,
void *userdata,
uint32_t activation_flags) {
@@ -1260,7 +1339,6 @@ static int attach_luks2_by_fido2_via_plugin(
name,
"systemd-fido2",
until,
- headless,
userdata,
activation_flags,
"Please enter security token PIN:",
@@ -1315,7 +1393,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
for (;;) {
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
- r = attach_luks2_by_fido2_via_plugin(cd, name, until, arg_headless, arg_fido2_device, flags);
+ r = attach_luks2_by_fido2_via_plugin(cd, name, until, arg_fido2_device, flags);
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
"Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking.");
@@ -1331,10 +1409,11 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
until,
- arg_headless,
required,
- &decrypted_key, &decrypted_key_size,
- arg_ask_password_flags);
+ "cryptsetup.fido2-pin",
+ arg_ask_password_flags,
+ &decrypted_key,
+ &decrypted_key_size);
else
r = acquire_fido2_key_auto(
cd,
@@ -1342,9 +1421,10 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
friendly,
arg_fido2_device,
until,
- arg_headless,
- &decrypted_key, &decrypted_key_size,
- arg_ask_password_flags);
+ "cryptsetup.fido2-pin",
+ arg_ask_password_flags,
+ &decrypted_key,
+ &decrypted_key_size);
if (r >= 0)
break;
}
@@ -1405,7 +1485,7 @@ static int attach_luks2_by_pkcs11_via_plugin(
const char *name,
const char *friendly_name,
usec_t until,
- bool headless,
+ const char *askpw_credential,
uint32_t flags) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
@@ -1417,7 +1497,7 @@ static int attach_luks2_by_pkcs11_via_plugin(
systemd_pkcs11_plugin_params params = {
.friendly_name = friendly_name,
.until = until,
- .headless = headless,
+ .askpw_credential = askpw_credential,
.askpw_flags = arg_ask_password_flags,
};
@@ -1481,7 +1561,13 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
for (;;) {
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
- r = attach_luks2_by_pkcs11_via_plugin(cd, name, friendly, until, arg_headless, flags);
+ r = attach_luks2_by_pkcs11_via_plugin(
+ cd,
+ name,
+ friendly,
+ until,
+ "cryptsetup.pkcs11-pin",
+ flags);
else {
r = decrypt_pkcs11_key(
name,
@@ -1490,7 +1576,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
until,
- arg_headless,
+ arg_ask_password_flags,
&decrypted_key, &decrypted_key_size);
if (r >= 0)
break;
@@ -1615,7 +1701,6 @@ static int attach_luks2_by_tpm2_via_plugin(
struct crypt_device *cd,
const char *name,
usec_t until,
- bool headless,
uint32_t flags) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
@@ -1635,7 +1720,6 @@ static int attach_luks2_by_tpm2_via_plugin(
name,
"systemd-tpm2",
until,
- headless,
&params,
flags,
"Please enter TPM2 PIN:",
@@ -1650,18 +1734,16 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
struct crypt_device *cd,
const char *name,
const char *key_file,
- const void *key_data,
- size_t key_data_size,
+ const struct iovec *key_data,
usec_t until,
uint32_t flags,
bool pass_volume_key) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
- _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_(iovec_done_erase) struct iovec decrypted_key = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_free_ char *friendly = NULL;
int keyslot = arg_key_slot, r;
- size_t decrypted_key_size;
assert(cd);
assert(name);
@@ -1672,7 +1754,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_oom();
for (;;) {
- if (key_file || key_data) {
+ if (key_file || iovec_is_set(key_data)) {
/* If key data is specified, use that */
r = acquire_tpm2_key(
@@ -1680,21 +1762,22 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
UINT16_MAX,
- /* pubkey= */ NULL, /* pubkey_size= */ 0,
+ /* pubkey= */ NULL,
/* pubkey_pcr_mask= */ 0,
/* signature_path= */ NULL,
/* pcrlock_path= */ NULL,
/* primary_alg= */ 0,
key_file, arg_keyfile_size, arg_keyfile_offset,
- key_data, key_data_size,
- /* policy_hash= */ NULL, /* policy_hash_size= */ 0, /* we don't know the policy hash */
- /* salt= */ NULL, /* salt_size= */ 0,
- /* srk_buf= */ NULL, /* srk_buf_size= */ 0,
+ key_data,
+ /* policy_hash= */ NULL, /* we don't know the policy hash */
+ /* salt= */ NULL,
+ /* srk= */ NULL,
+ /* pcrlock_nv= */ NULL,
arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0,
until,
- arg_headless,
+ "cryptsetup.tpm2-pin",
arg_ask_password_flags,
- &decrypted_key, &decrypted_key_size);
+ &decrypted_key);
if (r >= 0)
break;
if (IN_SET(r, -EACCES, -ENOLCK))
@@ -1707,7 +1790,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return -EAGAIN; /* Mangle error code: let's make any form of TPM2 failure non-fatal. */
}
} else {
- r = attach_luks2_by_tpm2_via_plugin(cd, name, until, arg_headless, flags);
+ r = attach_luks2_by_tpm2_via_plugin(cd, name, until, flags);
if (r >= 0)
return 0;
/* EAGAIN means: no tpm2 chip found
@@ -1725,8 +1808,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
}
if (r == -EOPNOTSUPP) { /* Plugin not available, let's process TPM2 stuff right here instead */
- _cleanup_free_ void *blob = NULL, *policy_hash = NULL;
- size_t blob_size, policy_hash_size;
bool found_some = false;
int token = 0; /* first token to look at */
@@ -1735,8 +1816,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
* works. */
for (;;) {
- _cleanup_free_ void *pubkey = NULL, *salt = NULL, *srk_buf = NULL;
- size_t pubkey_size = 0, salt_size = 0, srk_buf_size = 0;
+ _cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
+ _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {};
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags tpm2_flags;
@@ -1747,13 +1828,14 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
token, /* search for the token with this index, or any later index than this */
&hash_pcr_mask,
&pcr_bank,
- &pubkey, &pubkey_size,
+ &pubkey,
&pubkey_pcr_mask,
&primary_alg,
- &blob, &blob_size,
- &policy_hash, &policy_hash_size,
- &salt, &salt_size,
- &srk_buf, &srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
&tpm2_flags,
&keyslot,
&token);
@@ -1778,21 +1860,22 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
arg_tpm2_device,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ &pubkey,
pubkey_pcr_mask,
arg_tpm2_signature,
arg_tpm2_pcrlock,
primary_alg,
/* key_file= */ NULL, /* key_file_size= */ 0, /* key_file_offset= */ 0, /* no key file */
- blob, blob_size,
- policy_hash, policy_hash_size,
- salt, salt_size,
- srk_buf, srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
tpm2_flags,
until,
- arg_headless,
+ "cryptsetup.tpm2-pin",
arg_ask_password_flags,
- &decrypted_key, &decrypted_key_size);
+ &decrypted_key);
if (IN_SET(r, -EACCES, -ENOLCK))
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking.");
if (r != -EPERM)
@@ -1837,17 +1920,16 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
}
- assert(decrypted_key);
if (pass_volume_key)
- r = measured_crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags);
+ r = measured_crypt_activate_by_volume_key(cd, name, decrypted_key.iov_base, decrypted_key.iov_len, flags);
else {
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
ssize_t base64_encoded_size;
/* Before using this key as passphrase we base64 encode it, for compat with homed */
- base64_encoded_size = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
+ base64_encoded_size = base64mem(decrypted_key.iov_base, decrypted_key.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
return log_oom();
@@ -2045,7 +2127,7 @@ static int attach_luks_or_plain_or_bitlk(
crypt_get_device_name(cd));
if (arg_tpm2_device || arg_tpm2_device_auto)
- return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key);
+ return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, &IOVEC_MAKE(key_data, key_data_size), until, flags, pass_volume_key);
if (arg_fido2_device || arg_fido2_device_auto)
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key);
if (arg_pkcs11_uri || arg_pkcs11_uri_auto)
@@ -2289,6 +2371,15 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
+/* since cryptsetup 2.7.0 (Jan 2024) */
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
+ if (arg_link_key_description) {
+ r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
+ }
+#endif
+
if (arg_header) {
r = crypt_set_data_device(cd, source);
if (r < 0)
@@ -2302,7 +2393,6 @@ static int run(int argc, char *argv[]) {
volume,
/* type= */ NULL,
until,
- arg_headless,
/* userdata= */ NULL,
flags,
"Please enter LUKS2 token PIN:",
@@ -2326,8 +2416,10 @@ static int run(int argc, char *argv[]) {
}
#endif
+ bool use_cached_passphrase = true;
+ _cleanup_strv_free_erase_ char **passwords = NULL;
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
- _cleanup_strv_free_erase_ char **passwords = NULL;
+ log_debug("Beginning attempt %u to unlock.", tries);
/* When we were able to acquire multiple keys, let's always process them in this order:
*
@@ -2338,7 +2430,9 @@ static int run(int argc, char *argv[]) {
* 5. We enquire the user for a password
*/
- if (!key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto && !arg_fido2_device && !arg_fido2_device_auto && !arg_tpm2_device && !arg_tpm2_device_auto) {
+ if (!passwords && !key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto && !arg_fido2_device && !arg_fido2_device_auto && !arg_tpm2_device && !arg_tpm2_device_auto) {
+
+ /* If we have nothing to try anymore, then acquire a new password */
if (arg_try_empty_password) {
/* Hmm, let's try an empty password now, but only once */
@@ -2358,7 +2452,8 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No passphrase or recovery key registered.");
}
- r = get_password(volume, source, until, tries == 0 && !arg_verify, passphrase_type, &passwords);
+ r = get_password(volume, source, until, use_cached_passphrase && !arg_verify, passphrase_type, &passwords);
+ use_cached_passphrase = false;
if (r == -EAGAIN)
continue;
if (r < 0)
@@ -2375,17 +2470,44 @@ static int run(int argc, char *argv[]) {
if (r != -EAGAIN)
return r;
- /* Key not correct? Let's try again! */
+ /* Key not correct? Let's try again, but let's invalidate one of the passed fields,
+ * so that we fallback to the next best thing. */
- key_file = NULL;
- key_data = erase_and_free(key_data);
- key_data_size = 0;
- arg_pkcs11_uri = mfree(arg_pkcs11_uri);
- arg_pkcs11_uri_auto = false;
- arg_fido2_device = mfree(arg_fido2_device);
- arg_fido2_device_auto = false;
- arg_tpm2_device = mfree(arg_tpm2_device);
- arg_tpm2_device_auto = false;
+ if (arg_tpm2_device || arg_tpm2_device_auto) {
+ arg_tpm2_device = mfree(arg_tpm2_device);
+ arg_tpm2_device_auto = false;
+ continue;
+ }
+
+ if (arg_fido2_device || arg_fido2_device_auto) {
+ arg_fido2_device = mfree(arg_fido2_device);
+ arg_fido2_device_auto = false;
+ continue;
+ }
+
+ if (arg_pkcs11_uri || arg_pkcs11_uri_auto) {
+ arg_pkcs11_uri = mfree(arg_pkcs11_uri);
+ arg_pkcs11_uri_auto = false;
+ continue;
+ }
+
+ if (key_data) {
+ key_data = erase_and_free(key_data);
+ key_data_size = 0;
+ continue;
+ }
+
+ if (key_file) {
+ key_file = NULL;
+ continue;
+ }
+
+ if (passwords) {
+ passwords = strv_free_erase(passwords);
+ continue;
+ }
+
+ log_debug("Prepared for next attempt to unlock.");
}
if (arg_tries != 0 && tries >= arg_tries)
@@ -2395,7 +2517,7 @@ static int run(int argc, char *argv[]) {
const char *volume = ASSERT_PTR(argv[optind + 1]);
if (argc - optind >= 3)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach does not accept more than one argument.");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "detach does not accept more than one argument.");
if (!filename_is_valid(volume))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
diff --git a/src/cryptsetup/meson.build b/src/cryptsetup/meson.build
index 90e2be7..9ccc098 100644
--- a/src/cryptsetup/meson.build
+++ b/src/cryptsetup/meson.build
@@ -11,10 +11,6 @@ if conf.get('HAVE_P11KIT') == 1
systemd_cryptsetup_sources += files('cryptsetup-pkcs11.c')
endif
-if conf.get('HAVE_TPM2') == 1
- systemd_cryptsetup_sources += files('cryptsetup-tpm2.c')
-endif
-
executables += [
executable_template + {
'name' : 'systemd-cryptsetup',
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c
index e7a38d4..bfd7d3a 100644
--- a/src/cryptsetup/cryptsetup-tpm2.c
+++ b/src/shared/cryptsetup-tpm2.c
@@ -12,7 +12,11 @@
#include "sha256.h"
#include "tpm2-util.h"
-static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) {
+static int get_pin(
+ usec_t until,
+ const char *askpw_credential,
+ AskPasswordFlags askpw_flags,
+ char **ret_pin_str) {
_cleanup_(erase_and_freep) char *pin_str = NULL;
_cleanup_strv_free_erase_ char **pin = NULL;
int r;
@@ -23,22 +27,21 @@ static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headl
if (r < 0)
return log_error_errno(r, "Failed to acquire PIN from environment: %m");
if (!r) {
- if (headless)
+ if (FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS))
return log_error_errno(
SYNTHETIC_ERRNO(ENOPKG),
"PIN querying disabled via 'headless' option. "
"Use the '$PIN' environment variable.");
+ AskPasswordRequest req = {
+ .message = "Please enter TPM2 PIN:",
+ .icon = "drive-harddisk",
+ .keyring = "tpm2-pin",
+ .credential = askpw_credential,
+ };
+
pin = strv_free_erase(pin);
- r = ask_password_auto(
- "Please enter TPM2 PIN:",
- "drive-harddisk",
- NULL,
- "tpm2-pin",
- "cryptsetup.tpm2-pin",
- until,
- ask_password_flags,
- &pin);
+ r = ask_password_auto(&req, until, askpw_flags, &pin);
if (r < 0)
return log_error_errno(r, "Failed to ask for user pin: %m");
assert(strv_length(pin) == 1);
@@ -58,8 +61,7 @@ int acquire_tpm2_key(
const char *device,
uint32_t hash_pcr_mask,
uint16_t pcr_bank,
- const void *pubkey,
- size_t pubkey_size,
+ const struct iovec *pubkey,
uint32_t pubkey_pcr_mask,
const char *signature_path,
const char *pcrlock_path,
@@ -67,29 +69,24 @@ int acquire_tpm2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
- const void *key_data,
- size_t key_data_size,
- const void *policy_hash,
- size_t policy_hash_size,
- const void *salt,
- size_t salt_size,
- const void *srk_buf,
- size_t srk_buf_size,
+ const struct iovec *key_data,
+ const struct iovec *policy_hash,
+ const struct iovec *salt,
+ const struct iovec *srk,
+ const struct iovec *pcrlock_nv,
TPM2Flags flags,
usec_t until,
- bool headless,
- AskPasswordFlags ask_password_flags,
- void **ret_decrypted_key,
- size_t *ret_decrypted_key_size) {
+ const char *askpw_credential,
+ AskPasswordFlags askpw_flags,
+ struct iovec *ret_decrypted_key) {
_cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL;
_cleanup_free_ void *loaded_blob = NULL;
_cleanup_free_ char *auto_device = NULL;
- size_t blob_size;
- const void *blob;
+ struct iovec blob;
int r;
- assert(salt || salt_size == 0);
+ assert(iovec_is_valid(salt));
if (!device) {
r = tpm2_find_device_auto(&auto_device);
@@ -101,10 +98,9 @@ int acquire_tpm2_key(
device = auto_device;
}
- if (key_data) {
- blob = key_data;
- blob_size = key_data_size;
- } else {
+ if (iovec_is_set(key_data))
+ blob = *key_data;
+ else {
_cleanup_free_ char *bindname = NULL;
/* If we read the salt via AF_UNIX, make this client recognizable */
@@ -117,11 +113,11 @@ int acquire_tpm2_key(
key_file_size == 0 ? SIZE_MAX : key_file_size,
READ_FULL_FILE_CONNECT_SOCKET,
bindname,
- (char**) &loaded_blob, &blob_size);
+ (char**) &loaded_blob, &blob.iov_len);
if (r < 0)
return r;
- blob = loaded_blob;
+ blob.iov_base = loaded_blob;
}
if (pubkey_pcr_mask != 0) {
@@ -136,6 +132,14 @@ int acquire_tpm2_key(
r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy);
if (r < 0)
return r;
+ if (r == 0) {
+ /* Not found? Then search among passed credentials */
+ r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume.");
+ }
}
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
@@ -147,20 +151,16 @@ int acquire_tpm2_key(
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ pubkey,
pubkey_pcr_mask,
signature_json,
/* pin= */ NULL,
FLAGS_SET(flags, TPM2_FLAGS_USE_PCRLOCK) ? &pcrlock_policy : NULL,
primary_alg,
- blob,
- blob_size,
+ &blob,
policy_hash,
- policy_hash_size,
- srk_buf,
- srk_buf_size,
- ret_decrypted_key,
- ret_decrypted_key_size);
+ srk,
+ ret_decrypted_key);
if (r < 0)
return log_error_errno(r, "Failed to unseal secret using TPM2: %m");
@@ -173,15 +173,15 @@ int acquire_tpm2_key(
if (i <= 0)
return -EACCES;
- r = get_pin(until, ask_password_flags, headless, &pin_str);
+ r = get_pin(until, askpw_credential, askpw_flags, &pin_str);
if (r < 0)
return r;
- if (salt_size > 0) {
+ if (iovec_is_set(salt)) {
uint8_t salted_pin[SHA256_DIGEST_SIZE] = {};
CLEANUP_ERASE(salted_pin);
- r = tpm2_util_pbkdf2_hmac_sha256(pin_str, strlen(pin_str), salt, salt_size, salted_pin);
+ r = tpm2_util_pbkdf2_hmac_sha256(pin_str, strlen(pin_str), salt->iov_base, salt->iov_len, salted_pin);
if (r < 0)
return log_error_errno(r, "Failed to perform PBKDF2: %m");
@@ -195,20 +195,16 @@ int acquire_tpm2_key(
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ pubkey,
pubkey_pcr_mask,
signature_json,
b64_salted_pin,
- pcrlock_path ? &pcrlock_policy : NULL,
+ FLAGS_SET(flags, TPM2_FLAGS_USE_PCRLOCK) ? &pcrlock_policy : NULL,
primary_alg,
- blob,
- blob_size,
+ &blob,
policy_hash,
- policy_hash_size,
- srk_buf,
- srk_buf_size,
- ret_decrypted_key,
- ret_decrypted_key_size);
+ srk,
+ ret_decrypted_key);
if (r < 0) {
log_error_errno(r, "Failed to unseal secret using TPM2: %m");
@@ -228,18 +224,14 @@ int find_tpm2_auto_data(
int start_token,
uint32_t *ret_hash_pcr_mask,
uint16_t *ret_pcr_bank,
- void **ret_pubkey,
- size_t *ret_pubkey_size,
+ struct iovec *ret_pubkey,
uint32_t *ret_pubkey_pcr_mask,
uint16_t *ret_primary_alg,
- void **ret_blob,
- size_t *ret_blob_size,
- void **ret_policy_hash,
- size_t *ret_policy_hash_size,
- void **ret_salt,
- size_t *ret_salt_size,
- void **ret_srk_buf,
- size_t *ret_srk_buf_size,
+ struct iovec *ret_blob,
+ struct iovec *ret_policy_hash,
+ struct iovec *ret_salt,
+ struct iovec *ret_srk,
+ struct iovec *ret_pcrlock_nv,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {
@@ -249,9 +241,8 @@ int find_tpm2_auto_data(
assert(cd);
for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
- _cleanup_free_ void *blob = NULL, *policy_hash = NULL, *pubkey = NULL, *salt = NULL, *srk_buf = NULL;
+ _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- size_t blob_size, policy_hash_size, pubkey_size, salt_size = 0, srk_buf_size = 0;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags flags;
@@ -268,13 +259,14 @@ int find_tpm2_auto_data(
&keyslot,
&hash_pcr_mask,
&pcr_bank,
- &pubkey, &pubkey_size,
+ &pubkey,
&pubkey_pcr_mask,
&primary_alg,
- &blob, &blob_size,
- &policy_hash, &policy_hash_size,
- &salt, &salt_size,
- &srk_buf, &srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
&flags);
if (r == -EUCLEAN) /* Gracefully handle issues in JSON fields not owned by us */
continue;
@@ -289,20 +281,16 @@ int find_tpm2_auto_data(
*ret_hash_pcr_mask = hash_pcr_mask;
*ret_pcr_bank = pcr_bank;
- *ret_pubkey = TAKE_PTR(pubkey);
- *ret_pubkey_size = pubkey_size;
+ *ret_pubkey = TAKE_STRUCT(pubkey);
*ret_pubkey_pcr_mask = pubkey_pcr_mask;
*ret_primary_alg = primary_alg;
- *ret_blob = TAKE_PTR(blob);
- *ret_blob_size = blob_size;
- *ret_policy_hash = TAKE_PTR(policy_hash);
- *ret_policy_hash_size = policy_hash_size;
- *ret_salt = TAKE_PTR(salt);
- *ret_salt_size = salt_size;
+ *ret_blob = TAKE_STRUCT(blob);
+ *ret_policy_hash = TAKE_STRUCT(policy_hash);
+ *ret_salt = TAKE_STRUCT(salt);
*ret_keyslot = keyslot;
*ret_token = token;
- *ret_srk_buf = TAKE_PTR(srk_buf);
- *ret_srk_buf_size = srk_buf_size;
+ *ret_srk = TAKE_STRUCT(srk);
+ *ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv);
*ret_flags = flags;
return 0;
}
diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/shared/cryptsetup-tpm2.h
index a50a943..b9905f4 100644
--- a/src/cryptsetup/cryptsetup-tpm2.h
+++ b/src/shared/cryptsetup-tpm2.h
@@ -16,8 +16,7 @@ int acquire_tpm2_key(
const char *device,
uint32_t hash_pcr_mask,
uint16_t pcr_bank,
- const void *pubkey,
- size_t pubkey_size,
+ const struct iovec *pubkey,
uint32_t pubkey_pcr_mask,
const char *signature_path,
const char *pcrlock_path,
@@ -25,20 +24,16 @@ int acquire_tpm2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
- const void *key_data,
- size_t key_data_size,
- const void *policy_hash,
- size_t policy_hash_size,
- const void *salt,
- size_t salt_size,
- const void *srk_buf,
- size_t salt_srk_buf_size,
+ const struct iovec *key_data,
+ const struct iovec *policy_hash,
+ const struct iovec *salt,
+ const struct iovec *srk,
+ const struct iovec *pcrlock_nv,
TPM2Flags flags,
usec_t until,
- bool headless,
- AskPasswordFlags ask_password_flags,
- void **ret_decrypted_key,
- size_t *ret_decrypted_key_size);
+ const char *askpw_credential,
+ AskPasswordFlags askpw_flags,
+ struct iovec *ret_decrypted_key);
int find_tpm2_auto_data(
struct crypt_device *cd,
@@ -46,18 +41,14 @@ int find_tpm2_auto_data(
int start_token,
uint32_t *ret_hash_pcr_mask,
uint16_t *ret_pcr_bank,
- void **ret_pubkey,
- size_t *ret_pubkey_size,
+ struct iovec *ret_pubkey,
uint32_t *ret_pubkey_pcr_mask,
uint16_t *ret_primary_alg,
- void **ret_blob,
- size_t *ret_blob_size,
- void **ret_policy_hash,
- size_t *ret_policy_hash_size,
- void **ret_salt,
- size_t *ret_salt_size,
- void **ret_srk_buf,
- size_t *ret_srk_size,
+ struct iovec *ret_blob,
+ struct iovec *ret_policy_hash,
+ struct iovec *ret_salt,
+ struct iovec *ret_srk,
+ struct iovec *ret_pcrlock_nv,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token);
@@ -69,8 +60,7 @@ static inline int acquire_tpm2_key(
const char *device,
uint32_t hash_pcr_mask,
uint16_t pcr_bank,
- const void *pubkey,
- size_t pubkey_size,
+ const struct iovec *pubkey,
uint32_t pubkey_pcr_mask,
const char *signature_path,
const char *pcrlock_path,
@@ -78,20 +68,16 @@ static inline int acquire_tpm2_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
- const void *key_data,
- size_t key_data_size,
- const void *policy_hash,
- size_t policy_hash_size,
- const void *salt,
- size_t salt_size,
- const void *srk_buf,
- size_t salt_srk_buf_size,
+ const struct iovec *key_data,
+ const struct iovec *policy_hash,
+ const struct iovec *salt,
+ const struct iovec *srk,
+ const struct iovec *pcrlock_nv,
TPM2Flags flags,
usec_t until,
- bool headless,
- AskPasswordFlags ask_password_flags,
- void **ret_decrypted_key,
- size_t *ret_decrypted_key_size) {
+ const char *askpw_credential,
+ AskPasswordFlags askpw_flags,
+ struct iovec *ret_decrypted_key) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support not available.");
@@ -103,18 +89,14 @@ static inline int find_tpm2_auto_data(
int start_token,
uint32_t *ret_hash_pcr_mask,
uint16_t *ret_pcr_bank,
- void **ret_pubkey,
- size_t *ret_pubkey_size,
+ struct iovec *ret_pubkey,
uint32_t *ret_pubkey_pcr_mask,
uint16_t *ret_primary_alg,
- void **ret_blob,
- size_t *ret_blob_size,
- void **ret_policy_hash,
- size_t *ret_policy_hash_size,
- void **ret_salt,
- size_t *ret_salt_size,
- void **ret_srk_buf,
- size_t *ret_srk_size,
+ struct iovec *ret_blob,
+ struct iovec *ret_policy_hash,
+ struct iovec *ret_salt,
+ struct iovec *ret_srk,
+ struct iovec *ret_pcrlock_nv,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {