/** * @file ex_hlse_boot.c * @author NXP Semiconductors * @version 1.0 * @par License * * Copyright 2016,2020 NXP * SPDX-License-Identifier: Apache-2.0 * * @par Description * Handover of SCP03 session keys from bootloader to OS. Refer to ::exHlseBoot for more details. */ #include #include #include #include #include #include "a71ch_ex_hlse.h" #include "a71_debug.h" #include "sm_types.h" #include "sm_apdu.h" #include "tst_sm_util.h" #include "sm_printf.h" #include "axHostCrypto.h" #include "tstHostCrypto.h" #include "scp.h" #include "ax_util.h" #if defined(SCI2C) #include "sci2c.h" #endif #include "tst_a71ch_util.h" #include "tst_hlse_a71ch_util.h" /// @cond static U8 writeStateToFile(char *szFilename, SmCommState_t *commState, Scp03SessionState_t *scp03State); static U8 readStateFromFile(char *szFilename, SmCommState_t *commState, Scp03SessionState_t *scp03State); char* axExHlseBootGetBootModeAsString(U8 bootMode) { if (bootMode == BOOT_SKIP_EXAMPLE) { return "Skip boot example"; } else if (bootMode == BOOT_SIMULATED_CYCLE) { return "Do full boot cycle (Bootloader/OS combined)"; } else if (bootMode == BOOT_BOOTLOADER_ROLE) { return "Mimick behaviour of bootloader only (store session state on filesystem)"; } else if (bootMode == BOOT_HOST_OS_RESUME) { return "Mimick behaviour of Host OS only (retrieve session state from filesystem)"; } else { PRINTF("bootMode not defined\r\n"); assert(0); return "not defined"; } } static void signalFunctionCallback(ScpEvent_t event, void *context) { AX_UNUSED_ARG(context); PRINTF("scpCallback: "); switch (event) { case SCP_WRONG_PADDING: PRINTF("Wrong padding\r\n"); break; case SCP_WRONG_RESPMAC: PRINTF("Wrong response mac\r\n"); break; case SCP_GENERIC_FAILURE: PRINTF("Non specified failure\r\n"); break; default: PRINTF("Unknown event type\r\n"); break; } return; } /// @endcond /** * This example illustrates that the HostOS does NOT need to know the SCP03 Base Keys * to establish an SCP03 session (provided the boot loader has established the * SCP03 session and saved the SCP03 session state) * * When using SCI2C the bootloader must also save the SCI2C state. * * - The boot loader * - Sets an initial SCP03 base key set (based on random data retrieved from * the SM (Secure Module)) * - Establishes an SCP03 session * - Stores the SCP03 session (optionally also SCI2C state) * * - The OS * - Retrieves the SCP03 session and communication state * - Resumes the SCP03 session * * \note When the OS takes over from the boot loader the communication link with * the Secure Element may not be broken. * \note Storing the session and communication state on the filesystem is done for convenience * in this example. Use an appropriate and secure sharing mechanism in a product implementation. * \note Full functionality of this example is only available when connecting to the A71CH over SCI2C. * @param[in] bootMode One of the following values * - ::BOOT_SIMULATED_CYCLE Can be used to simulate handover of session keys (no dependency on link protocol) * - ::BOOT_BOOTLOADER_ROLE Play the role of initial bootloader and store session and communication state to filesystem * - ::BOOT_HOST_OS_RESUME Play the role of OS and retrieve session and communication state from the filesystem */ U8 exHlseBoot(U8 bootMode) { U8 result = 1; U8 initMode = INIT_MODE_NO_RESET; U8 scpKeyEncBase[SCP_KEY_SIZE]; U8 scpKeyMacBase[SCP_KEY_SIZE]; U8 scpKeyDekBase[SCP_KEY_SIZE]; U8 dataRef[] = {0xBE, 0xFA, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; U16 dataRefLen = sizeof(dataRef); U8 dataFetch[8]; U16 packetSize; U16 connectStatus; U8 Atr[64] = {0}; U16 AtrLen = sizeof(Atr); SmCommState_t commState; Scp03SessionState_t sessionState; U16 sw = SW_OK; #if defined(SCI2C) char szFilename[] = "sessionState"; #endif PRINTF("\r\n-----------\r\nStart exBoot(%s)\r\n------------\r\n", axExHlseBootGetBootModeAsString(bootMode)); if (bootMode == BOOT_SKIP_EXAMPLE) { PRINTF("***** WARNING: exBoot example is skipped *****\r\n"); } else if (bootMode == BOOT_SIMULATED_CYCLE) { initMode = INIT_MODE_RESET; // Installing Callback (this step is optional) SCP_Subscribe(signalFunctionCallback, NULL); DEV_ClearChannelState(); #if defined(SCI2C) SM_Close(NULL, SMCOM_CLOSE_MODE_TERMINATE); #endif connectStatus = SM_Connect(NULL, &commState, Atr, &AtrLen); if (connectStatus != SW_OK) { sm_printf(CONSOLE, "Failed to establish connection to Secure Module: 0x%04" PRIX32 "\r\n", connectStatus); result = 0; return result; } else { #ifndef SMCOM_JRCP_V1 int i=0; sm_printf(CONSOLE, "ATR=0x"); for (i=0; i> 8); sm_printf(CONSOLE, "\r\nSCP_GP_PutKeys(keyVersion=0x%02" PRIX16 ")\r\n", keyVersion); #if 0 err = SCP_GP_PutKeys(keyVersion, keyEnc, keyMac, keyDek, currentKeyDek, AES_KEY_LEN_nBYTE); #else err = hlse_SCP_GP_PutKeys(keyVersion, keyEnc, keyMac, keyDek, currentKeyDek, AES_KEY_LEN_nBYTE); #endif result &= AX_CHECK_SW(err, SW_OK, "err"); PRINTF( "\r\n-----------\r\nEnd axExHlseCreateAndSetInitialHostScpKeys(), result = %s\r\n------------\r\n", ((result == 1)? "OK": "FAILED")); return result; } /** * The host locally stores the SCP03 base keys passed as parameters and establishes * the authenticated and encrypted SCP03 channel with the A71CH. * * @param[in] keyEnc IN: SCP03 base key * @param[in] keyMac IN: SCP03 base key * @param[in] keyDek IN: SCP03 base key */ U8 axExHlseAuthenticate(U8 *keyEnc, U8 *keyMac, U8 *keyDek) { U8 sCounter[3]; U16 sCounterLen = sizeof(sCounter); U8 result = 1; U16 err = 0; PRINTF( "\r\n-----------\r\nStart axExHlseAuthenticate()\r\n------------\r\n"); // Authenticate Channel sm_printf(CONSOLE, "\r\nSCP_Authenticate()\r\n"); #if 0 err = SCP_Authenticate(keyEnc, keyMac, keyDek, SCP_KEY_SIZE, sCounter, &sCounterLen); #else err = hlse_SCP_Authenticate(keyEnc, keyMac, keyDek, SCP_KEY_SIZE, sCounter, &sCounterLen); #endif result &= AX_CHECK_SW(err, SW_OK, "err"); result &= AX_CHECK_U16(sCounterLen, 0, "Only expected when SCP03 is configured for pseudo-random challenge"); PRINTF( "\r\n-----------\r\nEnd axExHlseAuthenticate(), result = %s\r\n------------\r\n", ((result == 1)? "OK": "FAILED")); return result; } /// @cond static U8 writeStateToFile(char *szFilename, SmCommState_t *commState, Scp03SessionState_t *scp03State) { U8 result = 1; #ifdef FTR_FILE_SYSTEM FILE *fHandle = NULL; fHandle = fopen(szFilename, "w"); if (fHandle == NULL) { sm_printf(DBGOUT, "Failed to open file %s for writing\r\n", szFilename); return 0; } fwrite((const void *) commState, sizeof(SmCommState_t), 1, fHandle); fwrite((const void *) scp03State, sizeof(Scp03SessionState_t), 1, fHandle); fclose(fHandle); #endif return result; } static U8 readStateFromFile(char *szFilename, SmCommState_t *commState, Scp03SessionState_t *scp03State) { U8 result = 1; #ifdef FTR_FILE_SYSTEM FILE *fHandle = NULL; fHandle = fopen(szFilename, "r"); if (fHandle == NULL) { sm_printf(DBGOUT, "Failed to open file %s for reading", szFilename); return 0; } fread((void *) commState, sizeof(SmCommState_t), 1, fHandle); fread((void *) scp03State, sizeof(Scp03SessionState_t), 1, fHandle); fclose(fHandle); #endif return result; } /// @endcond