tpm2-util: more iovec'ification

Let's move more code to using struct iovec for passing around binary
chunks of data.

No real changes in behaviour, just refactoring.
This commit is contained in:
Lennart Poettering
2024-01-05 11:34:46 +01:00
parent 9d1c3e9413
commit 8d042bc40a
15 changed files with 477 additions and 641 deletions
+21 -10
View File
@@ -9,6 +9,7 @@
#include "fileio.h"
#include "glob-util.h"
#include "io-util.h"
#include "iovec-util.h"
#include "label-util.h"
#include "mkdir-label.h"
#include "mount-util.h"
@@ -271,20 +272,23 @@ static int maybe_decrypt_and_write_credential(
size_t size,
uint64_t *left) {
_cleanup_free_ void *plaintext = NULL;
_cleanup_(iovec_done_erase) struct iovec plaintext = {};
size_t add;
int r;
if (encrypted) {
size_t plaintext_size = 0;
r = decrypt_credential_and_warn(id, now(CLOCK_REALTIME), NULL, NULL, data, size,
&plaintext, &plaintext_size);
r = decrypt_credential_and_warn(
id,
now(CLOCK_REALTIME),
/* tpm2_device= */ NULL,
/* tpm2_signature_path= */ NULL,
&IOVEC_MAKE(data, size),
&plaintext);
if (r < 0)
return r;
data = plaintext;
size = plaintext_size;
data = plaintext.iov_base;
size = plaintext.iov_len;
}
add = strlen(id) + size;
@@ -684,7 +688,7 @@ static int acquire_credentials(
/* Finally, we add in literally specified credentials. If the credentials already exist, we'll not
* add them, so that they can act as a "default" if the same credential is specified multiple times. */
HASHMAP_FOREACH(sc, context->set_credentials) {
_cleanup_(erase_and_freep) void *plaintext = NULL;
_cleanup_(iovec_done_erase) struct iovec plaintext = {};
const char *data;
size_t size, add;
@@ -698,11 +702,18 @@ static int acquire_credentials(
return log_debug_errno(errno, "Failed to test if credential %s exists: %m", sc->id);
if (sc->encrypted) {
r = decrypt_credential_and_warn(sc->id, now(CLOCK_REALTIME), NULL, NULL, sc->data, sc->size, &plaintext, &size);
r = decrypt_credential_and_warn(
sc->id,
now(CLOCK_REALTIME),
/* tpm2_device= */ NULL,
/* tpm2_signature_path= */ NULL,
&IOVEC_MAKE(sc->data, sc->size),
&plaintext);
if (r < 0)
return r;
data = plaintext;
data = plaintext.iov_base;
size = plaintext.iov_len;
} else {
data = sc->data;
size = sc->size;
+25 -29
View File
@@ -421,22 +421,21 @@ static int verb_cat(int argc, char **argv, void *userdata) {
}
if (encrypted) {
_cleanup_(erase_and_freep) void *plaintext = NULL;
size_t plaintext_size;
_cleanup_(iovec_done_erase) struct iovec plaintext = {};
r = decrypt_credential_and_warn(
*cn,
timestamp,
arg_tpm2_device,
arg_tpm2_signature,
data, size,
&plaintext, &plaintext_size);
&IOVEC_MAKE(data, size),
&plaintext);
if (r < 0)
return r;
erase_and_free(data);
data = TAKE_PTR(plaintext);
size = plaintext_size;
data = TAKE_PTR(plaintext.iov_base);
size = plaintext.iov_len;
}
r = write_blob(stdout, data, size);
@@ -448,11 +447,9 @@ static int verb_cat(int argc, char **argv, void *userdata) {
}
static int verb_encrypt(int argc, char **argv, void *userdata) {
_cleanup_(iovec_done_erase) struct iovec plaintext = {}, output = {};
_cleanup_free_ char *base64_buf = NULL, *fname = NULL;
_cleanup_(erase_and_freep) char *plaintext = NULL;
const char *input_path, *output_path, *name;
_cleanup_free_ void *output = NULL;
size_t plaintext_size, output_size;
ssize_t base64_size;
usec_t timestamp;
int r;
@@ -462,9 +459,9 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
input_path = empty_or_dash(argv[1]) ? NULL : argv[1];
if (input_path)
r = read_full_file_full(AT_FDCWD, input_path, UINT64_MAX, CREDENTIAL_SIZE_MAX, READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &plaintext, &plaintext_size);
r = read_full_file_full(AT_FDCWD, input_path, UINT64_MAX, CREDENTIAL_SIZE_MAX, READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, (char**) &plaintext.iov_base, &plaintext.iov_len);
else
r = read_full_stream_full(stdin, NULL, UINT64_MAX, CREDENTIAL_SIZE_MAX, READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER, &plaintext, &plaintext_size);
r = read_full_stream_full(stdin, NULL, UINT64_MAX, CREDENTIAL_SIZE_MAX, READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER, (char**) &plaintext.iov_base, &plaintext.iov_len);
if (r == -E2BIG)
return log_error_errno(r, "Plaintext too long for credential (allowed size: %zu).", (size_t) CREDENTIAL_SIZE_MAX);
if (r < 0)
@@ -503,12 +500,12 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
arg_tpm2_pcr_mask,
arg_tpm2_public_key,
arg_tpm2_public_key_pcr_mask,
plaintext, plaintext_size,
&output, &output_size);
&plaintext,
&output);
if (r < 0)
return r;
base64_size = base64mem_full(output, output_size, arg_pretty ? 69 : 79, &base64_buf);
base64_size = base64mem_full(output.iov_base, output.iov_len, arg_pretty ? 69 : 79, &base64_buf);
if (base64_size < 0)
return base64_size;
@@ -544,11 +541,10 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
}
static int verb_decrypt(int argc, char **argv, void *userdata) {
_cleanup_(erase_and_freep) void *plaintext = NULL;
_cleanup_free_ char *input = NULL, *fname = NULL;
_cleanup_(iovec_done_erase) struct iovec input = {}, plaintext = {};
_cleanup_free_ char *fname = NULL;
_cleanup_fclose_ FILE *output_file = NULL;
const char *input_path, *output_path, *name;
size_t input_size, plaintext_size;
usec_t timestamp;
FILE *f;
int r;
@@ -558,9 +554,9 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
input_path = empty_or_dash(argv[1]) ? NULL : argv[1];
if (input_path)
r = read_full_file_full(AT_FDCWD, argv[1], UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX, READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &input, &input_size);
r = read_full_file_full(AT_FDCWD, argv[1], UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX, READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, (char**) &input, &input.iov_len);
else
r = read_full_stream_full(stdin, NULL, UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX, READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, &input, &input_size);
r = read_full_stream_full(stdin, NULL, UINT64_MAX, CREDENTIAL_ENCRYPTED_SIZE_MAX, READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, (char**) &input, &input.iov_len);
if (r == -E2BIG)
return log_error_errno(r, "Data too long for encrypted credential (allowed size: %zu).", (size_t) CREDENTIAL_ENCRYPTED_SIZE_MAX);
if (r < 0)
@@ -592,8 +588,8 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
timestamp,
arg_tpm2_device,
arg_tpm2_signature,
input, input_size,
&plaintext, &plaintext_size);
&input,
&plaintext);
if (r < 0)
return r;
@@ -606,7 +602,7 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
} else
f = stdout;
r = write_blob(f, plaintext, plaintext_size);
r = write_blob(f, plaintext.iov_base, plaintext.iov_len);
if (r < 0)
return r;
@@ -614,14 +610,14 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
}
static int verb_setup(int argc, char **argv, void *userdata) {
size_t size;
_cleanup_(iovec_done_erase) struct iovec host_key = {};
int r;
r = get_credential_host_secret(CREDENTIAL_SECRET_GENERATE|CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED, NULL, &size);
r = get_credential_host_secret(CREDENTIAL_SECRET_GENERATE|CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED, &host_key);
if (r < 0)
return log_error_errno(r, "Failed to setup credentials host key: %m");
log_info("%zu byte credentials host key set up.", size);
log_info("%zu byte credentials host key set up.", host_key.iov_len);
return EXIT_SUCCESS;
}
@@ -1032,8 +1028,8 @@ static int vl_method_encrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
arg_tpm2_pcr_mask,
arg_tpm2_public_key,
arg_tpm2_public_key_pcr_mask,
p.text ?: p.data.iov_base, p.text ? strlen(p.text) : p.data.iov_len,
&output.iov_base, &output.iov_len);
p.text ? &IOVEC_MAKE_STRING(p.text) : &p.data,
&output);
if (r < 0)
return r;
@@ -1106,8 +1102,8 @@ static int vl_method_decrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
p.timestamp,
arg_tpm2_device,
arg_tpm2_signature,
p.blob.iov_base, p.blob.iov_len,
&output.iov_base, &output.iov_len);
&p.blob,
&output);
if (r == -EBADMSG)
return varlink_error(link, "io.systemd.Credentials.BadFormat", NULL);
if (r == -EREMOTE)
+26 -30
View File
@@ -143,12 +143,10 @@ int enroll_tpm2(struct crypt_device *cd,
bool use_pin,
const char *pcrlock_path) {
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *signature_json = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_free_ void *srk_buf = NULL;
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
_cleanup_free_ void *blob = NULL, *pubkey = NULL;
_cleanup_(iovec_done) struct iovec srk = {}, blob = {}, pubkey = {};
_cleanup_(iovec_done_erase) struct iovec secret = {};
const char *node;
_cleanup_(erase_and_freep) char *pin_str = NULL;
ssize_t base64_encoded_size;
@@ -194,7 +192,7 @@ int enroll_tpm2(struct crypt_device *cd,
}
TPM2B_PUBLIC public = {};
r = tpm2_load_pcr_public_key(pubkey_path, &pubkey, &pubkey_size);
r = tpm2_load_pcr_public_key(pubkey_path, &pubkey.iov_base, &pubkey.iov_len);
if (r < 0) {
if (pubkey_path || signature_path || r != -ENOENT)
return log_error_errno(r, "Failed to read TPM PCR public key: %m");
@@ -202,7 +200,7 @@ int enroll_tpm2(struct crypt_device *cd,
log_debug_errno(r, "Failed to read TPM2 PCR public key, proceeding without: %m");
pubkey_pcr_mask = 0;
} else {
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
r = tpm2_tpm2b_public_from_pem(pubkey.iov_base, pubkey.iov_len, &public);
if (r < 0)
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
@@ -271,7 +269,7 @@ int enroll_tpm2(struct crypt_device *cd,
r = tpm2_calculate_sealing_policy(
hash_pcr_values,
n_hash_pcr_values,
pubkey ? &public : NULL,
iovec_is_set(&pubkey) ? &public : NULL,
use_pin,
pcrlock_path ? &pcrlock_policy : NULL,
&policy);
@@ -283,21 +281,21 @@ int enroll_tpm2(struct crypt_device *cd,
seal_key_handle,
&device_key_public,
/* attributes= */ NULL,
/* secret= */ NULL, /* secret_size= */ 0,
/* secret= */ NULL,
&policy,
pin_str,
&secret, &secret_size,
&blob, &blob_size,
&srk_buf, &srk_buf_size);
&secret,
&blob,
&srk);
else
r = tpm2_seal(tpm2_context,
seal_key_handle,
&policy,
pin_str,
&secret, &secret_size,
&blob, &blob_size,
&secret,
&blob,
/* ret_primary_alg= */ NULL,
&srk_buf, &srk_buf_size);
&srk);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
@@ -313,33 +311,32 @@ int enroll_tpm2(struct crypt_device *cd,
}
/* If possible, verify the sealed data object. */
if ((!pubkey || signature_json) && !any_pcr_value_specified && !device_key) {
_cleanup_(erase_and_freep) void *secret2 = NULL;
size_t secret2_size;
if ((!iovec_is_set(&pubkey) || signature_json) && !any_pcr_value_specified && !device_key) {
_cleanup_(iovec_done_erase) struct iovec secret2 = {};
log_debug("Unsealing for verification...");
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
hash_pcr_bank,
pubkey, pubkey_size,
&pubkey,
pubkey_pcr_mask,
signature_json,
pin_str,
pcrlock_path ? &pcrlock_policy : NULL,
/* primary_alg= */ 0,
blob, blob_size,
policy.buffer, policy.size,
srk_buf, srk_buf_size,
&secret2, &secret2_size);
&blob,
&IOVEC_MAKE(policy.buffer, policy.size),
&srk,
&secret2);
if (r < 0)
return log_error_errno(r, "Failed to unseal secret using TPM2: %m");
if (memcmp_nn(secret, secret_size, secret2, secret2_size) != 0)
if (iovec_memcmp(&secret, &secret2) != 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 seal/unseal verification failed.");
}
/* let's base64 encode the key to use, for compat with homed (and it's easier to every type it in by keyboard, if that might end up being necessary. */
base64_encoded_size = base64mem(secret, secret_size, &base64_encoded);
base64_encoded_size = base64mem(secret.iov_base, secret.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
return log_error_errno(base64_encoded_size, "Failed to base64 encode secret key: %m");
@@ -361,14 +358,13 @@ int enroll_tpm2(struct crypt_device *cd,
keyslot,
hash_pcr_mask,
hash_pcr_bank,
pubkey, pubkey_size,
&pubkey,
pubkey_pcr_mask,
/* primary_alg= */ 0,
blob, blob_size,
policy.buffer, policy.size,
use_pin ? binary_salt : NULL,
use_pin ? sizeof(binary_salt) : 0,
srk_buf, srk_buf_size,
&blob,
&IOVEC_MAKE(policy.buffer, policy.size),
use_pin ? &IOVEC_MAKE(binary_salt, sizeof(binary_salt)) : NULL,
&srk,
flags,
&v);
if (r < 0)
@@ -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 = {};
_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 = {
@@ -79,21 +78,16 @@ _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,
&flags);
if (r < 0)
return log_debug_open_error(cd, r);
@@ -105,28 +99,23 @@ _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,
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 +166,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 = {};
_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 +185,12 @@ _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,
&flags);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m");
@@ -220,15 +203,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 +224,8 @@ _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)));
}
/*
+14 -21
View File
@@ -17,33 +17,26 @@ 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,
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 +51,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");
@@ -92,16 +85,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");
+6 -12
View File
@@ -10,21 +10,15 @@ 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 *pcrlock_path,
const char *pin,
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,
TPM2Flags flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
struct iovec *decrypted_key);
+39 -66
View File
@@ -58,8 +58,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 +66,23 @@ 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,
TPM2Flags flags,
usec_t until,
bool headless,
AskPasswordFlags ask_password_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_ 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 +94,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 +109,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) {
@@ -147,20 +139,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");
@@ -177,11 +165,11 @@ int acquire_tpm2_key(
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 +183,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,
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 +212,13 @@ 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,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {
@@ -249,9 +228,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 = {};
_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 +246,13 @@ 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,
&flags);
if (r == -EUCLEAN) /* Gracefully handle issues in JSON fields not owned by us */
continue;
@@ -289,20 +267,15 @@ 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_flags = flags;
return 0;
}
+22 -44
View File
@@ -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,15 @@ 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,
TPM2Flags flags,
usec_t until,
bool headless,
AskPasswordFlags ask_password_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
struct iovec *ret_decrypted_key);
int find_tpm2_auto_data(
struct crypt_device *cd,
@@ -46,18 +40,13 @@ 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,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token);
@@ -69,8 +58,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 +66,15 @@ 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,
TPM2Flags flags,
usec_t until,
bool headless,
AskPasswordFlags ask_password_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
struct iovec *ret_decrypted_key) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support not available.");
@@ -103,18 +86,13 @@ 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,
TPM2Flags *ret_flags,
int *ret_keyslot,
int *ret_token) {
+25 -30
View File
@@ -1650,18 +1650,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 +1670,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 +1678,21 @@ 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,
arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0,
until,
arg_headless,
arg_ask_password_flags,
&decrypted_key, &decrypted_key_size);
&decrypted_key);
if (r >= 0)
break;
if (IN_SET(r, -EACCES, -ENOLCK))
@@ -1725,8 +1723,7 @@ 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;
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {};
bool found_some = false;
int token = 0; /* first token to look at */
@@ -1735,8 +1732,7 @@ 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 = {};
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags tpm2_flags;
@@ -1747,13 +1743,13 @@ 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,
&tpm2_flags,
&keyslot,
&token);
@@ -1778,21 +1774,21 @@ 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,
tpm2_flags,
until,
arg_headless,
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 +1833,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 +2040,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)
+19 -21
View File
@@ -3774,17 +3774,15 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
if (IN_SET(p->encrypt, ENCRYPT_TPM2, ENCRYPT_KEY_FILE_TPM2)) {
#if HAVE_TPM2
_cleanup_(iovec_done) struct iovec pubkey = {}, blob = {}, srk = {};
_cleanup_(iovec_done_erase) struct iovec secret = {};
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *pubkey = NULL;
_cleanup_free_ void *blob = NULL, *srk_buf = NULL;
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
ssize_t base64_encoded_size;
int keyslot;
TPM2Flags flags = 0;
if (arg_tpm2_public_key_pcr_mask != 0) {
r = tpm2_load_pcr_public_key(arg_tpm2_public_key, &pubkey, &pubkey_size);
r = tpm2_load_pcr_public_key(arg_tpm2_public_key, &pubkey.iov_base, &pubkey.iov_len);
if (r < 0) {
if (arg_tpm2_public_key || r != -ENOENT)
return log_error_errno(r, "Failed to read TPM PCR public key: %m");
@@ -3795,8 +3793,8 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
}
TPM2B_PUBLIC public;
if (pubkey) {
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
if (iovec_is_set(&pubkey)) {
r = tpm2_tpm2b_public_from_pem(pubkey.iov_base, pubkey.iov_len, &public);
if (r < 0)
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
}
@@ -3853,7 +3851,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
r = tpm2_calculate_sealing_policy(
arg_tpm2_hash_pcr_values,
arg_tpm2_n_hash_pcr_values,
pubkey ? &public : NULL,
iovec_is_set(&pubkey) ? &public : NULL,
/* use_pin= */ false,
arg_tpm2_pcrlock ? &pcrlock_policy : NULL,
&policy);
@@ -3865,25 +3863,25 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
arg_tpm2_seal_key_handle,
&device_key_public,
/* attributes= */ NULL,
/* secret= */ NULL, /* secret_size= */ 0,
/* secret= */ NULL,
&policy,
/* pin= */ NULL,
&secret, &secret_size,
&blob, &blob_size,
&srk_buf, &srk_buf_size);
&secret,
&blob,
&srk);
else
r = tpm2_seal(tpm2_context,
arg_tpm2_seal_key_handle,
&policy,
/* pin= */ NULL,
&secret, &secret_size,
&blob, &blob_size,
&secret,
&blob,
/* ret_primary_alg= */ NULL,
&srk_buf, &srk_buf_size);
&srk);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
base64_encoded_size = base64mem(secret, secret_size, &base64_encoded);
base64_encoded_size = base64mem(secret.iov_base, secret.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
return log_error_errno(base64_encoded_size, "Failed to base64 encode secret key: %m");
@@ -3905,13 +3903,13 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
keyslot,
hash_pcr_mask,
hash_pcr_bank,
pubkey, pubkey_size,
&pubkey,
arg_tpm2_public_key_pcr_mask,
/* primary_alg= */ 0,
blob, blob_size,
policy.buffer, policy.size,
NULL, 0, /* no salt because tpm2_seal has no pin */
srk_buf, srk_buf_size,
&blob,
&IOVEC_MAKE(policy.buffer, policy.size),
/* salt= */ NULL, /* no salt because tpm2_seal has no pin */
&srk,
flags,
&v);
if (r < 0)
+130 -159
View File
@@ -138,14 +138,13 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
}
int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size) {
_cleanup_(iovec_done_erase) struct iovec ret_iovec = {};
_cleanup_(erase_and_freep) void *data = NULL;
_cleanup_free_ char *fn = NULL;
size_t sz = 0;
const char *d;
int r;
assert(ret);
/* Just like read_credential() but will also look for encrypted credentials. Note that services only
* receive decrypted credentials, hence use read_credential() for those. This helper here is for
* generators, i.e. code that runs outside of service context, and thus has no decrypted credentials
@@ -193,18 +192,21 @@ int read_credential_with_decryption(const char *name, void **ret, size_t *ret_si
now(CLOCK_REALTIME),
/* tpm2_device = */ NULL,
/* tpm2_signature_path = */ NULL,
data,
sz,
ret,
ret_size);
&IOVEC_MAKE(data, sz),
&ret_iovec);
if (r < 0)
return r;
if (ret)
*ret = TAKE_PTR(ret_iovec.iov_base);
if (ret_size)
*ret_size = ret_iovec.iov_len;
return 1; /* found */
not_found:
*ret = NULL;
if (ret)
*ret = NULL;
if (ret_size)
*ret_size = 0;
@@ -352,8 +354,7 @@ static int make_credential_host_secret(
CredentialSecretFlags flags,
const char *dirname,
const char *fn,
void **ret_data,
size_t *ret_size) {
struct iovec *ret) {
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -EBADF;
@@ -420,7 +421,7 @@ static int make_credential_host_secret(
goto fail;
}
if (ret_data) {
if (ret) {
void *copy;
copy = memdup(buf.data, sizeof(buf.data));
@@ -429,12 +430,9 @@ static int make_credential_host_secret(
goto fail;
}
*ret_data = copy;
*ret = IOVEC_MAKE(copy, sizeof(buf.data));
}
if (ret_size)
*ret_size = sizeof(buf.data);
return 0;
fail:
@@ -444,7 +442,7 @@ fail:
return r;
}
int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size) {
int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
_cleanup_free_ char *_dirname = NULL, *_filename = NULL;
_cleanup_close_ int dfd = -EBADF;
sd_id128_t machine_id;
@@ -512,7 +510,7 @@ int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *
"Failed to open %s/%s: %m", dirname, filename);
r = make_credential_host_secret(dfd, machine_id, flags, dirname, filename, ret, ret_size);
r = make_credential_host_secret(dfd, machine_id, flags, dirname, filename, ret);
if (r == -EEXIST) {
log_debug_errno(r, "Credential secret %s/%s appeared while we were creating it, rereading.",
dirname, filename);
@@ -579,12 +577,9 @@ int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *
if (!copy)
return log_oom_debug();
*ret = copy;
*ret = IOVEC_MAKE(copy, sz);
}
if (ret_size)
*ret_size = sz;
return 0;
}
@@ -683,17 +678,15 @@ struct _packed_ metadata_credential_header {
#define CREDENTIAL_FIELD_SIZE_MAX (16U*1024U)
static int sha256_hash_host_and_tpm2_key(
const void *host_key,
size_t host_key_size,
const void *tpm2_key,
size_t tpm2_key_size,
const struct iovec *host_key,
const struct iovec *tpm2_key,
uint8_t ret[static SHA256_DIGEST_LENGTH]) {
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md = NULL;
unsigned l;
assert(host_key_size == 0 || host_key);
assert(tpm2_key_size == 0 || tpm2_key);
assert(iovec_is_valid(host_key));
assert(iovec_is_valid(tpm2_key));
assert(ret);
/* Combines the host key and the TPM2 HMAC hash into a SHA256 hash value we'll use as symmetric encryption key. */
@@ -705,10 +698,10 @@ static int sha256_hash_host_and_tpm2_key(
if (EVP_DigestInit_ex(md, EVP_sha256(), NULL) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initial SHA256 context.");
if (host_key && EVP_DigestUpdate(md, host_key, host_key_size) != 1)
if (iovec_is_set(host_key) && EVP_DigestUpdate(md, host_key->iov_base, host_key->iov_len) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to hash host key.");
if (tpm2_key && EVP_DigestUpdate(md, tpm2_key, tpm2_key_size) != 1)
if (iovec_is_set(tpm2_key) && EVP_DigestUpdate(md, tpm2_key->iov_base, tpm2_key->iov_len) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to hash TPM2 key.");
assert(EVP_MD_CTX_size(md) == SHA256_DIGEST_LENGTH);
@@ -729,28 +722,23 @@ int encrypt_credential_and_warn(
uint32_t tpm2_hash_pcr_mask,
const char *tpm2_pubkey_path,
uint32_t tpm2_pubkey_pcr_mask,
const void *input,
size_t input_size,
void **ret,
size_t *ret_size) {
const struct iovec *input,
struct iovec *ret) {
_cleanup_(iovec_done) struct iovec tpm2_blob = {}, tpm2_policy_hash = {}, iv = {}, pubkey = {};
_cleanup_(iovec_done_erase) struct iovec tpm2_key = {}, output = {}, host_key = {};
_cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL;
_cleanup_(erase_and_freep) void *host_key = NULL, *tpm2_key = NULL;
size_t host_key_size = 0, tpm2_key_size = 0, tpm2_blob_size = 0, tpm2_policy_hash_size = 0, output_size, p, ml;
_cleanup_free_ void *tpm2_blob = NULL, *tpm2_policy_hash = NULL, *iv = NULL, *output = NULL;
_cleanup_free_ struct metadata_credential_header *m = NULL;
uint16_t tpm2_pcr_bank = 0, tpm2_primary_alg = 0;
struct encrypted_credential_header *h;
int ksz, bsz, ivsz, tsz, added, r;
_cleanup_free_ void *pubkey = NULL;
size_t pubkey_size = 0;
uint8_t md[SHA256_DIGEST_LENGTH];
const EVP_CIPHER *cc;
sd_id128_t id;
size_t p, ml;
assert(input || input_size == 0);
assert(iovec_is_valid(input));
assert(ret);
assert(ret_size);
if (!sd_id128_in_set(with_key,
_CRED_AUTO,
@@ -790,8 +778,7 @@ int encrypt_credential_and_warn(
CREDENTIAL_SECRET_GENERATE|
CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED|
(sd_id128_equal(with_key, _CRED_AUTO) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
&host_key,
&host_key_size);
&host_key);
if (r == -ENOMEDIUM && sd_id128_equal(with_key, _CRED_AUTO))
log_debug_errno(r, "Credential host secret location on temporary file system, not using.");
else if (r < 0)
@@ -824,7 +811,7 @@ int encrypt_credential_and_warn(
/* Load public key for PCR policies, if one is specified, or explicitly requested */
r = tpm2_load_pcr_public_key(tpm2_pubkey_path, &pubkey, &pubkey_size);
r = tpm2_load_pcr_public_key(tpm2_pubkey_path, &pubkey.iov_base, &pubkey.iov_len);
if (r < 0) {
if (tpm2_pubkey_path || r != -ENOENT || !sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD))
return log_error_errno(r, "Failed read TPM PCR public key: %m");
@@ -833,7 +820,7 @@ int encrypt_credential_and_warn(
}
}
if (!pubkey)
if (!iovec_is_set(&pubkey))
tpm2_pubkey_pcr_mask = 0;
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
@@ -855,8 +842,8 @@ int encrypt_credential_and_warn(
return log_error_errno(r, "Could not read PCR values: %m");
TPM2B_PUBLIC public;
if (pubkey) {
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
if (iovec_is_set(&pubkey)) {
r = tpm2_tpm2b_public_from_pem(pubkey.iov_base, pubkey.iov_len, &public);
if (r < 0)
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
}
@@ -865,7 +852,7 @@ int encrypt_credential_and_warn(
r = tpm2_calculate_sealing_policy(
tpm2_hash_pcr_values,
tpm2_n_hash_pcr_values,
pubkey ? &public : NULL,
iovec_is_set(&pubkey) ? &public : NULL,
/* use_pin= */ false,
/* pcrlock_policy= */ NULL,
&tpm2_policy);
@@ -876,11 +863,10 @@ int encrypt_credential_and_warn(
/* seal_key_handle= */ 0,
&tpm2_policy,
/* pin= */ NULL,
&tpm2_key, &tpm2_key_size,
&tpm2_blob, &tpm2_blob_size,
&tpm2_key,
&tpm2_blob,
&tpm2_primary_alg,
/* ret_srk_buf= */ NULL,
/* ret_srk_buf_size= */ NULL);
/* ret_srk= */ NULL);
if (r < 0) {
if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
log_warning("TPM2 present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled.");
@@ -890,25 +876,22 @@ int encrypt_credential_and_warn(
log_notice_errno(r, "TPM2 sealing didn't work, continuing without TPM2: %m");
}
tpm2_policy_hash_size = tpm2_policy.size;
tpm2_policy_hash = malloc(tpm2_policy_hash_size);
if (!tpm2_policy_hash)
if (!iovec_memdup(&IOVEC_MAKE(tpm2_policy.buffer, tpm2_policy.size), &tpm2_policy_hash))
return log_oom();
memcpy(tpm2_policy_hash, tpm2_policy.buffer, tpm2_policy_hash_size);
assert(tpm2_blob_size <= CREDENTIAL_FIELD_SIZE_MAX);
assert(tpm2_policy_hash_size <= CREDENTIAL_FIELD_SIZE_MAX);
assert(tpm2_blob.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
assert(tpm2_policy_hash.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
}
#endif
if (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD)) {
/* Let's settle the key type in auto mode now. */
if (host_key && tpm2_key)
id = pubkey ? CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK : CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC;
else if (tpm2_key)
id = pubkey ? CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK : CRED_AES256_GCM_BY_TPM2_HMAC;
else if (host_key)
if (iovec_is_set(&host_key) && iovec_is_set(&tpm2_key))
id = iovec_is_set(&pubkey) ? CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK : CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC;
else if (iovec_is_set(&tpm2_key))
id = iovec_is_set(&pubkey) ? CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK : CRED_AES256_GCM_BY_TPM2_HMAC;
else if (iovec_is_set(&host_key))
id = CRED_AES256_GCM_BY_HOST;
else if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
id = CRED_AES256_GCM_BY_NULL;
@@ -922,7 +905,7 @@ int encrypt_credential_and_warn(
log_warning("Using a null key for encryption and signing. Confidentiality or authenticity will not be provided.");
/* Let's now take the host key and the TPM2 key and hash it together, to use as encryption key for the data */
r = sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
r = sha256_hash_host_and_tpm2_key(&host_key, &tpm2_key, md);
if (r < 0)
return r;
@@ -939,11 +922,13 @@ int encrypt_credential_and_warn(
if (ivsz > 0) {
assert((size_t) ivsz <= CREDENTIAL_FIELD_SIZE_MAX);
iv = malloc(ivsz);
if (!iv)
iv.iov_base = malloc(ivsz);
if (!iv.iov_base)
return log_oom();
r = crypto_random_bytes(iv, ivsz);
iv.iov_len = ivsz;
r = crypto_random_bytes(iv.iov_base, iv.iov_len);
if (r < 0)
return log_error_errno(r, "Failed to acquired randomized IV: %m");
}
@@ -955,61 +940,61 @@ int encrypt_credential_and_warn(
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM), "Failed to allocate encryption object: %s",
ERR_error_string(ERR_get_error(), NULL));
if (EVP_EncryptInit_ex(context, cc, NULL, md, iv) != 1)
if (EVP_EncryptInit_ex(context, cc, NULL, md, iv.iov_base) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize encryption context: %s",
ERR_error_string(ERR_get_error(), NULL));
/* Just an upper estimate */
output_size =
output.iov_len =
ALIGN8(offsetof(struct encrypted_credential_header, iv) + ivsz) +
ALIGN8(tpm2_key ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob_size + tpm2_policy_hash_size : 0) +
ALIGN8(pubkey ? offsetof(struct tpm2_public_key_credential_header, data) + pubkey_size : 0) +
ALIGN8(iovec_is_set(&tpm2_key) ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob.iov_len + tpm2_policy_hash.iov_len : 0) +
ALIGN8(iovec_is_set(&pubkey) ? offsetof(struct tpm2_public_key_credential_header, data) + pubkey.iov_len : 0) +
ALIGN8(offsetof(struct metadata_credential_header, name) + strlen_ptr(name)) +
input_size + 2U * (size_t) bsz +
input->iov_len + 2U * (size_t) bsz +
tsz;
output = malloc0(output_size);
if (!output)
output.iov_base = malloc0(output.iov_len);
if (!output.iov_base)
return log_oom();
h = (struct encrypted_credential_header*) output;
h = (struct encrypted_credential_header*) output.iov_base;
h->id = id;
h->block_size = htole32(bsz);
h->key_size = htole32(ksz);
h->tag_size = htole32(tsz);
h->iv_size = htole32(ivsz);
memcpy(h->iv, iv, ivsz);
memcpy(h->iv, iv.iov_base, ivsz);
p = ALIGN8(offsetof(struct encrypted_credential_header, iv) + ivsz);
if (tpm2_key) {
if (iovec_is_set(&tpm2_key)) {
struct tpm2_credential_header *t;
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
t = (struct tpm2_credential_header*) ((uint8_t*) output.iov_base + p);
t->pcr_mask = htole64(tpm2_hash_pcr_mask);
t->pcr_bank = htole16(tpm2_pcr_bank);
t->primary_alg = htole16(tpm2_primary_alg);
t->blob_size = htole32(tpm2_blob_size);
t->policy_hash_size = htole32(tpm2_policy_hash_size);
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
memcpy(t->policy_hash_and_blob + tpm2_blob_size, tpm2_policy_hash, tpm2_policy_hash_size);
t->blob_size = htole32(tpm2_blob.iov_len);
t->policy_hash_size = htole32(tpm2_policy_hash.iov_len);
memcpy(t->policy_hash_and_blob, tpm2_blob.iov_base, tpm2_blob.iov_len);
memcpy(t->policy_hash_and_blob + tpm2_blob.iov_len, tpm2_policy_hash.iov_base, tpm2_policy_hash.iov_len);
p += ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob_size + tpm2_policy_hash_size);
p += ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + tpm2_blob.iov_len + tpm2_policy_hash.iov_len);
}
if (pubkey) {
if (iovec_is_set(&pubkey)) {
struct tpm2_public_key_credential_header *z;
z = (struct tpm2_public_key_credential_header*) ((uint8_t*) output + p);
z = (struct tpm2_public_key_credential_header*) ((uint8_t*) output.iov_base + p);
z->pcr_mask = htole64(tpm2_pubkey_pcr_mask);
z->size = htole32(pubkey_size);
memcpy(z->data, pubkey, pubkey_size);
z->size = htole32(pubkey.iov_len);
memcpy(z->data, pubkey.iov_base, pubkey.iov_len);
p += ALIGN8(offsetof(struct tpm2_public_key_credential_header, data) + pubkey_size);
p += ALIGN8(offsetof(struct tpm2_public_key_credential_header, data) + pubkey.iov_len);
}
/* Pass the encrypted + TPM2 header as AAD */
if (EVP_EncryptUpdate(context, NULL, &added, output, p) != 1)
if (EVP_EncryptUpdate(context, NULL, &added, output.iov_base, p) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to write AAD data: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -1025,53 +1010,52 @@ int encrypt_credential_and_warn(
memcpy_safe(m->name, name, ml);
/* And encrypt the metadata header */
if (EVP_EncryptUpdate(context, (uint8_t*) output + p, &added, (const unsigned char*) m, ALIGN8(offsetof(struct metadata_credential_header, name) + ml)) != 1)
if (EVP_EncryptUpdate(context, (uint8_t*) output.iov_base + p, &added, (const unsigned char*) m, ALIGN8(offsetof(struct metadata_credential_header, name) + ml)) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to encrypt metadata header: %s",
ERR_error_string(ERR_get_error(), NULL));
assert(added >= 0);
assert((size_t) added <= output_size - p);
assert((size_t) added <= output.iov_len - p);
p += added;
/* Then encrypt the plaintext */
if (EVP_EncryptUpdate(context, (uint8_t*) output + p, &added, input, input_size) != 1)
if (EVP_EncryptUpdate(context, (uint8_t*) output.iov_base + p, &added, input->iov_base, input->iov_len) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to encrypt data: %s",
ERR_error_string(ERR_get_error(), NULL));
assert(added >= 0);
assert((size_t) added <= output_size - p);
assert((size_t) added <= output.iov_len - p);
p += added;
/* Finalize */
if (EVP_EncryptFinal_ex(context, (uint8_t*) output + p, &added) != 1)
if (EVP_EncryptFinal_ex(context, (uint8_t*) output.iov_base + p, &added) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to finalize data encryption: %s",
ERR_error_string(ERR_get_error(), NULL));
assert(added >= 0);
assert((size_t) added <= output_size - p);
assert((size_t) added <= output.iov_len - p);
p += added;
assert(p <= output_size - tsz);
assert(p <= output.iov_len - tsz);
/* Append tag */
if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_GET_TAG, tsz, (uint8_t*) output + p) != 1)
if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_GET_TAG, tsz, (uint8_t*) output.iov_base + p) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get tag: %s",
ERR_error_string(ERR_get_error(), NULL));
p += tsz;
assert(p <= output_size);
assert(p <= output.iov_len);
output.iov_len = p;
if (DEBUG_LOGGING && input_size > 0) {
if (DEBUG_LOGGING && input->iov_len > 0) {
size_t base64_size;
base64_size = DIV_ROUND_UP(p * 4, 3); /* Include base64 size increase in debug output */
assert(base64_size >= input_size);
log_debug("Input of %zu bytes grew to output of %zu bytes (+%2zu%%).", input_size, base64_size, base64_size * 100 / input_size - 100);
base64_size = DIV_ROUND_UP(output.iov_len * 4, 3); /* Include base64 size increase in debug output */
assert(base64_size >= input->iov_len);
log_debug("Input of %zu bytes grew to output of %zu bytes (+%2zu%%).", input->iov_len, base64_size, base64_size * 100 / input->iov_len - 100);
}
*ret = TAKE_PTR(output);
*ret_size = p;
*ret = TAKE_STRUCT(output);
return 0;
}
@@ -1080,30 +1064,27 @@ int decrypt_credential_and_warn(
usec_t validate_timestamp,
const char *tpm2_device,
const char *tpm2_signature_path,
const void *input,
size_t input_size,
void **ret,
size_t *ret_size) {
const struct iovec *input,
struct iovec *ret) {
_cleanup_(erase_and_freep) void *host_key = NULL, *tpm2_key = NULL, *plaintext = NULL;
_cleanup_(iovec_done_erase) struct iovec host_key = {}, plaintext = {}, tpm2_key = {};
_cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL;
_cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL;
size_t host_key_size = 0, tpm2_key_size = 0, plaintext_size, p, hs;
struct encrypted_credential_header *h;
struct metadata_credential_header *m;
uint8_t md[SHA256_DIGEST_LENGTH];
bool with_tpm2, with_tpm2_pk, with_host_key, with_null;
const EVP_CIPHER *cc;
size_t p, hs;
int r, added;
assert(input || input_size == 0);
assert(iovec_is_valid(input));
assert(ret);
assert(ret_size);
h = (struct encrypted_credential_header*) input;
h = (struct encrypted_credential_header*) input->iov_base;
/* The ID must fit in, for the current and all future formats */
if (input_size < sizeof(h->id))
if (input->iov_len < sizeof(h->id))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
with_host_key = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK);
@@ -1141,7 +1122,7 @@ int decrypt_credential_and_warn(
}
/* Now we know the minimum header size */
if (input_size < offsetof(struct encrypted_credential_header, iv))
if (input->iov_len < offsetof(struct encrypted_credential_header, iv))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
/* Verify some basic header values */
@@ -1156,7 +1137,7 @@ int decrypt_credential_and_warn(
/* Ensure we have space for the full header now (we don't know the size of the name hence this is a
* lower limit only) */
if (input_size <
if (input->iov_len <
ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
ALIGN8(with_tpm2 ? offsetof(struct tpm2_credential_header, policy_hash_and_blob) : 0) +
ALIGN8(with_tpm2_pk ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
@@ -1168,7 +1149,7 @@ int decrypt_credential_and_warn(
if (with_tpm2) {
#if HAVE_TPM2
struct tpm2_credential_header* t = (struct tpm2_credential_header*) ((uint8_t*) input + p);
struct tpm2_credential_header* t = (struct tpm2_credential_header*) ((uint8_t*) input->iov_base + p);
struct tpm2_public_key_credential_header *z = NULL;
if (!TPM2_PCR_MASK_VALID(t->pcr_mask))
@@ -1184,7 +1165,7 @@ int decrypt_credential_and_warn(
/* Ensure we have space for the full TPM2 header now (still don't know the name, and its size
* though, hence still just a lower limit test only) */
if (input_size <
if (input->iov_len <
ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + le32toh(t->blob_size) + le32toh(t->policy_hash_size)) +
ALIGN8(with_tpm2_pk ? offsetof(struct tpm2_public_key_credential_header, data) : 0) +
@@ -1197,14 +1178,14 @@ int decrypt_credential_and_warn(
le32toh(t->policy_hash_size));
if (with_tpm2_pk) {
z = (struct tpm2_public_key_credential_header*) ((uint8_t*) input + p);
z = (struct tpm2_public_key_credential_header*) ((uint8_t*) input->iov_base + p);
if (!TPM2_PCR_MASK_VALID(le64toh(z->pcr_mask)) || le64toh(z->pcr_mask) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
if (le32toh(z->size) > PUBLIC_KEY_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected public key size.");
if (input_size <
if (input->iov_len <
ALIGN8(offsetof(struct encrypted_credential_header, iv) + le32toh(h->iv_size)) +
ALIGN8(offsetof(struct tpm2_credential_header, policy_hash_and_blob) + le32toh(t->blob_size) + le32toh(t->policy_hash_size)) +
ALIGN8(offsetof(struct tpm2_public_key_credential_header, data) + le32toh(z->size)) +
@@ -1226,21 +1207,16 @@ int decrypt_credential_and_warn(
r = tpm2_unseal(tpm2_context,
le64toh(t->pcr_mask),
le16toh(t->pcr_bank),
z ? z->data : NULL,
z ? le32toh(z->size) : 0,
z ? &IOVEC_MAKE(z->data, le32toh(z->size)) : NULL,
z ? le64toh(z->pcr_mask) : 0,
signature_json,
/* pin= */ NULL,
/* pcrlock_policy= */ NULL,
le16toh(t->primary_alg),
t->policy_hash_and_blob,
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),
le32toh(t->policy_hash_size),
/* srk_buf= */ NULL,
/* srk_buf_size= */ 0,
&tpm2_key,
&tpm2_key_size);
&IOVEC_MAKE(t->policy_hash_and_blob, le32toh(t->blob_size)),
&IOVEC_MAKE(t->policy_hash_and_blob + le32toh(t->blob_size), le32toh(t->policy_hash_size)),
/* srk= */ NULL,
&tpm2_key);
if (r < 0)
return log_error_errno(r, "Failed to unseal secret using TPM2: %m");
#else
@@ -1249,10 +1225,7 @@ int decrypt_credential_and_warn(
}
if (with_host_key) {
r = get_credential_host_secret(
0,
&host_key,
&host_key_size);
r = get_credential_host_secret(/* flags= */ 0, &host_key);
if (r < 0)
return log_error_errno(r, "Failed to determine local credential key: %m");
}
@@ -1260,7 +1233,7 @@ int decrypt_credential_and_warn(
if (with_null)
log_warning("Warning: using a null key for decryption and authentication. Confidentiality or authenticity are not provided.");
sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
sha256_hash_host_and_tpm2_key(&host_key, &tpm2_key, md);
assert_se(cc = EVP_aes_256_gcm());
@@ -1287,41 +1260,41 @@ int decrypt_credential_and_warn(
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set IV and key: %s",
ERR_error_string(ERR_get_error(), NULL));
if (EVP_DecryptUpdate(context, NULL, &added, input, p) != 1)
if (EVP_DecryptUpdate(context, NULL, &added, input->iov_base, p) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to write AAD data: %s",
ERR_error_string(ERR_get_error(), NULL));
plaintext = malloc(input_size - p - le32toh(h->tag_size));
if (!plaintext)
plaintext.iov_base = malloc(input->iov_len - p - le32toh(h->tag_size));
if (!plaintext.iov_base)
return -ENOMEM;
if (EVP_DecryptUpdate(
context,
plaintext,
plaintext.iov_base,
&added,
(uint8_t*) input + p,
input_size - p - le32toh(h->tag_size)) != 1)
(uint8_t*) input->iov_base + p,
input->iov_len - p - le32toh(h->tag_size)) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decrypt data: %s",
ERR_error_string(ERR_get_error(), NULL));
assert(added >= 0);
assert((size_t) added <= input_size - p - le32toh(h->tag_size));
plaintext_size = added;
assert((size_t) added <= input->iov_len - p - le32toh(h->tag_size));
plaintext.iov_len = added;
if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_TAG, le32toh(h->tag_size), (uint8_t*) input + input_size - le32toh(h->tag_size)) != 1)
if (EVP_CIPHER_CTX_ctrl(context, EVP_CTRL_GCM_SET_TAG, le32toh(h->tag_size), (uint8_t*) input->iov_base + input->iov_len - le32toh(h->tag_size)) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set tag: %s",
ERR_error_string(ERR_get_error(), NULL));
if (EVP_DecryptFinal_ex(context, (uint8_t*) plaintext + plaintext_size, &added) != 1)
if (EVP_DecryptFinal_ex(context, (uint8_t*) plaintext.iov_base + plaintext.iov_len, &added) != 1)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Decryption failed (incorrect key?): %s",
ERR_error_string(ERR_get_error(), NULL));
plaintext_size += added;
plaintext.iov_len += added;
if (plaintext_size < ALIGN8(offsetof(struct metadata_credential_header, name)))
if (plaintext.iov_len < ALIGN8(offsetof(struct metadata_credential_header, name)))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Metadata header incomplete.");
m = plaintext;
m = plaintext.iov_base;
if (le64toh(m->timestamp) != USEC_INFINITY &&
le64toh(m->not_after) != USEC_INFINITY &&
@@ -1332,7 +1305,7 @@ int decrypt_credential_and_warn(
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Embedded credential name too long, refusing.");
hs = ALIGN8(offsetof(struct metadata_credential_header, name) + le32toh(m->name_size));
if (plaintext_size < hs)
if (plaintext.iov_len < hs)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Metadata header incomplete.");
if (le32toh(m->name_size) > 0) {
@@ -1374,32 +1347,30 @@ int decrypt_credential_and_warn(
}
if (ret) {
char *without_metadata;
_cleanup_(iovec_done_erase) struct iovec without_metadata = {};
without_metadata = memdup_suffix0((uint8_t*) plaintext + hs, plaintext_size - hs);
if (!without_metadata)
without_metadata.iov_len = plaintext.iov_len - hs;
without_metadata.iov_base = memdup_suffix0((uint8_t*) plaintext.iov_base + hs, without_metadata.iov_len);
if (!without_metadata.iov_base)
return log_oom();
*ret = without_metadata;
*ret = TAKE_STRUCT(without_metadata);
}
if (ret_size)
*ret_size = plaintext_size - hs;
return 0;
}
#else
int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size) {
int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
}
int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const void *input, size_t input_size, void **ret, size_t *ret_size) {
int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, struct iovec *ret) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
}
int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const void *input, size_t input_size, void **ret, size_t *ret_size) {
int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, struct iovec *ret) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Support for encrypted credentials not available.");
}
+3 -3
View File
@@ -53,7 +53,7 @@ typedef enum CredentialSecretFlags {
CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS = 1 << 2,
} CredentialSecretFlags;
int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size);
int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret);
int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed);
@@ -77,5 +77,5 @@ int get_credential_user_password(const char *username, char **ret_password, bool
#define _CRED_AUTO SD_ID128_MAKE(a2,19,cb,07,85,b2,4c,04,b1,6d,18,ca,b9,d2,ee,01)
#define _CRED_AUTO_INITRD SD_ID128_MAKE(02,dc,8e,de,3a,02,43,ab,a9,ec,54,9c,05,e6,a0,71)
int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const void *input, size_t input_size, void **ret, size_t *ret_size);
int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const void *input, size_t input_size, void **ret, size_t *ret_size);
int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_hash_pcr_mask, const char *tpm2_pubkey_path, uint32_t tpm2_pubkey_pcr_mask, const struct iovec *input, struct iovec *ret);
int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const char *tpm2_signature_path, const struct iovec *input, struct iovec *ret);
+100 -147
View File
@@ -5067,28 +5067,22 @@ int tpm2_calculate_seal(
TPM2_HANDLE parent_handle,
const TPM2B_PUBLIC *parent_public,
const TPMA_OBJECT *attributes,
const void *secret,
size_t secret_size,
const struct iovec *secret,
const TPM2B_DIGEST *policy,
const char *pin,
void **ret_secret,
size_t *ret_secret_size,
void **ret_blob,
size_t *ret_blob_size,
void **ret_serialized_parent,
size_t *ret_serialized_parent_size) {
struct iovec *ret_secret,
struct iovec *ret_blob,
struct iovec *ret_serialized_parent) {
#if HAVE_OPENSSL
int r;
assert(parent_public);
assert(secret || secret_size == 0);
assert(iovec_is_valid(secret));
assert(secret || ret_secret);
assert(!(secret && ret_secret)); /* Either provide a secret, or we create one, but not both */
assert(ret_blob);
assert(ret_blob_size);
assert(ret_serialized_parent);
assert(ret_serialized_parent_size);
log_debug("Calculating sealed object.");
@@ -5109,27 +5103,27 @@ int tpm2_calculate_seal(
parent_handle);
}
_cleanup_(erase_and_freep) void *generated_secret = NULL;
_cleanup_(iovec_done_erase) struct iovec generated_secret = {};
if (!secret) {
/* No secret provided, generate a random secret. We use SHA256 digest length, though it can
* be up to TPM2_MAX_SEALED_DATA. The secret length is not limited to the nameAlg hash
* size. */
secret_size = TPM2_SHA256_DIGEST_SIZE;
generated_secret = malloc(secret_size);
if (!generated_secret)
generated_secret.iov_len = TPM2_SHA256_DIGEST_SIZE;
generated_secret.iov_base = malloc(generated_secret.iov_len);
if (!generated_secret.iov_base)
return log_oom_debug();
r = crypto_random_bytes(generated_secret, secret_size);
r = crypto_random_bytes(generated_secret.iov_base, generated_secret.iov_len);
if (r < 0)
return log_debug_errno(r, "Failed to generate secret key: %m");
secret = generated_secret;
secret = &generated_secret;
}
if (secret_size > TPM2_MAX_SEALED_DATA)
if (secret->iov_len > TPM2_MAX_SEALED_DATA)
return log_debug_errno(SYNTHETIC_ERRNO(EOVERFLOW),
"Secret size %zu too large, limit is %d bytes.",
secret_size, TPM2_MAX_SEALED_DATA);
secret->iov_len, TPM2_MAX_SEALED_DATA);
TPM2B_DIGEST random_seed;
TPM2B_ENCRYPTED_SECRET seed;
@@ -5138,7 +5132,7 @@ int tpm2_calculate_seal(
return r;
TPM2B_PUBLIC public;
r = tpm2_calculate_seal_public(parent_public, attributes, policy, &random_seed, secret, secret_size, &public);
r = tpm2_calculate_seal_public(parent_public, attributes, policy, &random_seed, secret->iov_base, secret->iov_len, &public);
if (r < 0)
return r;
@@ -5148,13 +5142,12 @@ int tpm2_calculate_seal(
return r;
TPM2B_PRIVATE private;
r = tpm2_calculate_seal_private(parent_public, &name, pin, &random_seed, secret, secret_size, &private);
r = tpm2_calculate_seal_private(parent_public, &name, pin, &random_seed, secret->iov_base, secret->iov_len, &private);
if (r < 0)
return r;
_cleanup_free_ void *blob = NULL;
size_t blob_size;
r = tpm2_marshal_blob(&public, &private, &seed, &blob, &blob_size);
_cleanup_(iovec_done) struct iovec blob = {};
r = tpm2_marshal_blob(&public, &private, &seed, &blob.iov_base, &blob.iov_len);
if (r < 0)
return log_debug_errno(r, "Could not create sealed blob: %m");
@@ -5163,25 +5156,20 @@ int tpm2_calculate_seal(
if (r < 0)
return r;
_cleanup_free_ void *serialized_parent = NULL;
size_t serialized_parent_size;
_cleanup_(iovec_done) struct iovec serialized_parent = {};
r = tpm2_calculate_serialize(
parent_handle,
&parent_name,
parent_public,
&serialized_parent,
&serialized_parent_size);
&serialized_parent.iov_base,
&serialized_parent.iov_len);
if (r < 0)
return r;
if (ret_secret)
*ret_secret = TAKE_PTR(generated_secret);
if (ret_secret_size)
*ret_secret_size = secret_size;
*ret_blob = TAKE_PTR(blob);
*ret_blob_size = blob_size;
*ret_serialized_parent = TAKE_PTR(serialized_parent);
*ret_serialized_parent_size = serialized_parent_size;
*ret_secret = TAKE_STRUCT(generated_secret);
*ret_blob = TAKE_STRUCT(blob);
*ret_serialized_parent = TAKE_STRUCT(serialized_parent);
return 0;
#else /* HAVE_OPENSSL */
@@ -5193,21 +5181,16 @@ int tpm2_seal(Tpm2Context *c,
uint32_t seal_key_handle,
const TPM2B_DIGEST *policy,
const char *pin,
void **ret_secret,
size_t *ret_secret_size,
void **ret_blob,
size_t *ret_blob_size,
struct iovec *ret_secret,
struct iovec *ret_blob,
uint16_t *ret_primary_alg,
void **ret_srk_buf,
size_t *ret_srk_buf_size) {
struct iovec *ret_srk) {
uint16_t primary_alg = 0;
int r;
assert(ret_secret);
assert(ret_secret_size);
assert(ret_blob);
assert(ret_blob_size);
/* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
* is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
@@ -5271,7 +5254,7 @@ int tpm2_seal(Tpm2Context *c,
return log_debug_errno(r, "Failed to generate secret key: %m");
_cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
if (ret_srk_buf) {
if (ret_srk) {
_cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
if (IN_SET(seal_key_handle, 0, TPM2_SRK_HANDLE)) {
@@ -5309,7 +5292,7 @@ int tpm2_seal(Tpm2Context *c,
if (seal_key_handle != 0)
log_debug("Using primary alg sealing, but seal key handle also provided; ignoring seal key handle.");
/* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */
/* TODO: force all callers to provide ret_srk, so we can stop sealing with the legacy templates. */
primary_alg = TPM2_ALG_ECC;
TPM2B_PUBLIC template = {
@@ -5353,47 +5336,46 @@ int tpm2_seal(Tpm2Context *c,
if (r < 0)
return r;
_cleanup_(erase_and_freep) void *secret = NULL;
secret = memdup(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
if (!secret)
_cleanup_(iovec_done_erase) struct iovec secret = {};
secret.iov_base = memdup(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
if (!secret.iov_base)
return log_oom_debug();
secret.iov_len = hmac_sensitive.data.size;
log_debug("Marshalling private and public part of HMAC key.");
_cleanup_free_ void *blob = NULL;
size_t blob_size = 0;
r = tpm2_marshal_blob(public, private, /* seed= */ NULL, &blob, &blob_size);
_cleanup_(iovec_done) struct iovec blob = {};
r = tpm2_marshal_blob(public, private, /* seed= */ NULL, &blob.iov_base, &blob.iov_len);
if (r < 0)
return log_debug_errno(r, "Could not create sealed blob: %m");
if (DEBUG_LOGGING)
log_debug("Completed TPM2 key sealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
_cleanup_free_ void *srk_buf = NULL;
size_t srk_buf_size = 0;
if (ret_srk_buf) {
if (ret_srk) {
_cleanup_(iovec_done) struct iovec srk = {};
_cleanup_(Esys_Freep) void *tmp = NULL;
r = tpm2_serialize(c, primary_handle, &tmp, &srk_buf_size);
size_t tmp_size;
r = tpm2_serialize(c, primary_handle, &tmp, &tmp_size);
if (r < 0)
return r;
/*
* make a copy since we don't want the caller to understand that
* ESYS allocated the pointer. It would make tracking what deallocator
* to use for srk_buf in which context a PITA.
* to use for srk in which context a PITA.
*/
srk_buf = memdup(tmp, srk_buf_size);
if (!srk_buf)
srk.iov_base = memdup(tmp, tmp_size);
if (!srk.iov_base)
return log_oom_debug();
srk.iov_len = tmp_size;
*ret_srk_buf = TAKE_PTR(srk_buf);
*ret_srk_buf_size = srk_buf_size;
*ret_srk = TAKE_STRUCT(srk);
}
*ret_secret = TAKE_PTR(secret);
*ret_secret_size = hmac_sensitive.data.size;
*ret_blob = TAKE_PTR(blob);
*ret_blob_size = blob_size;
*ret_secret = TAKE_STRUCT(secret);
*ret_blob = TAKE_STRUCT(blob);
if (ret_primary_alg)
*ret_primary_alg = primary_alg;
@@ -5406,31 +5388,24 @@ int tpm2_seal(Tpm2Context *c,
int tpm2_unseal(Tpm2Context *c,
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,
JsonVariant *signature,
const char *pin,
const Tpm2PCRLockPolicy *pcrlock_policy,
uint16_t primary_alg,
const void *blob,
size_t blob_size,
const void *known_policy_hash,
size_t known_policy_hash_size,
const void *srk_buf,
size_t srk_buf_size,
void **ret_secret,
size_t *ret_secret_size) {
const struct iovec *blob,
const struct iovec *known_policy_hash,
const struct iovec *srk,
struct iovec *ret_secret) {
TSS2_RC rc;
int r;
assert(blob);
assert(blob_size > 0);
assert(known_policy_hash_size == 0 || known_policy_hash);
assert(pubkey_size == 0 || pubkey);
assert(iovec_is_set(blob));
assert(iovec_is_valid(known_policy_hash));
assert(iovec_is_valid(pubkey));
assert(ret_secret);
assert(ret_secret_size);
assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
@@ -5448,7 +5423,7 @@ int tpm2_unseal(Tpm2Context *c,
TPM2B_PUBLIC public;
TPM2B_PRIVATE private;
TPM2B_ENCRYPTED_SECRET seed = {};
r = tpm2_unmarshal_blob(blob, blob_size, &public, &private, &seed);
r = tpm2_unmarshal_blob(blob->iov_base, blob->iov_len, &public, &private, &seed);
if (r < 0)
return log_debug_errno(r, "Could not extract parts from blob: %m");
@@ -5461,8 +5436,8 @@ int tpm2_unseal(Tpm2Context *c,
}
_cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
if (srk_buf) {
r = tpm2_deserialize(c, srk_buf, srk_buf_size, &primary_handle);
if (iovec_is_set(srk)) {
r = tpm2_deserialize(c, srk->iov_base, srk->iov_len, &primary_handle);
if (r < 0)
return r;
} else if (primary_alg != 0) {
@@ -5518,14 +5493,13 @@ int tpm2_unseal(Tpm2Context *c,
return r;
TPM2B_PUBLIC pubkey_tpm2b;
_cleanup_free_ void *fp = NULL;
size_t fp_size = 0;
if (pubkey) {
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &pubkey_tpm2b);
_cleanup_(iovec_done) struct iovec fp = {};
if (iovec_is_set(pubkey)) {
r = tpm2_tpm2b_public_from_pem(pubkey->iov_base, pubkey->iov_len, &pubkey_tpm2b);
if (r < 0)
return log_debug_errno(r, "Could not create TPMT_PUBLIC: %m");
r = tpm2_tpm2b_public_to_fingerprint(&pubkey_tpm2b, &fp, &fp_size);
r = tpm2_tpm2b_public_to_fingerprint(&pubkey_tpm2b, &fp.iov_base, &fp.iov_len);
if (r < 0)
return log_debug_errno(r, "Could not get key fingerprint: %m");
}
@@ -5563,8 +5537,8 @@ int tpm2_unseal(Tpm2Context *c,
policy_session,
hash_pcr_mask,
pcr_bank,
pubkey ? &pubkey_tpm2b : NULL,
fp, fp_size,
iovec_is_set(pubkey) ? &pubkey_tpm2b : NULL,
fp.iov_base, fp.iov_len,
pubkey_pcr_mask,
signature,
!!pin,
@@ -5575,8 +5549,8 @@ int tpm2_unseal(Tpm2Context *c,
/* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not
* wait until the TPM2 tells us to go away. */
if (known_policy_hash_size > 0 &&
memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash, known_policy_hash_size) != 0)
if (iovec_is_set(known_policy_hash) &&
memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash->iov_base, known_policy_hash->iov_len) != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
"Current policy digest does not match stored policy digest, cancelling "
"TPM2 authentication attempt.");
@@ -5598,17 +5572,17 @@ int tpm2_unseal(Tpm2Context *c,
log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
}
_cleanup_(erase_and_freep) char *secret = NULL;
secret = memdup(unsealed->buffer, unsealed->size);
_cleanup_(iovec_done_erase) struct iovec secret = {};
secret.iov_base = memdup(unsealed->buffer, unsealed->size);
explicit_bzero_safe(unsealed->buffer, unsealed->size);
if (!secret)
if (!secret.iov_base)
return log_oom_debug();
secret.iov_len = unsealed->size;
if (DEBUG_LOGGING)
log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
*ret_secret = TAKE_PTR(secret);
*ret_secret_size = unsealed->size;
*ret_secret = TAKE_STRUCT(secret);
return 0;
}
@@ -6967,18 +6941,13 @@ int tpm2_make_luks2_json(
int keyslot,
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,
uint16_t primary_alg,
const void *blob,
size_t blob_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,
TPM2Flags flags,
JsonVariant **ret) {
@@ -6986,9 +6955,9 @@ int tpm2_make_luks2_json(
_cleanup_free_ char *keyslot_as_string = NULL;
int r;
assert(blob || blob_size == 0);
assert(policy_hash || policy_hash_size == 0);
assert(pubkey || pubkey_size == 0);
assert(iovec_is_valid(pubkey));
assert(iovec_is_valid(blob));
assert(iovec_is_valid(policy_hash));
if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
return -ENOMEM;
@@ -7011,17 +6980,17 @@ int tpm2_make_luks2_json(
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-tpm2")),
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_IOVEC_BASE64(blob)),
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(hmj)),
JSON_BUILD_PAIR_CONDITION(!!tpm2_hash_alg_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_hash_alg_to_string(pcr_bank))),
JSON_BUILD_PAIR_CONDITION(!!tpm2_asym_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_asym_alg_to_string(primary_alg))),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_IOVEC_HEX(policy_hash)),
JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN)),
JSON_BUILD_PAIR("tpm2_pcrlock", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PCRLOCK)),
JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey_pcrs", JSON_BUILD_VARIANT(pkmj)),
JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey", JSON_BUILD_BASE64(pubkey, pubkey_size)),
JSON_BUILD_PAIR_CONDITION(salt, "tpm2_salt", JSON_BUILD_BASE64(salt, salt_size)),
JSON_BUILD_PAIR_CONDITION(srk_buf, "tpm2_srk", JSON_BUILD_BASE64(srk_buf, srk_buf_size))));
JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey", JSON_BUILD_IOVEC_BASE64(pubkey)),
JSON_BUILD_PAIR_CONDITION(iovec_is_set(salt), "tpm2_salt", JSON_BUILD_IOVEC_BASE64(salt)),
JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk))));
if (r < 0)
return r;
@@ -7036,22 +7005,16 @@ int tpm2_parse_luks2_json(
int *ret_keyslot,
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,
TPM2Flags *ret_flags) {
_cleanup_free_ void *blob = NULL, *policy_hash = NULL, *pubkey = NULL, *salt = NULL, *srk_buf = NULL;
size_t blob_size = 0, policy_hash_size = 0, pubkey_size = 0, salt_size = 0, srk_buf_size = 0;
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {};
uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0;
uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */
uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
@@ -7116,7 +7079,7 @@ int tpm2_parse_luks2_json(
if (!w)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-blob' field.");
r = json_variant_unbase64(w, &blob, &blob_size);
r = json_variant_unbase64_iovec(w, &blob);
if (r < 0)
return log_debug_errno(r, "Invalid base64 data in 'tpm2-blob' field.");
@@ -7124,7 +7087,7 @@ int tpm2_parse_luks2_json(
if (!w)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-policy-hash' field.");
r = json_variant_unhex(w, &policy_hash, &policy_hash_size);
r = json_variant_unhex_iovec(w, &policy_hash);
if (r < 0)
return log_debug_errno(r, "Invalid base64 data in 'tpm2-policy-hash' field.");
@@ -7146,7 +7109,7 @@ int tpm2_parse_luks2_json(
w = json_variant_by_key(v, "tpm2_salt");
if (w) {
r = json_variant_unbase64(w, &salt, &salt_size);
r = json_variant_unbase64_iovec(w, &salt);
if (r < 0)
return log_debug_errno(r, "Invalid base64 data in 'tpm2_salt' field.");
}
@@ -7160,7 +7123,7 @@ int tpm2_parse_luks2_json(
w = json_variant_by_key(v, "tpm2_pubkey");
if (w) {
r = json_variant_unbase64(w, &pubkey, &pubkey_size);
r = json_variant_unbase64_iovec(w, &pubkey);
if (r < 0)
return log_debug_errno(r, "Failed to decode PCR public key.");
} else if (pubkey_pcr_mask != 0)
@@ -7168,7 +7131,7 @@ int tpm2_parse_luks2_json(
w = json_variant_by_key(v, "tpm2_srk");
if (w) {
r = json_variant_unbase64(w, &srk_buf, &srk_buf_size);
r = json_variant_unbase64_iovec(w, &srk);
if (r < 0)
return log_debug_errno(r, "Invalid base64 data in 'tpm2_srk' field.");
}
@@ -7180,31 +7143,21 @@ int tpm2_parse_luks2_json(
if (ret_pcr_bank)
*ret_pcr_bank = pcr_bank;
if (ret_pubkey)
*ret_pubkey = TAKE_PTR(pubkey);
if (ret_pubkey_size)
*ret_pubkey_size = pubkey_size;
*ret_pubkey = TAKE_STRUCT(pubkey);
if (ret_pubkey_pcr_mask)
*ret_pubkey_pcr_mask = pubkey_pcr_mask;
if (ret_primary_alg)
*ret_primary_alg = primary_alg;
if (ret_blob)
*ret_blob = TAKE_PTR(blob);
if (ret_blob_size)
*ret_blob_size = blob_size;
*ret_blob = TAKE_STRUCT(blob);
if (ret_policy_hash)
*ret_policy_hash = TAKE_PTR(policy_hash);
if (ret_policy_hash_size)
*ret_policy_hash_size = policy_hash_size;
*ret_policy_hash = TAKE_STRUCT(policy_hash);
if (ret_salt)
*ret_salt = TAKE_PTR(salt);
if (ret_salt_size)
*ret_salt_size = salt_size;
*ret_salt = TAKE_STRUCT(salt);
if (ret_flags)
*ret_flags = flags;
if (ret_srk_buf)
*ret_srk_buf = TAKE_PTR(srk_buf);
if (ret_srk_buf_size)
*ret_srk_buf_size = srk_buf_size;
if (ret_srk)
*ret_srk = TAKE_STRUCT(srk);
return 0;
}
+5 -5
View File
@@ -277,7 +277,7 @@ int tpm2_calculate_policy_or(const TPM2B_DIGEST *branches, size_t n_branches, TP
int tpm2_calculate_policy_super_pcr(Tpm2PCRPrediction *prediction, uint16_t algorithm, TPM2B_DIGEST *pcr_policy);
int tpm2_calculate_serialize(TPM2_HANDLE handle, const TPM2B_NAME *name, const TPM2B_PUBLIC *public, void **ret_serialized, size_t *ret_serialized_size);
int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, const TPM2B_PUBLIC *public, bool use_pin, const Tpm2PCRLockPolicy *policy, TPM2B_DIGEST *digest);
int tpm2_calculate_seal(TPM2_HANDLE parent_handle, const TPM2B_PUBLIC *parent_public, const TPMA_OBJECT *attributes, const void *secret, size_t secret_size, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_serialized_parent, size_t *ret_serialized_parent_size);
int tpm2_calculate_seal(TPM2_HANDLE parent_handle, const TPM2B_PUBLIC *parent_public, const TPMA_OBJECT *attributes, const struct iovec *secret, const TPM2B_DIGEST *policy, const char *pin, struct iovec *ret_secret, struct iovec *ret_blob, struct iovec *ret_serialized_parent);
int tpm2_get_srk_template(TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template);
int tpm2_get_best_srk_template(Tpm2Context *c, TPMT_PUBLIC *ret_template);
@@ -285,8 +285,8 @@ int tpm2_get_best_srk_template(Tpm2Context *c, TPMT_PUBLIC *ret_template);
int tpm2_get_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);
int tpm2_get_or_create_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);
int tpm2_seal(Tpm2Context *c, uint32_t seal_key_handle, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
int tpm2_unseal(Tpm2Context *c, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, const Tpm2PCRLockPolicy *pcrlock_policy, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
int tpm2_seal(Tpm2Context *c, uint32_t seal_key_handle, const TPM2B_DIGEST *policy, const char *pin, struct iovec *ret_secret, struct iovec *ret_blob, uint16_t *ret_primary_alg, struct iovec *ret_srk);
int tpm2_unseal(Tpm2Context *c, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, const Tpm2PCRLockPolicy *pcrlock_policy, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *srk, struct iovec *ret_secret);
#if HAVE_OPENSSL
int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret);
@@ -383,8 +383,8 @@ int tpm2_find_device_auto(char **ret);
int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret);
int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret);
int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const void *blob, size_t blob_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, TPM2Flags flags, JsonVariant **ret);
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, void **ret_pubkey, size_t *ret_pubkey_size, 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, TPM2Flags *ret_flags);
int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, TPM2Flags flags, JsonVariant **ret);
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec *ret_blob, struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, TPM2Flags *ret_flags);
/* Default to PCR 7 only */
#define TPM2_PCR_INDEX_DEFAULT UINT32_C(7)
+24 -29
View File
@@ -1100,42 +1100,38 @@ static void calculate_seal_and_unseal(
assert_se(asprintf(&secret_string, "The classified documents are in room %x", parent_index) > 0);
size_t secret_size = strlen(secret_string) + 1;
_cleanup_free_ void *blob = NULL;
size_t blob_size = 0;
_cleanup_free_ void *serialized_parent = NULL;
size_t serialized_parent_size;
_cleanup_(iovec_done) struct iovec blob = {}, serialized_parent = {};
assert_se(tpm2_calculate_seal(
parent_index,
parent_public,
/* attributes= */ NULL,
secret_string, secret_size,
&IOVEC_MAKE(secret_string, secret_size),
/* policy= */ NULL,
/* pin= */ NULL,
/* ret_secret= */ NULL, /* ret_secret_size= */ 0,
&blob, &blob_size,
&serialized_parent, &serialized_parent_size) >= 0);
/* ret_secret= */ NULL,
&blob,
&serialized_parent) >= 0);
_cleanup_free_ void *unsealed_secret = NULL;
size_t unsealed_secret_size;
_cleanup_(iovec_done) struct iovec unsealed_secret = {};
assert_se(tpm2_unseal(
c,
/* hash_pcr_mask= */ 0,
/* pcr_bank= */ 0,
/* pubkey= */ NULL, /* pubkey_size= */ 0,
/* pubkey= */ NULL,
/* pubkey_pcr_mask= */ 0,
/* signature= */ NULL,
/* pin= */ NULL,
/* pcrlock_policy= */ NULL,
/* primary_alg= */ 0,
blob, blob_size,
/* known_policy_hash= */ NULL, /* known_policy_hash_size= */ 0,
serialized_parent, serialized_parent_size,
&unsealed_secret, &unsealed_secret_size) >= 0);
&blob,
/* known_policy_hash= */ NULL,
&serialized_parent,
&unsealed_secret) >= 0);
assert_se(memcmp_nn(secret_string, secret_size, unsealed_secret, unsealed_secret_size) == 0);
assert_se(memcmp_nn(secret_string, secret_size, unsealed_secret.iov_base, unsealed_secret.iov_len) == 0);
char unsealed_string[unsealed_secret_size];
assert_se(snprintf(unsealed_string, unsealed_secret_size, "%s", (char*) unsealed_secret) == (int) unsealed_secret_size - 1);
char unsealed_string[unsealed_secret.iov_len];
assert_se(snprintf(unsealed_string, unsealed_secret.iov_len, "%s", (char*) unsealed_secret.iov_base) == (int) unsealed_secret.iov_len - 1);
log_debug("Unsealed secret is: %s", unsealed_string);
}
@@ -1187,34 +1183,33 @@ static void check_seal_unseal_for_handle(Tpm2Context *c, TPM2_HANDLE handle) {
log_debug("Check seal/unseal for handle 0x%" PRIx32, handle);
_cleanup_free_ void *secret = NULL, *blob = NULL, *srk = NULL, *unsealed_secret = NULL;
size_t secret_size, blob_size, srk_size, unsealed_secret_size;
_cleanup_(iovec_done) struct iovec secret = {}, blob = {}, srk = {}, unsealed_secret = {};
assert_se(tpm2_seal(
c,
handle,
&policy,
/* pin= */ NULL,
&secret, &secret_size,
&blob, &blob_size,
&secret,
&blob,
/* ret_primary_alg= */ NULL,
&srk, &srk_size) >= 0);
&srk) >= 0);
assert_se(tpm2_unseal(
c,
/* hash_pcr_mask= */ 0,
/* pcr_bank= */ 0,
/* pubkey= */ NULL, /* pubkey_size= */ 0,
/* pubkey= */ NULL,
/* pubkey_pcr_mask= */ 0,
/* signature= */ NULL,
/* pin= */ NULL,
/* pcrlock_policy= */ NULL,
/* primary_alg= */ 0,
blob, blob_size,
/* policy_hash= */ NULL, /* policy_hash_size= */ 0,
srk, srk_size,
&unsealed_secret, &unsealed_secret_size) >= 0);
&blob,
/* policy_hash= */ NULL,
&srk,
&unsealed_secret) >= 0);
assert_se(memcmp_nn(secret, secret_size, unsealed_secret, unsealed_secret_size) == 0);
assert_se(iovec_memcmp(&secret, &unsealed_secret) == 0);
}
static void check_seal_unseal(Tpm2Context *c) {