Merge pull request #23511 from diabonas/tpm2-pin-systemd-gpt-auto-generator

cryptsetup: make systemd-gpt-auto-generator work with TPM2 and PIN
This commit is contained in:
Lennart Poettering
2022-08-08 15:40:03 +02:00
committed by GitHub
8 changed files with 139 additions and 52 deletions
@@ -43,18 +43,11 @@ _public_ int cryptsetup_token_open_pin(
assert_se(token == r);
assert(json);
if (pin && memchr(pin, 0, pin_size - 1))
return crypt_log_error_errno(cd, ENOANO, "PIN must be characters string.");
r = crypt_normalize_pin(pin, pin_size, &pin_string);
if (r < 0)
return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
/* pin was passed as pin = pin, pin_size = strlen(pin). We need to add terminating
* NULL byte to addressable memory*/
if (pin && pin[pin_size-1] != '\0') {
pin_string = strndup(pin, pin_size);
if (!pin_string)
return crypt_log_oom(cd);
}
return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string ?: pin, password, password_len);
return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string, password, password_len);
}
/*
@@ -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);
+4 -11
View File
@@ -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);
+58 -15
View File
@@ -851,20 +851,24 @@ static int acquire_pins_from_env_variable(char ***ret_pins) {
}
#endif
static int attach_luks2_by_fido2_via_plugin(
static int crypt_activate_by_token_pin_ask_password(
struct crypt_device *cd,
const char *name,
const char *type,
usec_t until,
bool headless,
void *usrptr,
uint32_t activation_flags) {
uint32_t activation_flags,
const char *message,
const char *key_name,
const char *credential_name) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
_cleanup_strv_free_erase_ char **pins = NULL;
int r;
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -875,7 +879,7 @@ static int attach_luks2_by_fido2_via_plugin(
return r;
STRV_FOREACH(p, pins) {
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -887,12 +891,12 @@ static int attach_luks2_by_fido2_via_plugin(
for (;;) {
pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
r = ask_password_auto(message, "drive-harddisk", NULL, key_name, credential_name, until, flags, &pins);
if (r < 0)
return r;
STRV_FOREACH(p, pins) {
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -907,6 +911,27 @@ static int attach_luks2_by_fido2_via_plugin(
#endif
}
static int attach_luks2_by_fido2_via_plugin(
struct crypt_device *cd,
const char *name,
usec_t until,
bool headless,
void *usrptr,
uint32_t activation_flags) {
return crypt_activate_by_token_pin_ask_password(
cd,
name,
"systemd-fido2",
until,
headless,
usrptr,
activation_flags,
"Please enter security token PIN:",
"fido2-pin",
"cryptsetup.fido2-pin");
}
static int attach_luks_or_plain_or_bitlk_by_fido2(
struct crypt_device *cd,
const char *name,
@@ -1250,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
@@ -1264,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, &params, 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,
&params,
flags,
"Please enter TPM2 PIN:",
"tpm2-pin",
"cryptsetup.tpm2-pin");
#else
return -EOPNOTSUPP;
#endif
@@ -1329,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)
@@ -1853,7 +1886,17 @@ static int run(int argc, char *argv[]) {
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
if (!key_file && !key_data) {
r = crypt_activate_by_token(cd, volume, CRYPT_ANY_TOKEN, NULL, flags);
r = crypt_activate_by_token_pin_ask_password(
cd,
volume,
NULL,
until,
arg_headless,
NULL,
flags,
"Please enter LUKS2 token PIN:",
"luks2-pin",
"cryptsetup.luks2-pin");
if (r >= 0) {
log_debug("Volume %s activated with LUKS token id %i.", volume, r);
return 0;
+11
View File
@@ -29,6 +29,17 @@ env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm
# Check failure with wrong PIN
env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
# Check LUKS2 token plugin unlock (i.e. without specifying tpm2-device=auto)
if cryptsetup --help | grep -q 'LUKS2 external token plugin support is compiled-in'; then
env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1
/usr/lib/systemd/systemd-cryptsetup detach test-volume
# Check failure with wrong PIN
env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 && { echo 'unexpected success'; exit 1; }
else
echo 'cryptsetup has no LUKS2 token plugin support, skipping'
fi
# Check failure with wrong PCR (and correct PIN)
tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000
env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }