/* Copyright 2019,2020 NXP * * This software is owned or controlled by NXP and may only be used * strictly in accordance with the applicable license terms. By expressly * accepting such terms or by downloading, installing, activating and/or * otherwise using the software, you are agreeing that you have read, and * that you agree to comply with and are bound by, such license terms. If * you do not agree to be bound by the applicable license terms, then you * may not retain, install, activate or otherwise use the software. */ #if defined(SSS_USE_FTR_FILE) #include "fsl_sss_ftr.h" #else #include "fsl_sss_ftr_default.h" #endif #include "usb_device_config.h" #include "usb.h" #include "usb_device.h" #include "usb_device_class.h" #include "usb_device_ccid.h" #include "usb_device_dci.h" #include "usb_device_ch9.h" #include "usb_device_descriptor.h" #include "emvl1_interface.h" #include "smart_card.h" #include "fsl_device_registers.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_smartcard_s05x.h" #include "emvl1_core.h" #include "smCom.h" #include <ax_reset.h> #include <stdio.h> #include <stdlib.h> #if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U)) #include "fsl_sysmpu.h" #endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */ #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U) #include "usb_phy.h" #endif #if (USB_DEVICE_CONFIG_USE_TASK < 1U) #error USB_DEVICE_CONFIG_USE_TASK need to > 0U, Please change the MARCO USB_DEVICE_CONFIG_USE_TASK in file "usb_device_config.h". #endif #include "pin_mux.h" #include <fsl_smartcard.h> #include "ex_sss_boot.h" #include <sm_timer.h> #if SSS_HAVE_HOSTCRYPTO_MBEDTLS #include <ksdk_mbedtls.h> #endif // If you want to enable debug in this file. //#define NX_LOG_ENABLE_APP_DEBUG 1 #include <nxLog_App.h> #include <PlugAndTrust_Pkg_Ver.h> extern smartcard_context_t g_SmartCardContext; #if LOG_DEBUG_ENABLED static const char *DEF_smartcard_control(smartcard_control_t control); static const char *DEF_smartcard_interface_control(smartcard_interface_control_t control); static const char *DEF_smartcard_direction(smartcard_direction_t direction); #endif uint32_t gWtxCnt; static ex_sss_boot_ctx_t gsssCCIDBootCtx; static void *g_conn_ctx = NULL; SE05x_CCID_Base_t gse05x_ccid_base; void USB_DeviceClockInit(void) { SystemCoreClockUpdate(); CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcIrc48M, 48000000U); } void USB_DeviceIsrEnable(void) { uint8_t irqNumber; uint8_t usbDeviceKhciIrq[] = USB_IRQS; irqNumber = usbDeviceKhciIrq[CONTROLLER_ID - kUSB_ControllerKhci0]; /* Install isr, set priority, and enable IRQ. */ NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY); EnableIRQ((IRQn_Type)irqNumber); } #if USB_DEVICE_CONFIG_USE_TASK void USB_DeviceTaskFn(void *deviceHandle) { USB_DeviceKhciTaskFunction(deviceHandle); } #endif /*! * @brief Fills in the configuration structure with default values. * * @param config The Smart card user configuration structure which contains configuration structure of type * smartcard_interface_config_t. * Function fill in members: * clockToResetDelay = 42000, * vcc = kSmartcardVoltageClassB3_3V, * with default values. */ void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config) { assert((NULL != config)); LOG_D("P:GetDefaultConfig"); /* Initializes the configure structure to zero. */ memset(config, 0, sizeof(*config)); /* EMV default values */ config->clockToResetDelay = SMARTCARD_INIT_DELAY_CLOCK_CYCLES; config->vcc = kSMARTCARD_VoltageClassB3_3V; return; } /*! * @brief Initializes a Smart card interface instance. * * @param base The Smart card peripheral base address. * @param config The user configuration structure of type smartcard_interface_config_t. Call the * function SMARTCARD_PHY_GetDefaultConfig() to fill the configuration structure. * @param srcClock_Hz Smart card clock generation module source clock. * * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. */ status_t SMARTCARD_SE05x_Init(SE05x_CCID_Base_t *base, smartcard_interface_config_t const *context) { status_t retVal; sm_initSleep(); #if (AX_EMBEDDED) && defined(MBEDTLS) CRYPTO_InitHardware(); #endif retVal = kStatus_SMARTCARD_Success; return retVal; } /*! * @brief De-initializes a Smart card interface, stops the Smart card clock, and disables the VCC. * * @param base The Smart card peripheral module base address. * @param config The user configuration structure of type smartcard_interface_config_t. */ void SMARTCARD_PHY_Deinit(SE05x_CCID_Base_t *base, smartcard_interface_config_t const *config) { LOG_D("P:Deinit"); ex_sss_session_close((&gsssCCIDBootCtx)); return; } /*! * @brief Activates the Smart card IC. * * @param base The Smart card peripheral module base address. * @param context A pointer to a Smart card driver context structure. * @param resetType type of reset to be performed, possible values * = kSmartcardColdReset, kSmartcardWarmReset * * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. */ status_t SMARTCARD_PHY_Activate(SE05x_CCID_Base_t *base, smartcard_context_t *context, smartcard_reset_type_t resetType) { LOG_D("P:Activate"); context->cardParams.atrValid = false; sss_status_t status = kStatus_SSS_Fail; #if SSS_HAVE_SE05X gsssCCIDBootCtx.se05x_open_ctx.skip_select_applet = 1; #endif status = ex_sss_boot_open((&gsssCCIDBootCtx), NULL); #if SSS_HAVE_SE05X sss_se05x_session_t * se05x_session = (sss_se05x_session_t *) &gsssCCIDBootCtx.session; pSe05xSession_t se05xSession; se05xSession = &se05x_session->s_ctx; g_conn_ctx = (void *) se05xSession->conn_ctx; #endif LOG_D("P:Init status=%X", status); if (status == kStatus_SSS_Success) { context->cardParams.t1Indicated = 1; context->cardParams.present = 1; context->cardParams.active = 1; return kStatus_SMARTCARD_Success; } else { return kStatus_SMARTCARD_CardNotActivated; } } /*! * @brief De-activates the Smart card IC. * * @param base The Smart card peripheral module base address. * @param context A pointer to a Smart card driver context structure. * * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. */ status_t SMARTCARD_PHY_Deactivate(SE05x_CCID_Base_t *base, smartcard_context_t *context) { LOG_D("P:Deactivate"); ex_sss_session_close((&gsssCCIDBootCtx)); return kStatus_SMARTCARD_Success; } static void smartcard_se05x_SetTransferType( SE05x_CCID_Base_t *base, smartcard_context_t *context, smartcard_control_t control) { LOG_D("S:SetTransferType %s", DEF_smartcard_control(control)); } /*! * @brief Controls the Smart card interface IC. * * @param base The Smart card peripheral module base address. * @param context A pointer to a Smart card driver context structure. * @param control A interface command type. * @param param Integer value specific to control type * * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. */ status_t SMARTCARD_PHY_Control( SE05x_CCID_Base_t *base, smartcard_context_t *context, smartcard_interface_control_t control, uint32_t param) { LOG_D("P:Control %s=%d", DEF_smartcard_interface_control(control), param); if ((NULL == context)) { return kStatus_SMARTCARD_InvalidInput; } if (kSMARTCARD_InterfaceReadStatus == control) { switch (param) { case kSMARTCARD_EnableADT: /* Do nothing, ADT counter has been loaded and started after reset * and during starting TS delay counter only. This is because, once * TS counter has been triggered with RCV_EN down-up, we should not * trigger again after TS is received(to avoid missing next character to * TS. Rather, after TS is received, the ATR duration counter should just * be restarted w/o re-triggering the counter. */ //context->cardParams.atrValid = 1; context->cardParams.present = 1; context->cardParams.t1Indicated = 1; context->cardParams.present = true; context->cardParams.active = false; context->cardParams.faulty = false; context->IFSD = 0xFE; context->cardParams.status = 1; //SMARTCARD_SE05X_STATUS_PRES; break; case kSMARTCARD_DisableADT: // base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; /* Stop ADT specific counter and it's interrupt to occur */ // base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK; // base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK; // base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK; break; case kSMARTCARD_EnableGTV: /* Enable GTV specific interrupt */ // base->INT_MASK &= ~EMVSIM_INT_MASK_BGT_ERR_IM_MASK; break; case kSMARTCARD_DisableGTV: /* Disable GTV specific interrupt */ // base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK; break; case kSMARTCARD_ResetWWT: /* Reset WWT Timer */ // base->CTRL &= ~(EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK); // base->CTRL |= (EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK); break; case kSMARTCARD_EnableWWT: /* BGT must be masked */ // base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK; /* Enable WWT Timer interrupt to occur */ // base->INT_MASK &= (~EMVSIM_INT_MASK_CWT_ERR_IM_MASK & ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK); break; case kSMARTCARD_DisableWWT: /* Disable WWT Timer interrupt to occur */ // base->INT_MASK |= (EMVSIM_INT_MASK_CWT_ERR_IM_MASK | EMVSIM_INT_MASK_BWT_ERR_IM_MASK); break; case kSMARTCARD_ResetCWT: /* Reset CWT Timer */ // base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK; // base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; break; case kSMARTCARD_EnableCWT: // base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; /* Enable CWT Timer interrupt to occur */ // base->INT_MASK &= ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK; break; case kSMARTCARD_DisableCWT: /* CWT counter is for receive mode only */ // base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK; /* Disable CWT Timer interrupt to occur */ // base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK; break; case kSMARTCARD_ResetBWT: /* Reset BWT Timer */ // base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK; // base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; break; case kSMARTCARD_EnableBWT: // base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; /* Enable BWT Timer interrupt to occur */ // base->INT_MASK &= ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK; break; case kSMARTCARD_DisableBWT: /* Disable BWT Timer interrupt to occur */ // base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK; break; case kSMARTCARD_EnableInitDetect: /* Clear all ISO7816 interrupt flags */ // base->RX_STATUS = 0xFFFFFFFFu; /* Enable initial character detection : hardware method */ context->transferState = kSMARTCARD_WaitingForTSState; /* Enable initial character detection */ // base->CTRL |= EMVSIM_CTRL_ICM_MASK; // base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; break; case kSMARTCARD_EnableAnack: /* Enable NACK-on-error interrupt to occur */ // base->CTRL |= EMVSIM_CTRL_ANACK_MASK; break; case kSMARTCARD_DisableAnack: /* Disable NACK-on-error interrupt to occur */ // base->CTRL &= ~EMVSIM_CTRL_ANACK_MASK; break; case kSMARTCARD_ConfigureBaudrate: /* Set default baudrate/ETU time based on EMV parameters and card clock */ // base->DIVISOR = ((context->cardParams.Fi / context->cardParams.currentD) & 0x1FFu); break; case kSMARTCARD_SetupATRMode: /* Set in default ATR mode */ smartcard_se05x_SetTransferType(base, context, kSMARTCARD_SetupATRMode); break; case kSMARTCARD_SetupT0Mode: /* Set transport protocol type to T=0 */ smartcard_se05x_SetTransferType(base, context, kSMARTCARD_SetupT0Mode); break; case kSMARTCARD_SetupT1Mode: /* Set transport protocol type to T=1 */ smartcard_se05x_SetTransferType(base, context, kSMARTCARD_SetupT1Mode); break; case kSMARTCARD_EnableReceiverMode: /* Enable receiver mode and switch to receive direction */ // base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; /* Set receiver threshold value to 1 */ // base->RX_THD = ((base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK) | 1); /* Enable RDT interrupt */ // base->INT_MASK &= ~EMVSIM_INT_MASK_RDT_IM_MASK; break; case kSMARTCARD_DisableReceiverMode: /* Disable receiver */ // base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; break; case kSMARTCARD_EnableTransmitterMode: /* Enable transmitter mode and switch to transmit direction */ // base->CTRL |= EMVSIM_CTRL_XMT_EN_MASK; break; case kSMARTCARD_DisableTransmitterMode: /* Disable transmitter */ // base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK; break; case kSMARTCARD_ResetWaitTimeMultiplier: // base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK; /* Reset Wait Timer Multiplier * EMV Formula : WTX x (11 + ((2^BWI + 1) x 960 x D)) */ // temp32 = ((uint8_t)param) * // (11u + (((1 << context->cardParams.BWI) + 1u) * 960u * context->cardParams.currentD)); #ifdef CARDSIM_EXTRADELAY_USED // temp32 += context->cardParams.currentD * 50; #endif // base->BWT_VAL = temp32; /* Set flag to SMARTCARD context accordingly */ //if (param > 1u) { context->wtxRequested = true; //} //else { // context->wtxRequested = false; //} // base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; break; default: return kStatus_SMARTCARD_InvalidInput; } } return kStatus_USB_Success; } #define RET_STR(var, enum_prfx, enum_sfx) \ if ((var) == (enum_prfx##_##enum_sfx)) \ return #enum_sfx; #if defined(__CC_ARM) || (defined(__ARMCC_VERSION)) || defined(__GNUC__) int main(void) #else void main(void) #endif { BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); USB_DeviceApplicationInit(); LOG_I(PLUGANDTRUST_PROD_NAME_VER_FULL); g_SmartCardContext.base = (void *)&gse05x_ccid_base; axReset_HostConfigure(); axReset_PowerUp(); while (1U) { #if USB_DEVICE_CONFIG_USE_TASK USB_DeviceTaskFn(g_UsbDeviceCcidSmartCard.deviceHandle); #endif } } status_t SMARTCARD_SE05x_TransferNonBlocking( SE05x_CCID_Base_t *base, smartcard_context_t *context, smartcard_xfer_t *xfer) { LOG_D("S:XFer d=%s sz=%d", DEF_smartcard_direction(xfer->direction), xfer->size); if (xfer->direction == kSMARTCARD_Receive) { if (context->cardParams.atrValid == false) { // https://www.javacardos.com/tools/atr /* clang-format off */ const char atrU8[] = { //0x85, 0x81, 0x21, 0x4D, 0x11, 0x22, 0x33, 0x44, 0x55, 0x79 //0x3B, //0xD3, 0x22, 0x03, 0x91, 0x11, 0x31, 0x31, 0x55, 0x70, 0x67, 0x68, 0x58 //0xD3, 0x44, 0x04, 0x91, 0x01, 0x31, 0x2E, 0x66, 0x70, 0x67, 0x68, 0x05 // 3B D3 44 01 91 81 31 2E 82 70 67 68 64 // 0xD3, 0x44, 0x01, 0x91, 0x81, 0x31, 0x2E, 0x82, 0x70, 0x67, 0x68, 0x64 // 3B 93 12 91 81 31 FE 31 70 67 68 10 0x93, 0x12, 0x91, 0x81, 0x31, 0xFE, 0x31, 0x70, 0x67, 0x68, 0x10, // with t=0 // 3B D3 12 01 C0 02 31 FE 32 70 67 68 80 // 0xD3, 0x12, 0x01, 0xC0, 0x02, 0x31, 0xFE, 0x32, 0x70, 0x67, 0x68, 0x80, }; /* clang-format on */ context->xBuff = xfer->buff; memcpy(context->xBuff, atrU8, sizeof(atrU8)); context->xSize = xfer->size - sizeof(atrU8); context->tType = kSMARTCARD_T1Transport; context->resetType = kSMARTCARD_WarmReset; return kStatus_SMARTCARD_Success; } } return kStatus_SMARTCARD_OtherError; } int32_t SMARTCARD_SE05x_GetTransferRemainingBytes(SE05x_CCID_Base_t *base, smartcard_context_t *context) { LOG_D("S:GetTransferRemainingBytes"); if (context->xIsBusy) { return -1; //context->xSize; } return 0; } status_t SMARTCARD_SE05x_Control( SE05x_CCID_Base_t *base, smartcard_context_t *context, smartcard_control_t control, uint32_t param) { LOG_D("S:Control %s=%d", DEF_smartcard_control(control), param); return kStatus_SMARTCARD_Success; } void SysTick_Handler_APP_CB(void) { if (g_SmartCardContext.xIsBusy ) { if (kSMARTCARD_WaitingForTSState == g_SmartCardContext.transferState) { g_SmartCardContext.xIsBusy = 0; g_SmartCardContext.transferState = kSMARTCARD_IdleState; } if (g_SmartCardContext.transferState == kSMARTCARD_TransmittingState) { gWtxCnt++; if (gWtxCnt > 4000) { usb_status_t status; gWtxCnt = 0; status = USB_DeviceSendWtxRequest(); if (status != kStatus_USB_Success) { LOG_E("Bulk In Wtx request failed"); } } } } } const char gp_select_applet[] = {0x00, 0xA4, 0x04, 0x00}; uint8_t EMVL1_SendApduCommand( uint8_t *commandApdu, uint32_t commandApduLength, uint8_t *ResponseApdu, uint32_t *ResponseApduLength) { U32 status = SW_OK; g_SmartCardContext.direction = kSMARTCARD_Transmit; g_SmartCardContext.transferState = kSMARTCARD_TransmittingState; g_SmartCardContext.xIsBusy = 1; if (((commandApduLength + 9) % 64) == 0) { uint8_t index = 4; uint32_t LcVal = commandApdu[index++]; uint32_t CmdLenLe = commandApduLength; if (LcVal == 0) { CmdLenLe = commandApduLength - 2; // Last 2 bytes are Le not counted in Lc LcVal = commandApdu[index++] & 0xFF; LcVal = LcVal << 8; LcVal |= commandApdu[index++] & 0xFF; } if (LcVal != (CmdLenLe - index)) { /* * USB 64 byte boundary * =================================== * Remove one extra byte added at the end by the application */ commandApduLength -= 1; } } status = smCom_TransceiveRaw(g_conn_ctx, commandApdu, commandApduLength, ResponseApdu, ResponseApduLength); gWtxCnt = 0; if (status == SW_OK && (*ResponseApduLength) >= 2) { g_SmartCardContext.xIsBusy = 0; g_SmartCardContext.direction = kSMARTCARD_Receive; g_SmartCardContext.transferState = kSMARTCARD_IdleState; g_SmartCardContext.xSize = *ResponseApduLength; return kStatus_CCID_EMV_Success; } else { return kStatus_CCID_EMV_Error; } } #if LOG_DEBUG_ENABLED static const char *DEF_smartcard_direction(smartcard_direction_t direction) { RET_STR(direction, kSMARTCARD, Receive); RET_STR(direction, kSMARTCARD, Transmit); return "unknown: smartcard_direction_t"; } static const char *DEF_smartcard_control(smartcard_control_t control) { RET_STR(control, kSMARTCARD, EnableADT); RET_STR(control, kSMARTCARD, DisableADT); RET_STR(control, kSMARTCARD, EnableGTV); RET_STR(control, kSMARTCARD, DisableGTV); RET_STR(control, kSMARTCARD, ResetWWT); RET_STR(control, kSMARTCARD, EnableWWT); RET_STR(control, kSMARTCARD, DisableWWT); RET_STR(control, kSMARTCARD, ResetCWT); RET_STR(control, kSMARTCARD, EnableCWT); RET_STR(control, kSMARTCARD, DisableCWT); RET_STR(control, kSMARTCARD, ResetBWT); RET_STR(control, kSMARTCARD, EnableBWT); RET_STR(control, kSMARTCARD, DisableBWT); RET_STR(control, kSMARTCARD, EnableInitDetect); RET_STR(control, kSMARTCARD, EnableAnack); RET_STR(control, kSMARTCARD, DisableAnack); RET_STR(control, kSMARTCARD, ConfigureBaudrate); RET_STR(control, kSMARTCARD, SetupATRMode); RET_STR(control, kSMARTCARD, SetupT0Mode); RET_STR(control, kSMARTCARD, SetupT1Mode); RET_STR(control, kSMARTCARD, EnableReceiverMode); RET_STR(control, kSMARTCARD, DisableReceiverMode); RET_STR(control, kSMARTCARD, EnableTransmitterMode); RET_STR(control, kSMARTCARD, DisableTransmitterMode); RET_STR(control, kSMARTCARD, ResetWaitTimeMultiplier); return "unknown: smartcard_control_t"; } static const char *DEF_smartcard_interface_control(smartcard_interface_control_t control) { RET_STR(control, kSMARTCARD, InterfaceSetVcc); RET_STR(control, kSMARTCARD, InterfaceSetClockToResetDelay); RET_STR(control, kSMARTCARD, InterfaceReadStatus); return "unknown: smartcard_interface_control_t"; } #endif