cryptsetup: implement cryptsetup_token_open_pin for systemd-tpm2 LUKS2 token
This finishes the implementation started in commit
1f895adac2 ("cryptsetup: add libcryptsetup TPM2
PIN support").
Note that the previous implementation took a shortcut by returning EOPNOTSUPP
instead of the correct ENOANO as per the cryptsetup documentation. This meant
that systemd-cryptsetup fell back to the non-plugin implementation in order to
ask for the PIN. Since this does not happen any more when returning ENOANO, we
need to ask for the PIN in attach_luks2_by_tpm2_via_plugin() instead like
attach_luks2_by_fido2_via_plugin() does.
This commit is contained in:
@@ -35,22 +35,11 @@ static int log_debug_open_error(struct crypt_device *cd, int r) {
|
||||
return crypt_log_debug_errno(cd, r, TOKEN_NAME " open failed: %m.");
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from within following libcryptsetup calls
|
||||
* provided conditions further below are met:
|
||||
*
|
||||
* crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
|
||||
*
|
||||
* - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
|
||||
* (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
|
||||
* and token is assigned to at least single keyslot).
|
||||
*
|
||||
* - if plugin defines validate function (see cryptsetup_token_validate below) it must have
|
||||
* passed the check (aka return 0)
|
||||
*/
|
||||
_public_ int cryptsetup_token_open(
|
||||
_public_ int cryptsetup_token_open_pin(
|
||||
struct crypt_device *cd, /* is always LUKS2 context */
|
||||
int token /* is always >= 0 */,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||
size_t *password_len,
|
||||
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||
@@ -66,8 +55,9 @@ _public_ int cryptsetup_token_open(
|
||||
_cleanup_free_ void *blob = NULL, *policy_hash = NULL;
|
||||
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
|
||||
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL;
|
||||
|
||||
assert(!pin || pin_size);
|
||||
assert(password);
|
||||
assert(password_len);
|
||||
assert(token >= 0);
|
||||
@@ -77,6 +67,10 @@ _public_ int cryptsetup_token_open(
|
||||
assert(token == r);
|
||||
assert(json);
|
||||
|
||||
r = crypt_normalize_pin(pin, pin_size, &pin_string);
|
||||
if (r < 0)
|
||||
return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
|
||||
|
||||
if (usrptr)
|
||||
params = *(systemd_tpm2_plugin_params *)usrptr;
|
||||
|
||||
@@ -105,6 +99,7 @@ _public_ int cryptsetup_token_open(
|
||||
policy_hash,
|
||||
policy_hash_size,
|
||||
flags,
|
||||
pin_string,
|
||||
&decrypted_key,
|
||||
&decrypted_key_size);
|
||||
if (r < 0)
|
||||
@@ -122,6 +117,29 @@ _public_ int cryptsetup_token_open(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from within following libcryptsetup calls
|
||||
* provided conditions further below are met:
|
||||
*
|
||||
* crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
|
||||
*
|
||||
* - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
|
||||
* (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
|
||||
* and token is assigned to at least single keyslot).
|
||||
*
|
||||
* - if plugin defines validate function (see cryptsetup_token_validate below) it must have
|
||||
* passed the check (aka return 0)
|
||||
*/
|
||||
_public_ int cryptsetup_token_open(
|
||||
struct crypt_device *cd, /* is always LUKS2 context */
|
||||
int token /* is always >= 0 */,
|
||||
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||
size_t *password_len,
|
||||
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||
|
||||
return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* libcryptsetup callback for memory deallocation of 'password' parameter passed in
|
||||
* any crypt_token_open_* plugin function
|
||||
|
||||
@@ -56,3 +56,29 @@ int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string) {
|
||||
|
||||
_cleanup_free_ char *pin_string = NULL;
|
||||
|
||||
assert(pin || !pin_size);
|
||||
assert(ret_pin_string);
|
||||
|
||||
if (!pin) {
|
||||
*ret_pin_string = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Refuse embedded NULL bytes, but allow trailing NULL */
|
||||
if (memchr(pin, 0, pin_size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* Enforce trailing NULL byte if missing */
|
||||
pin_string = memdup_suffix0(pin, pin_size);
|
||||
if (!pin_string)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_pin_string = TAKE_PTR(pin_string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,3 +36,5 @@ int crypt_dump_buffer_to_hex_string(
|
||||
char **ret_dump_str);
|
||||
|
||||
int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str);
|
||||
|
||||
int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string);
|
||||
|
||||
@@ -22,11 +22,11 @@ int acquire_luks2_key(
|
||||
const void *policy_hash,
|
||||
size_t policy_hash_size,
|
||||
TPM2Flags flags,
|
||||
const char *pin,
|
||||
void **ret_decrypted_key,
|
||||
size_t *ret_decrypted_key_size) {
|
||||
|
||||
_cleanup_free_ char *auto_device = NULL;
|
||||
_cleanup_(erase_and_freep) char *pin_str = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret_decrypted_key);
|
||||
@@ -42,22 +42,15 @@ int acquire_luks2_key(
|
||||
device = auto_device;
|
||||
}
|
||||
|
||||
r = getenv_steal_erase("PIN", &pin_str);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire PIN from environment: %m");
|
||||
if (!r) {
|
||||
/* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's
|
||||
* internal handling. */
|
||||
if (flags & TPM2_FLAGS_USE_PIN)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if ((flags & TPM2_FLAGS_USE_PIN) && !pin)
|
||||
return -ENOANO;
|
||||
|
||||
return tpm2_unseal(
|
||||
device,
|
||||
pcr_mask, pcr_bank,
|
||||
primary_alg,
|
||||
key_data, key_data_size,
|
||||
policy_hash, policy_hash_size, pin_str,
|
||||
policy_hash, policy_hash_size, pin,
|
||||
ret_decrypted_key, ret_decrypted_key_size);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ int acquire_luks2_key(
|
||||
const void *policy_hash,
|
||||
size_t policy_hash_size,
|
||||
TPM2Flags flags,
|
||||
const char *pin,
|
||||
void **ret_decrypted_key,
|
||||
size_t *ret_decrypted_key_size);
|
||||
|
||||
|
||||
@@ -1275,11 +1275,11 @@ static int make_tpm2_device_monitor(
|
||||
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
|
||||
int r;
|
||||
|
||||
systemd_tpm2_plugin_params params = {
|
||||
.search_pcr_mask = arg_tpm2_pcr_mask,
|
||||
.device = arg_tpm2_device
|
||||
@@ -1289,11 +1289,17 @@ static int attach_luks2_by_tpm2_via_plugin(
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Libcryptsetup has external plugins support disabled.");
|
||||
|
||||
r = crypt_activate_by_token_pin(cd, name, "systemd-tpm2", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
|
||||
if (r > 0) /* returns unlocked keyslot id on success */
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
return crypt_activate_by_token_pin_ask_password(
|
||||
cd,
|
||||
name,
|
||||
"systemd-tpm2",
|
||||
until,
|
||||
headless,
|
||||
¶ms,
|
||||
flags,
|
||||
"Please enter TPM2 PIN:",
|
||||
"tpm2-pin",
|
||||
"cryptsetup.tpm2-pin");
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
@@ -1354,7 +1360,9 @@ 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, flags);
|
||||
r = attach_luks2_by_tpm2_via_plugin(cd, name, until, arg_headless, flags);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
/* EAGAIN means: no tpm2 chip found
|
||||
* EOPNOTSUPP means: no libcryptsetup plugins support */
|
||||
if (r == -ENXIO)
|
||||
|
||||
Reference in New Issue
Block a user