blob: e713513c076e8ac50a5f3ae3f68f8d2398f84806 [file] [log] [blame]
/* Copyright 2020 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/* ************************************************************************** */
/* Includes */
/* ************************************************************************** */
#include <ex_sss.h>
#include <ex_sss_auth.h>
#include <ex_sss_boot.h>
#include <fsl_sss_se05x_apis.h>
#include <nxEnsure.h>
#include <nxLog_App.h>
#include <se05x_APDU_apis.h>
#include <se05x_ReadWithAttestation.h>
#include <se05x_enums.h>
/* ************************************************************************** */
/* Local Defines */
/* ************************************************************************** */
#define EC_KEY_BIT_LEN 256
#if (SSS_HAVE_SE05X_AUTH_USERID) || (SSS_HAVE_SE05X_AUTH_USERID_PLATFSCP03) //UserID Session
#define EX_LOCAL_OBJ_AUTH_ID EX_SSS_AUTH_SE05X_UserID_AUTH_ID
#elif (SSS_HAVE_SE05X_AUTH_NONE) || (SSS_HAVE_SE05X_AUTH_PLATFSCP03) //No auth
#define EX_LOCAL_OBJ_AUTH_ID EX_SSS_AUTH_SE05X_NONE_AUTH_ID
#elif (SSS_HAVE_SE05X_AUTH_AESKEY) || (SSS_HAVE_SE05X_AUTH_AESKEY_PLATFSCP03) //AESKey
#define EX_LOCAL_OBJ_AUTH_ID EX_SSS_AUTH_SE05X_APPLETSCP_AUTH_ID
#elif (SSS_HAVE_SE05X_AUTH_ECKEY) || (SSS_HAVE_SE05X_AUTH_ECKEY_PLATFSCP03) //ECKey session
#define EX_LOCAL_OBJ_AUTH_ID EX_SSS_AUTH_SE05X_ECKEY_ECDSA_AUTH_ID
#endif
#define AUTHENTICATION_OBJ_ATTR_POLICYLEN_OFFSET 14
#define KEYOBJ_VERSION_LENGTH 4
/* ************************************************************************** */
/* Structures and Typedefs */
/* ************************************************************************** */
typedef struct authObj_attributes
{
uint16_t auth_attempts_cntr;
uint16_t max_auth_attempts_cntr;
} authObj_attributes_t;
typedef struct non_authObj_attributes
{
uint16_t min_tagLen_for_AEAD;
uint16_t rfu;
} non_authObj_attributes_t;
typedef union attr {
authObj_attributes_t authObjAttr;
non_authObj_attributes_t nonAuthObjAttr;
} attr_u;
typedef struct ObjAttr {
uint32_t object_id;
SE05x_SecObjTyp_t object_type;
SE05x_SetIndicator_t auth_attr;
attr_u attr;
uint32_t auth_obj_id_owner;
SE05x_Origin_t object_origin;
uint32_t object_version;
} ObjAttr_t;
/* ************************************************************************** */
/* Global Variables */
/* ************************************************************************** */
static ex_sss_boot_ctx_t gex_sss_attst_read_boot_ctx;
/* ************************************************************************** */
/* Static function declarations */
/* ************************************************************************** */
/* ************************************************************************** */
/* Private Functions */
/* ************************************************************************** */
static sss_status_t create_attestation_key(ex_sss_boot_ctx_t *pCtx, size_t keyBitLen);
static sss_status_t create_object_to_attest(ex_sss_boot_ctx_t *pCtx);
static void log_attribute_type(const SE05x_SecObjTyp_t type);
static void log_attribute_auth(const SE05x_SetIndicator_t auth);
static void log_attribute_access_rule(uint32_t ar_header);
static void log_attribute_origin(const SE05x_Origin_t origin);
sss_status_t read_large_object_with_attestation(ex_sss_boot_ctx_t *pCtx,
sss_se05x_key_store_t *keyStore,
sss_se05x_object_t *keyObject,
uint8_t *key,
size_t *keylen,
size_t *pKeyBitLen,
sss_se05x_object_t *keyObject_attst,
sss_algorithm_t algorithm_attst,
uint8_t *random_attst,
size_t randomLen_attst,
sss_se05x_attst_data_t *attst_data);
static sss_status_t create_host_public_key(
ex_sss_boot_ctx_t *pCtx, uint32_t keyId, size_t keyBitLen, sss_object_t *verification_object);
static void clean_attestation_objects(ex_sss_boot_ctx_t *pCtx, uint32_t attestation_key_id, uint32_t keyid_to_attest);
/* ************************************************************************** */
/* Public Functions */
/* ************************************************************************** */
#define EX_SSS_BOOT_PCONTEXT (&gex_sss_attst_read_boot_ctx)
#define EX_SSS_BOOT_DO_ERASE 1
#define EX_SSS_BOOT_EXPOSE_ARGC_ARGV 0
#include <ex_sss_main_inc.h>
sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx)
{
LOG_I("Running example se05x_ReadWithAttestation");
sss_status_t status = kStatus_SSS_Success;
uint8_t obj[2500] = {0};
size_t objByteLen = sizeof(obj);
size_t objBitLen = objByteLen * 8;
sss_object_t sss_object_to_attest;
sss_object_t sss_attestation_object;
sss_algorithm_t algorithm = kAlgorithm_SSS_ECDSA_SHA256;
uint32_t auth_obj = 0;
/* Variables for verification */
sss_object_t verification_object = {0};
uint8_t plainData[2500] = {0};
size_t plainDataLen = sizeof(plainData);
uint8_t digest[64] = {0};
size_t digestLen = sizeof(digest);
sss_digest_t digest_ctx;
sss_algorithm_t digest_algorithm = kAlgorithm_SSS_SHA256;
sss_asymmetric_t verify_ctx;
uint8_t datai = 0;
uint8_t *att = NULL;
uint8_t i = 0;
size_t attr_Len = 0;
uint8_t attr_Cnt = 0;
//uint8_t attr_policyLen =0;
/* doc:start:read-w-attestation */
/* Prepare/init attestation data structure */
sss_se05x_attst_comp_data_t comp_data[2] = {0};
sss_se05x_attst_data_t att_data = {.valid_number = 2};
/* Random data from the host to check if SE
* answers to current attestation request and
* not an older response is used */
/* clang-format off */
uint8_t freshness[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };
/* doc:end:read-w-attestation */
/* Generate Random Attestation key
* We use NIST-P 256 in this example
*/
status = create_attestation_key(pCtx, EC_KEY_BIT_LEN);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = create_host_public_key(
pCtx, ATTESTATION_KEY_ID, EC_KEY_BIT_LEN, &verification_object);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Import any object into the SE which will be
* read with attestation. In this example, we are
* importing a binary objecct
*/
status = create_object_to_attest(pCtx);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Initialize Attesttation Object */
status = sss_key_object_init(&sss_attestation_object, &pCtx->ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status =
sss_key_object_get_handle(&sss_attestation_object, ATTESTATION_KEY_ID);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Initialize object to attest */
status = sss_key_object_init(&sss_object_to_attest, &pCtx->ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_get_handle(&sss_object_to_attest, OBJECT_KEY_ID);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* doc:start:read-w-attestation */
memcpy(&att_data.data, &comp_data[0], sizeof(comp_data));
att_data.data[0].attributeLen = sizeof(att_data.data[0].attribute);
att_data.data[0].outrandomLen = sizeof(att_data.data[0].outrandom);
att_data.data[0].chipIdLen = sizeof(att_data.data[0].attribute);
att_data.data[0].signatureLen = sizeof(att_data.data[0].signature);
att_data.data[1].attributeLen = sizeof(att_data.data[1].attribute);
att_data.data[1].outrandomLen = sizeof(att_data.data[1].outrandom);
att_data.data[1].chipIdLen = sizeof(att_data.data[1].attribute);
att_data.data[1].signatureLen = sizeof(att_data.data[1].signature);
/* clang-format on */
/* Execute attested read
* We use attestation object to attest (sign) all read data + object attributes
* Returns object attributes and signature in att_data
*/
status = sss_se05x_key_store_get_key_attst((sss_se05x_key_store_t *)&pCtx->ks,
(sss_se05x_object_t *)&sss_object_to_attest,
obj,
&objByteLen,
&objBitLen,
(sss_se05x_object_t *)&sss_attestation_object,
algorithm,
freshness,
sizeof(freshness),
&att_data);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Perform verification operation here on the following data
* (key + offset) +
* att_data->data[0].attribute +
* att_data->data[0].timestamp +
* att_data->data[0].outrandom +
* att_data->data[0].chipId
* with signature
* att_data->data[0].signature
*
* We perform signature verification on host.
* First we digest the data then pass it to verify API
*/
memcpy(plainData, obj, objByteLen);
memcpy(plainData + objByteLen, att_data.data[0].attribute, att_data.data[0].attributeLen);
memcpy(plainData + objByteLen + att_data.data[0].attributeLen,
&(att_data.data[0].timeStamp),
att_data.data[0].timeStampLen);
memcpy(plainData + objByteLen + att_data.data[0].attributeLen + att_data.data[0].timeStampLen,
att_data.data[0].outrandom,
att_data.data[0].outrandomLen);
memcpy(plainData + objByteLen + att_data.data[0].attributeLen + att_data.data[0].timeStampLen +
att_data.data[0].outrandomLen,
att_data.data[0].chipId,
att_data.data[0].chipIdLen);
plainDataLen = objByteLen + att_data.data[0].attributeLen + att_data.data[0].timeStampLen +
att_data.data[0].outrandomLen + att_data.data[0].chipIdLen;
status = sss_digest_context_init(&digest_ctx, &pCtx->host_session, digest_algorithm, kMode_SSS_Digest);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_digest_one_go(&digest_ctx, plainData, plainDataLen, digest, &digestLen);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
sss_digest_context_free(&digest_ctx);
/* Verify signature */
sss_asymmetric_context_init(&verify_ctx, &pCtx->host_session, &verification_object, algorithm, kMode_SSS_Verify);
status = sss_asymmetric_verify_digest(
&verify_ctx, digest, digestLen, att_data.data[0].signature, att_data.data[0].signatureLen);
sss_asymmetric_context_free(&verify_ctx);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* doc:end:read-w-attestation */
/* Only look at first part of attested data
* object-type-dependend further parts contain same policy data */
LOG_MAU8_D("Key att content", obj, objByteLen);
LOG_MAU8_I("Key att data", (uint8_t *)att_data.data[datai].attribute, att_data.data[datai].attributeLen);
att = (uint8_t *)att_data.data[datai].attribute;
ObjAttr_t attrib = { 0 };
attr_Len = att_data.data[datai].attributeLen;
attrib.object_id = (uint32_t)att[attr_Cnt] << 24 | att[attr_Cnt + 1] << 16 | \
att[attr_Cnt + 2] << 8 | att[attr_Cnt + 3] << 0;
attr_Cnt += 4;
attrib.object_type = att[attr_Cnt++];
attrib.auth_attr = att[attr_Cnt++];
LOG_I("Object Id 0x%04X", attrib.object_id);
LOG_I("Object Type 0x%X", attrib.object_type);
/* Log object type */
log_attribute_type(attrib.object_type);
LOG_I("Object Auth Attribute 0x%X", attrib.auth_attr);
/* Log Object Auth Attribute */
log_attribute_auth(attrib.auth_attr);
i = AUTHENTICATION_OBJ_ATTR_POLICYLEN_OFFSET;
//attr_policyLen = att[i];
/* Check for existing policies and loop over them to log */
while (att[i] >= 4) {
uint8_t ar_length = att[i++];
if ((ar_length < 4) | (ar_length > 40))
LOG_E("Access rule header invalid length 0X%02X", ar_length);
auth_obj = (uint32_t)att[i] << 24 | att[i + 1] << 16 | att[i + 2] << 8 | att[i + 3];
LOG_I("Auth Object:");
if (auth_obj == 0) {
LOG_I("\tNo authentication required");
}
else {
LOG_I("\tAuthentication required");
LOG_I("\t0x%08X", auth_obj);
}
i += 4;
uint32_t ar_header = (uint32_t)att[i] << 24 | att[i + 1] << 16 | att[i + 2] << 8 | att[i + 3];
i += 4;
/* Log Access Rules (Policies) associated with the object */
log_attribute_access_rule(ar_header);
/* Print AR extension for POLICY_OBJ_REQUIRE_PCR_VALUE */
if (ar_length > 4) {
if (ar_header & POLICY_OBJ_REQUIRE_PCR_VALUE) {
LOG_MAU8_I("AR Extension: ", att + i + 4, ar_length - 4);
i += ar_length;
}
}
}
/* Parse origin flag */
attrib.object_origin = att[i++];
if (i == attr_Len)
{ /*Data is retrieved for Se050*/
attrib.attr.authObjAttr.auth_attempts_cntr = (uint16_t)att[attr_Cnt] << 8 | att[attr_Cnt + 1];
attr_Cnt += 2;
attrib.auth_obj_id_owner = (uint32_t)att[attr_Cnt] << 24 | att[attr_Cnt + 1] << 16 | \
att[attr_Cnt + 2] << 8 | att[attr_Cnt + 3] << 0;
attr_Cnt += 4;
attrib.attr.authObjAttr.max_auth_attempts_cntr = (uint16_t)att[attr_Cnt] << 8 |\
att[attr_Cnt + 1];
attr_Cnt += 2;
if (attr_Cnt == AUTHENTICATION_OBJ_ATTR_POLICYLEN_OFFSET)
{
//origin needs to be filled and printed
log_attribute_origin(attrib.object_origin);
status = kStatus_SSS_Success;
}
}
else
{
attrib.object_version = att[i] << 24 | att[i + 1] << 16 | att[i + 2] << 8 | att[i + 3];
i += KEYOBJ_VERSION_LENGTH;
if (i == attr_Len)
{ /*Data is retrieved for Se051*/
if (attrib.auth_attr == kSE05x_SetIndicator_NOT_SET || attrib.auth_attr == kSE05x_SetIndicator_SET)
{
if (attrib.auth_attr == kSE05x_SetIndicator_NOT_SET)
{
attrib.attr.nonAuthObjAttr.min_tagLen_for_AEAD = (uint16_t)att[attr_Cnt] << 8 | att[attr_Cnt + 1];
attr_Cnt += 2;
attrib.auth_obj_id_owner = (uint32_t)att[attr_Cnt] << 24 | att[attr_Cnt + 1] << 16 | \
att[attr_Cnt + 2] << 8 | att[attr_Cnt + 3] << 0;
attr_Cnt += 4;
attrib.attr.nonAuthObjAttr.rfu = (uint16_t)att[attr_Cnt] << 8 | \
att[attr_Cnt + 1];
/* Log min tagLen for AEAD obj*/
LOG_I("tagLen for AEAD:0x%02X", attrib.attr.nonAuthObjAttr.min_tagLen_for_AEAD);
/* Log RFU bytes*/
LOG_I("RFU bytes:0x%02X", attrib.attr.nonAuthObjAttr.rfu);
}
else if (attrib.auth_attr == kSE05x_SetIndicator_SET)
{
attrib.attr.authObjAttr.auth_attempts_cntr = (uint16_t)att[attr_Cnt] << 8 | att[attr_Cnt + 1];
attr_Cnt += 2;
attrib.auth_obj_id_owner = (uint32_t)att[attr_Cnt] << 24 | att[attr_Cnt + 1] << 16 | \
att[attr_Cnt + 2] << 8 | att[attr_Cnt + 3] << 0;
attr_Cnt += 4;
attrib.attr.authObjAttr.max_auth_attempts_cntr = (uint16_t)att[attr_Cnt] << 8 | \
att[attr_Cnt + 1];
/* Log Auth attempts cntr*/
LOG_I("Auth attempts cntr:0x%02X", attrib.attr.authObjAttr.auth_attempts_cntr);
/* Log Max auth attempts cntr*/
LOG_I("Max auth attempts cntr:0x%02X", attrib.attr.authObjAttr.max_auth_attempts_cntr);
}
attr_Cnt += 2;
if (attr_Cnt == AUTHENTICATION_OBJ_ATTR_POLICYLEN_OFFSET)
{
/* Log object id owner*/
LOG_I("Owner:0x%04X", attrib.auth_obj_id_owner);
/* Log object origin*/
LOG_I("Object origin : 0x%X", attrib.object_origin);
log_attribute_origin(attrib.object_origin);
/* Log object version*/
LOG_I("Object Version : 0x%04X", attrib.object_version);
status = kStatus_SSS_Success;
}
}
else
{
status = kStatus_SSS_Fail;
}
}
else
{
status = kStatus_SSS_Fail;
}
}
if (kStatus_SSS_Success == status) {
LOG_I("se05x_ReadWithAttestation Example Success !!!");
}
else {
LOG_E("se05x_ReadWithAttestation Example Failed !!!");
}
cleanup:
clean_attestation_objects(pCtx, ATTESTATION_KEY_ID, OBJECT_KEY_ID);
sss_key_object_free(&verification_object);
return status;
}
static sss_status_t create_attestation_key(ex_sss_boot_ctx_t *pCtx, size_t keyBitLen)
{
sss_status_t status = kStatus_SSS_Fail;
size_t keylen = keyBitLen / 8;
uint32_t keyId = ATTESTATION_KEY_ID;
sss_object_t key_attst = {0};
sss_cipher_type_t cipherType = kSSS_CipherType_EC_NIST_P;
const sss_policy_u key_pol = {.type = KPolicy_Asym_Key,
.auth_obj_id = EX_LOCAL_OBJ_AUTH_ID,
.policy = {.asymmkey = {
.can_Sign = 1,
.can_Verify = 1,
.can_Encrypt = 1,
.can_Decrypt = 1,
.can_KD = 1,
.can_Wrap = 1,
.can_Write = 1,
.can_Gen = 1,
.can_Import_Export = 1,
.can_KA = 1,
.can_Read = 1,
.can_Attest = 1,
}}};
const sss_policy_u common = {.type = KPolicy_Common,
.auth_obj_id = EX_LOCAL_OBJ_AUTH_ID,
.policy = {.common = {
.can_Delete = 1,
}}};
sss_policy_t policy_for_ec_key = {.nPolicies = 2, .policies = {&key_pol, &common}};
status = sss_key_object_init(&key_attst, &pCtx->ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Generate asymmetric key */
status = sss_key_object_allocate_handle(
&key_attst, keyId, kSSS_KeyPart_Pair, cipherType, keylen, kKeyObject_Mode_Persistent);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_store_generate_key(&pCtx->ks, &key_attst, keyBitLen, &policy_for_ec_key);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
cleanup:
return status;
}
static sss_status_t create_host_public_key(
ex_sss_boot_ctx_t *pCtx, uint32_t keyId, size_t keyBitLen, sss_object_t *verification_object)
{
sss_status_t status = kStatus_SSS_Fail;
sss_object_t attestation_key = {0};
uint8_t public_key[100] = {0};
size_t public_key_len = sizeof(public_key);
status = sss_key_object_init(&attestation_key, &pCtx->ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_get_handle(&attestation_key, keyId);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_store_get_key(&pCtx->ks, &attestation_key, public_key, &public_key_len, &keyBitLen);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_init(verification_object, &pCtx->host_ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(verification_object,
__LINE__,
kSSS_KeyPart_Public,
attestation_key.cipherType,
public_key_len,
kKeyObject_Mode_Persistent);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_store_set_key(&pCtx->host_ks, verification_object, public_key, public_key_len, keyBitLen, NULL, 0);
cleanup:
return status;
}
static sss_status_t create_object_to_attest(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
sss_object_t object_to_attest = {0};
sss_key_part_t key_part = kSSS_KeyPart_Default;
sss_cipher_type_t cipherType = kSSS_CipherType_Binary;
uint8_t data[] = OBJECT_TO_ATTEST;
size_t dataLen = sizeof(data);
uint32_t keyId = OBJECT_KEY_ID;
const sss_policy_u obj_pol = {.type = KPolicy_File,
.auth_obj_id = EX_LOCAL_OBJ_AUTH_ID,
.policy = {.file = {
.can_Write = 1,
.can_Read = 1,
}}};
const sss_policy_u common = {.type = KPolicy_Common,
.auth_obj_id = EX_LOCAL_OBJ_AUTH_ID,
.policy = {.common = {
.can_Delete = 1,
}}};
sss_policy_t policy_for_bin_obj = {.nPolicies = 2, .policies = {&obj_pol, &common}};
status = sss_key_object_init(&object_to_attest, &pCtx->ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
/* Generate asymmetric key */
status = sss_key_object_allocate_handle(
&object_to_attest, keyId, key_part, cipherType, dataLen, kKeyObject_Mode_Persistent);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_store_set_key(
&pCtx->ks, &object_to_attest, data, dataLen, dataLen, &policy_for_bin_obj, sizeof(policy_for_bin_obj));
cleanup:
return status;
}
static void log_attribute_type(const SE05x_SecObjTyp_t type)
{
LOG_I("Type:");
switch (type) {
case kSE05x_SecObjTyp_EC_KEY_PAIR:
LOG_I("\tEC_KEY_PAIR");
break;
case kSE05x_SecObjTyp_EC_PRIV_KEY:
LOG_I("\tEC_PRIV_KEY");
break;
case kSE05x_SecObjTyp_EC_PUB_KEY:
LOG_I("\tEC_PUB_KEY");
break;
case kSE05x_SecObjTyp_RSA_KEY_PAIR:
LOG_I("\tRSA_KEY_PAIR");
break;
case kSE05x_SecObjTyp_RSA_KEY_PAIR_CRT:
LOG_I("\tRSA_KEY_PAIR_CRT");
break;
case kSE05x_SecObjTyp_RSA_PRIV_KEY:
LOG_I("\tRSA_PRIV_KEY");
break;
case kSE05x_SecObjTyp_RSA_PRIV_KEY_CRT:
LOG_I("\tRSA_PRIV_KEY_CRT");
break;
case kSE05x_SecObjTyp_RSA_PUB_KEY:
LOG_I("\tRSA_PUB_KEY");
break;
case kSE05x_SecObjTyp_AES_KEY:
LOG_I("\tAES_KEY");
break;
case kSE05x_SecObjTyp_DES_KEY:
LOG_I("\tDES_KEY");
break;
case kSE05x_SecObjTyp_BINARY_FILE:
LOG_I("\tBINARY_FILE");
break;
case kSE05x_SecObjTyp_UserID:
LOG_I("\tUserID");
break;
case kSE05x_SecObjTyp_COUNTER:
LOG_I("\tCOUNTER");
break;
case kSE05x_SecObjTyp_PCR:
LOG_I("\tPCR_KEY_PAIR");
break;
case kSE05x_SecObjTyp_CURVE:
LOG_I("\tCURVE");
break;
case kSE05x_SecObjTyp_HMAC_KEY:
LOG_I("\tHMAC_KEY");
break;
default:
LOG_E("Unknown secure object type\n");
}
}
static void log_attribute_auth(const SE05x_SetIndicator_t auth)
{
LOG_I("Auth:");
switch (auth) {
case kSE05x_SetIndicator_NOT_SET:
LOG_I("\tNot Set");
break;
case kSE05x_SetIndicator_SET:
LOG_I("\tSet");
break;
default:
LOG_E("not allwed set indicator in object attribute\n");
}
}
static void log_attribute_origin(const SE05x_Origin_t origin)
{
LOG_I("Origin:");
switch (origin) {
case kSE05x_Origin_INTERNAL:
LOG_I("\tINTERNAL");
break;
case kSE05x_Origin_EXTERNAL:
LOG_I("\tEXTERNAL");
break;
case kSE05x_Origin_PROVISIONED:
LOG_I("\tPROVISIONED");
break;
case kSE05x_Origin_NA:
default:
LOG_E("\tORIGIN INVALID");
}
}
static void log_attribute_access_rule(uint32_t ar_header)
{
LOG_I("Policies:");
if (ar_header & POLICY_OBJ_FORBID_ALL) {
LOG_I("\tPOLICY_OBJ_FORBID_ALL");
};
if (ar_header & POLICY_OBJ_ALLOW_SIGN) {
LOG_I("\tPOLICY_OBJ_ALLOW_SIGN");
};
if (ar_header & POLICY_OBJ_ALLOW_VERIFY) {
LOG_I("\tPOLICY_OBJ_ALLOW_VERIFY");
};
if (ar_header & POLICY_OBJ_ALLOW_KA) {
LOG_I("\tPOLICY_OBJ_ALLOW_KA");
};
if (ar_header & POLICY_OBJ_ALLOW_ENC) {
LOG_I("\tPOLICY_OBJ_ALLOW_ENC");
};
if (ar_header & POLICY_OBJ_ALLOW_DEC) {
LOG_I("\tPOLICY_OBJ_ALLOW_DEC");
};
if (ar_header & POLICY_OBJ_ALLOW_KDF) {
LOG_I("\tPOLICY_OBJ_ALLOW_KDF");
};
if (ar_header & POLICY_OBJ_ALLOW_WRAP) {
LOG_I("\tPOLICY_OBJ_ALLOW_WRAP");
};
if (ar_header & POLICY_OBJ_ALLOW_READ) {
LOG_I("\tPOLICY_OBJ_ALLOW_READ");
};
if (ar_header & POLICY_OBJ_ALLOW_WRITE) {
LOG_I("\tPOLICY_OBJ_ALLOW_WRITE");
};
if (ar_header & POLICY_OBJ_ALLOW_GEN) {
LOG_I("\tPOLICY_OBJ_ALLOW_GEN");
};
if (ar_header & POLICY_OBJ_ALLOW_DELETE) {
LOG_I("\tPOLICY_OBJ_ALLOW_DELETE");
};
if (ar_header & POLICY_OBJ_REQUIRE_SM) {
LOG_I("\tPOLICY_OBJ_REQUIRE_SM");
};
if (ar_header & POLICY_OBJ_REQUIRE_PCR_VALUE) {
LOG_I("\tPOLICY_OBJ_REQUIRE_PCR_VALUE");
};
if (ar_header & POLICY_OBJ_ALLOW_ATTESTATION) {
LOG_I("\tPOLICY_OBJ_ALLOW_ATTESTATION");
};
if (ar_header & POLICY_OBJ_ALLOW_DESFIRE_AUTHENTICATION) {
LOG_I("\tPOLICY_OBJ_ALLOW_DESFIRE_AUTHENTICATION");
};
if (ar_header & POLICY_OBJ_ALLOW_DESFIRE_DUMP_SESSION_KEYS) {
LOG_I("\tPOLICY_OBJ_ALLOW_DESFIRE_DUMP_SESSION_KEYS");
};
if (ar_header & POLICY_OBJ_ALLOW_IMPORT_EXPORT) {
LOG_I("\tOLICY_OBJ_ALLOW_IMPORT_EXPORT");
};
}
static void clean_attestation_objects(ex_sss_boot_ctx_t *pCtx, uint32_t attestation_key_id, uint32_t keyid_to_attest)
{
sss_status_t status = kStatus_SSS_Fail;
sss_object_t object_to_delete = {0};
status = sss_key_object_init(&object_to_delete, &pCtx->ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Delete attestation object */
status = sss_key_object_get_handle(&object_to_delete, attestation_key_id);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_store_erase_key(&pCtx->ks, &object_to_delete);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Delete object to attest */
status = sss_key_object_get_handle(&object_to_delete, keyid_to_attest);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_store_erase_key(&pCtx->ks, &object_to_delete);
exit:
return;
}
/* doc:start:read-large-binary-obj-w-attestation */
sss_status_t read_large_object_with_attestation(ex_sss_boot_ctx_t *pCtx,
sss_se05x_key_store_t *keyStore,
sss_se05x_object_t *keyObject,
uint8_t *key,
size_t *keylen,
size_t *pKeyBitLen,
sss_se05x_object_t *keyObject_attst,
sss_algorithm_t algorithm_attst,
uint8_t *random_attst,
size_t randomLen_attst,
sss_se05x_attst_data_t *attst_data)
{
smStatus_t status = SM_NOT_OK;
sss_status_t sss_status = kStatus_SSS_Fail;
uint16_t rem_data = 0;
uint16_t offset = 0;
uint16_t size = 0;
size_t max_buffer = 0;
size_t signatureLen = 0;
uint32_t attestID;
SE05x_AttestationAlgo_t attestAlgo = kSE05x_AttestationAlgo_EC_SHA_256;
attestID = keyObject_attst->keyId;
/* Variables for verification */
sss_object_t verification_object = {0};
uint8_t plainData[2500] = {0};
size_t plainDataLen = sizeof(plainData);
uint8_t digest[64] = {0};
size_t digestLen = sizeof(digest);
sss_digest_t digest_ctx;
sss_algorithm_t algorithm = kAlgorithm_SSS_ECDSA_SHA256;
sss_algorithm_t digest_algorithm = kAlgorithm_SSS_SHA256;
sss_asymmetric_t verify_ctx;
if (kStatus_SSS_Success != create_host_public_key(pCtx, attestID, EC_KEY_BIT_LEN, &verification_object)) {
goto cleanup;
}
status = Se05x_API_ReadSize(&keyStore->session->s_ctx, keyObject->keyId, &size);
ENSURE_OR_GO_CLEANUP(status == SM_OK);
if (*keylen < size) {
LOG_E("Insufficient buffer ");
goto cleanup;
}
rem_data = size;
*keylen = size;
while (rem_data > 0) {
uint16_t chunk = (rem_data > BINARY_WRITE_MAX_LEN) ? BINARY_WRITE_MAX_LEN : rem_data;
rem_data = rem_data - chunk;
max_buffer = chunk;
signatureLen = attst_data->data[0].signatureLen;
attst_data->data[0].timeStampLen = sizeof(SE05x_TimeStamp_t);
status = Se05x_API_ReadObject_W_Attst(&keyStore->session->s_ctx,
keyObject->keyId,
offset,
chunk,
attestID,
attestAlgo,
random_attst,
randomLen_attst,
(key + offset),
&max_buffer,
attst_data->data[0].attribute,
&(attst_data->data[0].attributeLen),
&(attst_data->data[0].timeStamp),
attst_data->data[0].outrandom,
&(attst_data->data[0].outrandomLen),
attst_data->data[0].chipId,
&(attst_data->data[0].chipIdLen),
attst_data->data[0].signature,
&signatureLen);
attst_data->data[0].signatureLen -= signatureLen;
attst_data->valid_number = 1;
ENSURE_OR_GO_CLEANUP(status == SM_OK);
/* Perform verification operation here on the following data
* (key + offset) +
* attst_data->data[0].attribute +
* attst_data->data[0].timestamp +
* attst_data->data[0].outrandom +
* attst_data->data[0].chipId
* with signature
* attst_data->data[0].signature
*
* We perform signature verification on host.
* First we digest the data then pass it to verify API
*/
memcpy(plainData, (key + offset), max_buffer);
memcpy(plainData + max_buffer, attst_data->data[0].attribute, attst_data->data[0].attributeLen);
memcpy(plainData + max_buffer + attst_data->data[0].attributeLen,
&(attst_data->data[0].timeStamp),
attst_data->data[0].timeStampLen);
memcpy(plainData + max_buffer + attst_data->data[0].attributeLen + attst_data->data[0].timeStampLen,
attst_data->data[0].outrandom,
attst_data->data[0].outrandomLen);
memcpy(plainData + max_buffer + attst_data->data[0].attributeLen + attst_data->data[0].timeStampLen +
attst_data->data[0].outrandomLen,
attst_data->data[0].chipId,
attst_data->data[0].chipIdLen);
plainDataLen = max_buffer + attst_data->data[0].attributeLen + attst_data->data[0].timeStampLen +
attst_data->data[0].outrandomLen + attst_data->data[0].chipIdLen;
sss_status = sss_digest_context_init(&digest_ctx, &pCtx->host_session, digest_algorithm, kMode_SSS_Digest);
ENSURE_OR_GO_CLEANUP(sss_status == kStatus_SSS_Success);
sss_status = sss_digest_one_go(&digest_ctx, plainData, plainDataLen, digest, &digestLen);
ENSURE_OR_GO_CLEANUP(sss_status == kStatus_SSS_Success);
sss_digest_context_free(&digest_ctx);
/* Verify signature */
sss_asymmetric_context_init(
&verify_ctx, &pCtx->host_session, &verification_object, algorithm, kMode_SSS_Verify);
sss_status =
sss_asymmetric_verify_digest(&verify_ctx, digest, digestLen, attst_data->data[0].signature, signatureLen);
sss_asymmetric_context_free(&verify_ctx);
ENSURE_OR_GO_CLEANUP(sss_status == kStatus_SSS_Success);
offset = offset + chunk;
}
cleanup:
return sss_status;
}
/* doc:end:read-large-binary-obj-w-attestation */