/*
 * Attestation related functions and definitions.
 *
 * 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.
 */
#ifndef PVATTEST_ATTESTATION_H
#define PVATTEST_ATTESTATION_H
/* Must be included before any other header */
#include "config.h"

#include <openssl/sha.h>

#include "libpv/glib-helper.h"
#include "libpv/crypto.h"
#include "libpv/cert.h"

#include "common.h"
#include "types.h"
#include "arcb.h"

#define ATT_CONFIG_UID_SIZE 16

typedef struct {
	uint8_t pld[SHA512_DIGEST_LENGTH];
	uint8_t ald[SHA512_DIGEST_LENGTH];
	uint8_t tld[SHA512_DIGEST_LENGTH];
	uint8_t tag[AES_256_GCM_TAG_SIZE];
	uint8_t config_uid[ATT_CONFIG_UID_SIZE];
} __packed att_meas_ctx_t;
G_STATIC_ASSERT(sizeof(att_meas_ctx_t) == 224);

/**
 * att_gen_measurement_hmac_sha512:
 *
 * @meas_ctx: measurement context.
 * @measurement_key: AES-256-GCM key for generating the measurement calculation.
 * @optional_user_data: NULL or up to 256 bytes GBytes.
 * @optional_nonce: NULL or a nonce of exactly `ARCB_V1_NONCE_SIZE` bytes
 * @optional_additional_data: NULL or up to 0x8000 bytes of GBytes.
 * @error: GError. *error will != NULL if error occurs.
 *
 * Calculates the measurement value.
 * If the input data is the same which the UV used in the Retrieve Attestation Measurement
 * the result should be identical to the data in the ´Measurement Data Address´ UVC.
 *
 * Returns: (nullable) (transfer full): a hmac_sha512 of the given data.
 */
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)
	PV_NONNULL(1, 2);

/**
 * att_extract_from_hdr:
 *
 * @se_hdr: binary SE guest header.
 * @error: GError. *error will != NULL if error occurs.
 *
 * Verifies that SE header size and magic ,but no cryptographical verification.
 * Then, find and extracts pld, ald, tld, and SE tagi and adds it to the context.
 *
 * Returns: new attestation measurement context.
 */
att_meas_ctx_t *att_extract_from_hdr(GBytes *se_hdr, GError **error) PV_NONNULL(1);

/** att_add_uid:
 *
 * @meas_ctx: measurement context.
 * @config_uid: pointer to config UID. Must be `ATT_CONFIG_UID_SIZE` bytes long.
 *
 * Copies the config UID to the measurement context.
 * Wrong size is considered as a Programming error.
 */
void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid) PV_NONNULL(1, 2);

/** att_verify_measurement:
 *
 * @calculated_measurement: measurement calculated by a trusted system
 * @uvio_measurement: measurement generated by an UV
 * @error: GError. *error will != NULL if error occurs.
 *
 * Returns: TRUE if measurements are identical, otherwise FALSE
 */
gboolean att_verify_measurement(const GBytes *calculated_measurement,
				const GBytes *uvio_measurement, GError **error) PV_NONNULL(1, 2);

#define ATT_ERROR g_quark_from_static_string("pv-att_error-quark")
typedef enum att_error {
	ATT_ERR_INVALID_HDR,
	ATT_ERR_INVALID_USER_DATA,
	ATT_ERR_MEASUREMENT_VERIFICATION_FAILED,
	ATT_ERR_PHKH_NO_FIT_IN_USER_DATA,
	ATT_ERR_PHKH_NO_MATCH,
} att_error_e;

#endif /* PVATTEST_ATTESTATION_H */
