summaryrefslogtreecommitdiff
path: root/src/cryptsetup
diff options
context:
space:
mode:
authorWilliam Roberts <william.c.roberts@intel.com>2023-01-18 08:45:53 -0600
committerLuca Boccassi <luca.boccassi@gmail.com>2023-01-18 21:58:33 +0000
commitaae6eb96117acd54ce5ac572aac6a11b34c4ad99 (patch)
tree82c3781c1d15e1c3bf2c50abbd5f94eab782c879 /src/cryptsetup
parentf2af682cd6308f9b26035b83063e6aa8593e468c (diff)
downloadsystemd-aae6eb96117acd54ce5ac572aac6a11b34c4ad99.tar.gz
tpm2: add salt to pin
Add a salt to the pin and store it in the TPM2 LUKS header for future this. This adds entropy to user supplied pins and helps brute forcing the passphrase on the key residing in the TPM or brute forcing bind key encrypted sessions with low entropy passphrases. Signed-off-by: malikabhi05 <abhishek.malik@intel.com> Signed-off-by: William Roberts <william.c.roberts@intel.com>
Diffstat (limited to 'src/cryptsetup')
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c15
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c21
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h2
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.c31
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.h8
-rw-r--r--src/cryptsetup/cryptsetup.c7
6 files changed, 74 insertions, 10 deletions
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
index 1eb924529c..dd379169ff 100644
--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
@@ -42,8 +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;
- size_t blob_size, policy_hash_size, decrypted_key_size, pubkey_size;
+ _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL, *salt = NULL;
+ size_t blob_size, policy_hash_size, decrypted_key_size, pubkey_size, salt_size = 0;
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
@@ -90,6 +90,8 @@ _public_ int cryptsetup_token_open_pin(
&blob_size,
&policy_hash,
&policy_hash_size,
+ &salt,
+ &salt_size,
&flags);
if (r < 0)
return log_debug_open_error(cd, r);
@@ -110,6 +112,8 @@ _public_ int cryptsetup_token_open_pin(
blob_size,
policy_hash,
policy_hash_size,
+ salt,
+ salt_size,
flags,
&decrypted_key,
&decrypted_key_size);
@@ -168,9 +172,9 @@ _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;
+ _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL, *salt = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- size_t blob_size, policy_hash_size, pubkey_size;
+ size_t blob_size, policy_hash_size, pubkey_size, salt_size = 0;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags flags = 0;
@@ -195,6 +199,8 @@ _public_ void cryptsetup_token_dump(
&blob_size,
&policy_hash,
&policy_hash_size,
+ &salt,
+ &salt_size,
&flags);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m");
@@ -227,6 +233,7 @@ _public_ void cryptsetup_token_dump(
crypt_log(cd, "\ttpm2-blob: %s\n", blob_str);
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-salt: %s\n", true_false(salt));
}
/*
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
index be496d4949..80a2c0d316 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
@@ -9,6 +9,7 @@
#include "luks2-tpm2.h"
#include "parse-util.h"
#include "random-util.h"
+#include "sha256.h"
#include "strv.h"
#include "tpm2-util.h"
@@ -26,12 +27,15 @@ int acquire_luks2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ const void *salt,
+ size_t salt_size,
TPM2Flags flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
_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(ret_decrypted_key);
@@ -50,6 +54,23 @@ int acquire_luks2_key(
if ((flags & TPM2_FLAGS_USE_PIN) && !pin)
return -ENOANO;
+ /* If we're using a PIN, and the luks header has a salt, it better have a pin too */
+ if ((flags & TPM2_FLAGS_USE_PIN) && salt && !pin)
+ return -ENOANO;
+
+ if (pin) {
+ 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);
+ if (r < 0)
+ return log_error_errno(r, "Failed to perform PBKDF2: %m");
+
+ r = base64mem(salted_pin, sizeof(salted_pin), &b64_salted_pin);
+ if (r < 0)
+ return log_error_errno(r, "Failed to base64 encode salted pin: %m");
+ pin = b64_salted_pin;
+ }
+
if (pubkey_pcr_mask != 0) {
r = tpm2_load_pcr_signature(signature_path, &signature_json);
if (r < 0)
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
index f3625124e5..36d514caa0 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
@@ -20,6 +20,8 @@ int acquire_luks2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ const void *salt,
+ size_t salt_size,
TPM2Flags flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c
index 838c02bfc9..2a8a38c593 100644
--- a/src/cryptsetup/cryptsetup-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tpm2.c
@@ -9,6 +9,7 @@
#include "json.h"
#include "parse-util.h"
#include "random-util.h"
+#include "sha256.h"
#include "tpm2-util.h"
static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) {
@@ -69,6 +70,8 @@ int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ const void *salt,
+ size_t salt_size,
TPM2Flags flags,
usec_t until,
bool headless,
@@ -140,7 +143,7 @@ int acquire_tpm2_key(
ret_decrypted_key_size);
for (int i = 5;; i--) {
- _cleanup_(erase_and_freep) char *pin_str = NULL;
+ _cleanup_(erase_and_freep) char *pin_str = NULL, *b64_salted_pin = NULL;
if (i <= 0)
return -EACCES;
@@ -149,13 +152,28 @@ int acquire_tpm2_key(
if (r < 0)
return r;
+ if (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);
+ if (r < 0)
+ return log_error_errno(r, "Failed to perform PBKDF2: %m");
+
+ r = base64mem(salted_pin, sizeof(salted_pin), &b64_salted_pin);
+ if (r < 0)
+ return log_error_errno(r, "Failed to base64 encode salted pin: %m");
+ } else
+ /* no salting needed, backwards compat with non-salted pins */
+ b64_salted_pin = TAKE_PTR(pin_str);
+
r = tpm2_unseal(device,
hash_pcr_mask,
pcr_bank,
pubkey, pubkey_size,
pubkey_pcr_mask,
signature_json,
- pin_str,
+ b64_salted_pin,
primary_alg,
blob,
blob_size,
@@ -188,6 +206,8 @@ int find_tpm2_auto_data(
size_t *ret_blob_size,
void **ret_policy_hash,
size_t *ret_policy_hash_size,
+ void **ret_salt,
+ size_t *ret_salt_size,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {
@@ -197,9 +217,9 @@ 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;
+ _cleanup_free_ void *blob = NULL, *policy_hash = NULL, *pubkey = NULL, *salt = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- size_t blob_size, policy_hash_size, pubkey_size;
+ size_t blob_size, policy_hash_size, pubkey_size, salt_size = 0;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags flags;
@@ -221,6 +241,7 @@ int find_tpm2_auto_data(
&primary_alg,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
+ &salt, &salt_size,
&flags);
if (r == -EUCLEAN) /* Gracefully handle issues in JSON fields not owned by us */
continue;
@@ -243,6 +264,8 @@ int find_tpm2_auto_data(
*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_keyslot = keyslot;
*ret_token = token;
*ret_flags = flags;
diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h
index a34eb8443d..f6549b7d1d 100644
--- a/src/cryptsetup/cryptsetup-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tpm2.h
@@ -28,6 +28,8 @@ int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ const void *salt,
+ size_t salt_size,
TPM2Flags flags,
usec_t until,
bool headless,
@@ -49,6 +51,8 @@ int find_tpm2_auto_data(
size_t *ret_blob_size,
void **ret_policy_hash,
size_t *ret_policy_hash_size,
+ void **ret_salt,
+ size_t *ret_salt_size,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token);
@@ -72,6 +76,8 @@ static inline int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ const void *salt,
+ size_t salt_size,
TPM2Flags flags,
usec_t until,
bool headless,
@@ -97,6 +103,8 @@ static inline int find_tpm2_auto_data(
size_t *ret_blob_size,
void **ret_policy_hash,
size_t *ret_policy_hash_size,
+ void **ret_salt,
+ size_t *ret_salt_size,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 2c9d416734..d40fe7bfad 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -1658,6 +1658,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
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,
arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0,
until,
arg_headless,
@@ -1703,8 +1704,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
* works. */
for (;;) {
- _cleanup_free_ void *pubkey = NULL;
- size_t pubkey_size = 0;
+ _cleanup_free_ void *pubkey = NULL, *salt = NULL;
+ size_t pubkey_size = 0, salt_size = 0;
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags tpm2_flags;
@@ -1720,6 +1721,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
&primary_alg,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
+ &salt, &salt_size,
&tpm2_flags,
&keyslot,
&token);
@@ -1749,6 +1751,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
/* 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,
tpm2_flags,
until,
arg_headless,