blob: 25e251c9dafb76508c03c382a4f626eaac7ade2f [file] [log] [blame]
/**
* @file tst_a71ch_util.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2016,2020 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* This module implements test bench utility functions specific to the a71ch
* @par History
* 1.0 2016-Oct-1 : Initial version
*/
/*******************************************************************
* standard include files
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*******************************************************************
* project specific include files
*******************************************************************/
#include "scp.h"
#include "sm_apdu.h"
#include "sm_errors.h"
#include "tst_sm_util.h"
#include "tst_a71ch_util.h"
#include "ax_util.h"
#include "a71_debug.h"
#include "tstHostCrypto.h"
#include "global_platf.h"
/**
* Initializes the A71CH module.
* All initialization states are only reachable when the A71CH is in Debug Mode
*
* \param[in] initMode Either ::INIT_MODE_RESET, ::INIT_MODE_RESET_SELECT, ::INIT_MODE_NO_RESET,
* ::INIT_MODE_RESET_DO_SCP03, ::INIT_MODE_RESET_SELECT_DO_SCP03 or ::INIT_MODE_NO_RESET_DO_SCP03
* \retval 0 failure
* \retval 1 success
*/
U8 a71chInitModule(U8 initMode)
{
U8 result = 1;
U16 err = 0;
U8 resetMode = 0;
U8 scp03Mode = 0;
U8 appletName[] = APPLET_NAME;
U16 appletNameLen = APPLET_NAME_LEN;
U8 response[256];
U16 responseLen = sizeof(response);
PRINTF("\na71chInitModule(%s)\n", getInitModeAsString(initMode));
resetMode = initMode & INIT_MODE_RESET_MASK;
switch(resetMode)
{
case INIT_MODE_PATTERN_RESET:
PRINTF("Reset A71CH.\n");
err = A71_DbgReset();
result &= AX_CHECK_SW(err, SW_OK, "Failed to reset module");
break;
case INIT_MODE_PATTERN_RESET_SELECT:
PRINTF("Reset A71CH.\n");
err = A71_DbgReset();
result &= AX_CHECK_SW(err, SW_OK, "Failed to reset module");
PRINTF("Select applet.\n");
err = GP_Select(NULL, appletName, appletNameLen, response, &responseLen);
result &= AX_CHECK_SW(err, SW_OK, "Failed to select applet");
break;
case INIT_MODE_PATTERN_NO_RESET:
result &= 1;
break;
}
scp03Mode = initMode & INIT_MODE_SCP03_MASK;
switch(scp03Mode)
{
case INIT_MODE_PATTERN_PLAIN_COM:
result &= 1;
break;
case INIT_MODE_PATTERN_DO_SCP03:
result = a71chSetupScp03();
break;
}
return result;
}
/**
* Determine whether the initMode implies setting up an SCP03 channel.
*
* \param[in] initMode Either ::INIT_MODE_RESET, ::INIT_MODE_RESET_SELECT, ::INIT_MODE_NO_RESET,
* ::INIT_MODE_RESET_DO_SCP03, ::INIT_MODE_RESET_SELECT_DO_SCP03 or ::INIT_MODE_NO_RESET_DO_SCP03
* \retval 0 No it does not imply an SCP03 channel
* \retval 1 Yes it implies an SCP03 channel
*/
int a71chScp03Requested(U8 initMode)
{
int scpRequested = 1;
U8 scp03Mode = initMode & INIT_MODE_SCP03_MASK;
switch(scp03Mode)
{
case INIT_MODE_PATTERN_PLAIN_COM:
scpRequested = 0;
break;
case INIT_MODE_PATTERN_DO_SCP03:
scpRequested = 1;
break;
}
return scpRequested;
}
/**
* Return the string corresponding to the initMode passed as parameter
*
* \param[in] initMode Either ::INIT_MODE_RESET, ::INIT_MODE_RESET_SELECT, ::INIT_MODE_NO_RESET,
* ::INIT_MODE_RESET_DO_SCP03, ::INIT_MODE_RESET_SELECT_DO_SCP03 or ::INIT_MODE_NO_RESET_DO_SCP03
* \returns initMode as a string or "not defined"
*/
const char* getInitModeAsString(U8 initMode)
{
if (initMode == INIT_MODE_NO_RESET)
{
return "No init action";
}
else if (initMode == INIT_MODE_RESET)
{
return "Reset";
}
else if (initMode == INIT_MODE_RESET_SELECT)
{
return "Reset + Select applet";
}
else if (initMode == INIT_MODE_RESET_DO_SCP03)
{
return "Reset + Setup SCP03 channel";
}
else if (initMode == INIT_MODE_RESET_SELECT_DO_SCP03)
{
return "Reset + Select applet + Setup SCP03 channel";
}
else if (initMode == INIT_MODE_NO_RESET_DO_SCP03)
{
return "Setup SCP03 channel";
}
else
{
PRINTF("initMode not defined\n");
assert(0);
return "not defined";
}
}
/**
* Establish an SCP03 channel with random keys.
* Best called implicitly via ::a71chInitModule
*
* \retval 0 failure
* \retval 1 success
*/
U8 a71chSetupScp03()
{
#if defined(NO_SECURE_CHANNEL_SUPPORT)
U8 result = 0;
#else
U8 result = 1;
U16 err = 0;
U8 random[3*SCP_KEY_SIZE];
U8 randomLen = (U8)sizeof(random);
U8 *currentKeyDek = NULL;
U8 keyVersion = 1;
U8 keyEnc[SCP_KEY_SIZE];
U8 keyMac[SCP_KEY_SIZE];
U8 keyDek[SCP_KEY_SIZE];
U8 sCounter[3];
U16 sCounterLen = sizeof(sCounter);
PRINTF( "\n-----------\nStart a71chSetupScp03()\n------------\n");
DEV_ClearChannelState();
// Security module generates random data for initial SCP03 keys
sm_printf(CONSOLE, "\nA71_GetRandom(randomLen=%d)\n", randomLen);
err = A71_GetRandom(random, randomLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
if (result != 1) { goto SCP03_EXIT; }
// Storing Static Keys
memcpy(keyEnc, random, SCP_KEY_SIZE);
memcpy(keyMac, random + SCP_KEY_SIZE, SCP_KEY_SIZE);
memcpy(keyDek, random + (2*SCP_KEY_SIZE), SCP_KEY_SIZE);
keyVersion = (U8) (SST_HOST_SCP_KEYSET >> 8);
sm_printf(CONSOLE, "\nSCP_GP_PutKeys(keyVersion=0x%02X)\n", keyVersion);
err = SCP_GP_PutKeys(keyVersion, keyEnc, keyMac, keyDek, currentKeyDek, AES_KEY_LEN_nBYTE);
result &= AX_CHECK_SW(err, SW_OK, "err");
if (result != 1) { goto SCP03_EXIT; }
// Authenticate Channel
sm_printf(CONSOLE, "\nSCP_Authenticate()\n");
err = SCP_Authenticate(keyEnc, keyMac, keyDek, SCP_KEY_SIZE, sCounter, &sCounterLen);
result &= AX_CHECK_SW(err, SW_OK, "err");
result &= AX_CHECK_U16(sCounterLen, 0, "Only expected when SCP03 is configured for pseudo-random challenge");
SCP03_EXIT:
PRINTF( "\n-----------\nEnd a71chSetupScp03(), result = %s\n------------\n",
((result == 1)? "OK": "FAILED"));
#endif
return result;
}
/**
* Issue an A71_GetModuleInfo call, print status to stdout and return select parameters to caller.
*
* \param[out] scpState Either ::A71CH_SCP_MANDATORY, ::A71CH_SCP_NOT_SET_UP or ::A71CH_SCP_KEYS_SET
*
* \retval 0 failure
* \retval 1 success
*/
U8 a71chShowModuleInfo(U8 *scpState)
{
U8 result = 1;
U16 err;
U16 selectResponse = 0;
U8 debugOn = 0;
U8 restrictedKpIdx = 0;
U8 transportLockState = 0;
U8 injectLockState = 0;
U16 gpStorageSize = 0;
sm_printf(CONSOLE, "A71_GetModuleInfo().\n");
err = A71_GetModuleInfo(&selectResponse, &debugOn, &restrictedKpIdx, &transportLockState, scpState, &injectLockState, &gpStorageSize);
result &= AX_CHECK_SW(err, SW_OK, "Failed to retrieve module info.");
if (err == SW_OK)
{
PRINTF("A71CH in %s\n", (debugOn == 0) ? "Production Version" : "Debug Mode Version");
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("scpState: 0x%02X (%s)\n", *scpState,
(*scpState == A71CH_SCP_MANDATORY) ? "SCP is mandatory" :
(*scpState == A71CH_SCP_NOT_SET_UP) ? "SCP is not set up" :
(*scpState == A71CH_SCP_KEYS_SET) ? "SCP keys set" : "Undefined SCP 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);
}
return result;
}