[Pcsclite-cvs-commit] CVS Drivers/ccid/src
CVS User rousseau
ludovic.rousseau@free.fr
Tue, 19 Oct 2004 01:22:06 -0600
Update of /cvsroot/pcsclite/Drivers/ccid/src
In directory haydn:/tmp/cvs-serv9364
Modified Files:
commands.c commands.h
Log Message:
Add support of character level communication (CCID_CLASS_CHARACTER).
Thanks to Jeffrey Dai
--- /cvsroot/pcsclite/Drivers/ccid/src/commands.c 2004/09/30 14:00:13 1.32
+++ /cvsroot/pcsclite/Drivers/ccid/src/commands.c 2004/10/19 07:22:06 1.33
@@ -1,6 +1,6 @@
/*
commands.c: Commands sent to the card
- Copyright (C) 2003 Ludovic Rousseau
+ Copyright (C) 2003-2004 Ludovic Rousseau
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
*/
/*
- * $Id: commands.c,v 1.32 2004/09/30 14:00:13 rousseau Exp $
+ * $Id: commands.c,v 1.33 2004/10/19 07:22:06 rousseau Exp $
*/
#include <string.h>
@@ -52,6 +52,10 @@
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
unsigned char rx_buffer[]);
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index, unsigned int
+ tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned
+ char rx_buffer[]);
+
static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
unsigned char rx_buffer[]);
@@ -418,6 +422,18 @@
tx_length, tx_buffer, rx_length, rx_buffer);
break;
+ case CCID_CLASS_CHARACTER:
+ if (protocol == T_0)
+ return_value = CmdXfrBlockCHAR_T0(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ if (protocol == T_1)
+ return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+ break;
+
default:
*rx_length = 0;
return_value = IFD_COMMUNICATION_ERROR;
@@ -434,7 +450,7 @@
*
****************************************************************************/
RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
- const unsigned char tx_buffer[], unsigned char bBWI)
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI)
{
unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
@@ -444,7 +460,8 @@
cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
cmd[6] = (*ccid_descriptor->pbSeq)++;
cmd[7] = bBWI; /* extend block waiting timeout */
- cmd[8] = cmd[9] = 0; /* RFU */
+ cmd[8] = rx_length & 0xFF; /* Expected length */
+ cmd[9] = (rx_length >> 8) & 0xFF;
memcpy(cmd+10, tx_buffer, tx_length);
if (WritePort(reader_index, 10+tx_length, cmd) != STATUS_SUCCESS)
@@ -513,16 +530,336 @@
DEBUG_COMM2("T=0: %d bytes", tx_length);
- return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0);
+ return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0, 0);
if (return_value != IFD_SUCCESS)
return return_value;
-
+
return CCID_Receive(reader_index, rx_length, rx_buffer);
} /* CmdXfrBlockTPDU_T0 */
/*****************************************************************************
*
+ * T0CmdParsing
+ *
+ ****************************************************************************/
+static RESPONSECODE T0CmdParsing(unsigned char *cmd, unsigned int cmd_len,
+ unsigned int *exp_len)
+{
+ *exp_len = 0;
+
+ /* Ref: 7816-4 Annex A */
+ switch (cmd_len)
+ {
+ case 4: /* Case 1 */
+ *exp_len = 2; /* SW1 and SW2 only */
+ break;
+
+ case 5: /* Case 2 */
+ if (cmd[4] != 0)
+ *exp_len = cmd[4] + 2;
+ else
+ *exp_len = 256 + 2;
+ break;
+
+ default: /* Case 3 */
+ if (cmd_len > 5 && cmd_len == (unsigned int)(cmd[4] + 5))
+ *exp_len = 2; /* SW1 and SW2 only */
+ else
+ return IFD_COMMUNICATION_ERROR; /* situation not supported */
+ break;
+ }
+
+ return IFD_SUCCESS;
+} /* T0CmdParsing */
+
+
+/*****************************************************************************
+ *
+ * T0ProcACK
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcACK(unsigned int reader_index,
+ unsigned char **snd_buf, unsigned int *snd_len,
+ unsigned char **rcv_buf, unsigned int *rcv_len,
+ unsigned char **in_buf, unsigned int *in_len,
+ unsigned int proc_len, int is_rcv)
+{
+ RESPONSECODE return_value;
+ unsigned int remain_len;
+ unsigned char tmp_buf[512];
+ unsigned int ret_len;
+
+ DEBUG_COMM2("Enter, is_rcv = %d", is_rcv);
+
+ if (is_rcv == 1)
+ { /* Receiving mode */
+ if (*in_len > 0)
+ { /* There are still available data in our buffer */
+ if (*in_len >= proc_len)
+ {
+ /* We only need to get the data from our buffer */
+ memcpy(*rcv_buf, *in_buf, proc_len);
+ *rcv_buf += proc_len;
+ *in_buf += proc_len;
+ *rcv_len += proc_len;
+ *in_len -= proc_len;
+
+ return IFD_SUCCESS;
+ }
+ else
+ {
+ /* Move all data in the input buffer to the reply buffer */
+ remain_len = proc_len - *in_len;
+ memcpy(*rcv_buf, *in_buf, *in_len);
+ *rcv_buf += *in_len;
+ *in_buf += *in_len;
+ *rcv_len += *in_len;
+ *in_len = 0;
+ }
+ }
+ else
+ /* There is no data in our tmp_buf,
+ * we have to read all data we needed */
+ remain_len = proc_len;
+
+ /* Read the expected data from the smartcard */
+ if (*in_len != 0)
+ {
+ DEBUG_CRITICAL("*in_len != 0");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memset(tmp_buf, 0, sizeof(tmp_buf));
+
+ ret_len = remain_len;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return_value = CCID_Receive(reader_index, &ret_len, tmp_buf);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ memcpy(*rcv_buf, tmp_buf, remain_len);
+ *rcv_buf += remain_len, *rcv_len += remain_len;
+
+ /* If ret_len != remain_len, our logic is erroneous */
+ if (ret_len != remain_len)
+ {
+ DEBUG_CRITICAL("ret_len != remain_len");
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+ else
+ { /* Sending mode */
+
+ return_value = CCID_Transmit(reader_index, proc_len, *snd_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ *snd_len -= proc_len;
+ *snd_buf += proc_len;
+ }
+
+ DEBUG_COMM("Exit");
+
+ return IFD_SUCCESS;
+} /* T0ProcACK */
+
+
+/*****************************************************************************
+ *
+ * T0ProcSW1
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcSW1(unsigned int reader_index,
+ unsigned char *rcv_buf, unsigned int *rcv_len,
+ unsigned char *in_buf, unsigned int in_len)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ UCHAR tmp_buf[512];
+ unsigned char *rcv_buf_tmp = rcv_buf;
+ const unsigned int rcv_len_tmp = *rcv_len;
+ unsigned char sw1, sw2;
+
+ /* store the SW1 */
+ sw1 = *rcv_buf = *in_buf;
+ rcv_buf++;
+ in_buf++;
+ in_len--;
+ (*rcv_len)++;
+
+ /* store the SW2 */
+ if (0 == in_len)
+ {
+ return_value = CCID_Transmit(reader_index, 0, rcv_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_len = 1;
+
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_buf = tmp_buf;
+ }
+ sw2 = *rcv_buf = *in_buf;
+ rcv_buf++;
+ in_buf++;
+ in_len--;
+ (*rcv_len)++;
+
+ if (return_value != IFD_SUCCESS)
+ {
+ rcv_buf_tmp[0] = rcv_buf_tmp[1] = 0;
+ *rcv_len = rcv_len_tmp;
+ }
+
+ DEBUG_COMM3("Exit: SW=%02X %02X", sw1, sw2);
+
+ return return_value;
+} /* T0ProcSW1 */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockCHAR_T0
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index,
+ unsigned int snd_len, unsigned char snd_buf[], unsigned int *rcv_len,
+ unsigned char rcv_buf[])
+{
+ int is_rcv;
+ unsigned char tmp_buf[512];
+ unsigned int exp_len, in_len;
+ unsigned char ins, *in_buf;
+ RESPONSECODE return_value = IFD_SUCCESS;
+
+ DEBUG_COMM2("T=0: %d bytes", snd_len);
+
+ in_buf = tmp_buf;
+ in_len = 0;
+ *rcv_len = 0;
+
+ return_value = T0CmdParsing(snd_buf, snd_len, &exp_len);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("T0CmdParsing failed");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (snd_len == 5 || snd_len == 4)
+ is_rcv = 1;
+ else
+ is_rcv = 0;
+
+ /* Command to send to the smart card (must be 5 bytes, from 7816 p.15) */
+ unsigned char cmd[5];
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* Make sure this is a valid command by checking the INS field */
+ ins = cmd[1];
+ if ((ins & 0xF0) == 0x60 || /* 7816-3 8.3.2 */
+ (ins & 0xF0) == 0x90)
+ {
+ DEBUG_CRITICAL2("fatal: INS (0x%02X) = 0x6X or 0x9X", ins);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return_value = CCID_Transmit(reader_index, 5, cmd, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ while (1)
+ {
+ if (in_len == 0)
+ {
+ in_len = 1;
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("CCID_Receive failed");
+ return return_value;
+ }
+ in_buf = tmp_buf;
+ }
+ if (in_len == 0)
+ {
+ /* Suppose we should be able to get data.
+ * If not, error. Set the time-out error */
+ DEBUG_CRITICAL("error: in_len = 0");
+ return IFD_RESPONSE_TIMEOUT;
+ }
+
+ /* Start to process the procedure bytes */
+ if (*in_buf == 0x60)
+ {
+ in_len = 0;
+ return_value = CCID_Transmit(reader_index, 0, cmd, 1, 0);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == ins || *in_buf == (ins ^ 0x01))
+ {
+ /* ACK => To transfer all remaining data bytes */
+ in_buf++, in_len--;
+ if (is_rcv)
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, exp_len - *rcv_len, 1);
+ else
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, snd_len, 0);
+
+ if (*rcv_len == exp_len)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == (ins ^ 0xFF) || *in_buf == (ins ^ 0xFE))
+ {
+ /* ACK => To transfer 1 remaining bytes */
+ in_buf++, in_len--;
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, 1, is_rcv);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if ((*in_buf & 0xF0) == 0x60 || (*in_buf & 0xF0) == 0x90)
+ /* SW1 */
+ return T0ProcSW1(reader_index, rcv_buf, rcv_len, in_buf, in_len);
+
+ /* Error, unrecognized situation found */
+ DEBUG_CRITICAL2("Unrecognized Procedure byte (0x%02X) found!", *in_buf);
+ return return_value;
+ }
+
+ return return_value;
+} /* CmdXfrBlockCHAR_T0 */
[25 lines skipped]
--- /cvsroot/pcsclite/Drivers/ccid/src/commands.h 2004/07/28 08:33:18 1.12
+++ /cvsroot/pcsclite/Drivers/ccid/src/commands.h 2004/10/19 07:22:06 1.13
@@ -18,7 +18,7 @@
*/
/*
- * $Id: commands.h,v 1.12 2004/07/28 08:33:18 rousseau Exp $
+ * $Id: commands.h,v 1.13 2004/10/19 07:22:06 rousseau Exp $
*/
#define SIZE_GET_SLOT_STATUS 10
@@ -46,7 +46,7 @@
unsigned char rx_buffer[], int protoccol);
RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
- const unsigned char tx_buffer[], unsigned char bBWI);
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI);
RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
unsigned char rx_buffer[]);
@@ -54,3 +54,5 @@
RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
unsigned int length, unsigned char buffer[]);
+int isCharLevel(int reader_index);
+