blob: 8b61a01a3179b6c8ffc89e06c5df3ed1d0e16e3b [file] [log] [blame]
/**
* @file ex_hlse_cert.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2018 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* Example using Certificate objects
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sm_printf.h"
#include "HLSEAPI.h"
#include "sm_types.h"
#include "sm_apdu.h"
#include "tst_sm_util.h"
#include "a71ch_util.h"
#include "HLSEAPI.h"
#include "tst_a71ch_util.h"
#include "tst_hlse_a71ch_util.h"
static U8 exDataObjUsage(U8 initMode);
static U8 exMixedCertsAndDataObj(U8 initMode, U16 nBaseSize, U16 nObj);
static U8 exCertUsageBasic(U8 initMode);
static U8 exCertUsageEnlarge(U8 initMode);
static U8 exCertUsageGpTableLengthUnknown(U8 initMode);
static U8 exCertUsageReadOnly(U8 initMode);
static U8 exCertEnumerate(void);
static U8 exCertGetAttr(void);
static U8 exCertSetAttr(void);
// internal utilities
static HLSE_RET_CODE patchCertificateInitialTL(U8 *clientCertDer, U16 clientCertDerLen);
static HLSE_RET_CODE getObject(HLSE_OBJECT_HANDLE handle, U8 *data, U16 *len);
static HLSE_RET_CODE setObject(HLSE_OBJECT_HANDLE handle, U8 *data, U16 len);
/**
* Demonstrate usage of certificate objects
*/
U8 exHlseCert()
{
U8 result = 1;
PRINTF("\r\n-----------\r\nStart exHlseCert()\r\n------------\r\n");
DEV_ClearChannelState();
// Example of Data object usage
result &= exDataObjUsage(INIT_MODE_RESET);
#if AX_EMBEDDED
result &= exMixedCertsAndDataObj(INIT_MODE_RESET, 40 /* size */, 8 /* num of objects */);
#else
result &= exMixedCertsAndDataObj(INIT_MODE_RESET, 300 /* size */, 8 /* num of objects */);
#endif
// Example certificate usage with enhanced validations
result &= exCertUsageBasic(INIT_MODE_RESET);
// Example certificate usage enlarging and updating a certificate
result &= exCertUsageEnlarge(INIT_MODE_RESET);
// Example of Certificate creation / enumeration / Get / Set / Delete - when Read Only attribute used
result &= exCertUsageReadOnly(INIT_MODE_RESET);
// Example certificate usage when map contains indirect length (to be obtained from TLV of actual object)
result &= exCertUsageGpTableLengthUnknown(INIT_MODE_RESET);
// overall result
PRINTF("\r\n-----------\r\nEnd exHlseCert(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate usage of certificate object:
*
* Simulate the following scenario and aim to verify it works correctly:
*
* - Create Certificate
* - Read certificate data and verify correctness
* - Index ok
* - Value was correctly set
* - Update Certificate contents
* - Verify Certificate updated correctly
* - Delete certificate
* - Verify deletion
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
*/
static U8 exCertUsageBasic(U8 initMode)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE certHandles[5];
U16 certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
HLSE_OBJECT_INDEX index = 0;
HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE;
// Cert for this test is 50 bytes which occupies 2 chunks of 32 bytes on the GP Storage
U8 certData[50];
HLSE_ATTRIBUTE attr[3];
unsigned short templateSize = 3;
U8 data[50]; // to hold data to update certificate
memset(certHandles, 0x00, sizeof(certHandles));
memset(certData, 0xAA, sizeof(certData));
PRINTF("\r\n-----------\r\nStart exCertUsageBasic(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = certData;
attr[2].valueLen = sizeof(certData);
// Create certificate object index = 0
PRINTF("\r\nHLSE_CreateObject() - Create certificate object...\r\n------------\r\n");
hlseRc = HLSE_CreateObject(attr, templateSize, &certHandles[0]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// assumption : correct slot in GP Table data was occupied
// TODO: consider additional low level test for it
// Now read certificate data and verify correctness
// Find certificate where index=0
// enumerate objects - we should have one certificate by now with index 0
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, 1, "err");
// Get the attributes of the single certificate we have created
// - Object Index
// - Certificate data
PRINTF("\r\nHLSE_GetObjectAttribute()...\r\n");
{
U32 certIndex = 0xFFFFFFFF;
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_INDEX;
attrL.value = &certIndex;
attrL.valueLen = sizeof(certIndex);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF("\tcert index = 0x%lx\r\n", certIndex);
result &= AX_CHECK_U16((U16)certIndex, 0x00, "err");
}
PRINTF("Verify Certificate contents...\r\n");
{
U8 readCertData[50];
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("certOnA71CH", readCertData, sizeof(certData),
"expected cert data", certData, sizeof(certData), AX_COLON_32);
}
PRINTF("Update Certificate contents...\r\n");
{
HLSE_ATTRIBUTE attrL;
memset(data, 0xAB, sizeof(data));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = data;
attrL.valueLen = sizeof(data);
hlseRc = HLSE_SetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("Verify Certificate Updated correctly...\r\n");
{
U8 readCertData[50];
HLSE_ATTRIBUTE attrL;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(certData),
"expected cert data", data, sizeof(data), AX_COLON_32);
}
// Delete the certificate
PRINTF("\r\nHLSE_EraseObject()...\r\n");
hlseRc = HLSE_EraseObject(certHandles[certHandlesNum - 1]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Verify it was actually deleted
// enumerate objects - we should have no certificates by now
PRINTF("\r\nVerify object was erased...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, 0, "err");
PRINTF("\r\n-----------\r\nEnd exCertUsageBasic(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate usage of a data object:
*
* Simulate the following scenario and aim to verify it works correctly:
*
* - Create Data Object
* - Shows how to obtain the object GP offset
* - Read Data object and verify correctness
* - Index ok
* - Value was correctly set
* - Update Data Object contents
* - Verify Data Object updated correctly
*
* - Show direct update of partial block in Data Object
* - Show direct read of partial block in Data Object
* - Show direct Read / Write with offset that exceeds object boundaries is not allowed
* - Show direct Read / Write with length that exceeds object boundaries is not allowed
*
* - Delete Data Object
* - Verify deletion
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
*/
static U8 exDataObjUsage(U8 initMode)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE handles[5];
U16 handlesNum = sizeof(handles) / sizeof(HLSE_OBJECT_HANDLE);
HLSE_OBJECT_INDEX index = 0;
HLSE_OBJECT_TYPE objType = HLSE_DATA;
// data for this test is 100 bytes which occupies 2 chunks of 32 bytes on the GP Storage
U8 data[50];
HLSE_ATTRIBUTE attr[3];
unsigned short templateSize = 3;
//U8 updateData[50]; // to hold data to update data object
memset(handles, 0x00, sizeof(handles));
memset(data, 0xAA, sizeof(data));
PRINTF("\r\n-----------\r\nStart exDataObjUsage(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = data;
attr[2].valueLen = sizeof(data);
// Create data object index = 0
PRINTF("\r\nHLSE_CreateObject() - Create Data object...\r\n------------\r\n");
hlseRc = HLSE_CreateObject(attr, templateSize, &handles[0]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// assumption : correct slot in GP Table data was occupied
// TODO: consider additional low level test for it
// Now read data object and verify correctness
// Find data object where index=0
// enumerate objects - we should have one certificate by now with index 0
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
handlesNum = sizeof(handles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_DATA, handles, &handlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(handlesNum, 1, "err");
// show how to get the object's GP offset
PRINTF("\r\nGet object GP offset...\r\n");
{
U16 offset;
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_OFFSET;
attrL.value = &offset;
attrL.valueLen = sizeof(offset);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF("\tdata object offset = 0x%u\r\n", offset);
}
// make sure our data object is the one we previously created
// Get the attributes of the single data object we have
PRINTF("\r\nHLSE_GetObjectAttribute()...\r\n");
{
U32 dataIndex = 0xFFFFFFFF;
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_INDEX;
attrL.value = &dataIndex;
attrL.valueLen = sizeof(dataIndex);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF("\tdata object index = 0x%lx\r\n", dataIndex);
result &= AX_CHECK_U16((U16)dataIndex, 0x00, "err");
}
PRINTF("Verify Data object contents...\r\n");
{
U8 readData[50];
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readData;
attrL.valueLen = sizeof(readData);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("dataOnA71CH", readData, sizeof(data),
"expected data", data, sizeof(data), AX_COLON_32);
}
PRINTF("Update Data object contents...\r\n");
{
HLSE_ATTRIBUTE attrL;
memset(data, 0xAB, sizeof(data));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = data;
attrL.valueLen = sizeof(data);
hlseRc = HLSE_SetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("Verify Data object Updated correctly...\r\n");
{
U8 readData[50];
HLSE_ATTRIBUTE attrL;
memset(readData, 0x00, sizeof(readData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readData;
attrL.valueLen = sizeof(readData);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readData, sizeof(readData),
"expected data", data, sizeof(data), AX_COLON_32);
}
PRINTF("Show usage of direct read / Update access to Data Object...\r\n");
{
HLSE_ATTRIBUTE attrL;
HLSE_DIRECT_ACCESS_ATTRIBUTE_VALUE theValue;
U8 buffer[50]; // a buffer to hold the read data
U8 refBuffer2[50];
memset(buffer, 0x00, sizeof(buffer));
attrL.type = HLSE_ATTR_DIRECT_ACCESS_OBJECT_VALUE;
PRINTF(" Verify Direct Read of Data Object...\r\n");
theValue.offset = 0;
theValue.bytes = 32;
theValue.buffer = buffer;
theValue.bufferLen = sizeof(buffer);
attrL.value = &theValue;
attrL.valueLen = sizeof(theValue);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("dataOnA71CH", buffer, theValue.bytes,
"expected data", data, theValue.bytes, AX_COLON_32);
// Now show usage of direct update to data object - update 10 bytes at offset 0 to 0x11
memset(buffer, 0x11, 10);
theValue.bytes = 10;
theValue.buffer = buffer;
hlseRc = HLSE_SetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF(" Verify Direct Update of Data Object...\r\n");
memcpy(refBuffer2, buffer, 50);
memset(buffer, 0x00, sizeof(buffer));
theValue.bytes = 32;
theValue.buffer = buffer;
theValue.bufferLen = sizeof(buffer);
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("dataOnA71CH", buffer, theValue.bytes,
"expected data", refBuffer2, theValue.bytes, AX_COLON_32);
PRINTF(" Test Direct Read / Write with offset that exceeds object boundaries...\r\n");
{
// Note : data object 0 is at offset 0 , size 50 bytes
memset(buffer, 0x00, sizeof(buffer));
theValue.offset = 100;
theValue.bytes = 50;
theValue.buffer = buffer;
theValue.bufferLen = sizeof(buffer);
// Read with offset exceeding object boundary - not allowed
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_MEMORY, "err");
// Write with offset exceeding object boundary - not allowed
hlseRc = HLSE_SetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_MEMORY, "err");
}
PRINTF(" Test Direct Read / Write with length that exceeds object boundaries...\r\n");
{
// Note : data object 0 is at offset 0 , size 50 bytes
memset(buffer, 0x00, sizeof(buffer));
theValue.offset = 30;
theValue.bytes = 50;
theValue.buffer = buffer;
theValue.bufferLen = sizeof(buffer);
// Read exceeding object boundary - not allowed
hlseRc = HLSE_GetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_MEMORY, "err");
// Write exceeding object boundary - not allowed
hlseRc = HLSE_SetObjectAttribute(handles[handlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_MEMORY, "err");
}
}
// Delete the Data object
PRINTF("\r\nHLSE_EraseObject()...\r\n");
hlseRc = HLSE_EraseObject(handles[handlesNum - 1]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Verify it was actually deleted
// enumerate objects - we should have no certificates by now
PRINTF("\r\nVerify object was erased...\r\n");
handlesNum = sizeof(handles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_DATA, handles, &handlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(handlesNum, 0, "err");
PRINTF("\r\n-----------\r\nEnd exDataObjUsage(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
#define N_ADV_CERT 255
#define MAX_ADV_CERT_SIZE (4096 - 32)
#define LEN_SHORT_FORM_MAX 127
#define LEN_LONG_FORM_ONE_BYTE_MAX 255
#define LEN_LONG_FORM_TWO_BYTE_MAX 65536
#define ERR_GP_NO_CERT 0x2000
/**
* An Example to show usage of mixed certificates and data objects
*
* Scenario:
* - Create certificates and data objects
* - Read back the certificate and data objects
* - verify objects exists
* - verify object's length matches
* - verify objects's data matches
* - Delete a random number of objects
* - Read back the remaining certificate and data objects
* - verify objects exists
* - verify object's length matches
* - verify objects's data matches
* - Update an objects with new data
* - Read back the remaining certificate and data objects
* - verify objects exists
* - verify object's length matches
* - verify objects's data matches
* - Delete all objects
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
* @param[in] nBaseSize base size of Cert/Data object to create
* @param[in] nObj number of total objects to create
*/
static U8 exMixedCertsAndDataObj(U8 initMode, U16 nBaseSize, U16 nObj)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE mixedHandles[N_ADV_CERT]; // to hold handles of objects created
HLSE_OBJECT_INDEX index = 0;
HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE;
U8 *refData[N_ADV_CERT];
U16 effectiveSize[N_ADV_CERT];
U8 *refDataU[N_ADV_CERT];
U16 effectiveSizeU[N_ADV_CERT];
HLSE_ATTRIBUTE attr[3];
unsigned short templateSize = 3;
U8 data[MAX_ADV_CERT_SIZE]; // to hold data to read certificate
U8 nObjCreated = 0; // certs and data objects
U8 nObjToDelete = 0;
U8 handleIndDeleted[N_ADV_CERT]; // to hold array ind of handle deleted
U8 handleAlreadySelected = 0;
int i, j;
PRINTF("\r\n-----------\r\nStart exMixedCertsAndDataObjUsage(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
memset(mixedHandles, 0x00, sizeof(mixedHandles));
memset(handleIndDeleted, 0x00, sizeof(handleIndDeleted));
// Create reference arrays containing random values which could serve as certificates or data objects
srand(0);
for (i = 0; i < nObj; i++)
{
effectiveSize[i] = (U16)(nBaseSize - (i % 24));
refData[i] = (U8 *)malloc(effectiveSize[i]);
for (j = 0; j < effectiveSize[i]; j++)
{
refData[i][j] = (U8)rand();
}
}
// Create reference arrays containing random values which could serve as certificates or data objects, for updating the objects later
for (i = 0; i < nObj; i++)
{
effectiveSizeU[i] = (U16)(nBaseSize - (i % 24));
refDataU[i] = (U8 *)malloc(effectiveSizeU[i]);
for (j = 0; j < effectiveSizeU[i]; j++)
{
refDataU[i][j] = (U8)rand();
}
}
// Since the reference data arrays can be used as certificate we have to patch it to make sure it begins with a TLV of the certificate size,
// as this determines the certificate value returned when we retrieve it
for (i = 0; i < nObj; i++)
{
hlseRc = patchCertificateInitialTL(refData[i], effectiveSize[i]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "Failed to patch initial TL of certificate");
hlseRc = patchCertificateInitialTL(refDataU[i], effectiveSizeU[i]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "Failed to patch initial TL of certificate");
}
PRINTF("\r\n-----------\r\nStart intMixedCertsAndDataObjUsage()\r\n------------\r\n");
for (i = 0; i < nObj; i++)
{
index = (HLSE_OBJECT_INDEX)i;
// create mixed data objects and certficiates objects
objType = (i % 2 == 0) ? HLSE_CERTIFICATE : HLSE_DATA;
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = refData[i];
attr[2].valueLen = effectiveSize[i];
// Create certificate object @ index
PRINTF("\r\nHLSE_CreateObject(index=%lu, size=%d) - Create %s object...\r\n------------\r\n",
index, attr[2].valueLen, (objType == HLSE_CERTIFICATE ? "Certificate" : "Data"));
hlseRc = HLSE_CreateObject(attr, templateSize, &mixedHandles[i]);
if ((hlseRc == HLSE_ERR_MEMORY) && (index > 4)) {
// this is acceptable since we managed to create at least 5 certificates
PRINTF("\r\nGp Memory filled up");
break;
}
else if (hlseRc == HLSE_SW_OK)
{
nObjCreated++;
}
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("\r\nCreated %02d total objects ( mixed data and certificates objects )...", nObjCreated);
PRINTF("\r\nNow read back certificates and data objects...");
for (i = 0; i < nObjCreated; i++)
{
U16 dataLen = MAX_ADV_CERT_SIZE;
U8 localScore = 1;
hlseRc = getObject(mixedHandles[i], data, &dataLen);
localScore &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Does the length match?
localScore &= AX_CHECK_U16(dataLen, effectiveSize[i], "dataLen");
// Does the data match?
localScore &= AX_COMPARE_BYTE_ARRAY("data", data, dataLen, "refData", refData[i], effectiveSize[i], AX_COLON_16);
if (localScore != 1) { PRINTF("\r\nFailed to retrieve certificate at index %d (expected size=%d)\r\n", i, effectiveSize[i]); }
result &= localScore;
}
// Delete a random number of objects
do {
nObjToDelete = (U8)(rand() % (nObjCreated / 2));
} while (nObjToDelete == 0);
PRINTF("\r\nAbout to delete %d objects...", nObjToDelete);
for (i = 0; i < nObjToDelete; i++)
{
handleAlreadySelected = 0;
// find an index to delete
do {
// index in mixedHandles array of handle to delete
index = (U8)(rand() % nObjCreated);
// verify this index was not already deleted
if (handleIndDeleted[index] == 1) {
// need to select another handle
handleAlreadySelected = 1;
}
else {
handleAlreadySelected = 0;
}
} while (handleAlreadySelected == 1);
// set this index as a handle which was deleted
handleIndDeleted[index] = 1;
// Delete the object
PRINTF("\r\nHLSE_EraseObject(), handle=0x%lX...\r\n", mixedHandles[index]);
hlseRc = HLSE_EraseObject(mixedHandles[index]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
// Verify the remaining objects are still ok
PRINTF("\r\nNow read back remaining certificates and data objects...\r\n");
for (i = 0; i < nObjCreated; i++)
{
U16 dataLen = MAX_ADV_CERT_SIZE;
U8 localScore = 1;
// ignore this handle if was deleted
if (handleIndDeleted[i] != 0)
{
// skip this deleted object;
continue;
}
hlseRc = getObject(mixedHandles[i], data, &dataLen);
localScore &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Does the length match?
localScore &= AX_CHECK_U16(dataLen, effectiveSize[i], "dataLen");
// Does the certificate match?
localScore &= AX_COMPARE_BYTE_ARRAY("data", data, dataLen, "refData", refData[i], effectiveSize[i], AX_COLON_16);
if (localScore != 1) { PRINTF("\r\nFailed to retrieve certificate at index %d (expected size=%d)\r\n", i, effectiveSize[i]); }
result &= localScore;
}
// Update remaining objects with the alternate reference data, and verify updated data succesfull
PRINTF("\r\nNow update remaining certificates and data objects...\r\n");
for (i = 0; i < nObjCreated; i++)
{
U16 dataLen;
U8 localScore = 1;
// ignore this handle if was deleted
if (handleIndDeleted[i] != 0)
{
// skip this deleted object;
continue;
}
// Set object with new data
memcpy(data, refDataU[i], effectiveSizeU[i]);
dataLen = effectiveSizeU[i];
hlseRc = setObject(mixedHandles[i], data, dataLen);
localScore &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Get updated data
memset(data, 0, sizeof(data));
dataLen = MAX_ADV_CERT_SIZE;
hlseRc = getObject(mixedHandles[i], data, &dataLen);
localScore &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Does the length match?
localScore &= AX_CHECK_U16(dataLen, effectiveSizeU[i], "dataLen");
// Does the data match?
localScore &= AX_COMPARE_BYTE_ARRAY("data", data, dataLen, "refData", refDataU[i], effectiveSizeU[i], AX_COLON_16);
if (localScore != 1) { PRINTF("\r\nFailed to retrieve certificate at index %d (expected size=%d)\r\n", i, effectiveSize[i]); }
result &= localScore;
}
/*
* Delete all objects
*/
PRINTF("\r\nNow Delete all objects...\r\n");
for (i = 0; i < nObjCreated; i++)
{
// ignore this handle if was deleted
if (handleIndDeleted[i] != 0)
{
// skip this deleted object;
continue;
}
// set this index as a handle which was deleted
handleIndDeleted[i] = 1;
// Delete the object
PRINTF("\r\nHLSE_EraseObject(), handle=0x%lX...\r\n", mixedHandles[i]);
hlseRc = HLSE_EraseObject(mixedHandles[i]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
for (i = 0; i < nObjCreated; i++)
{
free(refData[i]);
free(refDataU[i]);
}
PRINTF("\r\n-----------\r\nEnd exMixedCertsAndDataObjUsage(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate usage of certificate objects:
*
* Simulate the following scenario and aim to verify it works correctly:
*
* - Create certificates
* - Verify cannot create additional certificate
* - Verify allows to enlarge a certificate with size within allocated boundary
* - Verify cannot enlarge beyond the allocated boundary
* - Delete the certificate
* - Recreate it with bigger size
* - Verify last certificate created still exists
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
*/
static U8 exCertUsageEnlarge(U8 initMode)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
// num of certificates to try to create ( actually created depends on GP memory availability )
U8 nCertsToCreate = 50;
// Note at max of 254 objects could be stored in the Gp table
// we allocate here space for one more in case we want to check that more that that is not possible
HLSE_OBJECT_HANDLE certHandles[255 + 1];
U8 nCertsCreated = 0;
// to hold actual handles created
//HLSE_OBJECT_HANDLE certHandle0;
//HLSE_OBJECT_HANDLE certHandle1;
HLSE_OBJECT_HANDLE certHandle2;
HLSE_OBJECT_HANDLE certHandle3;
//HLSE_OBJECT_HANDLE certHandle4;
HLSE_OBJECT_HANDLE lastCertHandle;
HLSE_OBJECT_INDEX index = 0;
HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE;
U8 indexCert;
U16 certHandlesNum;
// Cert for this test is 32 bytes which occupies 2 chunks of 32 bytes on the GP Storage
U8 certData[50];
HLSE_ATTRIBUTE attr[3];
unsigned short templateSize = 3;
U8 dataIn2Chunks[60]; // to hold data to update certificate - within 2 chunks boundary
U8 dataIn3Chunks[90]; // to hold data to update certificate - within 3 chunks boundary
memset(certHandles, 0x00, sizeof(certHandles));
memset(certData, 0xAA, sizeof(certData));
PRINTF("\r\n-----------\r\nStart exCertUsageEnlarge(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = certData;
attr[2].valueLen = sizeof(certData);
PRINTF("\r\nAbout to create up to %02d certificates...", nCertsToCreate);
for (indexCert = 0; indexCert < nCertsToCreate; indexCert++)
{
index = indexCert;
memset(certData, (0xAA+index), sizeof(certData));
PRINTF("\r\nHLSE_CreateObject() - Create certificate object(0x%02lx)", index);
hlseRc = HLSE_CreateObject(attr, templateSize, &certHandles[indexCert]);
if ((hlseRc != HLSE_SW_OK) && (indexCert > 4)) {
// this is acceptable since we managed to create 5 certificates
break;
}
else if (hlseRc == HLSE_SW_OK )
{
nCertsCreated++;
}
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("\r\nCreated %02d certificates...", nCertsCreated);
// save the handles as the values in the array might be changed . not reflecting the actual handles , after deletion
//certHandle0 = certHandles[0];
//certHandle1 = certHandles[1];
certHandle2 = certHandles[2];
certHandle3 = certHandles[3];
//certHandle4 = certHandles[4];
lastCertHandle = certHandles[nCertsCreated - 1];
// Enlarge certificate at index=2 within boundary
PRINTF("Try to Enlarge Certificate contents within 2 chunks...\r\n");
{
HLSE_ATTRIBUTE attrL;
memset(dataIn2Chunks, 0xBB, sizeof(dataIn2Chunks));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = dataIn2Chunks;
attrL.valueLen = sizeof(dataIn2Chunks);
hlseRc = HLSE_SetObjectAttribute(certHandle2, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("Verify Certificate Updated correctly...\r\n");
{
U8 readCertData[60];
HLSE_ATTRIBUTE attrL;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandle2, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(readCertData),
"expected cert data", dataIn2Chunks, sizeof(dataIn2Chunks), AX_COLON_32);
}
// Enlarge certificate at index=2, over the boundary - not allowed - need to delete it and recreate it
PRINTF("Try to Enlarge Certificate with 3 chunks data over the allocated size - not allowed...\r\n");
{
HLSE_ATTRIBUTE attrL;
memset(dataIn3Chunks, 0xCC, sizeof(dataIn3Chunks));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = dataIn3Chunks;
attrL.valueLen = sizeof(dataIn3Chunks);
hlseRc = HLSE_SetObjectAttribute(certHandle2, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_MEMORY, "err");
}
PRINTF("Verify Certificate contents has not changed...\r\n");
{
U8 readCertData[60];
HLSE_ATTRIBUTE attrL;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandle2, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(readCertData),
"expected cert data", dataIn2Chunks, sizeof(dataIn2Chunks), AX_COLON_32);
}
// enumerate objects - we should have nCertsCreated objects
memset(certHandles, 0, sizeof(certHandles));
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, nCertsCreated, "err");
// Need to delete the object and recreate it
PRINTF("\r\nHLSE_EraseObject()...\r\n");
hlseRc = HLSE_EraseObject(certHandle2);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
nCertsCreated--;
// enumerate objects - we should have nCertsCreated objects
memset(certHandles, 0, sizeof(certHandles));
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, nCertsCreated, "err");
//
// recreate it - should now succeed
index = 2;
// set the reference data that in cert 3 that is expected not to change
memset(dataIn2Chunks, (0xBB + index), sizeof(certData));
{
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = dataIn2Chunks;
attr[2].valueLen = sizeof(dataIn2Chunks);
PRINTF("\r\nHLSE_CreateObject() - Create certificate object(0x%02lx)\r\n", index);
hlseRc = HLSE_CreateObject(attr, templateSize, &certHandle2);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
nCertsCreated++;
}
PRINTF("Verify Certificate Updated correctly...\r\n");
{
U8 readCertData[60];
HLSE_ATTRIBUTE attrL;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandle2, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(readCertData),
"expected cert data", dataIn2Chunks, sizeof(dataIn2Chunks), AX_COLON_32);
}
PRINTF("Verify Cert 4 still exists\r\n");
{
U8 readCertData[90];
HLSE_ATTRIBUTE attrL;
index = 3;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandle3 /*certHandles[index]*/, &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// set the reference data that in cert 3 that is expected not to change
memset(certData, (0xAA + index), sizeof(certData));
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(certData),
"expected cert data", certData, sizeof(certData), AX_COLON_32);
}
//
// note : last certificate depends on max certifcate which are allowed at Gp table
PRINTF("Verify last Certificate created in table still exists\r\n");
{
U8 readCertData[90];
HLSE_ATTRIBUTE attrL;
index = nCertsCreated - 1;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(lastCertHandle , &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// set the reference data that in lasr cert that is expected not to change
memset(certData, (0xAA + index), sizeof(certData));
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(certData),
"expected cert data", certData, sizeof(certData), AX_COLON_32);
}
// enumerate objects - we should have certHandlesNum objects
memset(certHandles, 0, sizeof(certHandles));
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, nCertsCreated, "err");
// delete all certs
for (indexCert = 0; indexCert < certHandlesNum; indexCert++)
{
index = indexCert;
PRINTF("\r\nHLSE_EraseObject() - index 0x%02lx", index);
hlseRc = HLSE_EraseObject(certHandles[index]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("\r\n-----------\r\nEnd exCertUsageEnlarge(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate usage of certificate objects:
*
* this example Verifies correct operation in case when length of certificate object was Unknown at the
* time the mapping table was created
*
* Detailed explanation :
*
* - The abstraction for various objects that reside in the GP Storage area is achieved by maintaining a
* lookup table (mapping) at the end of the GP Storage area to holds information about the logical objects that exist
* in the GP Storage
*
* - The gp table is rewritten(whole) each time an object is inserted or deleted
* - Each object is aligned to occupy at least the amount of memory on the boundary of the GP storage, that is 32 bytes.
* E.g. an object of 17 bytes will occupy 32 bytes
*
* In cases where the length of an object is not known at the time the table entry is set, the MSBit (0x8000) will be set
* in the length as an indicator for the host library to know that the data is in TLV format and that the actual length
* can be obtained by reading the first bytes of the object's data.
*
* Example pre setup required:
*
* - We want to have a single certificate at offset 0 in the GP storage
* - we want to have a mapping table with one entry in which the length of the certificate object is unknown.
*
* Simulate the following scenario to verify it works correctly:
*
* - Create A Mapping table with one entry with length unknown as follows:
*
* \verbatim
*
* Notes:
* X+1 is the address of the last byte of the GP Storage.
* N is the object number from 1 to N
*
* Address Value
* ------- ----------------------
* X-1*6+0 First Object Class - 1 byte value : 0
* X-1*6+1 First Object Index - 1 byte value : 0
* X-1*6+2 First Object Length MSB - 1 byte value : 0x80 ( 0x8000 the MSBit Indicates Indirect length)
* X-1*6+3 First Object Length LSB - 1 byte value : 0x00
* X-1*6+4 First Object Offset MSB - 1 byte value : 0
* X-1*6+5 First Object Offset LSB - 1 byte value : 0
* X Update Counter - 1 byte value : 1
* X+1 Number of table entries - 1 byte value : 1
* End of GP Storage
*
* \endverbatim
*
* - Write simulated certificate object at offset 0 of gp storage
* use TLV length encoded length:
* - 2 bytes 0x81, 0x..
* - 3 bytes 0x82, 0x00, 0x..
*
* - Read certificate data and verify correctness
* - index ok
* - value was correctly set
* - Update Certificate contents
* - Verify Certificate Updated correctly
* - Delete certificate
* - Verify deletion
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
*/
static U8 exCertUsageGpTableLengthUnknown(U8 initMode)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE certHandles[5];
U16 certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
HLSE_OBJECT_INDEX index = 0;
HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE;
// Cert for this test is 50 bytes which occupies 2 chunks of 32 bytes on the GP Storage
U8 certData[50];
HLSE_ATTRIBUTE attr[3];
unsigned short templateSize = 3;
U8 data[50]; // to hold data to update certificate
memset(certHandles, 0x00, sizeof(certHandles));
memset(certData, 0xAA, sizeof(certData));
// Set header data - to be able to simulate length is unknown in the GP table at time Gp table was created -
// so it will be retrieved from this header
certData[0] = 0x30; // tag
certData[1] = 0x81; // length in next byte
certData[2] = 0x2F; // length is 47 bytes
PRINTF("\r\n-----------\r\nStart exCertUsageGpTableLengthUnknown(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = certData;
attr[2].valueLen = sizeof(certData);
// Create certificate object index = 0
PRINTF("\r\nHLSE_CreateObject() - Create certificate object, use 2 bytes encoded length in header...\r\n------------\r\n");
hlseRc = HLSE_CreateObject(attr, templateSize, &certHandles[0]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// We now have a mapping table, starting at the beginning of the last chunk of the GP storage (order is backward) which consists of 32 bytes composed of:
//
// Start of last chunk of GP storage :
// Address Offset Value
// ------- ------------------ ----------------------
// ... (note invalid entries are filled with 0xff)
// ... ... ...
// 4088 [0x00000018] 0x09 class certificate 1
// 4089 [0x00000019] 0x00 index
// 4090 [0x0000001a] 0x00 Length MSB Byte
// 4091 [0x0000001b] 0x32 Length LSB Byte means size is 50 bytes = sizeof(certData)
// 4092 [0x0000001c] 0x00 Offset MSB Byte offset 0
// 4093 [0x0000001d] 0x00 Offset LSB Byte
// 4094 [0x0000001e] 0x01 update counter
// 4095 [0x0000001f] 0x01 number of entries (Note it is in the last byte of the GP storage)
// End of Gp Storage
// We'll now overrun this map to contain 0x8000 in the length to indicate indirect length
PRINTF("\r\noverwrite gp table map to have indirect length indication...\r\n");
{
U16 gpSize;
//HLSE_RET_CODE lReturn = HLSE_SW_OK;
U8 dataL[32];
U8 dataSize = sizeof(dataL);
hlseRc = hlse_GetGPDataSize(&gpSize);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Read the entire table - consists of one chunk 5 entries
hlseRc = A71_GetGpData(gpSize - 32, dataL, 32);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Now overwrite Gp Table with indirect length
dataL[dataSize - 2 - 1*6 + 2] = 0x80;
dataL[dataSize - 2 - 1*6 + 3] = 0x00;
// dataL[2] = 0x80;
// dataL[3] = 0x00;
#if 0 // just for debug !!
// data format to check
U8 altData[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // invalid entry
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // invalid entry
0x09, 0x02, 0x80, 0x00, 0x06, 0x00, // third certificate
0x09, 0x01, 0x80, 0x00, 0x02, 0x00, // second certificate
0x09, 0x00, 0x80, 0x00, 0x00, 0x00, // first certificate
0x00, 0x03 // update counter + num of entries
};
memcpy(dataL, altData, 32);
#endif
hlseRc = A71_SetGpData(gpSize - 32, dataL, 32);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
// enumerate objects - we should have one certificate by now with index 0
PRINTF("\r\nHLSE_EnumerateObjects()...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, 1, "err");
// make sure our certificate is the one we previously created
// Get the attributes of the single certificate we have
PRINTF("\r\nHLSE_GetObjectAttribute()...\r\n");
{
U32 certIndex = 0xFFFFFFFF;
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_INDEX;
attrL.value = &certIndex;
attrL.valueLen = sizeof(certIndex);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF("\tcert index = 0x%lx\r\n", certIndex);
result &= AX_CHECK_U16((U16)certIndex, 0x00, "err");
}
PRINTF("Verify Certificate contents...\r\n");
{
U8 readCertData[50];
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("certOnA71CH", readCertData, sizeof(certData),
"expected cert data", certData, sizeof(certData), AX_COLON_32);
}
PRINTF("Update Certificate contents , use 3 bytes encoded length in header...\r\n");
{
HLSE_ATTRIBUTE attrL;
memset(data, 0xAB, sizeof(data));
// Now use 3 bytes indirect length
// Set header data - to be able to simulate length is unknown in the GP table at time Gp table was created -
// so it will be retrieved from this header
data[0] = 0x06; // tag
data[1] = 0x82; // length in next 2 bytes
data[2] = 0x00; // MSB 0
data[3] = 0x2E; // length is 46 bytes
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = data;
attrL.valueLen = sizeof(data);
hlseRc = HLSE_SetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
// We'll now overrun this map to contain 0x8000 in the length to indicate indirect length
{
U16 gpSize;
//HLSE_RET_CODE lReturn = HLSE_SW_OK;
U8 dataL[32];
hlseRc = hlse_GetGPDataSize(&gpSize);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Read the entire table - consists of one chunk 5 entries
hlseRc = A71_GetGpData(gpSize - 32, dataL, 32);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Now overrite with indirect length
dataL[2] = 0x80;
dataL[3] = 0x00;
hlseRc = A71_SetGpData(gpSize - 32, dataL, 32);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("Verify Certificate Updated correctly...\r\n");
{
U8 readCertData[50];
HLSE_ATTRIBUTE attrL;
memset(readCertData, 0x00, sizeof(readCertData));
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = readCertData;
attrL.valueLen = sizeof(readCertData);
hlseRc = HLSE_GetObjectAttribute(certHandles[certHandlesNum - 1], &attrL);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_COMPARE_BYTE_ARRAY("read data", readCertData, sizeof(certData),
"expected cert data", data, sizeof(data), AX_COLON_32);
}
// Delete the certificate
PRINTF("\r\nHLSE_EraseObject()...\r\n");
hlseRc = HLSE_EraseObject(certHandles[certHandlesNum - 1]);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Verify it was actually deleted
// enumerate objects - we should have no certificates by now
PRINTF("\r\nVerify object was erased...\r\n");
certHandlesNum = sizeof(certHandles) / sizeof(HLSE_OBJECT_HANDLE);
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, certHandles, &certHandlesNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
result &= AX_CHECK_U16(certHandlesNum, 0, "err");
PRINTF("\r\n-----------\r\nEnd exCertUsageGpTableLengthUnknown(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate
*
* - Creating 3 read only certificates
* - Verify erasure of existing cert is disallowed since it's Read Only
* - Verify recreation of existing cert is disallowed since it's Read Only
* - Certificate Enumeration
* - Get Certificate value
* - Verify unable to update certificate value since it's Read Only
*
* @param[in] initMode Visit the documentation of ::a71chInitModule for more information on this parameter
*/
static U8 exCertUsageReadOnly(U8 initMode)
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE objHandle, objHandle2, objHandle3, objHandle4;
HLSE_OBJECT_INDEX index = 1;
HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE;
U8 readOnly = 1;
U8 certData[50];
HLSE_ATTRIBUTE attr[4];
unsigned short templateSize = 4;
U8 largeCertData[300];
memset(certData, 0xAA, sizeof(certData));
memset(largeCertData, 0xAC, sizeof(largeCertData));
PRINTF("\r\n-----------\r\nStart exCertUsageReadOnly(%s)\r\n------------\r\n", getInitModeAsString(initMode));
// Initialize the A71CH (Debug mode restrictions may apply)
result &= hlse_a71chInitModule(initMode);
assert(result);
// start with clean GP table to avoid cached data from previous test
hlseRc = Debug_ForceReadGPDataTable();
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
attr[0].type = HLSE_ATTR_OBJECT_TYPE;
attr[0].value = &objType;
attr[0].valueLen = sizeof(objType);
attr[1].type = HLSE_ATTR_OBJECT_INDEX;
attr[1].value = &index;
attr[1].valueLen = sizeof(index);
attr[2].type = HLSE_ATTR_OBJECT_VALUE;
attr[2].value = certData;
attr[2].valueLen = sizeof(certData);
attr[3].type = HLSE_ATTR_READ_ONLY; // meaning further modification of the GP storage area is disallowed
attr[3].value = &readOnly;
attr[3].valueLen = sizeof(readOnly);
// Create certificate objects index 1 to 3 - with HLSE_ATTR_READ_ONLY
hlseRc = HLSE_CreateObject(attr, templateSize, &objHandle);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
index = 2;
hlseRc = HLSE_CreateObject(attr, templateSize, &objHandle2);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Create large certificate - READ ONLY
index = 3;
attr[2].value = largeCertData;
attr[2].valueLen = sizeof(largeCertData);
hlseRc = HLSE_CreateObject(attr, templateSize, &objHandle3);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Create large certificate
index = 4;
hlseRc = HLSE_CreateObject(attr, 3 /* without READ ONLY */, &objHandle4);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
// Try to erase certificate object at index 2 - should be disallowed as we created it with HLSE_ATTR_READ_ONLY attribute
hlseRc = HLSE_EraseObject(objHandle2);
result &= AX_CHECK_SW(hlseRc, HLSE_ERR_API_ERROR, "err");
// Certificate Enumeration
result &= exCertEnumerate();
// Get certificate Attributes
result &= exCertGetAttr();
// Set Certificate Attributes
result &= exCertSetAttr();
// Certificate Enumeration
result &= exCertEnumerate();
PRINTF("\r\n-----------\r\nEnd exCertUsageReadOnly(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Internal function , called from exCertUsageReadOnly()
*
* Demonstrate
* - using HLSE_EnumerateObjects() for certificate enumeration
* - using HLSE_GetObjectAttribute() to get certificate tag
*
*/
static U8 exCertEnumerate()
{
HLSE_OBJECT_HANDLE handles[10] = { 0 };
U16 handleNum = 10;
HLSE_RET_CODE hlseRc;
U16 i;
U8 result = 1;
PRINTF("\r\n-----------\r\nStart exCertEnumerate()\r\n------------\r\n");
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, handles, &handleNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
for (i = 0 ; i < handleNum ; ++i) {
U32 tag = 0;
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_OBJECT_INDEX;
attr.value = &tag;
attr.valueLen = sizeof(tag);
hlseRc = HLSE_GetObjectAttribute(handles[i], &attr);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
PRINTF("exCertEnumerate - tag = 0x%lx\r\n", tag);
}
PRINTF("\r\n-----------\r\nEnd exCertEnumerate(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Internal function , called from exCertUsageReadOnly()
*
* Demonstrate
* - using HLSE_EnumerateObjects() for certificate enumeration
* - using HLSE_GetObjectAttribute() with HLSE_ATTR_OBJECT_VALUE to get object's value
*
*/
static U8 exCertGetAttr()
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE handles[10] = { 0 };
U16 handleNum = 10;
U16 i;
PRINTF("\r\n-----------\r\nStart exCertGetAttr()\r\n------------\r\n");
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, handles, &handleNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
for (i = 0; i < handleNum; ++i) {
U8 data[300];
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_OBJECT_VALUE;
attr.value = data;
attr.valueLen = sizeof(data);
hlseRc = HLSE_GetObjectAttribute(handles[i], &attr);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("\r\n-----------\r\nEnd exCertGetAttr(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Demonstrate
* - using HLSE_EnumerateObjects() for certificate enumeration
* - shows using HLSE_SetObjectAttribute() to change an object's value fails when credential is frozen
*
*/
static U8 exCertSetAttr()
{
U8 result = 1;
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_HANDLE handles[10];
U16 handleNum = 10;
U8 certData[40];
U8 largeCertData[300];
U16 i ;
memset(certData, 0xBB, sizeof(certData));
memset(largeCertData, 0xBD, sizeof(largeCertData));
PRINTF("\r\n-----------\r\nStart exCertSetAttr()\r\n------------\r\n");
hlseRc = HLSE_EnumerateObjects(HLSE_CERTIFICATE, handles, &handleNum);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
for (i = 0; i < handleNum-2; ++i) {
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_OBJECT_VALUE;
attr.value = certData;
attr.valueLen = sizeof(certData);
hlseRc = HLSE_SetObjectAttribute(handles[i], &attr);
result &= AX_CHECK_SW(hlseRc, SW_COMMAND_NOT_ALLOWED, "Expected to fail, frozen credential cannot be changed");
}
// Try to update large cert data which is locked in GP storage
i = handleNum - 2;
{
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_OBJECT_VALUE;
attr.value = largeCertData;
attr.valueLen = sizeof(largeCertData);
hlseRc = HLSE_SetObjectAttribute(handles[i], &attr);
result &= AX_CHECK_SW(hlseRc, SW_COMMAND_NOT_ALLOWED, "Expected to fail, frozen credential cannot be changed");
// Last one is not frozen and should allow update
i = handleNum - 1;
hlseRc = HLSE_SetObjectAttribute(handles[i], &attr);
result &= AX_CHECK_SW(hlseRc, HLSE_SW_OK, "err");
}
PRINTF("\r\n-----------\r\nEnd exCertSetAttr(), result = %s\r\n------------\r\n", ((result == 1) ? "OK" : "FAILED"));
return result;
}
/**
* Internal utility to patch the TLV header of a data buffer so it contains the
* certificate header TLV correct
*
* A certificate header consists of the 0x30 tag followes by a length which could be encoded as
* 1) one byte: the length byte in case of length <= 127
* 2) 2 bytes : 0x81 followed byte the length byte in case 127 < length <= 255
* 3) 3 bytes : 0x82 followed by 2 bytes length otherwise
*/
static HLSE_RET_CODE patchCertificateInitialTL(U8 *clientCertDer, U16 clientCertDerLen)
{
if (clientCertDerLen < 3)
{
// This is too short for a certificate
return ERR_GP_NO_CERT;
}
else if (clientCertDerLen <= LEN_SHORT_FORM_MAX)
{
clientCertDer[0] = 0x30;
clientCertDer[1] = (clientCertDerLen-2) & 0x00FF;
}
else if (clientCertDerLen <= LEN_LONG_FORM_ONE_BYTE_MAX)
{
clientCertDer[0] = 0x30;
clientCertDer[1] = 0x81;
clientCertDer[2] = (clientCertDerLen-3) & 0x00FF;
}
else
{
clientCertDer[0] = 0x30;
clientCertDer[1] = 0x82;
clientCertDer[2] = ((clientCertDerLen-4) >> 8) & 0x00FF;
clientCertDer[3] = (clientCertDerLen-4) & 0x00FF;
}
return HLSE_SW_OK;
}
/**
* Internal - called from exMixedCertsAndDataObjUsage
* Get an object's value and length based on based on object handle provided
*
* @param[in] handle object handle
* @param[out] data buffer to store object's value retrieved
* @param[in,out] len in - length of data buffer, out - actual object's length
*/
static HLSE_RET_CODE getObject(HLSE_OBJECT_HANDLE handle, U8 *data, U16 *len)
{
HLSE_RET_CODE hlseRc;
HLSE_ATTRIBUTE attr;
HLSE_OBJECT_TYPE type;
U16 offset;
// We are looking for the object on index i in handles array
type = HLSE_GET_OBJECT_TYPE(handle);
if (type == HLSE_CERTIFICATE) {
PRINTF("get Certificate Object, handle=0x%lX\n", handle);
}
else {
PRINTF("get Data Object, handle=0x%lX\n", handle);
}
// Read
attr.type = HLSE_ATTR_OBJECT_VALUE;
attr.value = data;
attr.valueLen = *len;
hlseRc = HLSE_GetObjectAttribute(handle, &attr);
if (hlseRc != HLSE_SW_OK) {
return hlseRc;
}
*len = attr.valueLen;
// obtain object's GP offset
{
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_OFFSET;
attrL.value = &offset;
attrL.valueLen = sizeof(offset);
hlseRc = HLSE_GetObjectAttribute(handle, &attrL);
if (hlseRc != HLSE_SW_OK) {
return hlseRc;
}
}
PRINTF("Object retrieved: Offset=%d, Size=%d\n", offset, *len);
return HLSE_SW_OK;
}
/**
* Internal - called from exMixedCertsAndDataObjUsage
* Set a Certificate or Data object's value based on on object handle provided
*
* @param[in] handle object handle
* @param[in] data buffer of data to set obj value
* @param[in] len in - length of data buffer
*/
static HLSE_RET_CODE setObject(HLSE_OBJECT_HANDLE handle, U8 *data, U16 len)
{
HLSE_RET_CODE hlseRc;
HLSE_OBJECT_TYPE type;
// We are looking for the object on index i in handles array
type = HLSE_GET_OBJECT_TYPE(handle);
if (type == HLSE_CERTIFICATE) {
PRINTF("Set Certificate Object, handle=0x%lX\n", handle);
}
else {
PRINTF("Set Data Object, handle=0x%lX\n", handle);
}
// Update
{
HLSE_ATTRIBUTE attrL;
attrL.type = HLSE_ATTR_OBJECT_VALUE;
attrL.value = data;
attrL.valueLen = len;
hlseRc = HLSE_SetObjectAttribute(handle, &attrL);
if (hlseRc != HLSE_SW_OK) {
return hlseRc;
}
}
return HLSE_SW_OK;
}