blob: c85d4d682a19e1a5621f0e2eb023985dd0e298e4 [file] [log] [blame]
/**
* @file configCmdInfo.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2017 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* Command handling for 'info'. Includes optional console print.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef OPENSSL
#include <openssl/pem.h>
#endif
// project specific include files
#include "sm_types.h"
#include "sm_apdu.h"
#include "tst_sm_util.h"
#include "tst_a71ch_util.h"
#include "probeAxUtil.h"
#include "configCmd.h"
#include "configCli.h" // Used for error codes.
#include "configState.h"
#include "HLSETypes.h"
#include "axHostCrypto.h"
#include "tstHostCrypto.h"
#include "HLSEAPI.h"
#define FLOW_VERBOSE_PROBE_A70
#ifdef FLOW_VERBOSE_PROBE_A70
#define FPRINTF(...) printf (__VA_ARGS__)
#else
#define FPRINTF(...)
#endif
// #define DBG_PROBE_A70
#ifdef DBG_PROBE_A70
#define DBGPRINTF(...) printf (__VA_ARGS__)
#else
#define DBGPRINTF(...)
#endif
#define HLSE_GP_DATA_CHUNK 32 //!< GP Data chunk size byted
/// GP Table Data Entry
typedef struct {
U8 klass;
U8 index;
U16 length;
U16 offset;
} HLSE_GP_DATA_TABLE_ENTRY;
#define HLSE_GP_DATA_TABLE_ENTRY_SIZE 6 //!< GP Table Entry size in bytes
/// Alligned number of chunks in which 'size' bytes occupies
#define HLSE_ALIGN_SIZE(size) ((size + HLSE_GP_DATA_CHUNK - 1) / HLSE_GP_DATA_CHUNK)
// This is a theoritical max , as it is stored as one byte in the beginning of the Gp Table - up to max 254 entries (0xFE)
// elements might be created . value of 0xFF is reserved for a deleted/invalid entry
#define HLSE_MAX_OBJECTS_IN_TABLE 254
// Max chunks which could be allowed in GP Data table
#define HLSE_GP_DATA_CHUNKS_NUM HLSE_ALIGN_SIZE(((HLSE_MAX_OBJECTS_IN_TABLE * 6) + 2))
/// GP Data Table
typedef struct {
U8 numOfEntries; //!< num of entries
U8 updateCounter; //!< update counter
HLSE_GP_DATA_TABLE_ENTRY entries[HLSE_MAX_OBJECTS_IN_TABLE]; //!< entries array
} HLSE_GP_DATA_TABLE;
static HLSE_RET_CODE DisplayObjectInfo();
/**
* A hook for the command line handler to invoke A71 commands
* \return Returns ::AX_CLI_EXEC_OK upon success
*/
int a7xConfigCmdInfo(a71_SecureStorageClass_t ssc, U16 offset, int nSegments, U16 *sw)
{
int error = AX_CLI_EXEC_FAILED;
U8 uid[A71CH_MODULE_UNIQUE_ID_LEN];
U16 uidLen = sizeof(uid);
U16 selectResponse = 0;
U8 debugOn = 0;
U8 restrictedKpIdx = 0;
U8 transportLockState = 0;
U8 scpState = A71CH_SCP_CHANNEL_STATE_UNKNOWN;
U8 injectLockState = 0;
U16 gpStorageSize = 0;
int nEccPair = 0;
int nEccPub = 0;
int nCnt = 0;
// int nSymKey = 0;
int nGpSections = 0;
// TODO: Recognize whether SCP03 has already been set up by the config tool. (Store this state in scpReq - to be renamed in scpChannelActive)
*sw = a7xCmdInfoDevice(uid, &uidLen, &selectResponse, &debugOn, &restrictedKpIdx, &transportLockState, &scpState, &injectLockState, &gpStorageSize);
if (*sw == SW_OK)
{
error = AX_CLI_EXEC_OK;
if ( (ssc == A71_SSC_MODULE) || (ssc == A71_SSC_ALL) )
{
a7xCmdInfoDevicePrettyPrint(uid, uidLen, selectResponse, debugOn, restrictedKpIdx, transportLockState, scpState, injectLockState, gpStorageSize);
}
}
else
{
error = AX_CLI_EXEC_FAILED;
return error;
}
if (gpStorageSize == 1024) {
nEccPair = A7X_CONFIG_KEY_PAIR_TYPE_A;
nEccPub = A7X_CONFIG_PUBLIC_KEY_TYPE_A;
nCnt = A7X_CONFIG_COUNTER_TYPE_A;
// nSymKey = A7X_CONFIG_SYM_KEY_TYPE_A;
nGpSections = A7X_CONFIG_GP_STORAGE_SECTION_TYPE_A;
}
else if (gpStorageSize == 4096) {
nEccPair = A7X_CONFIG_KEY_PAIR_TYPE_B;
nEccPub = A7X_CONFIG_PUBLIC_KEY_TYPE_B;
nCnt = A7X_CONFIG_COUNTER_TYPE_B;
// nSymKey = A7X_CONFIG_SYM_KEY_TYPE_B;
nGpSections = A7X_CONFIG_GP_STORAGE_SECTION_TYPE_B;
}
else {
// Defaulting to smallest credential set
printf("Warning: Tool does not know exact amount of credentials stored. Using default values.\n");
nEccPair = A7X_CONFIG_KEY_PAIR_TYPE_A;
nEccPub = A7X_CONFIG_PUBLIC_KEY_TYPE_A;
nCnt = A7X_CONFIG_COUNTER_TYPE_A;
// nSymKey = A7X_CONFIG_SYM_KEY_TYPE_A;
nGpSections = A7X_CONFIG_GP_STORAGE_SECTION_TYPE_A;
}
if ( (scpState != A71CH_SCP_MANDATORY) ||
((scpState == A71CH_SCP_MANDATORY) && (a7xConfigGetHostScp03State() == AX_SCP03_CHANNEL_ON)) )
{
eccKeyComponents_t eccKc[(A7X_CONFIG_KEY_PAIR_MAX > A7X_CONFIG_PUBLIC_KEY_MAX) ? A7X_CONFIG_KEY_PAIR_MAX : A7X_CONFIG_PUBLIC_KEY_MAX];
a71_CounterWrapper_t counterArray[A7X_CONFIG_COUNTER_MAX];
U8 data[A7X_CONFIG_GP_STORAGE_MAX];
U16 dataLen = sizeof(data);
// Only in this case can we query for the value of credentials
switch (ssc)
{
case A71_SSC_KEY_PAIR:
a7xCmdInfoEcc(ssc, nEccPair, eccKc);
error = a7xCmdInfoEccPrettyPrint(ssc, nEccPair, eccKc);
break;
case A71_SSC_PUBLIC_KEY:
a7xCmdInfoEcc(ssc, nEccPub, eccKc);
error = a7xCmdInfoEccPrettyPrint(ssc, nEccPub, eccKc);
break;
case A71_SSC_COUNTER:
a7xCmdInfoCounter(nCnt, counterArray);
error = a7xCmdInfoCounterPrettyPrint(nCnt, counterArray);
break;
case A71_SSC_OBJECTS:
error = DisplayObjectInfo();
break;
case A71_SSC_GP_DATA:
if ( (U16)(nSegments * A71CH_GP_STORAGE_GRANULARITY) > dataLen ) {
error = AX_CLI_BUFFER_SIZE_ERROR;
}
dataLen = (U16)(nSegments * A71CH_GP_STORAGE_GRANULARITY);
*sw = a7xCmdInfoGpData(data, dataLen, offset);
if (*sw == SW_OK) {
error = a7xCmdInfoGpDataPrettyPrint(data, offset, nSegments);
}
else {
printf("Could not retrieve data from gp storage.\n");
error = AX_CLI_EXEC_FAILED;
}
break;
case A71_SSC_CONFIG_KEY:
case A71_SSC_SYM_KEY:
printf("Not implemented.\n");
error = AX_CLI_NOT_IMPLEMENTED;
break;
case A71_SSC_ALL:
a7xCmdInfoEcc(A71_SSC_KEY_PAIR, nEccPair, eccKc);
error = a7xCmdInfoEccPrettyPrint(A71_SSC_KEY_PAIR, nEccPair, eccKc);
a7xCmdInfoEcc(A71_SSC_PUBLIC_KEY, nEccPub, eccKc);
error = a7xCmdInfoEccPrettyPrint(A71_SSC_PUBLIC_KEY, nEccPub, eccKc);
a7xCmdInfoCounter(nCnt, counterArray);
error = a7xCmdInfoCounterPrettyPrint(nCnt, counterArray);
*sw = a7xCmdInfoGpData(data, (U16)(nGpSections * A71CH_GP_STORAGE_GRANULARITY), 0);
if (*sw == SW_OK) {
error = a7xCmdInfoGpDataPrettyPrint(data, 0, nGpSections);
}
else {
printf("Could not retrieve data from gp storage.\n");
error = AX_CLI_EXEC_FAILED;
}
break;
case A71_SSC_MODULE:
// No action required
break;
case A71_SSC_UNDEF:
printf("Undefined Secure Storage Class.\n");
error = AX_CLI_ARG_VALUE_ERROR;
break;
}
}
else
{
// As we don't know the SCP03 keys - conditionally - display a warning on the console.
switch (ssc)
{
case A71_SSC_KEY_PAIR:
case A71_SSC_PUBLIC_KEY:
case A71_SSC_GP_DATA:
case A71_SSC_OBJECTS:
case A71_SSC_CONFIG_KEY:
case A71_SSC_SYM_KEY:
case A71_SSC_COUNTER:
case A71_SSC_ALL:
printf("info command needs prior setup of SCP03 channel.\n");
printf("Debug: a7xConfigGetHostScp03State() = 0x%02X\n", a7xConfigGetHostScp03State());
error = AX_CLI_EXEC_FAILED;
break;
case A71_SSC_MODULE:
// No action required
break;
case A71_SSC_UNDEF:
printf("Undefined Secure Storage Class.\n");
error = AX_CLI_ARG_VALUE_ERROR;
break;
}
}
return error;
}
/**
* Print to console
*/
int a7xCmdInfoDevicePrettyPrint(U8 *uid, U16 uidLen, U16 selectResponse, U8 debugOn, U8 restrictedKpIdx, U8 transportLockState, U8 scpState, U8 injectLockState, U16 gpStorageSize)
{
int idx = 0;
U8 certUid[A71CH_MODULE_CERT_UID_LEN];
printf("A71CH in %s (%s)\n",
(debugOn == 0) ? "Production Version" : "Debug Mode Version",
(scpState == A71CH_SCP_MANDATORY) ? "SCP03 is mandatory" :
(scpState == A71CH_SCP_NOT_SET_UP) ? "SCP03 is not set up" :
(scpState == A71CH_SCP_KEYS_SET) ? "SCP03 keys set" : "Undefined SCP state");
printf("selectResponse: 0x%04X\n", selectResponse);
if (restrictedKpIdx != A71CH_NO_RESTRICTED_KP)
{
printf("restricted keypair index: 0x%02X\n", restrictedKpIdx);
}
printf("transportLockState: 0x%02X (%s)\n", transportLockState,
(transportLockState == A71CH_TRANSPORT_LOCK_STATE_LOCKED) ? "Transport Lock is set" :
(transportLockState == A71CH_TRANSPORT_LOCK_STATE_UNLOCKED) ? "Open device, Transport Lock can no longer be set" :
(transportLockState == A71CH_TRANSPORT_LOCK_STATE_ALLOW_LOCK) ? "Transport Lock NOT YET set" : "Undefined Transport Lock state");
printf("injectLockState: 0x%02X (%s)\n", injectLockState,
(injectLockState == A71CH_INJECT_LOCK_STATE_LOCKED) ? "Locked" :
(injectLockState == A71CH_INJECT_LOCK_STATE_UNLOCKED) ? "Unlocked" : "Undefined Inject Lock State");
printf("gpStorageSize: %d\n", gpStorageSize);
axPrintByteArray("uid", uid, uidLen, AX_COLON_32);
certUid[idx++] = uid[A71CH_UID_IC_TYPE_OFFSET];
certUid[idx++] = uid[A71CH_UID_IC_TYPE_OFFSET+1];
certUid[idx++] = uid[A71CH_UID_IC_FABRICATION_DATA_OFFSET];
certUid[idx++] = uid[A71CH_UID_IC_FABRICATION_DATA_OFFSET+1];
certUid[idx++] = uid[A71CH_UID_IC_SERIAL_NR_OFFSET];
certUid[idx++] = uid[A71CH_UID_IC_SERIAL_NR_OFFSET+1];
certUid[idx++] = uid[A71CH_UID_IC_SERIAL_NR_OFFSET+2];
certUid[idx++] = uid[A71CH_UID_IC_BATCH_ID_OFFSET];
certUid[idx++] = uid[A71CH_UID_IC_BATCH_ID_OFFSET+1];
certUid[idx++] = uid[A71CH_UID_IC_BATCH_ID_OFFSET+2];
axPrintByteArray("certUid", certUid, (U16)idx, AX_COLON_32);
return AX_CLI_EXEC_OK;
}
/**
* API wrapper for info command. Can be called from GUI.
*/
U16 a7xCmdInfoDevice(U8 *uid, U16 *uidLen, U16 *selectResponse, U8 *debugOn, U8 *restrictedKpIdx, U8 *transportLockState, U8 *scpState, U8 *injectLockState, U16 *gpStorageSize)
{
U16 sw;
*selectResponse = 0x0000;
*debugOn = 0x00;
*restrictedKpIdx = 0x00;
*injectLockState = 0x00;
*gpStorageSize = 0x0000;
*scpState = A71CH_SCP_CHANNEL_STATE_UNKNOWN;
sw = A71_GetModuleInfo(selectResponse, debugOn, restrictedKpIdx, transportLockState, scpState, injectLockState, gpStorageSize);
// Retrieving UID can be protected by SCP03
if ( (*uidLen != 0) && (uid != NULL) && (sw == SW_OK) )
{
sw = A71_GetUniqueID(uid, uidLen);
if (sw != SW_OK)
{
DBGPRINTF("Failed to retrieve UID.\n");
}
}
return sw;
}
/**
* Print Public key to console
*/
int a7xCmdInfoEccPrettyPrint(a71_SecureStorageClass_t ssc, int nEcc, eccKeyComponents_t *eccKc)
{
int i = 0;
if (ssc == A71_SSC_KEY_PAIR) {
printf("Public Keys from ECC key pairs:\n");
}
else if (ssc == A71_SSC_PUBLIC_KEY) {
printf("Public Keys:\n");
}
else {
printf("Wrong ssc requested: 0x%02X\n", ssc);
return AX_CLI_API_ERROR;
}
for (i=0; i<nEcc; i++)
{
printf("\tidx=0x%02X ", i);
if (eccKc[i].pubLen > 0) {
axPrintByteArray("ECC_PUB", eccKc[i].pub, eccKc[i].pubLen, AX_COLON_32);
}
else {
printf("n.a.\n");
}
}
return AX_CLI_EXEC_OK;
}
/**
* API wrapper for info command. Can be called from GUI.
*/
U16 a7xCmdInfoEcc(a71_SecureStorageClass_t ssc, int nEcc, eccKeyComponents_t *eccKc)
{
U16 sw = SW_OK;
int i = 0;
// Initialize data structures.
for (i=0; i<nEcc; i++)
{
eccKc[i].bits = 256;
eccKc[i].curve = ECCCurve_NIST_P256;
eccKc[i].pubLen = sizeof(eccKc[i].pub);
eccKc[i].privLen = sizeof(eccKc[i].priv);
}
for (i=0; i<nEcc; i++)
{
switch (ssc)
{
case A71_SSC_KEY_PAIR:
sw = A71_GetPublicKeyEccKeyPair((U8)i, eccKc[i].pub, &(eccKc[i].pubLen));
if (sw != SW_OK) { eccKc[i].pubLen = 0; }
break;
case A71_SSC_PUBLIC_KEY:
sw = A71_GetEccPublicKey((U8)i, eccKc[i].pub, &(eccKc[i].pubLen));
if (sw != SW_OK) { eccKc[i].pubLen = 0; }
break;
default:
eccKc[i].pubLen = 0;
break;
}
}
// We always claim success for the overall operation.
// In case a specific public key could not be retrieved, its length has been set to zero
return SW_OK;
}
int a7xCmdInfoCounterPrettyPrint(int nCnt, a71_CounterWrapper_t *counterArray)
{
int i = 0;
printf("Monotonic counter values:\n");
for (i=0; i<nCnt; i++)
{
printf("\tidx=0x%02X ", i);
if (counterArray[i].available == 0x01) {
printf("0x%08X\n", counterArray[i].counter);
}
else {
printf("n.a.\n");
}
}
return AX_CLI_EXEC_OK;
}
U16 a7xCmdInfoCounter(int nCnt, a71_CounterWrapper_t *counterArray)
{
U16 sw = SW_OK;
int i = 0;
// Initialize data structures.
for (i=0; i<nCnt; i++)
{
counterArray[i].available = 0x00;
counterArray[i].counter = 0;
}
for (i=0; i<nCnt; i++)
{
sw = A71_GetCounter((U8)i, &(counterArray[i].counter));
if (sw == SW_OK)
{
counterArray[i].available = 0x01;
}
}
// We always claim success for the overall operation.
// In case a specific counter value could not be retrieved, its available field will be set to 0x00
return SW_OK;
}
int a7xCmdInfoGpDataPrettyPrint(U8 *data, U16 offset, int nSegments)
{
int i = 0;
char szOffset[64];
printf("GP Storage Data (%d segments from offset 0x%04X):\n", nSegments, offset);
for (i=0; i<nSegments; i++)
{
sprintf(szOffset, "\t0x%04X", offset + (i*A71CH_GP_STORAGE_GRANULARITY));
axPrintByteArray(szOffset, data+(i*A71CH_GP_STORAGE_GRANULARITY), A71CH_GP_STORAGE_GRANULARITY, AX_COMPACT_LINE);
}
return AX_CLI_EXEC_OK;
}
U16 a7xCmdInfoGpData(U8 *data, U16 dataLen, U16 offset)
{
U16 sw;
sw = A71_GetGpData(offset, data, dataLen);
return sw;
}
// ---
/**
* A hook for the command line handler to invoke A71 commands
*/
int a7xConfigCmdInfoStatus(U16 *sw)
{
int error = AX_CLI_EXEC_FAILED;
U8 scp03Status = 0x00;
U8 kpStatus[A7X_CONFIG_KEY_PAIR_MAX];
U16 kpStatusLen = sizeof(kpStatus);
U8 pubStatus[A7X_CONFIG_PUBLIC_KEY_MAX];
U16 pubStatusLen = sizeof(pubStatus);
U8 cfgStatus[A7X_CONFIG_CFG_KEY_MAX];
U16 cfgStatusLen = sizeof(cfgStatus);
U8 symStatus[A7X_CONFIG_SYM_KEY_MAX];
U16 symStatusLen = sizeof(symStatus);
U8 cntStatus[A7X_CONFIG_COUNTER_MAX];
U16 cntStatusLen = sizeof(cntStatus);
U8 gpStatus[A7X_CONFIG_GP_STORAGE_SECTION_MAX];
U16 gpStatusLen = sizeof(gpStatus);
// U16 selectResponse = 0;
// U8 debugOn = 0;
// U8 injectLockState = 0;
// U16 gpStorageSize = 0;
*sw = a7xCmdInfoStatus(&scp03Status, kpStatus, &kpStatusLen, pubStatus, &pubStatusLen, cfgStatus, &cfgStatusLen,
symStatus, &symStatusLen, cntStatus, &cntStatusLen, gpStatus, &gpStatusLen);
if (*sw == SW_OK)
{
error = AX_CLI_EXEC_OK;
a7xCmdInfoStatusPrettyPrint(scp03Status, kpStatus, kpStatusLen, pubStatus, pubStatusLen, cfgStatus, cfgStatusLen,
symStatus, symStatusLen, cntStatus, cntStatusLen, gpStatus, gpStatusLen);
}
return error;
}
static int a7xCmdInfoStatusCredStatusPrettyPrint(char *szObjectName, U8 *statusArray, U16 arrayLen)
{
int i;
printf("%s status:\n", szObjectName);
for (i=0; i<arrayLen; i++)
{
printf("\tIndex=%d: %s %s\n", i,
((statusArray[i] & A7X_CONFIG_CRED_INIT_MASK) == A7X_CONFIG_CRED_INITIALIZED) ? "Initialized" : "Empty",
((statusArray[i] & A7X_CONFIG_CRED_LOCK_MASK) == A7X_CONFIG_CRED_LOCKED) ? "Locked" : "Open");
}
return AX_CLI_EXEC_OK;
}
static int a7xCmdInfoStatusGpStatusPrettyPrint(char *szObjectName, U8 *statusArray, U16 arrayLen)
{
int i;
int nColumns = 4;
printf("%s status:\n", szObjectName);
for (i=0; i<arrayLen; i++)
{
printf("\tOffset=0x%04X: %s%s", i * A71CH_GP_STORAGE_GRANULARITY,
((statusArray[i] & A7X_CONFIG_CRED_LOCK_MASK) == A7X_CONFIG_CRED_LOCKED) ? "Lock" : "Open",
(((i+1) % nColumns) == 0) ? "\n" : " ");
}
return AX_CLI_EXEC_OK;
}
/**
* Print to console
*/
int a7xCmdInfoStatusPrettyPrint(U8 scp03Status, U8 *kpStatus, U16 kpStatusLen, U8 *pubStatus, U16 pubStatusLen, U8 *cfgStatus, U16 cfgStatusLen,
U8 *symStatus, U16 symStatusLen, U8 *cntStatus, U16 cntStatusLen, U8 *gpStatus, U16 gpStatusLen)
{
printf("SCP03 is %s\n", (scp03Status == A71CH_SCP_MANDATORY) ? "Mandatory" : "Not enabled");
a7xCmdInfoStatusCredStatusPrettyPrint("Key Pair", kpStatus, kpStatusLen);
a7xCmdInfoStatusCredStatusPrettyPrint("Public Key", pubStatus, pubStatusLen);
a7xCmdInfoStatusCredStatusPrettyPrint("Config Key", cfgStatus, cfgStatusLen);
a7xCmdInfoStatusCredStatusPrettyPrint("Sym Secret", symStatus, symStatusLen);
a7xCmdInfoStatusCredStatusPrettyPrint("Counter", cntStatus, cntStatusLen);
a7xCmdInfoStatusGpStatusPrettyPrint("General Purpose Storage", gpStatus, gpStatusLen);
return AX_CLI_EXEC_OK;
}
/**
* API wrapper for debug info command. Can be called from GUI.
*/
U16 a7xCmdInfoStatus(U8 *scp03Status, U8 *kpStatus, U16 *kpStatusLen, U8 *pubStatus, U16 *pubStatusLen, U8 *cfgStatus, U16 *cfgStatusLen,
U8 *symStatus, U16 *symStatusLen, U8 *cntStatus, U16 *cntStatusLen, U8 *gpStatus, U16 *gpStatusLen)
{
U16 sw;
U8 map[A71CH_MAP_SIZE_MAX];
U16 mapLen = sizeof(map);
int kpStatusOffset = 1;
int kpStatusN;
int pubStatusOffset;
int pubStatusN;
int cfgStatusOffset;
int cfgStatusN;
int symStatusOffset;
int symStatusN;
int cntStatusOffset;
int cntStatusN;
int gpStatusOffset;
int gpStatusN;
sw = A71_GetCredentialInfo(map, &mapLen);
if (sw == SW_OK)
{
switch (mapLen)
{
case A7X_CONFIG_MAP_SIZE_A71CH_TYPE_A:
kpStatusN = A7X_CONFIG_KEY_PAIR_TYPE_A;
pubStatusOffset = kpStatusOffset + kpStatusN;
pubStatusN = A7X_CONFIG_PUBLIC_KEY_TYPE_A;
cfgStatusOffset = pubStatusOffset + pubStatusN;
cfgStatusN = A7X_CONFIG_CFG_KEY_TYPE_A;
symStatusOffset = cfgStatusOffset + cfgStatusN;
symStatusN = A7X_CONFIG_SYM_KEY_TYPE_A;
cntStatusOffset = symStatusOffset + symStatusN;
cntStatusN = A7X_CONFIG_COUNTER_TYPE_A;
gpStatusOffset = cntStatusOffset + cntStatusN;
gpStatusN = A7X_CONFIG_GP_STORAGE_SECTION_TYPE_A;
break;
case A7X_CONFIG_MAP_SIZE_A71CH_TYPE_B:
kpStatusN = A7X_CONFIG_KEY_PAIR_TYPE_B;
pubStatusOffset = kpStatusOffset + kpStatusN;
pubStatusN = A7X_CONFIG_PUBLIC_KEY_TYPE_B;
cfgStatusOffset = pubStatusOffset + pubStatusN;
cfgStatusN = A7X_CONFIG_CFG_KEY_TYPE_B;
symStatusOffset = cfgStatusOffset + cfgStatusN;
symStatusN = A7X_CONFIG_SYM_KEY_TYPE_B;
cntStatusOffset = symStatusOffset + symStatusN;
cntStatusN = A7X_CONFIG_COUNTER_TYPE_B;
gpStatusOffset = cntStatusOffset + cntStatusN;
gpStatusN = A7X_CONFIG_GP_STORAGE_SECTION_TYPE_B;
break;
default:
// Unknown product variant
DBGPRINTF("Unknown mapLen: %d.", mapLen);
return ERR_WRONG_RESPONSE;
break;
}
*scp03Status = map[0];
if (*kpStatusLen < kpStatusN) { return ERR_BUF_TOO_SMALL; }
if (*pubStatusLen < pubStatusN) { return ERR_BUF_TOO_SMALL; }
if (*cfgStatusLen < cfgStatusN) { return ERR_BUF_TOO_SMALL; }
if (*symStatusLen < symStatusN) { return ERR_BUF_TOO_SMALL; }
if (*cntStatusLen < cntStatusN) { return ERR_BUF_TOO_SMALL; }
if (*gpStatusLen < gpStatusN) { return ERR_BUF_TOO_SMALL; }
memcpy(kpStatus, &map[kpStatusOffset], kpStatusN);
memcpy(pubStatus, &map[pubStatusOffset], pubStatusN);
memcpy(cfgStatus, &map[cfgStatusOffset], cfgStatusN);
memcpy(symStatus, &map[symStatusOffset], symStatusN);
memcpy(cntStatus, &map[cntStatusOffset], cntStatusN);
memcpy(gpStatus, &map[gpStatusOffset], gpStatusN);
*kpStatusLen = (U16)kpStatusN;
*pubStatusLen = (U16)pubStatusN;
*cfgStatusLen = (U16)cfgStatusN;
*symStatusLen = (U16)symStatusN;
*cntStatusLen = (U16)cntStatusN;
*gpStatusLen = (U16)gpStatusN;
}
return sw;
}
static HLSE_RET_CODE GetGPDataSize(U16* gpSize)
{
HLSE_RET_CODE lReturn = HLSE_SW_OK;
// Get the Module's handle
HLSE_OBJECT_HANDLE modHandle = 0;
//U16 modHandleNum = 1;
modHandle = HLSE_CREATE_HANDLE(1, HLSE_MODULE, 0);
{
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_MODULE_TOTAL_GP_SIZE;
attr.value = gpSize;
attr.valueLen = sizeof(U16);
lReturn = HLSE_GetObjectAttribute(modHandle, &attr);
}
return lReturn;
}
static HLSE_RET_CODE ParseGPDataTable(HLSE_GP_DATA_TABLE* table)
{
// NOTE: only one chunk is read. To be updated if a table with more than 5 objects is used
U16 gpSize;
HLSE_RET_CODE lReturn = HLSE_SW_OK;
U8 dataRead[HLSE_GP_DATA_CHUNK * HLSE_GP_DATA_CHUNKS_NUM];
U8 entryNum;
U16 dataReadByteSize = sizeof(dataRead);
int nObj;
U8 bValidEntry;
U8 nMaxObj;
U8 tmpClass, tmpIndex;
lReturn = GetGPDataSize(&gpSize);
if (lReturn != HLSE_SW_OK)
return lReturn;
memset(table, 0xFF, sizeof(HLSE_GP_DATA_TABLE));
table->numOfEntries = 0;
table->updateCounter = 0;
// Read the entire table
lReturn = A71_GetGpData(gpSize - dataReadByteSize, dataRead, dataReadByteSize);
if (lReturn != HLSE_SW_OK)
return lReturn;
table->numOfEntries = dataRead[dataReadByteSize - 1];
if (table->numOfEntries == 0xFF) {
return HLSE_SW_OK;
}
table->updateCounter = dataRead[dataReadByteSize - 2];
// Read only Valid entries up to numOfEntries starting from end of GP storage ( high address to low address )
nObj = 1; // first object to check if valid in GP Table
for (entryNum = 0; entryNum < table->numOfEntries; ++entryNum) {
// Notes:
// X + 1 is the address of the last byte of the GP Storage.
// N is the object number from 1 to N
// read from object 1 to numOfEntries (skipping invalid =(deleted) entries)
/*
Address Value
------- ----------------------
X-N*6+0 N'th Object Class - 1 byte
X-N*6+1 N'th Object Index - 1 byte
X-N*6+2 N'th Object Length MSB - 1 byte
X-N*6+3 N'th Object Length LSB - 1 byte
X-N*6+4 N'th Object Offset MSB - 1 byte
X-N*6+5 N'th Object Offset LSB - 1 byte
*/
bValidEntry = 0;
// max objects that could be held in the gp data table
nMaxObj = HLSE_MAX_OBJECTS_IN_TABLE; //((HLSE_GP_DATA_CHUNK * HLSE_GP_DATA_CHUNKS_NUM) - 2) / 6;
while (!bValidEntry && nObj <= nMaxObj) {
// check if entry is valid
tmpClass = dataRead[dataReadByteSize - 2 - nObj * 6 + 0];
tmpIndex = dataRead[dataReadByteSize - 2 - nObj * 6 + 1];
// skip to next valid entry
if (tmpClass != 0xFF && tmpIndex != 0xFF) {
// this is a valid entry
bValidEntry = 1;
break;
}
}
if (!bValidEntry) {
// error - no more valid entries in table , although num of entries in gp table says there are more !
break;
}
// fill this valid entry in our table
table->entries[entryNum].klass = dataRead[dataReadByteSize - 2 - nObj * 6 + 0];
table->entries[entryNum].index = dataRead[dataReadByteSize - 2 - nObj * 6 + 1];
table->entries[entryNum].length = dataRead[dataReadByteSize - 2 - nObj * 6 + 2] * 256 | dataRead[dataReadByteSize - 2 - nObj * 6 + 3];
table->entries[entryNum].offset = dataRead[dataReadByteSize - 2 - nObj * 6 + 4] * 256 | dataRead[dataReadByteSize - 2 - nObj * 6 + 5];
nObj++;
}
// sort the entries in ascending order of the offset
// SortTable(table);
return lReturn;
}
static HLSE_RET_CODE PrintObjectInfo(HLSE_OBJECT_TYPE objType, HLSE_GP_DATA_TABLE* gpTable)
{
HLSE_RET_CODE ret;
HLSE_OBJECT_HANDLE handles[HLSE_MAX_OBJECTS_IN_TABLE];
U16 handlesNum = HLSE_MAX_OBJECTS_IN_TABLE;
U16 i, j;
ret = HLSE_EnumerateObjects(objType, handles, &handlesNum);
if (ret != HLSE_SW_OK)
return ret;
printf("%s Objects: \n", (objType == HLSE_CERTIFICATE ? "Certificate" : "Data"));
for (i = 0; i < handlesNum; ++i) {
HLSE_OBJECT_INDEX index;
// get object index from applet
{
HLSE_ATTRIBUTE attr;
attr.type = HLSE_ATTR_OBJECT_INDEX;
attr.value = &index;
attr.valueLen = sizeof(index);
ret = HLSE_GetObjectAttribute(handles[i], &attr);
if (ret != HLSE_SW_OK)
return ret;
}
for (j = 0; j < gpTable->numOfEntries; ++j) {
if (gpTable->entries[j].index == index && gpTable->entries[j].klass == HLSE_GET_LOGICAL_OBJECT_CLASS(objType)) {
printf("\t idx=0x%02X Absolute offset = 0x%04X Actual Size = 0x%04X (%d)\n", index,
gpTable->entries[j].offset,
gpTable->entries[j].length,
gpTable->entries[j].length);
}
}
}
return ret;
}
static HLSE_RET_CODE DisplayObjectInfo()
{
HLSE_GP_DATA_TABLE gpTable;
HLSE_RET_CODE ret = HLSE_SW_OK;
// Read the mapping table
ret = ParseGPDataTable(&gpTable);
if (ret != HLSE_SW_OK)
return ret;
// enumerate Cert + Data objects
ret = PrintObjectInfo(HLSE_CERTIFICATE, &gpTable);
if (ret != HLSE_SW_OK)
return ret;
ret = PrintObjectInfo(HLSE_DATA, &gpTable);
if (ret != HLSE_SW_OK)
return ret;
return AX_CLI_EXEC_OK;
}