Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B2CA-969: Activate pinpad and fix CCID SC_Secure #499

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/sc_itf.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,15 @@ 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,
uint8_t bClassEnvelope);
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

Expand Down
10 changes: 10 additions & 0 deletions lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/usbd_ccid_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down
35 changes: 14 additions & 21 deletions lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 |\
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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;

Expand Down
66 changes: 36 additions & 30 deletions lib_stusb/STM32_USB_Device_Library/Class/CCID/src/usbd_ccid_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -525,49 +526,55 @@ 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;
RDR_to_PC_DataBlock(SLOTERROR_CMD_NOT_SUPPORTED);
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;
Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions lib_stusb/usbd_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
56 changes: 51 additions & 5 deletions lib_stusb_impl/usbd_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
cedelavergne-ledger marked this conversation as resolved.
Show resolved Hide resolved
// 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 =
cedelavergne-ledger marked this conversation as resolved.
Show resolved Hide resolved
#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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
cedelavergne-ledger marked this conversation as resolved.
Show resolved Hide resolved

// 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

/**
* @}
*/
Expand Down