diff --git a/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/sc_itf.h b/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/sc_itf.h index dfac8d607..8babdec31 100644 --- a/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/sc_itf.h +++ b/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/sc_itf.h @@ -64,7 +64,7 @@ uint8_t SC_ExecuteEscape (uint8_t* escapePtr, uint32_t escapeLen, uint8_t* responseBuff, uint16_t* responseLen); uint8_t SC_SetClock (uint8_t bClockCommand); -uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen); +uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen); uint8_t SC_Request_GetClockFrequencies(uint8_t* pbuf, uint16_t* len); uint8_t SC_Request_GetDataRates(uint8_t* pbuf, uint16_t* len); uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse, @@ -72,8 +72,7 @@ uint8_t SC_T0Apdu(uint8_t bmChanges, uint8_t bClassGetResponse, uint8_t SC_Mechanical(uint8_t bFunction); uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency, uint32_t dwDataRate); -uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter, - uint8_t* pbuf, uint32_t* returnLen ); +uint8_t SC_Secure(uint8_t* pbuf, uint32_t* returnLen); #endif // HAVE_USB_CLASS_CCID diff --git a/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h b/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h index 9326da8ff..1e077a7c8 100644 --- a/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h +++ b/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h @@ -58,6 +58,14 @@ #define VOLTAGE_SELECTION_5V 0x01 #define VOLTAGE_SELECTION_1V8 0x03 +/* PC_to_RDR_Secure PIN operations */ +#define PIN_OPR_VERIFICATION 0x00 +#define PIN_OPR_MODIFICATION 0x01 +#define PIN_OPR_TRANSFER 0x02 +#define PIN_OPR_WAIT_ICC_RESP 0x03 +#define PIN_OPR_CANCEL 0x04 +#define PIN_OPR_APDU_CLA 0xEF + #define PC_TO_RDR_ICCPOWERON 0x62 #define PC_TO_RDR_ICCPOWEROFF 0x63 #define PC_TO_RDR_GETSLOTSTATUS 0x65 @@ -223,6 +231,8 @@ void Set_CSW (uint8_t CSW_Status, uint8_t Send_Permission); void io_usb_ccid_set_card_inserted(unsigned int inserted); +void io_usb_ccid_configure_pinpad(uint8_t enabled); + #endif // HAVE_USB_CLASS_CCID #endif /* __USBD_CCID_IF_H */ diff --git a/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_cmd.c b/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_cmd.c index 31e4759a4..e75501c60 100644 --- a/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_cmd.c +++ b/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_cmd.c @@ -231,28 +231,25 @@ uint8_t PC_to_RDR_XfrBlock(void) if (error != 0) return error; - if (G_io_ccid.bulk_header.bulkout.dwLength > IO_CCID_DATA_BUFFER_SIZE) - { /* Check amount of Data Sent by Host is > than memory allocated ? */ + if (G_io_ccid.bulk_header.bulkout.dwLength > IO_CCID_DATA_BUFFER_SIZE) + { /* Check amount of Data Sent by Host is > than memory allocated ? */ - return SLOTERROR_BAD_DWLENGTH; - } + return SLOTERROR_BAD_DWLENGTH; + } - /* wLevelParameter = Size of expected data to be returned by the - bulk-IN endpoint */ - expectedLength = (G_io_ccid.bulk_header.bulkout.bSpecific_2 << 8) | - G_io_ccid.bulk_header.bulkout.bSpecific_1; + /* wLevelParameter = Size of expected data to be returned by the + bulk-IN endpoint */ + expectedLength = (G_io_ccid.bulk_header.bulkout.bSpecific_2 << 8) | + G_io_ccid.bulk_header.bulkout.bSpecific_1; - reqlen = G_io_ccid.bulk_header.bulkout.dwLength; - - G_io_ccid.bulk_header.bulkin.dwLength = (uint16_t)expectedLength; + reqlen = G_io_ccid.bulk_header.bulkout.dwLength; + G_io_ccid.bulk_header.bulkin.dwLength = (uint16_t)expectedLength; - error = SC_XferBlock(&G_io_ccid_data_buffer[0], - reqlen, - &expectedLength); + error = SC_XferBlock(&G_io_ccid_data_buffer[0], reqlen); - if (error != SLOT_NO_ERROR) + if (error != SLOT_NO_ERROR) { CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); } @@ -639,7 +636,6 @@ uint8_t PC_TO_RDR_SetDataRateAndClockFrequency(void) uint8_t error; uint32_t clockFrequency; uint32_t dataRate; - uint32_t temp =0; error = CCID_CheckCommandParams(CHK_PARAM_SLOT |\ CHK_PARAM_CARD_PRESENT |\ @@ -694,7 +690,6 @@ uint8_t PC_TO_RDR_SetDataRateAndClockFrequency(void) uint8_t PC_TO_RDR_Secure(void) { uint8_t error; - uint8_t bBWI; uint16_t wLevelParameter; uint32_t responseLen; @@ -708,14 +703,13 @@ uint8_t PC_TO_RDR_Secure(void) return error; } - bBWI = G_io_ccid.bulk_header.bulkout.bSpecific_0; wLevelParameter = (G_io_ccid.bulk_header.bulkout.bSpecific_1 + ((uint16_t)G_io_ccid.bulk_header.bulkout.bSpecific_2<<8)); if ((EXCHANGE_LEVEL_FEATURE == TPDU_EXCHANGE) || (EXCHANGE_LEVEL_FEATURE == SHORT_APDU_EXCHANGE)) { /* TPDU level & short APDU level, wLevelParameter is RFU, = 0000h */ - if (wLevelParameter != 0 ) + if (wLevelParameter != 0) { G_io_ccid.bulk_header.bulkin.dwLength = 0; CCID_UpdateCommandStatus(BM_COMMAND_STATUS_FAILED, BM_ICC_PRESENT_ACTIVE); @@ -724,8 +718,7 @@ uint8_t PC_TO_RDR_Secure(void) } } - error = SC_Secure(G_io_ccid.bulk_header.bulkout.dwLength - CCID_HEADER_SIZE, bBWI, wLevelParameter, - &G_io_ccid_data_buffer[0], &responseLen); + error = SC_Secure(&G_io_ccid_data_buffer[0], &responseLen); G_io_ccid.bulk_header.bulkin.dwLength = responseLen; diff --git a/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c b/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c index ef0302615..fc05b9466 100644 --- a/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c +++ b/lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c @@ -206,6 +206,7 @@ void CCID_BulkMessage_Out (USBD_HandleTypeDef *pdev, G_io_ccid.Ccid_BulkState = CCID_STATE_IDLE; // no break is intentional + __attribute__((fallthrough)); case CCID_STATE_IDLE: // prepare to receive another packet later on (to avoid troubles with timeout due to other hid command timeouting the ccid endpoint reply) USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE); @@ -525,35 +526,39 @@ uint8_t SC_SetDataRateAndClockFrequency(uint32_t dwClockFrequency, UNUSED(dwDataRate); return SLOT_NO_ERROR; } -uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter, - uint8_t* pbuf, uint32_t* returnLen ) { - UNUSED(bBWI); - UNUSED(wLevelParameter); - UNUSED(returnLen); - // return SLOTERROR_CMD_NOT_SUPPORTED; - uint16_t ret_len,off; +uint8_t SC_Secure(uint8_t* pbuf, uint32_t* returnLen) { + // Extract the APDU to send to the App switch(pbuf[0]) { - case 0: // verify pin - ret_len = dwLength - 15; - memmove(G_io_apdu_buffer, pbuf+15, dwLength-15); + case PIN_OPR_VERIFICATION: + // CCID Spec: APDU starts at offset 25, after the 10-Byte header + pbuf += 15; break; - case 1: // modify pin + case PIN_OPR_MODIFICATION: + // CCID Spec: APDU starts at offset 28, 29 or 30 + // depending on the nb of messages to display switch(pbuf[11]) { - case 3: - off = 20; + case 0: + // CCID Spec: No message to display + // APDU starts at offset 28, after the 10-Byte header + pbuf += 18; break; - case 2: case 1: - off = 19; + case 2: + // CCID Spec: 1 or 2 message(s) to display + // APDU starts at offset 29, after the 10-Byte header + pbuf += 19; break; - // 0 and 4-0xFF - default: - off = 18; + case 3: + // CCID Spec: 3 messages to display + // APDU starts at offset 30, after the 10-Byte header + pbuf += 20; break; + default: // unsupported + G_io_ccid.bulk_header.bulkin.dwLength = 0; + RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED); + CCID_Send_Reply(&USBD_Device); + return SLOTERROR_CMD_NOT_SUPPORTED; } - ret_len = dwLength-off; - // provide with the complete apdu - memmove(G_io_apdu_buffer, pbuf+off, dwLength-off); break; default: // unsupported G_io_ccid.bulk_header.bulkin.dwLength = 0; @@ -561,13 +566,15 @@ uint8_t SC_Secure(uint32_t dwLength, uint8_t bBWI, uint16_t wLevelParameter, CCID_Send_Reply(&USBD_Device); return SLOTERROR_CMD_NOT_SUPPORTED; } - return SC_XferBlock(G_io_apdu_buffer, ret_len, &ret_len); + // Change APDU CLA to be interpreted by the CCID compatible App (like OpenPGP) + pbuf[0] = PIN_OPR_APDU_CLA; + // The APDU has no data, only the header (size 5) + *returnLen = 5; + return SC_XferBlock(pbuf, *returnLen); } // prepare the apdu to be processed by the application -uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen, uint16_t* expectedLen) { - UNUSED(expectedLen); - +uint8_t SC_XferBlock (uint8_t* ptrBlock, uint32_t blockLen) { // check for overflow if (blockLen > IO_APDU_BUFFER_SIZE) { return SLOTERROR_BAD_LENTGH; @@ -614,11 +621,10 @@ void io_usb_ccid_set_card_inserted(unsigned int inserted) { #endif // HAVE_CCID_INTERRUPT } - - - - - +void io_usb_ccid_configure_pinpad(uint8_t enabled) { + const volatile uint8_t *cfgDesc = USBD_GetPinPadOffset(); + nvm_write((void *)cfgDesc, &enabled, 1); +} #endif // HAVE_USB_CLASS_CCID diff --git a/lib_stusb/usbd_conf.h b/lib_stusb/usbd_conf.h index c58b7f73e..886496c86 100644 --- a/lib_stusb/usbd_conf.h +++ b/lib_stusb/usbd_conf.h @@ -167,6 +167,7 @@ typedef unsigned short uint16_t; void *USBD_static_malloc(uint32_t size); void USBD_static_free(void *p); +const volatile uint8_t *USBD_GetPinPadOffset(void); void USB_power(unsigned char enabled); diff --git a/lib_stusb_impl/usbd_impl.c b/lib_stusb_impl/usbd_impl.c index 7fdfac406..70b6c6d65 100644 --- a/lib_stusb_impl/usbd_impl.c +++ b/lib_stusb_impl/usbd_impl.c @@ -353,21 +353,34 @@ static uint8_t const HID_ReportDesc_fido[] = { #define ARRAY_U2LE(l) (l)&0xFF, (l)>>8 +#define CFG_HDR_LEN (0x9) +#define CFG_HIDGEN_LEN (0x9+0x9+0x7+0x7) +#define CFG_IO_U2F_LEN (0x9+0x9+0x7+0x7) +#define CFG_USB_CCID_LEN (0x9+0x36+0x7+0x7) +#define CFG_WEBUSB_LEN (0x9+0x7+0x7) + /* USB HID device Configuration Descriptor */ +#ifdef HAVE_USB_CLASS_CCID +// Note: keeping const qualifier to ensure the good section is used by the linker. +// This table is mapped in NVRAM section and therefore it is correctly initialized, +// normal Read is possible and Write can be done through nvm_write() calls. +static __ALIGN_BEGIN uint8_t const N_USBD_CfgDesc[] __ALIGN_END = +#else static __ALIGN_BEGIN uint8_t const USBD_CfgDesc[] __ALIGN_END = +#endif // HAVE_USB_CLASS_CCID { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ - ARRAY_U2LE(0x9 /* wTotalLength: Bytes returned */ - +0x9+0x9+0x7+0x7 + ARRAY_U2LE(CFG_HDR_LEN /* wTotalLength: Bytes returned */ + +CFG_HIDGEN_LEN #ifdef HAVE_IO_U2F - +0x9+0x9+0x7+0x7 + +CFG_IO_U2F_LEN #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID - +0x9+0x36+0x7+0x7 + +CFG_USB_CCID_LEN #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB - +0x9+0x7+0x7 + +CFG_WEBUSB_LEN #endif // HAVE_WEBUSB ), 1 @@ -870,8 +883,13 @@ static uint8_t *USBD_GetDeviceQualifierDesc_impl(uint16_t *length) */ static uint8_t *USBD_GetCfgDesc_impl(uint16_t *length) { +#ifdef HAVE_USB_CLASS_CCID + *length = sizeof(N_USBD_CfgDesc); + return (uint8_t *) N_USBD_CfgDesc; +#else *length = sizeof(USBD_CfgDesc); return (uint8_t *) USBD_CfgDesc; +#endif } uint8_t *USBD_HID_GetHidDescriptor_impl(uint16_t *len) @@ -927,6 +945,34 @@ uint8_t *USBD_HID_GetReportDescriptor_impl(uint16_t *len) return 0; } +#ifdef HAVE_USB_CLASS_CCID +/** + * @brief Returns the pinpad value offset in the descriptor. + * @retval Offset + */ +const volatile uint8_t *USBD_GetPinPadOffset(void) +{ + unsigned short length = 0; + uint8_t *cfgDesc = NULL; + unsigned short offset = 0; + + cfgDesc = USBD_GetCfgDesc_impl(&length); + + offset = CFG_HDR_LEN + CFG_HIDGEN_LEN; +#ifdef HAVE_IO_U2F + offset += CFG_IO_U2F_LEN; +#endif // HAVE_IO_U2F + // Offset of the parameter 'bPINSupport' inside the CCID interface structure in N_USBD_CfgDesc + offset += 61; + + // Returns a const volatile pointer allowing callers to do + // - write operations through nvram_write + // - read operation without potential compilation optimization issue thanks to the volatile + // qualifier. + return (const volatile uint8_t *) (cfgDesc + offset); +} +#endif // HAVE_USB_CLASS_CCID + /** * @} */