#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"
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;
/* 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;
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;
}
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);
}
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;
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)
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;
}
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;
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)
timestamp,
arg_tpm2_device,
arg_tpm2_signature,
- input, input_size,
- &plaintext, &plaintext_size);
+ &input,
+ &plaintext);
if (r < 0)
return r;
} 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;
}
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;
}
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;
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)
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;
}
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");
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");
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);
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");
}
/* 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");
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)
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 = {
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);
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);
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;
&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");
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");
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)));
}
/*
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);
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");
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");
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);
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,
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);
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 */
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) {
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");
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");
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");
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) {
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;
&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;
*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;
}
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,
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,
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);
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,
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.");
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) {
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);
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(
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))
}
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 */
* 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;
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);
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)
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();
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)
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");
}
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");
}
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);
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");
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)
}
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
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;
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;
goto fail;
}
- if (ret_data) {
+ if (ret) {
void *copy;
copy = memdup(buf.data, sizeof(buf.data));
goto fail;
}
- *ret_data = copy;
+ *ret = IOVEC_MAKE(copy, sizeof(buf.data));
}
- if (ret_size)
- *ret_size = sizeof(buf.data);
-
return 0;
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;
"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);
if (!copy)
return log_oom_debug();
- *ret = copy;
+ *ret = IOVEC_MAKE(copy, sz);
}
- if (ret_size)
- *ret_size = sz;
-
return 0;
}
#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. */
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);
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,
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)
/* 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");
}
}
- if (!pubkey)
+ if (!iovec_is_set(&pubkey))
tpm2_pubkey_pcr_mask = 0;
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
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");
}
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);
/* 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.");
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;
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;
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");
}
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));
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;
}
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);
}
/* 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 */
/* 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) +
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))
/* 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) +
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)) +
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
}
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");
}
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());
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 &&
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) {
}
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.");
}
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);
#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);
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.");
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;
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;
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");
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 */
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
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)) {
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 = {
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;
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));
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");
}
_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) {
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");
}
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,
/* 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.");
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;
}
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) {
_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;
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;
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 */
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.");
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.");
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.");
}
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)
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.");
}
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;
}
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);
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);
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)
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);
}
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) {