From 8d042bc40aaf3c53e5eacfe846eb66a98401d691 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Nov 2023 17:18:43 +0100 Subject: [PATCH] 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. --- src/core/exec-credential.c | 31 +- src/creds/creds.c | 54 ++-- src/cryptenroll/cryptenroll-tpm2.c | 56 ++-- .../cryptsetup-token-systemd-tpm2.c | 53 ++-- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 35 +-- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h | 18 +- src/cryptsetup/cryptsetup-tpm2.c | 105 +++---- src/cryptsetup/cryptsetup-tpm2.h | 66 ++-- src/cryptsetup/cryptsetup.c | 55 ++-- src/partition/repart.c | 40 ++- src/shared/creds-util.c | 289 ++++++++---------- src/shared/creds-util.h | 6 +- src/shared/tpm2-util.c | 247 ++++++--------- src/shared/tpm2-util.h | 10 +- src/test/test-tpm2.c | 53 ++-- 15 files changed, 477 insertions(+), 641 deletions(-) diff --git a/src/core/exec-credential.c b/src/core/exec-credential.c index 6bcfb68d8f2..513087d0692 100644 --- a/src/core/exec-credential.c +++ b/src/core/exec-credential.c @@ -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; diff --git a/src/creds/creds.c b/src/creds/creds.c index f84eee292be..01b2844dd30 100644 --- a/src/creds/creds.c +++ b/src/creds/creds.c @@ -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) diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index 0268d8f7721..608b94ea780 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -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) diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index 6fee8319a7f..29cc1ac5430 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -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))); } /* diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c index 72be5cc71d3..e2e4d0dc049 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c @@ -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"); diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h index d84e5a3c3ba..20151d6ca9f 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h @@ -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); diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c index f59d5f9d1dc..fc0ec443a51 100644 --- a/src/cryptsetup/cryptsetup-tpm2.c +++ b/src/cryptsetup/cryptsetup-tpm2.c @@ -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; } diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h index a50a9435a98..a593e043749 100644 --- a/src/cryptsetup/cryptsetup-tpm2.h +++ b/src/cryptsetup/cryptsetup-tpm2.h @@ -16,8 +16,7 @@ int acquire_tpm2_key( const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, - const void *pubkey, - size_t pubkey_size, + const struct iovec *pubkey, uint32_t pubkey_pcr_mask, const char *signature_path, const char *pcrlock_path, @@ -25,20 +24,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) { diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index b56b51a134f..80f8f91948f 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -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) diff --git a/src/partition/repart.c b/src/partition/repart.c index 95cae94a8e0..b241f9bc61a 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -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) diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 22c5e423110..716543a2a78 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -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."); } diff --git a/src/shared/creds-util.h b/src/shared/creds-util.h index b34dba7cc2f..38d5086e8cf 100644 --- a/src/shared/creds-util.h +++ b/src/shared/creds-util.h @@ -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); diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 2c49dece020..bec84a3f03c 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -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; } diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 55d748159f3..e94b345de76 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -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) diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c index 19881c6e91f..eeaf0b7b885 100644 --- a/src/test/test-tpm2.c +++ b/src/test/test-tpm2.c @@ -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) { -- 2.39.2