2 * Implementation of T=1
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
7 * Copyright (C) 2004 Ludovic Rousseau <ludovic.rousseau@free.fr>
13 #include <ifdhandler.h>
27 #define T1_I_SEQ_SHIFT 6
30 #define T1_IS_ERROR(pcb) ((pcb) & 0x0F)
31 #define T1_EDC_ERROR 0x01
32 #define T1_OTHER_ERROR 0x02
33 #define T1_R_SEQ_SHIFT 4
36 #define T1_S_IS_RESPONSE(pcb) ((pcb) & T1_S_RESPONSE)
37 #define T1_S_TYPE(pcb) ((pcb) & 0x0F)
38 #define T1_S_RESPONSE 0x20
39 #define T1_S_RESYNC 0x00
41 #define T1_S_ABORT 0x02
44 #define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
56 /* internal state, do not mess with it. */
57 /* should be != DEAD after reset/init */
59 SENDING, RECEIVING, RESYNCH, DEAD
62 static void t1_set_checksum(t1_state_t *, int);
63 static unsigned int t1_block_type(unsigned char);
64 static unsigned int t1_seq(unsigned char);
65 static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
66 static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
67 static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
68 static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
71 * Set default T=1 protocol parameters
73 static void t1_set_defaults(t1_state_t * t1)
76 /* This timeout is rather insane, but we need this right now
77 * to support cryptoflex keygen */
85 static void t1_set_checksum(t1_state_t * t1, int csum)
88 case IFD_PROTOCOL_T1_CHECKSUM_LRC:
90 t1->checksum = csum_lrc_compute;
92 case IFD_PROTOCOL_T1_CHECKSUM_CRC:
94 t1->checksum = csum_crc_compute;
102 int t1_init(t1_state_t * t1, int lun)
105 t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
106 t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
107 t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
117 void t1_release(/*@unused@*/ t1_state_t * t1)
124 * Get/set parmaters for T1 protocol
126 int t1_set_param(t1_state_t * t1, int type, long value)
129 case IFD_PROTOCOL_T1_CHECKSUM_LRC:
130 case IFD_PROTOCOL_T1_CHECKSUM_CRC:
131 t1_set_checksum(t1, type);
133 case IFD_PROTOCOL_T1_IFSC:
136 case IFD_PROTOCOL_T1_IFSD:
139 case IFD_PROTOCOL_T1_STATE:
142 case IFD_PROTOCOL_T1_MORE:
146 DEBUG_INFO2("Unsupported parameter %d", type);
154 * Send an APDU through T=1
156 int t1_transceive(t1_state_t * t1, unsigned int dad,
157 const void *snd_buf, size_t snd_len,
158 void *rcv_buf, size_t rcv_len)
160 ct_buf_t sbuf, rbuf, tbuf;
161 unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
162 unsigned int slen, retries, resyncs;
163 size_t last_send = 0;
168 /* we can't talk to a dead card / reader. Reset it! */
169 if (t1->state == DEAD)
171 DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
176 retries = t1->retries;
179 /* Initialize send/recv buffer */
180 ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
181 ct_buf_init(&rbuf, rcv_buf, rcv_len);
183 /* Send the first block */
184 slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
192 n = t1_xcv(t1, sdata, slen, sizeof(sdata));
195 DEBUG_COMM("Parity error");
196 /* ISO 7816-3 Rule 7.4.2 */
200 /* ISO 7816-3 Rule 7.2 */
201 if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
203 DEBUG_COMM("Rule 7.2");
204 slen = t1_rebuild(t1, sdata);
208 slen = t1_build(t1, sdata,
209 dad, T1_R_BLOCK | T1_EDC_ERROR,
215 DEBUG_CRITICAL("fatal: transmit/receive failed");
220 if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
221 || (sdata[LEN] == 0xFF)) /* length == 0xFF (illegal) */
223 DEBUG_COMM("R-BLOCK required");
224 /* ISO 7816-3 Rule 7.4.2 */
228 /* ISO 7816-3 Rule 7.2 */
229 if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
231 DEBUG_COMM("Rule 7.2");
232 slen = t1_rebuild(t1, sdata);
236 slen = t1_build(t1, sdata,
237 dad, T1_R_BLOCK | T1_OTHER_ERROR,
242 if (!t1_verify_checksum(t1, sdata, n)) {
243 DEBUG_COMM("checksum failed");
244 /* ISO 7816-3 Rule 7.4.2 */
248 /* ISO 7816-3 Rule 7.2 */
249 if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
251 DEBUG_COMM("Rule 7.2");
252 slen = t1_rebuild(t1, sdata);
256 slen = t1_build(t1, sdata,
257 dad, T1_R_BLOCK | T1_EDC_ERROR,
263 switch (t1_block_type(pcb)) {
265 if ((sdata[LEN] != 0x00) /* length != 0x00 (illegal) */
266 || (pcb & 0x20) /* b6 of pcb is set */
269 DEBUG_COMM("R-Block required");
270 /* ISO 7816-3 Rule 7.4.2 */
274 /* ISO 7816-3 Rule 7.2 */
275 if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
277 DEBUG_COMM("Rule 7.2");
278 slen = t1_rebuild(t1, sdata);
282 slen = t1_build(t1, sdata,
283 dad, T1_R_BLOCK | T1_OTHER_ERROR,
288 if (((t1_seq(pcb) != t1->ns) /* wrong sequence number & no bit more */
292 DEBUG_COMM4("received: %d, expected: %d, more: %d",
293 t1_seq(pcb), t1->ns, t1->more);
295 /* ISO 7816-3 Rule 7.4.2 */
299 /* ISO 7816-3 Rule 7.2 */
300 if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
302 DEBUG_COMM("Rule 7.2");
303 slen = t1_rebuild(t1, sdata);
307 DEBUG_COMM("R-Block required");
308 slen = t1_build(t1, sdata,
309 dad, T1_R_BLOCK | T1_OTHER_ERROR,
314 if (t1->state == RECEIVING) {
315 /* ISO 7816-3 Rule 7.2 */
316 if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
318 /* ISO 7816-3 Rule 7.4.2 */
322 DEBUG_COMM("Rule 7.2");
323 slen = t1_rebuild(t1, sdata);
328 slen = t1_build(t1, sdata,
334 /* If the card terminal requests the next
335 * sequence number, it received the previous
336 * block successfully */
337 if (t1_seq(pcb) != t1->ns) {
338 ct_buf_get(&sbuf, NULL, last_send);
343 /* If there's no data available, the ICC
344 * shouldn't be asking for more */
345 if (ct_buf_avail(&sbuf) == 0)
348 slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
353 /* The first I-block sent by the ICC indicates
354 * the last block we sent was received successfully. */
355 if (t1->state == SENDING) {
357 ct_buf_get(&sbuf, NULL, last_send);
362 t1->state = RECEIVING;
364 /* If the block sent by the card doesn't match
365 * what we expected it to send, reply with
367 if (t1_seq(pcb) != t1->nr) {
368 DEBUG_COMM("wrong nr");
370 /* ISO 7816-3 Rule 7.4.2 */
374 slen = t1_build(t1, sdata, dad,
375 T1_R_BLOCK | T1_OTHER_ERROR,
382 if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
384 DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
388 if ((pcb & T1_MORE_BLOCKS) == 0)
391 slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
395 if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
396 /* ISO 7816-3 Rule 6.2 */
397 DEBUG_COMM("S-Block answer received");
398 /* ISO 7816-3 Rule 6.3 */
402 retries = t1->retries;
403 ct_buf_init(&rbuf, rcv_buf, rcv_len);
404 slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
409 if (T1_S_IS_RESPONSE(pcb))
411 /* ISO 7816-3 Rule 7.4.2 */
415 /* ISO 7816-3 Rule 7.2 */
416 if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
418 DEBUG_COMM("Rule 7.2");
419 slen = t1_rebuild(t1, sdata);
423 DEBUG_CRITICAL("wrong response S-BLOCK received");
424 slen = t1_build(t1, sdata,
425 dad, T1_R_BLOCK | T1_OTHER_ERROR,
430 ct_buf_init(&tbuf, sblk, sizeof(sblk));
432 DEBUG_COMM("S-Block request received");
433 switch (T1_S_TYPE(pcb)) {
437 DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
438 slen = t1_build(t1, sdata, dad,
439 T1_R_BLOCK | T1_OTHER_ERROR,
444 DEBUG_COMM("Resync requested");
445 /* the card is not allowed to send a resync. */
451 DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
452 slen = t1_build(t1, sdata, dad,
453 T1_R_BLOCK | T1_OTHER_ERROR,
458 /* ISO 7816-3 Rule 9 */
459 DEBUG_CRITICAL("abort requested");
465 DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
466 slen = t1_build(t1, sdata, dad,
467 T1_R_BLOCK | T1_OTHER_ERROR,
472 DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
473 if (sdata[DATA] == 0)
475 t1->ifsc = sdata[DATA];
476 ct_buf_putc(&tbuf, sdata[DATA]);
482 DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
483 slen = t1_build(t1, sdata, dad,
484 T1_R_BLOCK | T1_OTHER_ERROR,
489 DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
490 t1->wtx = sdata[DATA];
491 ct_buf_putc(&tbuf, sdata[DATA]);
495 DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
499 slen = t1_build(t1, sdata, dad,
500 T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
504 /* Everything went just splendid */
505 retries = t1->retries;
509 /* the number or resyncs is limited, too */
510 /* ISO 7816-3 Rule 6.4 */
514 /* ISO 7816-3 Rule 6 */
518 slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
527 return ct_buf_avail(&rbuf);
534 static unsigned t1_block_type(unsigned char pcb)
536 switch (pcb & 0xC0) {
546 static unsigned int t1_seq(unsigned char pcb)
548 switch (pcb & 0xC0) {
550 return (pcb >> T1_R_SEQ_SHIFT) & 1;
554 return (pcb >> T1_I_SEQ_SHIFT) & 1;
558 unsigned int t1_build(t1_state_t * t1, unsigned char *block,
559 unsigned char dad, unsigned char pcb,
560 ct_buf_t *bp, size_t *lenp)
565 len = bp ? ct_buf_avail(bp) : 0;
566 if (len > t1->ifsc) {
567 pcb |= T1_MORE_BLOCKS;
572 /* Add the sequence number */
573 switch (t1_block_type(pcb)) {
575 pcb |= t1->nr << T1_R_SEQ_SHIFT;
578 pcb |= t1->ns << T1_I_SEQ_SHIFT;
580 DEBUG_COMM2("more bit: %d", more);
589 memcpy(block + 3, ct_buf_head(bp), len);
593 len = t1_compute_checksum(t1, block, len + 3);
595 /* memorize the last sent block */
596 /* only 4 bytes since we are only interesed in R-blocks */
597 memcpy(t1->previous_block, block, 4);
603 t1_rebuild(t1_state_t *t1, unsigned char *block)
605 unsigned char pcb = t1 -> previous_block[1];
607 /* copy the last sent block */
608 if (T1_R_BLOCK == t1_block_type(pcb))
609 memcpy(block, t1 -> previous_block, 4);
612 DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
620 * Build/verify checksum
622 static unsigned int t1_compute_checksum(t1_state_t * t1,
623 unsigned char *data, size_t len)
625 return len + t1->checksum(data, len, data + len);
628 static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
631 unsigned char csum[2];
634 m = len - t1->rc_bytes;
640 t1->checksum(rbuf, m, csum);
641 if (!memcmp(rbuf + m, csum, n))
650 static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
654 _ccid_descriptor *ccid_desc ;
656 unsigned int rmax_int;
658 DEBUG_XXD("sending: ", block, slen);
660 ccid_desc = get_ccid_descriptor(t1->lun);
661 oldReadTimeout = ccid_desc->readTimeout;
665 /* set the new temporary timeout at WTX card request */
666 ccid_desc->readTimeout *= t1->wtx;
667 DEBUG_INFO2("New timeout at WTX request: %d sec",
668 ccid_desc->readTimeout);
671 if (isCharLevel(t1->lun))
675 n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
676 if (n != IFD_SUCCESS)
679 /* the second argument of CCID_Receive() is (unsigned int *)
680 * so we can't use &rmax since &rmax is a (size_t *) and may not
681 * be the same on 64-bits architectures for example (iMac G5) */
683 n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
685 if (n == IFD_PARITY_ERROR)
687 if (n != IFD_SUCCESS)
692 n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
693 if (n != IFD_SUCCESS)
697 n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
699 if (n == IFD_PARITY_ERROR)
701 if (n != IFD_SUCCESS)
708 n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);
709 t1->wtx = 0; /* reset to default value */
710 if (n != IFD_SUCCESS)
713 /* Get the response en bloc */
715 n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
717 if (n == IFD_PARITY_ERROR)
719 if (n != IFD_SUCCESS)
729 m = block[2] + 3 + t1->rc_bytes;
735 DEBUG_XXD("received: ", block, n);
737 /* Restore initial timeout */
738 ccid_desc->readTimeout = oldReadTimeout;
743 int t1_negotiate_ifsd(t1_state_t * t1, unsigned int dad, int ifsd)
746 unsigned char sdata[T1_BUFFER_SIZE];
748 unsigned int retries;
751 unsigned char snd_buf[1];
753 retries = t1->retries;
755 /* S-block IFSD request */
759 /* Initialize send/recv buffer */
760 ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
764 /* Build the block */
765 slen = t1_build(t1, sdata, 0, T1_S_BLOCK | T1_S_IFS, &sbuf, NULL);
768 n = t1_xcv(t1, sdata, slen, sizeof(sdata));
771 /* ISO 7816-3 Rule 7.4.2 */
777 DEBUG_CRITICAL("fatal: transmit/receive failed");
781 if ((-2 == n) /* Parity error */
782 || (sdata[DATA] != ifsd) /* Wrong ifsd received */
783 || (sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
784 || (!t1_verify_checksum(t1, sdata, n)) /* checksum failed */
785 || (n != 4 + (int)t1->rc_bytes) /* wrong frame length */
786 || (sdata[LEN] != 1) /* wrong data length */
787 || (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE | T1_S_IFS))) /* wrong PCB */