This adds support for a custom escape command that allows
OmniKey Cardman 3021/3121 (and likely other Omnikey readers)
to handle extended T=1 APDUs.

Note that this patch was written in a way that would minimize
the source changes. It could probably be abstracted away in
a much nicer way.

--- ccid-1.3.11/src/commands.c
+++ ccid-1.3.11/src/commands.c
@@ -81,6 +81,11 @@ enum {
         * Makes us map HW_ERROR to "no card inserted".
         */
        QUIRK_SLOTSTATUS_HWERR = 1,
+
+       /*
+        * Escape for extended APDUs
+        */
+       QUIRK_ESC_T1_TPDU = 2,
 };
 
 struct ccid_quirk {
@@ -102,6 +107,11 @@ static struct ccid_quirk ccid_quirktab[] = {
         */
        { 0x0a5c5800, QUIRK_SLOTSTATUS_HWERR },
        { 0x0a5c5801, QUIRK_SLOTSTATUS_HWERR },
+
+       /*
+        * OmniKey CardMan 3021/3121
+        */
+       { 0x076b3021, QUIRK_ESC_T1_TPDU },
 };
 
 static int ccid_quirk_lookup(_ccid_descriptor *ccid, unsigned int *quirks)
@@ -1144,8 +1154,13 @@ RESPONSECODE CmdXfrBlock(unsigned int reader_index, 
unsigned int tx_length,
                        break;
 
                case CCID_CLASS_SHORT_APDU:
-                       return_value = CmdXfrBlockTPDU_T0(reader_index,
-                               tx_length, tx_buffer, rx_length, rx_buffer);
+                       if (ccid_quirk_required(ccid_descriptor, 
QUIRK_ESC_T1_TPDU) && protocol == T_1)
+                               return_value = CmdXfrBlockTPDU_T1(reader_index, 
tx_length,
+                                               tx_buffer, rx_length, 
rx_buffer);
+                       else
+                               return_value = CmdXfrBlockTPDU_T0(reader_index,
+                                       tx_length, tx_buffer, rx_length, 
rx_buffer);
+
                        break;
 
                case CCID_CLASS_EXTENDED_APDU:
@@ -1181,7 +1196,8 @@ RESPONSECODE CmdXfrBlock(unsigned int reader_index, 
unsigned int tx_length,
 RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
        const unsigned char tx_buffer[], unsigned short rx_length, unsigned 
char bBWI)
 {
-       unsigned char cmd[10+CMD_BUF_SIZE];     /* CCID + APDU buffer */
+       unsigned char cmd[11+CMD_BUF_SIZE];     /* CCID + APDU buffer */
+       size_t cmdlen;
        _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
        status_t ret;
 
@@ -1227,13 +1243,30 @@ RESPONSECODE CCID_Transmit(unsigned int reader_index, 
unsigned int tx_length,
        }
 #endif
 
-       cmd[0] = 0x6F; /* XfrBlock */
-       i2dw(tx_length, cmd+1); /* APDU length */
-       cmd[5] = ccid_descriptor->bCurrentSlotIndex;    /* slot number */
-       cmd[6] = (*ccid_descriptor->pbSeq)++;
-       cmd[7] = bBWI;  /* extend block waiting timeout */
-       cmd[8] = rx_length & 0xFF;      /* Expected length, in character mode 
only */
-       cmd[9] = (rx_length >> 8) & 0xFF;
+       if (ccid_quirk_required(ccid_descriptor, QUIRK_ESC_T1_TPDU) &&
+           ccid_descriptor->cardProtocol == SCARD_PROTOCOL_T1)
+       {
+               cmd[0] = 0x6B;                                  /* Escape */
+               i2dw(tx_length+1, cmd+1);                       /* APDU length 
*/
+               cmd[5] = ccid_descriptor->bCurrentSlotIndex;    /* slot number 
*/
+               cmd[6] = (*ccid_descriptor->pbSeq)++;
+               cmd[7] = cmd[8] = cmd[9] = 0x00;                /* RFU */
+               cmd[10] = 0x1A;                                 /* custom cmd 
"send TPDU" */
+
+               cmdlen = 11;
+       }
+       else
+       {
+               cmd[0] = 0x6F; /* XfrBlock */
+               i2dw(tx_length, cmd+1); /* APDU length */
+               cmd[5] = ccid_descriptor->bCurrentSlotIndex;    /* slot number 
*/
+               cmd[6] = (*ccid_descriptor->pbSeq)++;
+               cmd[7] = bBWI;  /* extend block waiting timeout */
+               cmd[8] = rx_length & 0xFF;      /* Expected length, in 
character mode only */
+               cmd[9] = (rx_length >> 8) & 0xFF;
+
+               cmdlen = 10;
+       }
 
        /* check that the command is not too large */
        if (tx_length > CMD_BUF_SIZE)
@@ -1242,9 +1275,9 @@ RESPONSECODE CCID_Transmit(unsigned int reader_index, 
unsigned int tx_length,
                return IFD_NOT_SUPPORTED;
        }
 
-       memcpy(cmd+10, tx_buffer, tx_length);
+       memcpy(cmd+cmdlen, tx_buffer, tx_length);
 
-       ret = WritePort(reader_index, 10+tx_length, cmd);
+       ret = WritePort(reader_index, cmdlen+tx_length, cmd);
        if (STATUS_NO_SUCH_DEVICE == ret)
                return IFD_NO_SUCH_DEVICE;
        if (ret != STATUS_SUCCESS)
@@ -1262,7 +1295,7 @@ RESPONSECODE CCID_Transmit(unsigned int reader_index, 
unsigned int tx_length,
 RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
        unsigned char rx_buffer[], unsigned char *chain_parameter)
 {
-       unsigned char cmd[10+CMD_BUF_SIZE];     /* CCID + APDU buffer */
+       unsigned char cmd[11+CMD_BUF_SIZE];     /* CCID + APDU buffer */
        unsigned int length;
        RESPONSECODE return_value = IFD_SUCCESS;
        status_t ret;
@@ -1438,8 +1471,13 @@ time_request:
        }
 
        length = dw2i(cmd, 1);
-       if (length <= *rx_length)
+       if (length <= *rx_length) {
                *rx_length = length;
+
+               if (ccid_quirk_required(ccid_descriptor, QUIRK_ESC_T1_TPDU) &&
+                   ccid_descriptor->cardProtocol == SCARD_PROTOCOL_T1)
+                       *rx_length--;
+       }
        else
        {
                DEBUG_CRITICAL2("overrun by %d bytes", length - *rx_length);
@@ -1454,7 +1492,13 @@ time_request:
                return_value = IFD_COMMUNICATION_ERROR;
        }
        else
-               memcpy(rx_buffer, cmd+10, length);
+       {
+               if (ccid_quirk_required(ccid_descriptor, QUIRK_ESC_T1_TPDU) &&
+                   ccid_descriptor->cardProtocol == SCARD_PROTOCOL_T1)
+                       memcpy(rx_buffer, cmd+11, length-1);
+               else
+                       memcpy(rx_buffer, cmd+10, length);
+       }
 
        /* Extended case?
         * Only valid for RDR_to_PC_DataBlock frames */
@@ -1636,6 +1680,12 @@ static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int 
reader_index,
                }
                else
 #endif
+               if (ccid_quirk_required(ccid_descriptor, QUIRK_ESC_T1_TPDU))
+               {
+                       DEBUG_CRITICAL3("Ignoring dwMaxCCDMessageLength (tx=%d, 
max=%d)",
+                               tx_length, 
ccid_descriptor->dwMaxCCIDMessageLength-10);
+               }
+               else
                {
                        DEBUG_CRITICAL3("Command too long (%d bytes) for max: 
%d bytes",
                                tx_length, 
ccid_descriptor->dwMaxCCIDMessageLength-10);
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle

Reply via email to