mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
It's often useful to know how much data was actually copied, therefore let's introduce an nullable parameter `@copied` to `pv_gbytes_memcpy`. Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
149 lines
4.8 KiB
C
149 lines
4.8 KiB
C
/*
|
|
* Attestation related functions
|
|
*
|
|
* Copyright IBM Corp. 2022
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
/* Must be included before any other header */
|
|
#include "config.h"
|
|
|
|
#include "libpv/cert.h"
|
|
#include "libpv/hash.h"
|
|
#include "libpv/se-hdr.h"
|
|
|
|
#include "exchange_format.h"
|
|
#include "attestation.h"
|
|
|
|
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->pld) == sizeof(((struct pv_hdr_head *)0)->pld));
|
|
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->ald) == sizeof(((struct pv_hdr_head *)0)->ald));
|
|
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->tld) == sizeof(((struct pv_hdr_head *)0)->tld));
|
|
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->tag) == sizeof(((struct pv_hdr *)0)->tag));
|
|
|
|
struct att_meas_sizes {
|
|
uint16_t user_data_len;
|
|
uint16_t zeros;
|
|
uint32_t additional_data_len;
|
|
} __packed;
|
|
G_STATIC_ASSERT(sizeof(struct att_meas_sizes) == 8);
|
|
|
|
/*
|
|
* All optional arguments may be NULL
|
|
* user_data is up to 256 bytes long, or NULL.
|
|
* nonce is 16 bytes long or NULL.
|
|
* additional_data is up to 32768 bytes long or NULL.
|
|
*/
|
|
GBytes *att_gen_measurement_hmac_sha512(const att_meas_ctx_t *meas_ctx, GBytes *measurement_key,
|
|
GBytes *optional_user_data, GBytes *optional_nonce,
|
|
GBytes *optional_additional_data, GError **error)
|
|
{
|
|
struct att_meas_sizes meas_sizes = {};
|
|
g_autoptr(HMAC_CTX) hmac_ctx = NULL;
|
|
size_t additional_data_size = 0;
|
|
size_t user_data_size = 0;
|
|
size_t nonce_size = 0;
|
|
|
|
pv_wrapped_g_assert(meas_ctx);
|
|
pv_wrapped_g_assert(measurement_key);
|
|
|
|
if (optional_user_data)
|
|
user_data_size = g_bytes_get_size(optional_user_data);
|
|
if (optional_additional_data)
|
|
additional_data_size = g_bytes_get_size(optional_additional_data);
|
|
if (optional_nonce)
|
|
nonce_size = g_bytes_get_size(optional_nonce);
|
|
|
|
/* checks for these sizes resulting in GErrors are done before */
|
|
g_assert(user_data_size <= PVATTEST_USER_DATA_MAX_SIZE);
|
|
g_assert(additional_data_size <= PVATTEST_ADDITIONAL_MAX_SIZE);
|
|
g_assert(nonce_size == 0 || nonce_size == ARCB_V1_NONCE_SIZE);
|
|
|
|
pv_wrapped_g_assert(meas_ctx);
|
|
pv_wrapped_g_assert(measurement_key);
|
|
|
|
hmac_ctx = pv_hmac_ctx_new(measurement_key, EVP_sha512(), error);
|
|
if (!hmac_ctx)
|
|
return NULL;
|
|
|
|
meas_sizes.user_data_len = GUINT16_TO_BE((uint16_t)user_data_size);
|
|
meas_sizes.zeros = 0;
|
|
meas_sizes.additional_data_len = GUINT32_TO_BE((uint32_t)additional_data_size);
|
|
|
|
if (pv_hmac_ctx_update_raw(hmac_ctx, meas_ctx, sizeof(*meas_ctx), error) != 0)
|
|
return NULL;
|
|
|
|
/* add the sizes of user and additional data. */
|
|
if (pv_hmac_ctx_update_raw(hmac_ctx, &meas_sizes, sizeof(meas_sizes), error))
|
|
return NULL;
|
|
|
|
/* update optional data. if NULL passed (or size = 0) nothing will happen to the HMAC_CTX */
|
|
if (pv_hmac_ctx_update(hmac_ctx, optional_user_data, error) != 0)
|
|
return NULL;
|
|
if (pv_hmac_ctx_update(hmac_ctx, optional_nonce, error) != 0)
|
|
return NULL;
|
|
if (pv_hmac_ctx_update(hmac_ctx, optional_additional_data, error) != 0)
|
|
return NULL;
|
|
return pv_hamc_ctx_finalize(hmac_ctx, error);
|
|
}
|
|
|
|
att_meas_ctx_t *att_extract_from_hdr(GBytes *se_hdr, GError **error)
|
|
{
|
|
g_autofree att_meas_ctx_t *meas = NULL;
|
|
const struct pv_hdr *hdr = NULL;
|
|
size_t se_hdr_tag_offset;
|
|
size_t se_hdr_size;
|
|
uint8_t *hdr_u8;
|
|
|
|
pv_wrapped_g_assert(se_hdr);
|
|
|
|
hdr = g_bytes_get_data(se_hdr, &se_hdr_size);
|
|
hdr_u8 = (uint8_t *)hdr;
|
|
|
|
if (se_hdr_size < PV_V1_PV_HDR_MIN_SIZE) {
|
|
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_HDR,
|
|
_("Invalid SE header provided."));
|
|
return NULL;
|
|
}
|
|
|
|
if (GUINT32_FROM_BE(hdr->head.phs) != se_hdr_size ||
|
|
GUINT64_FROM_BE(hdr->head.magic) != PV_MAGIC_NUMBER) {
|
|
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_HDR,
|
|
_("Invalid SE header provided."));
|
|
return NULL;
|
|
}
|
|
|
|
se_hdr_tag_offset = GUINT32_FROM_BE(hdr->head.phs) - sizeof(hdr->tag);
|
|
meas = g_new0(att_meas_ctx_t, 1);
|
|
|
|
memcpy(meas->pld, hdr->head.pld, sizeof(meas->pld));
|
|
memcpy(meas->ald, hdr->head.ald, sizeof(meas->ald));
|
|
memcpy(meas->tld, hdr->head.tld, sizeof(meas->tld));
|
|
memcpy(meas->tag, hdr_u8 + se_hdr_tag_offset, sizeof(meas->tag));
|
|
|
|
return g_steal_pointer(&meas);
|
|
}
|
|
|
|
void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid)
|
|
{
|
|
pv_wrapped_g_assert(meas_ctx);
|
|
pv_wrapped_g_assert(config_uid);
|
|
|
|
g_assert(g_bytes_get_size(config_uid) == ATT_CONFIG_UID_SIZE);
|
|
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid, NULL);
|
|
}
|
|
|
|
gboolean att_verify_measurement(const GBytes *calculated_measurement,
|
|
const GBytes *uvio_measurement, GError **error)
|
|
{
|
|
pv_wrapped_g_assert(calculated_measurement);
|
|
pv_wrapped_g_assert(uvio_measurement);
|
|
|
|
if (g_bytes_compare(calculated_measurement, uvio_measurement) != 0) {
|
|
g_set_error(error, ATT_ERROR, ATT_ERR_MEASUREMENT_VERIFICATION_FAILED,
|
|
_("Calculated and received attestation measurement are not equal."));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|