/** | |
* @file configCmdScp.c | |
* @author NXP Semiconductors | |
* @version 1.0 | |
* @par License | |
* | |
* Copyright 2017 NXP | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* @par Description | |
* Command handling for 'scp'. Includes optional console handling | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctype.h> | |
#include <assert.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 "configState.h" | |
#include "a71_debug.h" | |
#include "ax_util.h" | |
#include "axHostCrypto.h" | |
#include "tstHostCrypto.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 | |
#if 0 | |
/** | |
* A hook for the command line handler to invoke A71 commands | |
*/ | |
int a7xConfigCmdSetEcc(a71_SecureStorageClass_t ssc, U8 index, eccKeyComponents_t *eccKc, U16 *sw) | |
{ | |
int error = AX_CLI_EXEC_FAILED; | |
*sw = a7xCmdSetEcc(ssc, index, eccKc); | |
if (*sw == SW_OK) | |
{ | |
error = AX_CLI_EXEC_OK; | |
} | |
return error; | |
} | |
/** | |
* API wrapper for set ecc (keypair/pub) command. Can be called from GUI. | |
*/ | |
U16 a7xCmdSetEcc(a71_SecureStorageClass_t ssc, U8 index, eccKeyComponents_t *eccKc) | |
{ | |
U16 sw; | |
switch (ssc) | |
{ | |
case A71_SSC_KEY_PAIR: | |
sw = A71_SetEccKeyPair(index, eccKc->pub, eccKc->pubLen, eccKc->priv, eccKc->privLen); | |
break; | |
case A71_SSC_PUBLIC_KEY: | |
sw = A71_SetEccPublicKey(index, eccKc->pub, eccKc->pubLen); | |
break; | |
default: | |
sw = A7X_CONFIG_STATUS_API_ERROR; | |
break; | |
} | |
return sw; | |
} | |
#endif | |
/** | |
* Clear the SCP03 state on the Host. As a result subsequent APDU commands will be | |
* sent in the clear. | |
*/ | |
int a7xConfigCmdScpClearHost() | |
{ | |
DEV_ClearChannelState(); | |
return a7xConfigSetHostScp03State(AX_SCP03_CHANNEL_OFF); | |
} | |
/** | |
* A hook for the command line handler to invoke A71 commands | |
*/ | |
int a7xConfigCmdScpFromKeyfile(ax_ScpCmdClass_t cmdClass, U8 keyVersion, char *szFilename, U16 *sw) | |
{ | |
U8 scp03Enc[AES_KEY_LEN_nBYTE]; | |
U8 scp03Mac[AES_KEY_LEN_nBYTE]; | |
U8 scp03Dek[AES_KEY_LEN_nBYTE]; | |
U8 *currentKeyDek = NULL; | |
U8 sCounter[3]; | |
U16 sCounterLen = sizeof(sCounter); | |
int error = AX_CLI_EXEC_FAILED; | |
error = a7xConfigGetScpKeysFromKeyfile(scp03Enc, scp03Mac, scp03Dek, szFilename); | |
if (error == AX_CLI_EXEC_OK) | |
{ | |
error = AX_CLI_EXEC_FAILED; | |
switch (cmdClass) | |
{ | |
case AX_SCP_CMD_AUTH: | |
*sw = SCP_Authenticate(scp03Enc, scp03Mac, scp03Dek, SCP_KEY_SIZE, sCounter, &sCounterLen); | |
if (*sw == SW_OK) | |
{ | |
a7xConfigSetHostScp03State(AX_SCP03_CHANNEL_ON); | |
error = AX_CLI_EXEC_OK; | |
} | |
break; | |
case AX_SCP_CMD_PUT: | |
*sw = SCP_GP_PutKeys(keyVersion, scp03Enc, scp03Mac, scp03Dek, currentKeyDek, SCP_KEY_SIZE); | |
if (*sw == SW_OK) | |
{ | |
error = AX_CLI_EXEC_OK; | |
} | |
break; | |
default: | |
error = AX_CLI_API_ERROR; | |
break; | |
} | |
} | |
return error; | |
} | |
/** | |
* Get scp keys from keyfile. Can be called from GUI. | |
*/ | |
int a7xConfigGetScpKeysFromKeyfile(U8 *enc, U8 *mac, U8 *dek, char *szKeyFile) | |
{ | |
int nRet = AX_CLI_EXEC_FAILED; | |
U8 hexArray[AES_KEY_LEN_nBYTE]; | |
char szLine[AX_LINE_MAX]; | |
char keyToken[128]; | |
unsigned int idx; | |
FILE *fHandle = NULL; | |
int fEnc = 0; | |
int fMac = 0; | |
int fDek = 0; | |
// Open the file | |
fHandle = fopen(szKeyFile, "r"); | |
if (fHandle == NULL) | |
{ | |
printf("Failed to open file %s for reading", szKeyFile); | |
return AX_CLI_FILE_OPEN_FAILED; | |
} | |
while (fgets(szLine, AX_LINE_MAX, fHandle) != NULL) | |
{ | |
DBGPRINTF("%s\n", szLine); | |
// Filter out lines STARTING with the comment '#' sign | |
for (idx=0; idx<strlen(szLine); idx++) { | |
if (!isspace(szLine[idx])) { | |
break; | |
} | |
} | |
if (szLine[idx] == '#') { continue; } | |
// Remove all contents from the command line starting with '#' | |
for (idx=0; idx<strlen(szLine); idx++) { | |
if (szLine[idx] == '#') { | |
szLine[idx] = '\0'; | |
break; | |
} | |
} | |
nRet = axCliGetKeyFixedLenHexValueFromLine(keyToken, sizeof(keyToken), hexArray, sizeof(hexArray), szLine); | |
if (nRet != AX_CLI_EXEC_OK) { | |
break; | |
} | |
if (!strcmp(keyToken, "ENC")) { | |
if (fEnc == 0) { | |
memcpy(enc, hexArray, sizeof(hexArray)); | |
fEnc = 1; | |
} | |
else { | |
// Duplicate key value | |
nRet = AX_CLI_FILE_FORMAT_ERROR; | |
break; | |
} | |
} | |
else if (!strcmp(keyToken, "MAC")) { | |
if (fMac == 0) { | |
memcpy(mac, hexArray, sizeof(hexArray)); | |
fMac = 1; | |
} | |
else { | |
// Duplicate key value | |
nRet = AX_CLI_FILE_FORMAT_ERROR; | |
break; | |
} | |
} | |
else if (!strcmp(keyToken, "DEK")) { | |
if (fDek == 0) { | |
memcpy(dek, hexArray, sizeof(hexArray)); | |
fDek = 1; | |
} | |
else { | |
// Duplicate key value | |
nRet = AX_CLI_FILE_FORMAT_ERROR; | |
break; | |
} | |
} | |
else { | |
printf("Unknown key name: %s\n", keyToken); | |
nRet = AX_CLI_FILE_FORMAT_ERROR; | |
break; | |
} | |
} | |
fclose(fHandle); | |
// Ensure we have a value for all keys | |
if ( (nRet != AX_CLI_EXEC_OK) || (fEnc != 1) || (fMac != 1) || (fDek !=1 ) ) { | |
nRet = AX_CLI_FILE_FORMAT_ERROR; | |
} | |
return nRet; | |
} |