/** * @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 #include #include #include /******************************************************************* * 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; }