blob: 706adb03f96f3283df0d368823a6d2ab09ffe756 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "hwsec-optee-ta/hwsec_session.h"
#include <stdint.h>
#include <string.h>
#include <tee_internal_api.h>
#include <tee_internal_api_extensions.h>
#include <tpm2/tpm_generated.h>
#include "hwsec-optee-ta/hwsec_cmd.h"
#define HWSEC_PTA_UUID \
{ \
0x721f4da9, 0xda05, 0x40d4, { \
0xa1, 0xa3, 0x83, 0x77, 0xc1, 0xe0, 0x8b, 0x0a \
} \
}
#define KEY_MAX_BITS 256
#define SALT_BUFFER_SIZE 68
#define HWSEC_NONCE_MIN_SIZE 16
#define HWSEC_NONCE_MAX_SIZE (sizeof(TPM2B_NONCE))
#define TPM_AUTH_KEY_INDEX 0x81000005
#define TPM_AUTH_PUB_MAX_LEN 128
#define GET_PUBKEY 0
static uint8_t buffer[HWSEC_COMMAND_MAX_LEN];
static TEE_Result get_auth_pubkey(uint8_t* auth_pubkey, int32_t* length) {
static const TEE_UUID uuid = HWSEC_PTA_UUID;
TEE_Result res = TEE_ERROR_GENERIC;
TEE_TASessionHandle sess;
res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL, &sess, NULL);
if (res != TEE_SUCCESS) {
EMSG("TEE_OpenTASession failed with code 0x%x", res);
return res;
}
uint32_t ptypes =
TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_VALUE_OUTPUT,
TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE);
TEE_Param params[TEE_NUM_PARAMS];
params[0].memref.size = *length;
params[0].memref.buffer = auth_pubkey;
res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE, GET_PUBKEY, ptypes,
params, NULL);
if (res != TEE_SUCCESS) {
EMSG("TEE_InvokeTACommand failed with code 0x%x", res);
goto cleanup_sess;
}
*length = params[1].value.a;
cleanup_sess:
TEE_CloseTASession(sess);
return res;
}
static TEE_Result InitHmacSha256Operation(TEE_OperationHandle* op,
uint8_t* key_data,
uint32_t key_len) {
TEE_Result res = TEE_ERROR_GENERIC;
TEE_ObjectHandle key = TEE_HANDLE_NULL;
TEE_Attribute hmac_key_attr;
TEE_InitRefAttribute(&hmac_key_attr, TEE_ATTR_SECRET_VALUE, key_data,
key_len);
res = TEE_AllocateTransientObject(TEE_TYPE_HMAC_SHA256, KEY_MAX_BITS, &key);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateTransientObject failed with code 0x%x", res);
return res;
}
res = TEE_PopulateTransientObject(key, &hmac_key_attr, 1);
if (res != TEE_SUCCESS) {
EMSG("TEE_PopulateTransientObject failed with code 0x%x", res);
goto cleanup_key;
}
res = TEE_AllocateOperation(op, TEE_ALG_HMAC_SHA256, TEE_MODE_MAC,
KEY_MAX_BITS);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateOperation failed with code 0x%x", res);
goto cleanup_key;
}
res = TEE_SetOperationKey(*op, key);
if (res != TEE_SUCCESS) {
EMSG("TEE_SetOperationKey failed with code 0x%x", res);
goto cleanup_op;
}
TEE_MACInit(*op, NULL, 0);
res = TEE_SUCCESS;
// We don't clean up the "op" here.
goto cleanup_key;
cleanup_op:
TEE_FreeOperation(*op);
cleanup_key:
TEE_FreeTransientObject(key);
return res;
}
static TEE_Result GenerateSalt(uint8_t salt[SHA256_DIGEST_SIZE],
TPM2B_ENCRYPTED_SECRET* encrypted_secret) {
TEE_Result res = TEE_ERROR_GENERIC;
TPM_RC tpm_rc;
int32_t tpm_auth_pub_len;
uint8_t tpm_auth_pub[TPM_AUTH_PUB_MAX_LEN];
uint8_t* tpm_auth_pub_ptr;
TPM2B_PUBLIC pub;
TPMS_ECC_POINT ephemeral_point;
uint32_t temp_len;
uint8_t z_value[SHA256_DIGEST_SIZE];
uint8_t party_u_info[SHA256_DIGEST_SIZE];
uint8_t party_v_info[SHA256_DIGEST_SIZE];
tpm_auth_pub_len = TPM_AUTH_PUB_MAX_LEN;
res = get_auth_pubkey(tpm_auth_pub, &tpm_auth_pub_len);
if (res != TEE_SUCCESS) {
EMSG("get_auth_pubkey failed with code 0x%x", res);
return res;
}
tpm_auth_pub_ptr = tpm_auth_pub;
tpm_rc = TPM2B_PUBLIC_Unmarshal(&pub, &tpm_auth_pub_ptr, &tpm_auth_pub_len);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("TPM2B_PUBLIC_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
}
if (pub.t.publicArea.type != TPM_ALG_ECC) {
EMSG("Invalid salting key type.");
return TEE_ERROR_NOT_SUPPORTED;
}
if (pub.t.publicArea.nameAlg != TPM_ALG_SHA256 ||
pub.t.publicArea.unique.ecc.x.t.size != SHA256_DIGEST_SIZE ||
pub.t.publicArea.unique.ecc.y.t.size != SHA256_DIGEST_SIZE) {
EMSG("Invalid ECC salting key attributes.");
return TEE_ERROR_NOT_SUPPORTED;
}
memcpy(party_v_info, pub.t.publicArea.unique.ecc.x.t.buffer,
SHA256_DIGEST_SIZE);
TEE_Attribute curv_attr;
TEE_InitValueAttribute(&curv_attr, TEE_ATTR_ECC_CURVE,
TEE_ECC_CURVE_NIST_P256, 0);
TEE_ObjectHandle key = TEE_HANDLE_NULL;
res = TEE_AllocateTransientObject(TEE_TYPE_ECDH_KEYPAIR, KEY_MAX_BITS, &key);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateTransientObject failed with code 0x%x", res);
return res;
}
res = TEE_GenerateKey(key, KEY_MAX_BITS, &curv_attr, 1);
if (res != TEE_SUCCESS) {
EMSG("TEE_GenerateKey failed with code 0x%x", res);
goto cleanup_key;
}
temp_len = SHA256_DIGEST_SIZE;
res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_ECC_PUBLIC_VALUE_X,
ephemeral_point.x.t.buffer, &temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_GetObjectBufferAttribute failed with code 0x%x", res);
goto cleanup_key;
} else if (temp_len > SHA256_DIGEST_SIZE) {
EMSG("Unsupported ephemeral_point_x length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_key;
} else if (temp_len < SHA256_DIGEST_SIZE) {
uint32_t diff = SHA256_DIGEST_SIZE - temp_len;
for (uint32_t i = 0; i < temp_len; i++) {
ephemeral_point.x.t.buffer[SHA256_DIGEST_SIZE - 1 - i] =
ephemeral_point.x.t.buffer[SHA256_DIGEST_SIZE - 1 - i - diff];
}
for (uint32_t i = 0; i < diff; i++) {
ephemeral_point.x.t.buffer[i] = 0;
}
}
ephemeral_point.x.t.size = SHA256_DIGEST_SIZE;
temp_len = SHA256_DIGEST_SIZE;
res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_ECC_PUBLIC_VALUE_Y,
ephemeral_point.y.t.buffer, &temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_GetObjectBufferAttribute failed with code 0x%x", res);
goto cleanup_key;
} else if (temp_len > SHA256_DIGEST_SIZE) {
EMSG("Unsupported ephemeral_point_y length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_key;
} else if (temp_len < SHA256_DIGEST_SIZE) {
uint32_t diff = SHA256_DIGEST_SIZE - temp_len;
for (uint32_t i = 0; i < temp_len; i++) {
ephemeral_point.y.t.buffer[SHA256_DIGEST_SIZE - 1 - i] =
ephemeral_point.y.t.buffer[SHA256_DIGEST_SIZE - 1 - i - diff];
}
for (uint32_t i = 0; i < diff; i++) {
ephemeral_point.y.t.buffer[i] = 0;
}
}
ephemeral_point.y.t.size = SHA256_DIGEST_SIZE;
memcpy(party_u_info, ephemeral_point.x.t.buffer, SHA256_DIGEST_SIZE);
uint8_t encrypted_salt[SALT_BUFFER_SIZE];
int32_t encrypted_salt_len;
uint8_t* encrypted_salt_ptr;
encrypted_salt_ptr = encrypted_salt;
encrypted_salt_len = SALT_BUFFER_SIZE;
temp_len = TPMS_ECC_POINT_Marshal(&ephemeral_point, &encrypted_salt_ptr,
&encrypted_salt_len);
if (temp_len != SALT_BUFFER_SIZE) {
EMSG("Unsupported encrypted_salt length %u", encrypted_salt_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_key;
}
memcpy(encrypted_secret->t.secret, encrypted_salt, temp_len);
encrypted_secret->t.size = temp_len;
TEE_OperationHandle op = TEE_HANDLE_NULL;
res = TEE_AllocateOperation(&op, TEE_ALG_ECDH_P256, TEE_MODE_DERIVE,
KEY_MAX_BITS);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateOperation failed with code 0x%x", res);
goto cleanup_key;
}
res = TEE_SetOperationKey(op, key);
if (res != TEE_SUCCESS) {
EMSG("TEE_SetOperationKey failed with code 0x%x", res);
goto cleanup_op_and_key;
}
// Free the previous key.
TEE_FreeTransientObject(key);
TEE_Attribute pubkey_attr[2];
TEE_InitRefAttribute(&pubkey_attr[0], TEE_ATTR_ECC_PUBLIC_VALUE_X,
pub.t.publicArea.unique.ecc.x.t.buffer,
pub.t.publicArea.unique.ecc.x.t.size);
TEE_InitRefAttribute(&pubkey_attr[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y,
pub.t.publicArea.unique.ecc.y.t.buffer,
pub.t.publicArea.unique.ecc.y.t.size);
res =
TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, KEY_MAX_BITS, &key);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateTransientObject failed with code 0x%x", res);
goto cleanup_op;
}
TEE_DeriveKey(op, pubkey_attr, 2, key);
temp_len = SHA256_DIGEST_SIZE;
res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_SECRET_VALUE, z_value,
&temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_GetObjectBufferAttribute failed with code 0x%x", res);
goto cleanup_op_and_key;
} else if (temp_len > SHA256_DIGEST_SIZE) {
EMSG("Unsupported z_value length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_op_and_key;
} else if (temp_len < SHA256_DIGEST_SIZE) {
uint32_t diff = SHA256_DIGEST_SIZE - temp_len;
for (uint32_t i = 0; i < temp_len; i++) {
z_value[SHA256_DIGEST_SIZE - 1 - i] =
z_value[SHA256_DIGEST_SIZE - 1 - i - diff];
}
for (uint32_t i = 0; i < diff; i++) {
z_value[i] = 0;
}
}
// Free the previous op.
TEE_FreeOperation(op);
res = TEE_AllocateOperation(&op, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0);
if (res != TEE_SUCCESS) {
EMSG("TEE_AllocateOperation failed with code 0x%x", res);
goto cleanup_key;
}
// Big-Endian 32-bit 1.
uint8_t marshaled_counter[4] = {0, 0, 0, 1};
TEE_DigestUpdate(op, marshaled_counter, 4);
TEE_DigestUpdate(op, z_value, SHA256_DIGEST_SIZE);
// The label constant for RSAES-OAEP and ECDH session secret generation,
// defined in the TPM 2.0 specs, Part 1, Annex B.10.2 and C.6.2.
TEE_DigestUpdate(op, "SECRET", 7);
TEE_DigestUpdate(op, party_u_info, SHA256_DIGEST_SIZE);
temp_len = SHA256_DIGEST_SIZE;
res =
TEE_DigestDoFinal(op, party_v_info, SHA256_DIGEST_SIZE, salt, &temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_DigestDoFinal failed with code 0x%x", res);
goto cleanup_op_and_key;
} else if (temp_len != SHA256_DIGEST_SIZE) {
EMSG("Unsupported seed length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_op_and_key;
}
res = TEE_SUCCESS;
cleanup_op_and_key:
TEE_FreeOperation(op);
cleanup_key:
TEE_FreeTransientObject(key);
return res;
cleanup_op:
TEE_FreeOperation(op);
return res;
}
TEE_Result OpenHwsecSession(TpmSession* session) {
TEE_Result res = TEE_ERROR_GENERIC;
TPM_RC tpm_rc;
uint8_t salt[SHA256_DIGEST_SIZE];
TPM2B_ENCRYPTED_SECRET encrypted_secret;
res = GenerateSalt(salt, &encrypted_secret);
if (res != TEE_SUCCESS) {
EMSG("GenerateSalt failed with code 0x%x", res);
return res;
}
session->nonce_caller.t.size = SHA1_DIGEST_SIZE;
TEE_GenerateRandom(session->nonce_caller.t.buffer,
session->nonce_caller.t.size);
uint8_t* cmd_ptr = buffer;
int32_t remaining = HWSEC_COMMAND_MAX_LEN;
UINT32 command_size = 0;
TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
TPM_CC cc = TPM_CC_StartAuthSession;
TPMI_DH_OBJECT tpm_key = TPM_AUTH_KEY_INDEX;
TPMI_DH_ENTITY bind = TPM_RH_NULL;
TPM_SE session_type = TPM_SE_HMAC;
TPMT_SYM_DEF symmetric = {
.algorithm = TPM_ALG_NULL,
};
TPMI_ALG_HASH auth_hash = TPM_ALG_SHA256;
command_size += TPMI_ST_COMMAND_TAG_Marshal(&tag, &cmd_ptr, &remaining);
command_size += UINT32_Marshal(&command_size, &cmd_ptr, &remaining);
command_size += TPM_CC_Marshal(&cc, &cmd_ptr, &remaining);
command_size += TPM_HANDLE_Marshal(&tpm_key, &cmd_ptr, &remaining);
command_size += TPM_HANDLE_Marshal(&bind, &cmd_ptr, &remaining);
command_size +=
TPM2B_NONCE_Marshal(&session->nonce_caller, &cmd_ptr, &remaining);
command_size +=
TPM2B_ENCRYPTED_SECRET_Marshal(&encrypted_secret, &cmd_ptr, &remaining);
command_size += UINT8_Marshal(&session_type, &cmd_ptr, &remaining);
command_size += TPMT_SYM_DEF_Marshal(&symmetric, &cmd_ptr, &remaining);
command_size += TPMI_ALG_HASH_Marshal(&auth_hash, &cmd_ptr, &remaining);
// Fix the command size.
cmd_ptr = buffer + 2;
remaining = HWSEC_COMMAND_MAX_LEN - 2;
UINT32_Marshal(&command_size, &cmd_ptr, &remaining);
size_t data_out = HWSEC_COMMAND_MAX_LEN;
res = SendHwsecRawCommand(buffer, HWSEC_COMMAND_MAX_LEN, &data_out);
if (res != TEE_SUCCESS) {
EMSG("Start session failed with code 0x%x", res);
return res;
}
remaining = data_out;
cmd_ptr = buffer;
tpm_rc = TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &cmd_ptr, &remaining);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("TPMI_ST_COMMAND_TAG_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
} else if (tag != TPM_ST_NO_SESSIONS) {
EMSG("Unknown tag");
return TEE_ERROR_CORRUPT_OBJECT;
}
tpm_rc = UINT32_Unmarshal(&command_size, &cmd_ptr, &remaining);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("UINT32_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
} else if (command_size != data_out) {
EMSG("Command output mismatch");
return TEE_ERROR_CORRUPT_OBJECT;
}
tpm_rc = UINT32_Unmarshal(&cc, &cmd_ptr, &remaining);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("UINT32_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
} else if (cc != TPM_RC_SUCCESS) {
EMSG("Start auth session failed with code 0x%x", cc);
return TEE_ERROR_BAD_STATE;
}
tpm_rc = TPM_HANDLE_Unmarshal(&session->session_handle, &cmd_ptr, &remaining);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("TPM_HANDLE_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
}
tpm_rc = TPM2B_NONCE_Unmarshal(&session->nonce_tpm, &cmd_ptr, &remaining);
if (tpm_rc != TPM_RC_SUCCESS) {
EMSG("TPM2B_NONCE_Unmarshal failed with code 0x%x", tpm_rc);
return TEE_ERROR_BAD_FORMAT;
}
if (remaining != 0) {
EMSG("Remaining unknown data in start session response");
return TEE_ERROR_CORRUPT_OBJECT;
}
TEE_OperationHandle op = TEE_HANDLE_NULL;
res = InitHmacSha256Operation(&op, salt, SHA256_DIGEST_SIZE);
if (res != TEE_SUCCESS) {
EMSG("InitHmacSha256Operation failed with code 0x%x", res);
return res;
}
// Big-Endian 32-bit 1.
uint8_t marshaled_counter[4] = {0, 0, 0, 1};
// Big-Endian 32-bit 256.
uint8_t digest_size_bits[4] = {0, 0, 1, 0};
TEE_MACUpdate(op, marshaled_counter, 4);
// The label constant for session key creation,
// defined in the TPM 2.0 specs, Part 1, Annex 19.6.8.
TEE_MACUpdate(op, "ATH", 4);
TEE_MACUpdate(op, session->nonce_tpm.t.buffer, session->nonce_tpm.t.size);
TEE_MACUpdate(op, session->nonce_caller.t.buffer,
session->nonce_caller.t.size);
uint32_t temp_len = SHA256_DIGEST_SIZE;
res = TEE_MACComputeFinal(op, digest_size_bits, 4, session->session_key,
&temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_MACComputeFinal failed with code 0x%x", res);
goto cleanup_op;
} else if (temp_len != SHA256_DIGEST_SIZE) {
EMSG("Unsupported session_key length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_op;
}
res = TEE_SUCCESS;
cleanup_op:
TEE_FreeOperation(op);
return res;
}
TEE_Result CloseHwsecSession(TpmSession* session) {
TEE_Result res = TEE_ERROR_GENERIC;
uint8_t* cmd_ptr = buffer;
int32_t remaining = HWSEC_COMMAND_MAX_LEN;
UINT32 command_size = 0;
TPMI_ST_COMMAND_TAG tag = TPM_ST_NO_SESSIONS;
TPM_CC cc = TPM_CC_FlushContext;
TPMI_DH_CONTEXT tpm_key = session->session_handle;
command_size += TPMI_ST_COMMAND_TAG_Marshal(&tag, &cmd_ptr, &remaining);
command_size += UINT32_Marshal(&command_size, &cmd_ptr, &remaining);
command_size += TPM_CC_Marshal(&cc, &cmd_ptr, &remaining);
command_size += TPM_HANDLE_Marshal(&tpm_key, &cmd_ptr, &remaining);
// Fix the command size.
cmd_ptr = buffer + 2;
remaining = HWSEC_COMMAND_MAX_LEN - 2;
UINT32_Marshal(&command_size, &cmd_ptr, &remaining);
size_t data_out = HWSEC_COMMAND_MAX_LEN;
res = SendHwsecRawCommand(buffer, HWSEC_COMMAND_MAX_LEN, &data_out);
if (res != TEE_SUCCESS) {
EMSG("Close session failed with code 0x%x", res);
return res;
}
return TEE_SUCCESS;
}
TEE_Result GetCommandAuthorization(TpmSession* session,
uint8_t command_hash[SHA256_DIGEST_SIZE],
TPMS_AUTH_COMMAND* auth) {
TEE_Result res = TEE_ERROR_GENERIC;
auth->sessionHandle = session->session_handle;
TPMA_SESSION session_attrs = {.continueSession = 1};
auth->sessionAttributes = session_attrs;
session->nonce_caller.t.size = SHA1_DIGEST_SIZE;
TEE_GenerateRandom(session->nonce_caller.t.buffer,
session->nonce_caller.t.size);
memcpy(&auth->nonce, &session->nonce_caller, sizeof(TPM2B_NONCE));
TEE_OperationHandle op = TEE_HANDLE_NULL;
res = InitHmacSha256Operation(&op, session->session_key, SHA256_DIGEST_SIZE);
if (res != TEE_SUCCESS) {
EMSG("InitHmacSha256Operation failed with code 0x%x", res);
return res;
}
TEE_MACUpdate(op, command_hash, SHA256_DIGEST_SIZE);
TEE_MACUpdate(op, session->nonce_caller.t.buffer,
session->nonce_caller.t.size);
TEE_MACUpdate(op, session->nonce_tpm.t.buffer, session->nonce_tpm.t.size);
uint32_t temp_len = SHA256_DIGEST_SIZE;
res = TEE_MACComputeFinal(op, &auth->sessionAttributes, 1,
auth->hmac.t.buffer, &temp_len);
if (res != TEE_SUCCESS) {
EMSG("TEE_MACComputeFinal failed with code 0x%x", res);
goto cleanup_op;
} else if (temp_len != SHA256_DIGEST_SIZE) {
EMSG("Unsupported session_key length %u", temp_len);
res = TEE_ERROR_NOT_SUPPORTED;
goto cleanup_op;
}
auth->hmac.t.size = SHA256_DIGEST_SIZE;
res = TEE_SUCCESS;
cleanup_op:
TEE_FreeOperation(op);
return res;
}
TEE_Result CheckResponseAuthorization(TpmSession* session,
uint8_t response_hash[SHA256_DIGEST_SIZE],
TPMS_AUTH_RESPONSE* auth) {
TEE_Result res = TEE_ERROR_GENERIC;
if (auth->hmac.t.size != SHA256_DIGEST_SIZE) {
EMSG("Unsupported hmac length %u", auth->hmac.t.size);
return TEE_ERROR_NOT_SUPPORTED;
}
if (auth->nonce.t.size < HWSEC_NONCE_MIN_SIZE ||
auth->nonce.t.size > HWSEC_NONCE_MAX_SIZE) {
EMSG("Unsupported nonce length %u", auth->nonce.t.size);
return TEE_ERROR_NOT_SUPPORTED;
}
memcpy(session->nonce_tpm.t.buffer, auth->nonce.t.buffer, auth->nonce.t.size);
session->nonce_tpm.t.size = auth->nonce.t.size;
uint8_t* buffer_ptr = buffer;
int32_t remaining = HWSEC_COMMAND_MAX_LEN;
UINT32 size = 0;
size +=
TPMA_SESSION_Marshal(&auth->sessionAttributes, &buffer_ptr, &remaining);
TEE_OperationHandle op = TEE_HANDLE_NULL;
res = InitHmacSha256Operation(&op, session->session_key, SHA256_DIGEST_SIZE);
if (res != TEE_SUCCESS) {
EMSG("InitHmacSha256Operation failed with code 0x%x", res);
return res;
}
TEE_MACUpdate(op, response_hash, SHA256_DIGEST_SIZE);
TEE_MACUpdate(op, session->nonce_tpm.t.buffer, session->nonce_tpm.t.size);
TEE_MACUpdate(op, session->nonce_caller.t.buffer,
session->nonce_caller.t.size);
res = TEE_MACCompareFinal(op, buffer, size, auth->hmac.t.buffer,
auth->hmac.t.size);
if (res != TEE_SUCCESS) {
EMSG("TEE_MACCompareFinal failed with code 0x%x", res);
goto cleanup_op;
}
res = TEE_SUCCESS;
cleanup_op:
TEE_FreeOperation(op);
return res;
}