| /** |
| * @file ax_sss_scp.c |
| * @author NXP Semiconductors |
| * @version 1.0 |
| * @par License |
| * |
| * Copyright 2016,2020 NXP |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * @par Description |
| * This file implements the setting up of the SCP03 communication channel. |
| * @note Execution flow and Error messages can be sent to the console by defining |
| * FLOW_VERBOSE and ERROR_VERBOSE respectively at the start of the source code file. |
| * @par History |
| * 1.0 26-march-2014 : Initial version |
| * |
| */ |
| #include <string.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <nxLog_scp.h> |
| #include <nxEnsure.h> |
| |
| |
| #include "ax_api.h" |
| #include "sm_apdu.h" |
| #include "sm_errors.h" |
| #include "HostCryptoAPI.h" |
| #include "ax_util.h" |
| #include "sm_printf.h" |
| #include "global_platf.h" |
| #include "ax_sss_scp.h" |
| |
| #include <fsl_sss_api.h> |
| |
| #if defined(SSS_USE_FTR_FILE) |
| #include "fsl_sss_ftr.h" |
| #else |
| #include "fsl_sss_ftr_default.h" |
| #endif |
| |
| #if SSS_HAVE_SCP_SCP03_SSS |
| static Scp_SSS_State_t scp_sss_State[2]; |
| #endif |
| // #define FLOW_VERBOSE //!< Define to enable execution flow messages |
| #define ERROR_VERBOSE //!< Define to enable reporting of error messages |
| |
| |
| /** |
| * Performs an SCP03 authentication with the SM and - when successful - computes |
| * the SCP03 session keys and initializes the current Session state. |
| * |
| * @param[in] keyObj SCP03 channel encryption base key Objects (aka static key) (16 bytes) |
| * @param[in,out] sCounter SCP03 sequence counter (3 bytes) |
| * @param[in,out] sCounterLen |
| */ |
| #if SSS_HAVE_SCP_SCP03_SSS |
| U16 SCP_SSS_Authenticate(SM_SECURE_SCP03_KEYOBJ * scp03Params, U8 *sCounter, U16 *sCounterLen) |
| { |
| ChannelId_t channelId; |
| U8 hostChallenge[] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 }; |
| U8 keyDivData[SCP_GP_IU_KEY_DIV_DATA_LEN]; |
| U16 keyDivDataLen = sizeof(keyDivData); |
| U8 keyInfo[SCP_GP_IU_KEY_INFO_LEN]; |
| U16 keyInfoLen = sizeof(keyInfo); |
| U8 cardChallenge[SCP_GP_CARD_CHALLENGE_LEN]; |
| U16 cardChallengeLen = sizeof(cardChallenge); |
| U8 cardCryptoGram[SCP_GP_IU_CARD_CRYPTOGRAM_LEN]; |
| U16 cardCryptoGramLen = sizeof(cardCryptoGram); |
| U8 seqCounter[SCP_GP_IU_SEQ_COUNTER_LEN]; |
| U16 seqCounterLen = sizeof(seqCounter); |
| U8 hostCryptogram[SCP_GP_IU_CARD_CRYPTOGRAM_LEN]; |
| sss_rng_context_t rngctx; |
| scp_CommandType_t dummy; |
| U16 err = 0; |
| sss_status_t status = kStatus_SSS_Fail; |
| channelId = DEV_GetSelectedChannel(&dummy); |
| |
| |
| status = sss_rng_context_init(&rngctx, scp03Params->pKeyEnc.keyStore->session /* Session */); |
| if (status == kStatus_SSS_Success) |
| { |
| status = sss_rng_get_random(&rngctx, hostChallenge,8); |
| } |
| sss_rng_context_free(&rngctx); |
| if (status != kStatus_SSS_Success) |
| return ERR_CRYPTO_ENGINE_FAILED; |
| |
| err = SCP_GP_InitializeUpdate(channelId, hostChallenge, sizeof(hostChallenge), |
| keyDivData, &keyDivDataLen, |
| keyInfo, &keyInfoLen, |
| cardChallenge, &cardChallengeLen, |
| cardCryptoGram, &cardCryptoGramLen, |
| seqCounter, &seqCounterLen); |
| if (err != SW_OK) |
| { |
| LOG_E("SCP_GP_InitializeUpdate fails with status: 0x%04X\r\n", err); |
| return err; |
| } |
| LOG_MAU8_D("keyDivData", keyDivData, keyDivDataLen); |
| LOG_MAU8_D("keyInfo", keyInfo, keyInfoLen); |
| LOG_MAU8_D("cardChallenge", cardChallenge, cardChallengeLen); |
| LOG_MAU8_D("cardCryptoGram", cardCryptoGram, cardCryptoGramLen); |
| if (seqCounterLen == SCP_GP_IU_SEQ_COUNTER_LEN) |
| { |
| LOG_MAU8_D("seqCounter", seqCounter, seqCounterLen); |
| if (*sCounterLen >= SCP_GP_IU_SEQ_COUNTER_LEN) |
| { |
| // Enough buffer space is provided by caller |
| memcpy(sCounter, seqCounter, seqCounterLen); |
| *sCounterLen = seqCounterLen; |
| } |
| else |
| { |
| return SCP_PARAMETER_ERROR; |
| } |
| } |
| else |
| { |
| *sCounterLen = 0; |
| } |
| |
| err = SCP_SSS_HostLocal_CalculateSessionKeys(channelId, scp03Params, hostChallenge, cardChallenge); |
| if (err != SW_OK) |
| { |
| LOG_E("SCP_HostLocal_CalculateSessionKeys fails with status: 0x%04X\r\n", err); |
| return err; |
| } |
| |
| err = SCP_SSS_HostLocal_VerifyCardCryptogram(channelId, hostChallenge, cardChallenge, cardCryptoGram); |
| if (err != SW_OK) |
| { |
| LOG_E("SCP_HostLocal_VerifyCardCryptogram fails with status: 0x%04X\r\n", err); |
| return err; |
| } |
| |
| err = SCP_SSS_HostLocal_CalculateHostCryptogram(channelId, hostChallenge, cardChallenge, hostCryptogram); |
| LOG_MAU8_D("hostCryptogram", hostCryptogram, SCP_GP_IU_CARD_CRYPTOGRAM_LEN); |
| if (err != SW_OK) |
| { |
| LOG_E("SCP_HostLocal_CalculateHostCryptogram fails with status: 0x%04X\r\n", err); |
| return err; |
| } |
| |
| err = SCP_SSS_GP_ExternalAuthenticate(channelId, hostCryptogram); |
| if (err != SW_OK) |
| { |
| LOG_E("SCP_GP_ExternalAuthenticate fails with status: 0x%04X\r\n", err); |
| return err; |
| } |
| |
| // At this stage we have authenticated successfully. |
| SCP_SSS_HostLocal_SetDefaultValueIcvCCounter(channelId); |
| DEV_SetChannelCommandType(channelId, C_MAC_C_ENC_R_MAC_R_ENC); |
| |
| return err; |
| } |
| |
| U16 SCP_SSS_HostLocal_CalculateSessionKeys(ChannelId_t channelId,SM_SECURE_SCP03_KEYOBJ *scp03Params, U8 *hostChallenge, U8 *cardChallenge) |
| { |
| int stateIdx = 0; |
| U8 ddA[128]; |
| U16 ddALen = sizeof(ddA); |
| U8 context[128]; |
| U16 contextLen = 0; |
| U8 sessionEncKey[AES_KEY_LEN_nBYTE]; |
| U8 sessionMacKey[AES_KEY_LEN_nBYTE]; |
| U8 sessionRmacKey[AES_KEY_LEN_nBYTE]; |
| U32 signatureLen = sizeof(sessionMacKey); |
| S32 ret; |
| sss_status_t status; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| LOG_I("HOST: Calculate session keys\r\n"); |
| |
| // Calculate the Derviation data |
| memcpy(context, hostChallenge, SCP_GP_HOST_CHALLENGE_LEN); |
| memcpy(&context[SCP_GP_HOST_CHALLENGE_LEN], cardChallenge, SCP_GP_CARD_CHALLENGE_LEN); |
| contextLen = SCP_GP_HOST_CHALLENGE_LEN + SCP_GP_CARD_CHALLENGE_LEN; |
| |
| // Calculate the Session-ENC key |
| DEV_setDataDerivationArray(ddA, &ddALen, |
| DATA_DERIVATION_SENC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, context, contextLen); |
| ret = SCP_SSS_CalculateCMAC(scp03Params->pKeyEnc, ddA, ddALen, sessionEncKey, &signatureLen); |
| if (ret != HOST_CRYPTO_OK) { return ERR_CRYPTO_ENGINE_FAILED; } |
| LOG_MAU8_D("sessionEncKey", sessionEncKey, AES_KEY_LEN_nBYTE); |
| /* Init ENC session key object */ |
| status = sss_key_object_init(&scp_sss_State[stateIdx].session.sEnckeyObj, scp03Params->pKeyEnc.keyStore); |
| if (status != kStatus_SSS_Success) |
| { |
| return SCP_FAIL; |
| } |
| ret = SCP_SSS_Save_SessionKeyObj(&scp_sss_State[stateIdx].session.sEnckeyObj, sessionEncKey); |
| if (ret == HOST_CRYPTO_ERROR) |
| { |
| return SCP_FAIL; |
| } |
| |
| // Calculate the Session-MAC key |
| DEV_setDataDerivationArray(ddA, &ddALen, |
| DATA_DERIVATION_SMAC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, context, contextLen); |
| ret = SCP_SSS_CalculateCMAC(scp03Params->pKeyMac, ddA, ddALen, sessionMacKey, &signatureLen); |
| if (ret != HOST_CRYPTO_OK) { return ERR_CRYPTO_ENGINE_FAILED; } |
| LOG_MAU8_D("sessionMacKey", sessionMacKey, AES_KEY_LEN_nBYTE); |
| /* Init MAC session key object */ |
| status = sss_key_object_init(&scp_sss_State[stateIdx].session.sMackeyObj, scp03Params->pKeyMac.keyStore); |
| if (status != kStatus_SSS_Success) |
| { |
| return SCP_FAIL; |
| } |
| ret = SCP_SSS_Save_SessionKeyObj(&scp_sss_State[stateIdx].session.sMackeyObj, sessionMacKey); |
| if (ret == HOST_CRYPTO_ERROR) |
| { |
| return SCP_FAIL; |
| } |
| |
| // Calculate the Session-RMAC key |
| DEV_setDataDerivationArray(ddA, &ddALen, |
| DATA_DERIVATION_SRMAC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, context, contextLen); |
| ret = SCP_SSS_CalculateCMAC(scp03Params->pKeyMac, ddA, ddALen, sessionRmacKey, &signatureLen); |
| if (ret != HOST_CRYPTO_OK) { return ERR_CRYPTO_ENGINE_FAILED; } |
| LOG_MAU8_D("sessionRmacKey", sessionRmacKey, AES_KEY_LEN_nBYTE); |
| /* Init RMAC session key object */ |
| status = sss_key_object_init(&scp_sss_State[stateIdx].session.sRMackeyObj, scp03Params->pKeyDek.keyStore); |
| if (status != kStatus_SSS_Success) |
| { |
| return SCP_FAIL; |
| } |
| ret = SCP_SSS_Save_SessionKeyObj(&scp_sss_State[stateIdx].session.sRMackeyObj, sessionRmacKey); |
| if (ret == HOST_CRYPTO_ERROR) |
| { |
| return SCP_FAIL; |
| } |
| |
| return SCP_OK; |
| } |
| |
| HLSE_RET_CODE SCP_SSS_CalculateCMAC(sss_object_t keyObj, |
| U8* inData, U32 inDataLen, |
| U8* outSignature, U32* outSignatureLen) |
| { |
| sss_mac_t macCtx; |
| sss_status_t status; |
| sss_algorithm_t algorithm; |
| sss_mode_t mode; |
| algorithm = kAlgorithm_SSS_CMAC_AES; |
| mode = kMode_SSS_Mac; |
| HLSE_RET_CODE ret = HOST_CRYPTO_ERROR; |
| |
| // Init Context |
| status = sss_mac_context_init( |
| &macCtx, keyObj.keyStore->session, &keyObj, algorithm, mode); |
| |
| if (status == kStatus_SSS_Success) |
| { |
| // Calculate CMAC |
| status = sss_mac_one_go( |
| &macCtx, inData, (size_t)inDataLen, |
| (uint8_t*)outSignature, (size_t*)outSignatureLen); |
| } |
| if (status == kStatus_SSS_Success) |
| { |
| ret = HOST_CRYPTO_OK; |
| } |
| return ret; |
| } |
| |
| U16 SCP_SSS_Save_SessionKeyObj(sss_object_t *keyObj, U8 *Sessionkey) |
| { |
| sss_status_t status; |
| static int i = 0; |
| U16 ret = HOST_CRYPTO_ERROR; |
| /* Allocate handle for SSS object */ |
| status = sss_key_object_allocate_handle(keyObj, |
| 0xAA58 + i, |
| kSSS_KeyPart_Default, |
| kSSS_CipherType_AES, |
| 16, |
| kKeyObject_Mode_Transient); |
| if (status == kStatus_SSS_Success) { |
| /* Set the key */ |
| status = sss_key_store_set_key( |
| keyObj->keyStore, keyObj, Sessionkey, 16, (16) * 8, NULL, 0); |
| } |
| if (status == kStatus_SSS_Success) { |
| /* Save the key store */ |
| status = sss_key_store_save(keyObj->keyStore); |
| } |
| |
| if (status == kStatus_SSS_Success) { |
| i++; |
| ret = HOST_CRYPTO_OK; |
| } |
| return ret; |
| } |
| |
| U16 SCP_SSS_HostLocal_VerifyCardCryptogram(ChannelId_t channelId, U8 *hostChallenge, U8 *cardChallenge ,U8 *cardCryptogram) |
| { |
| int stateIdx = 0; |
| U8 ddA[128]; |
| U16 ddALen = sizeof(ddA); |
| U8 context[128]; |
| U16 contextLen = 0; |
| U8 cardCryptogramFullLength[AES_KEY_LEN_nBYTE]; |
| U16 rv = SCP_OK; |
| U32 signatureLen = sizeof(cardCryptogramFullLength); |
| S32 ret; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| LOG_I("HOST: Verify Card Cryptogram\r\n"); |
| |
| memcpy(context, hostChallenge, SCP_GP_HOST_CHALLENGE_LEN); |
| memcpy(&context[SCP_GP_HOST_CHALLENGE_LEN], cardChallenge, SCP_GP_CARD_CHALLENGE_LEN); |
| contextLen = SCP_GP_HOST_CHALLENGE_LEN + SCP_GP_CARD_CHALLENGE_LEN; |
| |
| DEV_setDataDerivationArray(ddA, &ddALen, |
| DATA_CARD_CRYPTOGRAM, DATA_DERIVATION_L_64BIT, DATA_DERIVATION_KDF_CTR, context, contextLen); |
| |
| ret = SCP_SSS_CalculateCMAC(scp_sss_State[stateIdx].session.sMackeyObj, ddA, ddALen, cardCryptogramFullLength, &signatureLen); |
| if (ret != HOST_CRYPTO_OK) { return ERR_CRYPTO_ENGINE_FAILED; } |
| |
| LOG_MAU8_D("cardCryptogramFullLength - Verify", cardCryptogramFullLength, AES_KEY_LEN_nBYTE); |
| |
| // Verify whether the 8 left most byte of cardCryptogramFullLength match cardCryptogram |
| if (memcmp(cardCryptogramFullLength, cardCryptogram, SCP_GP_IU_CARD_CRYPTOGRAM_LEN) != 0) |
| { |
| rv = SCP_CARD_CRYPTOGRAM_FAILS_TO_VERIFY; |
| } |
| |
| return rv; |
| } |
| |
| U16 SCP_SSS_HostLocal_CalculateHostCryptogram(ChannelId_t channelId, U8 *hostChallenge, U8 *cardChallenge, U8 *hostCryptogram) |
| { |
| int stateIdx = 0; |
| U8 ddA[128]; |
| U16 ddALen = sizeof(ddA); |
| U8 context[128]; |
| U16 contextLen = 0; |
| U8 hostCryptogramFullLength[AES_KEY_LEN_nBYTE]; |
| U32 signatureLen = sizeof(hostCryptogramFullLength); |
| S32 ret; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| LOG_I("HOST: Calculate Host Cryptogram\r\n"); |
| |
| memcpy(context, hostChallenge, SCP_GP_HOST_CHALLENGE_LEN); |
| memcpy(&context[SCP_GP_HOST_CHALLENGE_LEN], cardChallenge, SCP_GP_CARD_CHALLENGE_LEN); |
| contextLen = SCP_GP_HOST_CHALLENGE_LEN + SCP_GP_CARD_CHALLENGE_LEN; |
| |
| DEV_setDataDerivationArray(ddA, &ddALen, |
| DATA_HOST_CRYPTOGRAM, DATA_DERIVATION_L_64BIT, DATA_DERIVATION_KDF_CTR, context, contextLen); |
| |
| ret = SCP_SSS_CalculateCMAC(scp_sss_State[stateIdx].session.sMackeyObj, ddA, ddALen, hostCryptogramFullLength, &signatureLen); |
| |
| if (ret != HOST_CRYPTO_OK) { return ERR_CRYPTO_ENGINE_FAILED; } |
| |
| // Chop of the tail of the hostCryptogramFullLength |
| memcpy(hostCryptogram, hostCryptogramFullLength, SCP_GP_IU_CARD_CRYPTOGRAM_LEN); |
| |
| return SCP_OK; |
| } |
| |
| U16 SCP_SSS_GP_ExternalAuthenticate(ChannelId_t channelId, U8* hostCryptogram) |
| { |
| U32 st = 0; |
| U8 txBuf[128]; |
| U8 cla = 0; |
| U8 response[128]; |
| U32 responseLen = 128; |
| U16 rv = 0; |
| U8 mcv[AES_KEY_LEN_nBYTE]; |
| U8 macToAdd[AES_KEY_LEN_nBYTE]; |
| int stateIdx = 0;// ADMIN_CHANNEL_STATE_IDX; |
| sss_mac_t macCtx; |
| sss_algorithm_t algorithm; |
| sss_mode_t mode; |
| algorithm = kAlgorithm_SSS_CMAC_AES; |
| mode = kMode_SSS_Mac; |
| size_t signatureLen = sizeof(macToAdd); |
| sss_status_t status; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| LOG_I(">> %s: Enter\r\n", "SCP_GP_ExternalAuthenticate"); |
| |
| cla = 0x84; |
| |
| txBuf[0] = cla; |
| txBuf[1] = INS_GP_EXTERNAL_AUTHENTICATE; |
| txBuf[2] = SECLVL_CDEC_RENC_CMAC_RMAC; |
| txBuf[3] = 0x00; |
| txBuf[4] = 0x10; // The Lc valus is set as-if the MAC has already been appended (SCP03 spec p16. Fig.6-1) |
| memcpy(&txBuf[5], hostCryptogram, SCP_GP_IU_CARD_CRYPTOGRAM_LEN); |
| |
| // Calculate the MAC value |
| status = sss_mac_context_init( |
| &macCtx, scp_sss_State[stateIdx].session.sMackeyObj.keyStore->session, |
| &scp_sss_State[stateIdx].session.sMackeyObj, algorithm, mode); |
| |
| if (status != kStatus_SSS_Success) |
| { |
| return ERR_CRYPTO_ENGINE_FAILED; |
| } |
| status = sss_mac_init(&macCtx); |
| if (status != kStatus_SSS_Success) |
| { |
| return ERR_CRYPTO_ENGINE_FAILED; |
| } |
| |
| /* |
| * For the EXTERNAL AUTHENTICATE command MAC verification, the "MAC chaining value" is set to 16 |
| * bytes '00'. (SCP03 spec p16) |
| */ |
| SCP_SSS_HostLocal_ResetMacChainingValue(channelId); |
| memcpy(mcv, scp_sss_State[stateIdx].session.mcv, AES_KEY_LEN_nBYTE); |
| |
| status = sss_mac_update( &macCtx, mcv, AES_KEY_LEN_nBYTE); |
| if (status != kStatus_SSS_Success) |
| { |
| return ERR_CRYPTO_ENGINE_FAILED; |
| } |
| status = sss_mac_update(&macCtx, txBuf, 13); |
| if (status != kStatus_SSS_Success) |
| { |
| return ERR_CRYPTO_ENGINE_FAILED; |
| } |
| status = sss_mac_finish(&macCtx, macToAdd, &signatureLen); |
| if (status != kStatus_SSS_Success) |
| { |
| return ERR_CRYPTO_ENGINE_FAILED; |
| } |
| memcpy(scp_sss_State[stateIdx].session.mcv, macToAdd, AES_KEY_LEN_nBYTE); |
| |
| memcpy(&txBuf[5 + SCP_GP_IU_CARD_CRYPTOGRAM_LEN], macToAdd, SCP_GP_IU_CARD_CRYPTOGRAM_LEN); |
| |
| LOG_MAU8_D("mcv", mcv, 16); |
| LOG_MAU8_D("txBuf", txBuf, 13); |
| LOG_MAU8_D("macToAdd", macToAdd, 16); |
| |
| #ifdef TGT_EDEV |
| if (channelId == AX_HOST_CHANNEL) |
| { |
| // Modify the CLA byte to tag this channel as a Host Channel |
| cla = 0xE4; |
| } |
| txBuf[0] = cla; |
| #endif |
| |
| st = smCom_TransceiveRaw(NULL, (U8*)txBuf, 5 + AES_KEY_LEN_nBYTE, response, &responseLen); |
| |
| if (st != SMCOM_OK) |
| { |
| LOG_E("SCP_GP_ExternalAuthenticate %lX\r\n", st); |
| rv = ERR_GENERAL_ERROR; |
| } |
| else |
| { |
| rv = CheckNoResponseDataRaw(response, (U16)responseLen); |
| } |
| return rv; |
| } |
| |
| |
| //State maintain functions (scp_sss_State) |
| |
| U16 SCP_SSS_HostLocal_SetDefaultValueIcvCCounter(ChannelId_t channelId) |
| { |
| U8 commandCounter[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; |
| int stateIdx = 0; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| memcpy(scp_sss_State[stateIdx].session.cCounter, commandCounter, 16); |
| |
| return SCP_OK; |
| } |
| |
| |
| U16 SCP_SSS_HostLocal_IncIcvCCounter(ChannelId_t channelId) |
| { |
| int stateIdx = 0; |
| int i = 15; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| i = 15; |
| while (i > 0) |
| { |
| if (scp_sss_State[stateIdx].session.cCounter[i] < 255) |
| { |
| scp_sss_State[stateIdx].session.cCounter[i] += 1; |
| break; |
| } |
| else |
| { |
| scp_sss_State[stateIdx].session.cCounter[i] = 0; |
| i--; |
| } |
| } |
| |
| return SCP_OK; |
| } |
| |
| U16 SCP_SSS_HostLocal_ResetMacChainingValue(ChannelId_t channelId) |
| { |
| int stateIdx = 0; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| memset(scp_sss_State[stateIdx].session.mcv, 0, SCP_MCV_LEN); |
| |
| return SCP_OK; |
| } |
| |
| U16 SCP_SSS_HostLocal_SetMacChainingValue(ChannelId_t channelId, U8 *mcv) |
| { |
| int stateIdx = 0; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| memcpy(scp_sss_State[stateIdx].session.mcv, mcv, SCP_MCV_LEN); |
| |
| return SCP_OK; |
| } |
| |
| /** |
| * Copy the session state into \p pSession. Caller must allocate memory of \p pSession. |
| * @param[in] channelId Either ::AX_HOST_CHANNEL or ::AX_ADMIN_CHANNEL. Must be ::AX_HOST_CHANNEL in case of A71CH. |
| * @param[in,out] pSession IN: pointer to allocated ::Scp03SessionState_t structure; OUT: retrieved state |
| * @retval ::SW_OK Upon successful execution |
| * @retval ::SCP_UNDEFINED_CHANNEL_ID In case an undefined ::ChannelId_t type was passed as parameter |
| */ |
| U16 SCP_SSS_HostLocal_GetSessionState(ChannelId_t channelId, Scp03_SSS_SessionState_t *pSession) |
| { |
| int stateIdx = 0; |
| |
| switch (channelId) |
| { |
| case AX_HOST_CHANNEL: |
| stateIdx = HOST_CHANNEL_STATE_IDX; |
| break; |
| case AX_ADMIN_CHANNEL: |
| stateIdx = ADMIN_CHANNEL_STATE_IDX; |
| break; |
| default: |
| return SCP_UNDEFINED_CHANNEL_ID; |
| } |
| |
| memcpy(pSession, &(scp_sss_State[stateIdx].session), sizeof(Scp03_SSS_SessionState_t)); |
| |
| return SCP_OK; |
| } |
| U16 SM_ChannelAuthenticate(SM_SECURE_SCP03_KEYOBJ *scp03Params, U8 *cCounter) |
| { |
| U16 counterLen = 16; |
| U16 lReturn = SCP_FAIL; |
| |
| lReturn = SCP_SSS_Authenticate(scp03Params, cCounter, &counterLen); |
| |
| if (lReturn != SW_OK) |
| return lReturn; |
| |
| |
| return lReturn; |
| } |
| |
| #endif |
| |
| #ifdef TGT_EDEV |
| #ifndef AX_SF |
| /** |
| * Performs a soft-reset of the Security Module, effectively resetting the SCP channels. |
| * This function is only available for the administrator |
| * @return status. |
| */ |
| U16 SM_SoftReset(void) |
| { |
| apdu_t apdu; |
| apdu_t * pApdu = (apdu_t *) &apdu; |
| U16 rv; |
| |
| pApdu->cla = AX_CLA; |
| pApdu->ins = INS_AX_SM; |
| pApdu->p1 = P1_SOFT_RESET; |
| pApdu->p2 = 0x00; |
| |
| AllocateAPDUBuffer(pApdu); |
| |
| SetApduHeader(pApdu, USE_STANDARD_APDU_LEN); |
| scp_Transceive(pApdu, SCP_MODE); |
| |
| // no response data expected |
| rv = CheckNoResponseData(pApdu); |
| |
| FreeAPDUBuffer(pApdu); |
| return rv; |
| } |
| #endif // AX_SF |
| #endif // TGT_EDEV |