/** | |
* @file configCmdObj.c | |
* @author NXP Semiconductors | |
* @version 1.0 | |
* @par License | |
* | |
* Copyright 2018 NXP | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* @par Description | |
* Command handling for 'obj'. Includes optional console handling | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <ctype.h> | |
// 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" | |
#include "a71_debug.h" | |
#include "HLSEAPI.h" | |
#include "axHostCrypto.h" | |
#include "tstHostCrypto.h" | |
#ifdef OPENSSL | |
#include <openssl/pem.h> | |
#endif | |
#define FLOW_VERBOSE_PROBE_A70 | |
#ifdef FLOW_VERBOSE_PROBE_A70 | |
#define FPRINTF(...) printf (__VA_ARGS__) | |
#else | |
#define FPRINTF(...) | |
#endif | |
// Warning: defining DBG_PROBE_A70 also exposes Private Key being set in log | |
// #define DBG_PROBE_A70 | |
#ifdef DBG_PROBE_A70 | |
#define DBGPRINTF(...) printf (__VA_ARGS__) | |
#else | |
#define DBGPRINTF(...) | |
#endif | |
/** | |
* a7xConfigCmdWriteObj - create object from hex data | |
*/ | |
U16 a7xConfigCmdWriteObj(int index, U8 * objData, U16 objDataLen, U16 *sw) { | |
HLSE_RET_CODE nRet = AX_CLI_EXEC_FAILED; | |
HLSE_OBJECT_HANDLE objHandle; | |
HLSE_OBJECT_TYPE objType = HLSE_DATA; | |
unsigned short templateSize = 3; | |
HLSE_ATTRIBUTE attr[3]; | |
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 = objData; | |
attr[2].valueLen = objDataLen; | |
nRet = HLSE_CreateObject(attr, templateSize, &objHandle); | |
if (nRet != HLSE_SW_OK) { | |
*sw = nRet; | |
return AX_CLI_EXEC_FAILED; | |
} | |
else { *sw = 0x9000; } | |
return AX_CLI_EXEC_OK; | |
} | |
/** | |
* a7xConfigCmdWriteObjFromSegments - create empty objects in size of n segments | |
*/ | |
int a7xConfigCmdWriteObjFromSegments(int index, int segments, U16 *sw) { | |
HLSE_RET_CODE nRet = AX_CLI_EXEC_FAILED; | |
U8 * buffer = 0; // a buffer to hold the read data | |
buffer = (U8 *)malloc(sizeof(U8) * (segments * 32) ); | |
memset(buffer, 0x0, segments * 32); | |
nRet = a7xConfigCmdWriteObj(index, buffer, (U16)(segments * 32), sw); | |
if (buffer) {free(buffer);} | |
return nRet; | |
} | |
/** | |
* a7xConfigCmdWriteObjFromfile - create object from file | |
*/ | |
static int SetObjectFromFile(int index, int offset, char *szFilename, int chunkSize, a71_ObjCmdClass_t cmdType, U16 *sw) { | |
HLSE_RET_CODE nRet = AX_CLI_EXEC_FAILED; | |
FILE *file; | |
unsigned char *buffer; | |
unsigned long fileLen; | |
U8 byteArray[4096]; | |
int i = 0; | |
int breakFromLoop = 0; | |
int readIndex = 0; | |
int bufSize = 0; | |
*sw = 0x0000; | |
if (chunkSize != 64 && chunkSize != 32) { | |
return AX_CLI_ARG_RANGE_ERROR; | |
} | |
printf("Filename: %s\n", szFilename); | |
file = fopen(szFilename, "r"); | |
if (!file) | |
{ | |
printf("Unable to open the file: %s\n", szFilename); | |
return AX_CLI_FILE_OPEN_FAILED; | |
} | |
//Get file length | |
fseek(file, 0, SEEK_END); | |
fileLen = ftell(file); | |
fseek(file, 0, SEEK_SET); | |
//Allocate memory | |
buffer = (unsigned char *)malloc(sizeof(unsigned char) * (fileLen * 2)); | |
if (!buffer) | |
{ | |
fprintf(stderr, "Memory error!"); | |
fclose(file); | |
return AX_CLI_DYN_ALLOC_ERROR; | |
} | |
//Read file contents into buffer | |
for (i = 0;i < (signed)fileLen;i += chunkSize) { | |
char tmp[10]; | |
int y; | |
// Read the chunk size make sure it is valid data | |
fread(buffer + i, chunkSize, 1, file); | |
for (y = 0;y < chunkSize;y++) { | |
if (!isxdigit(buffer[y + i]) && (buffer[y + i] < 'a' || buffer[y + i] > 'f' || buffer[y + i] < 'A' || buffer[y + i] > 'F')) { | |
if (feof(file)) { | |
breakFromLoop = 1; | |
readIndex += y; | |
break; | |
} | |
else { | |
fclose(file); | |
return AX_CLI_FILE_FORMAT_ERROR; | |
} | |
} | |
} | |
if (breakFromLoop) { | |
break; | |
} | |
// Now make sure this is the end of line size of chunk data | |
fread(tmp, 1, 1, file); | |
if (tmp[0] == '\r') { | |
fread(tmp, 1, 1, file); | |
} | |
if (tmp[0] != '\n') { | |
fclose(file); | |
return AX_CLI_FILE_FORMAT_ERROR; | |
} | |
readIndex += chunkSize; | |
// End of file exit reading loop | |
if (feof(file)) { | |
break; | |
} | |
} | |
buffer[readIndex] = 0x0; | |
fclose(file); | |
bufSize = strlen((const char *)buffer); | |
axConvertHexString2ByteArray(byteArray, (const char *)buffer, 0, bufSize / 2); | |
switch (cmdType) { | |
case A71_OBJ_WRITE: | |
// Create object | |
nRet = a7xConfigCmdWriteObj(index, (U8 *)byteArray, (U16)(bufSize / 2), sw); | |
break; | |
case A71_OBJ_UPDATE: | |
// Create object | |
nRet = (U16)a7xConfigCmdUpdateObj(index, offset, (U8 *)byteArray, (U16)(bufSize / 2), sw); | |
break; | |
default: | |
return AX_CLI_ARG_VALUE_ERROR; | |
}; | |
if (buffer) { free(buffer); } | |
return nRet; | |
} | |
/** | |
* a7xConfigCmdWriteObjFromfile - create object from file | |
*/ | |
int a7xConfigCmdWriteObjFromfile(int index, char *szFilename, int chunkSize, a71_ObjCmdClass_t cmdType, U16 *sw) { | |
return SetObjectFromFile(index, 0, szFilename, chunkSize, cmdType, sw); | |
} | |
/** | |
* a7xConfigCmdUpdateObjFromfile - update object from file | |
*/ | |
int a7xConfigCmdUpdateObjFromfile(int index, int offset, char *szFilename, int chunkSize, a71_ObjCmdClass_t cmdType, U16 *sw) { | |
return SetObjectFromFile(index, offset, szFilename, chunkSize, cmdType, sw); | |
} | |
/** | |
* a7xConfigCmdUpdateObjFromfile - update object from hex data | |
*/ | |
int a7xConfigCmdUpdateObj(int index, int offset, U8 * objData, U16 objDataLen, U16 *sw) { | |
HLSE_RET_CODE nRet = AX_CLI_EXEC_FAILED; | |
HLSE_ATTRIBUTE attr; | |
HLSE_RET_CODE hlseRc; | |
HLSE_OBJECT_HANDLE objHandles[5]; | |
HLSE_DIRECT_ACCESS_ATTRIBUTE_VALUE theValue; | |
HLSE_OBJECT_HANDLE curHandle; | |
HLSE_OBJECT_HANDLE objHandle; | |
U16 objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
int handleWasSet = 0; | |
int i; | |
// Set curHandle | |
curHandle = index; | |
attr.type = HLSE_ATTR_DIRECT_ACCESS_OBJECT_VALUE; | |
theValue.offset = (U16)offset; | |
theValue.bytes = objDataLen; | |
theValue.buffer = objData; | |
theValue.bufferLen = objDataLen; | |
attr.value = &theValue; | |
attr.valueLen = sizeof(theValue); | |
// Enumerate handles | |
objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
hlseRc = HLSE_EnumerateObjects(HLSE_DATA, objHandles, &objHandlesNum); | |
if (hlseRc != HLSE_SW_OK) { return AX_CLI_NO_OBJECTS; } | |
// Find object handle | |
// Find handle | |
for (i = 0;i < 5;i++) { | |
if ((objHandles[i] & 0xF) == curHandle) { | |
objHandle = objHandles[i]; | |
handleWasSet = 1; | |
break; | |
} | |
} | |
if (!handleWasSet) { return AX_CLI_OBJECT_NOT_FOUND; } | |
nRet = HLSE_SetObjectAttribute(objHandle, &attr); | |
if (nRet != HLSE_SW_OK) { | |
*sw = nRet; | |
return AX_CLI_EXEC_FAILED; | |
} | |
else { *sw = 0x9000; } | |
return AX_CLI_EXEC_OK; | |
} | |
/** | |
* a7xConfigCmdReadObj - read object data at offset | |
*/ | |
int a7xConfigCmdReadObj(int index, int offset, int length, int chunkSize, char *szFilename, U16 *sw) { | |
HLSE_RET_CODE nRet = AX_CLI_EXEC_FAILED; | |
HLSE_ATTRIBUTE attr; | |
int i; | |
int curLength = 0; | |
int writeLength = 0; | |
HLSE_RET_CODE hlseRc; | |
HLSE_DIRECT_ACCESS_ATTRIBUTE_VALUE theValue; | |
HLSE_OBJECT_HANDLE objHandles[5]; | |
HLSE_OBJECT_HANDLE curHandle; | |
HLSE_OBJECT_HANDLE readHandle; | |
int handleWasSet = 0; | |
U16 objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
U8 buffer[4096]; // a buffer to hold the read data | |
char objData[4096]; | |
int objDataBufSize = sizeof(objData); | |
FILE * pFile = NULL; | |
int saveObj = 0; | |
if (chunkSize != 64 && chunkSize != 32) { | |
return AX_CLI_ARG_RANGE_ERROR; | |
} | |
// Check if we have file name | |
if (szFilename[0] != 0x0) { saveObj = 1; } | |
// Set curHandle | |
curHandle = index; | |
// Enumerate handles | |
objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
hlseRc = HLSE_EnumerateObjects(HLSE_DATA, objHandles, &objHandlesNum); | |
if (hlseRc != HLSE_SW_OK) { return AX_CLI_NO_OBJECTS; } | |
// Find handle | |
for (i = 0;i < objHandlesNum;i++) { | |
if ((objHandles[i] & 0xF) == curHandle) { | |
readHandle = objHandles[i]; | |
handleWasSet = 1; | |
break; | |
} | |
} | |
if (!handleWasSet) { return AX_CLI_OBJECT_NOT_FOUND; } | |
if (length > 0) { | |
attr.type = HLSE_ATTR_DIRECT_ACCESS_OBJECT_VALUE; | |
theValue.offset = (U16)offset; | |
theValue.bytes = (U16)length; | |
theValue.buffer = buffer; | |
theValue.bufferLen = sizeof(buffer); | |
attr.value = &theValue; | |
attr.valueLen = sizeof(theValue); | |
} | |
else { | |
attr.type = HLSE_ATTR_OBJECT_VALUE; | |
attr.value = buffer; | |
attr.valueLen = sizeof(buffer);; | |
} | |
nRet = HLSE_GetObjectAttribute(readHandle, &attr); | |
if (nRet != HLSE_SW_OK) { | |
*sw = nRet; | |
return AX_CLI_EXEC_FAILED; | |
} | |
else { *sw = 0x9000; } | |
if (length > 0) { | |
axPrintByteArray("OBJ_DATA", (U8*)theValue.buffer, theValue.bufferLen, AX_COMPACT_32); | |
writeLength = curLength = theValue.bufferLen; | |
} | |
else { | |
axPrintByteArray("OBJ_DATA", (U8*)attr.value, attr.valueLen, AX_COMPACT_32); | |
writeLength = curLength = attr.valueLen; | |
} | |
// Create file according to the user file path | |
if (saveObj) { | |
if (length > 0) { | |
axConvertByteArray2HexString(objData, objDataBufSize, theValue.buffer, theValue.bufferLen, AX_COMPACT_LINE); | |
} | |
else { | |
axConvertByteArray2HexString(objData, objDataBufSize, attr.value, attr.valueLen, AX_COMPACT_LINE); | |
} | |
pFile = fopen(szFilename, "w"); | |
writeLength = writeLength * 2; | |
if (pFile) { | |
for (i = 0;i < curLength * 2;i += chunkSize) { | |
if (writeLength < chunkSize) { | |
fwrite(objData + i, writeLength, 1, pFile); | |
writeLength -= writeLength; | |
} | |
else { | |
fwrite(objData + i, chunkSize, 1, pFile); | |
writeLength -= chunkSize; | |
} | |
if ((i + chunkSize) < curLength*2) { | |
fwrite("\n", sizeof(char), 1, pFile); | |
} | |
} | |
fclose(pFile); | |
} | |
else { | |
return AX_CLI_EXEC_FAILED; | |
} | |
} | |
return AX_CLI_EXEC_OK; | |
} | |
/** | |
* a7xConfigCmdEraseObj - erase object at index x | |
*/ | |
int a7xConfigCmdEraseObj(int index, U16 *sw) { | |
int i; | |
HLSE_RET_CODE hlseRc; | |
HLSE_OBJECT_HANDLE objHandles[5]; | |
HLSE_OBJECT_HANDLE curHandle; | |
HLSE_OBJECT_HANDLE eraseHandle; | |
int handleWasSet = 0; | |
U16 objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
*sw = 0x0000; | |
memset(objHandles, 0x00, sizeof(objHandles)); | |
// Get Index | |
curHandle = index; | |
// Enumerate handles | |
objHandlesNum = sizeof(objHandles) / sizeof(HLSE_OBJECT_HANDLE); | |
hlseRc = HLSE_EnumerateObjects(HLSE_DATA, objHandles, &objHandlesNum); | |
if (hlseRc != HLSE_SW_OK) { return AX_CLI_NO_OBJECTS; } | |
// Find handle | |
for (i = 0;i < objHandlesNum;i++) { | |
if ((objHandles[i] & 0xF) == curHandle) { | |
eraseHandle = objHandles[i]; | |
handleWasSet = 1; | |
break; | |
} | |
} | |
if (!handleWasSet) { return AX_CLI_OBJECT_NOT_FOUND; } | |
// Erase | |
hlseRc = HLSE_EraseObject(eraseHandle); | |
if (hlseRc != HLSE_SW_OK) { | |
*sw = hlseRc; | |
return AX_CLI_EXEC_FAILED; | |
} | |
else { *sw = 0x9000; } | |
return AX_CLI_EXEC_OK; | |
} |