aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2011-12-05 03:00:14 +0000
committerNIIBE Yutaka <[email protected]>2011-12-05 03:00:14 +0000
commit37fadead90e985b544c9f817cf7c7b0ada797d3c (patch)
tree0da754178f257859dbe53db3854e7570d008f0a4
parentSupport the Cherry ST-2000 card reader. (diff)
downloadgnupg-37fadead90e985b544c9f817cf7c7b0ada797d3c.tar.gz
gnupg-37fadead90e985b544c9f817cf7c7b0ada797d3c.zip
Support extended APDU exchange level somehow.
* ccid-driver.c (ccid_transceive_apdu_level): Permit sending packet where apdulen <= 289. Support receiving packets in a chain.
-rw-r--r--scd/ccid-driver.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 7338ccc6f..5755b07f1 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -2590,8 +2590,8 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
/* The maximum length for a short APDU T=1 block is 261. For an
extended APDU T=1 block the maximum length 65544; however
- extended APDU exchange level is not yet supported. */
- if (apdulen > 261)
+ extended APDU exchange level is not fully supported yet. */
+ if (apdulen > 289)
return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
msg[0] = PC_to_RDR_XfrBlock;
@@ -2614,8 +2614,51 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
if (rc)
return rc;
- apdu = msg + 10;
- apdulen = msglen - 10;
+ if (msg[9] == 1)
+ {
+ size_t total_msglen = msglen;
+
+ while (1)
+ {
+ unsigned char status;
+
+ msg = recv_buffer + total_msglen;
+
+ msg[0] = PC_to_RDR_XfrBlock;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = bwi; /* bBWI */
+ msg[8] = 0x10; /* Request next data block */
+ msg[9] = 0;
+ set_msg_len (msg, 0);
+ msglen = 10;
+
+ rc = bulk_out (handle, msg, msglen, 0);
+ if (rc)
+ return rc;
+
+ rc = bulk_in (handle, msg, sizeof recv_buffer - total_msglen, &msglen,
+ RDR_to_PC_DataBlock, seqno, 5000, 0);
+ if (rc)
+ return rc;
+ status = msg[9];
+ memmove (msg, msg+10, msglen - 10);
+ total_msglen += msglen - 10;
+ if (total_msglen >= sizeof recv_buffer)
+ return CCID_DRIVER_ERR_OUT_OF_CORE;
+
+ if (status == 0x02)
+ break;
+ }
+
+ apdu = recv_buffer + 10;
+ apdulen = total_msglen - 10;
+ }
+ else
+ {
+ apdu = msg + 10;
+ apdulen = msglen - 10;
+ }
if (resp)
{