1 /* ccidmon.c - CCID monitor for use with the Linux usbmon facility.
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* This utility takes the output of usbmon, filters out the bulk data
22 and prints the CCID messages in a human friendly way.
41 #ifndef PACKAGE_VERSION
42 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
44 #ifndef PACKAGE_BUGREPORT
45 # define PACKAGE_BUGREPORT "devnull@example.org"
52 static int skip_escape
;
53 static int usb_bus
, usb_dev
;
71 RDR_to_PC_NotifySlotChange
= 0x50,
72 RDR_to_PC_HardwareError
= 0x51,
74 PC_to_RDR_SetParameters
= 0x61,
75 PC_to_RDR_IccPowerOn
= 0x62,
76 PC_to_RDR_IccPowerOff
= 0x63,
77 PC_to_RDR_GetSlotStatus
= 0x65,
78 PC_to_RDR_Secure
= 0x69,
79 PC_to_RDR_T0APDU
= 0x6a,
80 PC_to_RDR_Escape
= 0x6b,
81 PC_to_RDR_GetParameters
= 0x6c,
82 PC_to_RDR_ResetParameters
= 0x6d,
83 PC_to_RDR_IccClock
= 0x6e,
84 PC_to_RDR_XfrBlock
= 0x6f,
85 PC_to_RDR_Mechanical
= 0x71,
86 PC_to_RDR_Abort
= 0x72,
87 PC_to_RDR_SetDataRate
= 0x73,
89 RDR_to_PC_DataBlock
= 0x80,
90 RDR_to_PC_SlotStatus
= 0x81,
91 RDR_to_PC_Parameters
= 0x82,
92 RDR_to_PC_Escape
= 0x83,
93 RDR_to_PC_DataRate
= 0x84
97 #define digitp(p) ((p) >= '0' && (p) <= '9')
98 #define hexdigitp(a) (digitp (a) \
99 || ((a) >= 'A' && (a) <= 'F') \
100 || ((a) >= 'a' && (a) <= 'f'))
101 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
102 #define xtoi_1(p) ((p) <= '9'? ((p)- '0'): \
103 (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
107 /* Print diagnostic message and exit with failure. */
109 die (const char *format
, ...)
114 fprintf (stderr
, "%s: ", PGM
);
116 va_start (arg_ptr
, format
);
117 vfprintf (stderr
, format
, arg_ptr
);
125 /* Print diagnostic message. */
127 err (const char *format
, ...)
134 fprintf (stderr
, "%s: ", PGM
);
136 va_start (arg_ptr
, format
);
137 vfprintf (stderr
, format
, arg_ptr
);
143 /* Convert a little endian stored 4 byte value into an unsigned
146 convert_le_u32 (const unsigned char *buf
)
148 return buf
[0] | (buf
[1] << 8) | (buf
[2] << 16) | (buf
[3] << 24);
152 /* Convert a little endian stored 2 byte value into an unsigned
155 convert_le_u16 (const unsigned char *buf
)
157 return buf
[0] | (buf
[1] << 8);
164 print_pr_data (const unsigned char *data
, size_t datalen
, size_t off
)
169 for (; off
< datalen
; off
++)
171 if (!(off
% 16) || first
)
175 printf (" [%04d] ", off
);
177 printf (" %02X", data
[off
]);
187 print_p2r_header (const char *name
, const unsigned char *msg
, size_t msglen
)
189 printf ("%s:\n", name
);
192 printf (" dwLength ..........: %u\n", convert_le_u32 (msg
+1));
193 printf (" bSlot .............: %u\n", msg
[5]);
194 printf (" bSeq ..............: %u\n", msg
[6]);
199 print_p2r_iccpoweron (const unsigned char *msg
, size_t msglen
)
201 print_p2r_header ("PC_to_RDR_IccPowerOn", msg
, msglen
);
204 printf (" bPowerSelect ......: 0x%02x (%s)\n", msg
[7],
206 msg
[7] == 1? "5.0 V":
207 msg
[7] == 2? "3.0 V":
208 msg
[7] == 3? "1.8 V":"");
209 print_pr_data (msg
, msglen
, 8);
214 print_p2r_iccpoweroff (const unsigned char *msg
, size_t msglen
)
216 print_p2r_header ("PC_to_RDR_IccPowerOff", msg
, msglen
);
217 print_pr_data (msg
, msglen
, 7);
222 print_p2r_getslotstatus (const unsigned char *msg
, size_t msglen
)
224 print_p2r_header ("PC_to_RDR_GetSlotStatus", msg
, msglen
);
225 print_pr_data (msg
, msglen
, 7);
230 print_p2r_xfrblock (const unsigned char *msg
, size_t msglen
)
234 print_p2r_header ("PC_to_RDR_XfrBlock", msg
, msglen
);
237 printf (" bBWI ..............: 0x%02x\n", msg
[7]);
238 val
= convert_le_u16 (msg
+8);
239 printf (" wLevelParameter ...: 0x%04x%s\n", val
,
240 val
== 1? " (continued)":
241 val
== 2? " (continues+ends)":
242 val
== 3? " (continues+continued)":
243 val
== 16? " (DataBlock-expected)":"");
244 print_pr_data (msg
, msglen
, 10);
249 print_p2r_getparameters (const unsigned char *msg
, size_t msglen
)
251 print_p2r_header ("PC_to_RDR_GetParameters", msg
, msglen
);
252 print_pr_data (msg
, msglen
, 7);
257 print_p2r_resetparameters (const unsigned char *msg
, size_t msglen
)
259 print_p2r_header ("PC_to_RDR_ResetParameters", msg
, msglen
);
260 print_pr_data (msg
, msglen
, 7);
265 print_p2r_setparameters (const unsigned char *msg
, size_t msglen
)
267 print_p2r_header ("PC_to_RDR_SetParameters", msg
, msglen
);
270 printf (" bProtocolNum ......: 0x%02x\n", msg
[7]);
271 print_pr_data (msg
, msglen
, 8);
276 print_p2r_escape (const unsigned char *msg
, size_t msglen
)
280 print_p2r_header ("PC_to_RDR_Escape", msg
, msglen
);
281 print_pr_data (msg
, msglen
, 7);
286 print_p2r_iccclock (const unsigned char *msg
, size_t msglen
)
288 print_p2r_header ("PC_to_RDR_IccClock", msg
, msglen
);
291 printf (" bClockCommand .....: 0x%02x\n", msg
[7]);
292 print_pr_data (msg
, msglen
, 8);
297 print_p2r_to0apdu (const unsigned char *msg
, size_t msglen
)
299 print_p2r_header ("PC_to_RDR_T0APDU", msg
, msglen
);
302 printf (" bmChanges .........: 0x%02x\n", msg
[7]);
303 printf (" bClassGetResponse .: 0x%02x\n", msg
[8]);
304 printf (" bClassEnvelope ....: 0x%02x\n", msg
[9]);
305 print_pr_data (msg
, msglen
, 10);
310 print_p2r_secure (const unsigned char *msg
, size_t msglen
)
314 print_p2r_header ("PC_to_RDR_Secure", msg
, msglen
);
317 printf (" bBMI ..............: 0x%02x\n", msg
[7]);
318 val
= convert_le_u16 (msg
+8);
319 printf (" wLevelParameter ...: 0x%04x%s\n", val
,
320 val
== 1? " (continued)":
321 val
== 2? " (continues+ends)":
322 val
== 3? " (continues+continued)":
323 val
== 16? " (DataBlock-expected)":"");
324 print_pr_data (msg
, msglen
, 10);
329 print_p2r_mechanical (const unsigned char *msg
, size_t msglen
)
331 print_p2r_header ("PC_to_RDR_Mechanical", msg
, msglen
);
334 printf (" bFunction .........: 0x%02x\n", msg
[7]);
335 print_pr_data (msg
, msglen
, 8);
340 print_p2r_abort (const unsigned char *msg
, size_t msglen
)
342 print_p2r_header ("PC_to_RDR_Abort", msg
, msglen
);
343 print_pr_data (msg
, msglen
, 7);
348 print_p2r_setdatarate (const unsigned char *msg
, size_t msglen
)
350 print_p2r_header ("PC_to_RDR_SetDataRate", msg
, msglen
);
353 print_pr_data (msg
, msglen
, 7);
358 print_p2r_unknown (const unsigned char *msg
, size_t msglen
)
362 snprintf (buf
, sizeof buf
, "Unknown PC_to_RDR command 0x%02X",
364 print_p2r_header (buf
, msg
, msglen
);
367 print_pr_data (msg
, msglen
, 0);
372 print_p2r (const unsigned char *msg
, size_t msglen
)
374 switch (msglen
? msg
[0]:0)
376 case PC_to_RDR_IccPowerOn
:
377 print_p2r_iccpoweron (msg
, msglen
);
379 case PC_to_RDR_IccPowerOff
:
380 print_p2r_iccpoweroff (msg
, msglen
);
382 case PC_to_RDR_GetSlotStatus
:
383 print_p2r_getslotstatus (msg
, msglen
);
385 case PC_to_RDR_XfrBlock
:
386 print_p2r_xfrblock (msg
, msglen
);
388 case PC_to_RDR_GetParameters
:
389 print_p2r_getparameters (msg
, msglen
);
391 case PC_to_RDR_ResetParameters
:
392 print_p2r_resetparameters (msg
, msglen
);
394 case PC_to_RDR_SetParameters
:
395 print_p2r_setparameters (msg
, msglen
);
397 case PC_to_RDR_Escape
:
398 print_p2r_escape (msg
, msglen
);
400 case PC_to_RDR_IccClock
:
401 print_p2r_iccclock (msg
, msglen
);
403 case PC_to_RDR_T0APDU
:
404 print_p2r_to0apdu (msg
, msglen
);
406 case PC_to_RDR_Secure
:
407 print_p2r_secure (msg
, msglen
);
409 case PC_to_RDR_Mechanical
:
410 print_p2r_mechanical (msg
, msglen
);
412 case PC_to_RDR_Abort
:
413 print_p2r_abort (msg
, msglen
);
415 case PC_to_RDR_SetDataRate
:
416 print_p2r_setdatarate (msg
, msglen
);
419 print_p2r_unknown (msg
, msglen
);
426 print_r2p_header (const char *name
, const unsigned char *msg
, size_t msglen
)
428 printf ("%s:\n", name
);
431 printf (" dwLength ..........: %u\n", convert_le_u32 (msg
+1));
432 printf (" bSlot .............: %u\n", msg
[5]);
433 printf (" bSeq ..............: %u\n", msg
[6]);
434 printf (" bStatus ...........: %u\n", msg
[7]);
436 printf (" bError ............: %u\n", msg
[8]);
441 print_r2p_datablock (const unsigned char *msg
, size_t msglen
)
443 print_r2p_header ("RDR_to_PC_DataBlock", msg
, msglen
);
447 printf (" bChainParameter ...: 0x%02x%s\n", msg
[9],
448 msg
[9] == 1? " (continued)":
449 msg
[9] == 2? " (continues+ends)":
450 msg
[9] == 3? " (continues+continued)":
451 msg
[9] == 16? " (XferBlock-expected)":"");
452 print_pr_data (msg
, msglen
, 10);
457 print_r2p_slotstatus (const unsigned char *msg
, size_t msglen
)
459 print_r2p_header ("RDR_to_PC_SlotStatus", msg
, msglen
);
462 printf (" bClockStatus ......: 0x%02x%s\n", msg
[9],
463 msg
[9] == 0? " (running)":
464 msg
[9] == 1? " (stopped-L)":
465 msg
[9] == 2? " (stopped-H)":
466 msg
[9] == 3? " (stopped)":"");
467 print_pr_data (msg
, msglen
, 10);
472 print_r2p_parameters (const unsigned char *msg
, size_t msglen
)
474 print_r2p_header ("RDR_to_PC_Parameters", msg
, msglen
);
478 printf (" protocol ..........: T=%d\n", msg
[9]);
479 if (msglen
== 17 && msg
[9] == 1)
482 printf (" bmFindexDindex ....: %02X\n", msg
[10]);
483 printf (" bmTCCKST1 .........: %02X\n", msg
[11]);
484 printf (" bGuardTimeT1 ......: %02X\n", msg
[12]);
485 printf (" bmWaitingIntegersT1: %02X\n", msg
[13]);
486 printf (" bClockStop ........: %02X\n", msg
[14]);
487 printf (" bIFSC .............: %d\n", msg
[15]);
488 printf (" bNadValue .........: %d\n", msg
[16]);
491 print_pr_data (msg
, msglen
, 10);
496 print_r2p_escape (const unsigned char *msg
, size_t msglen
)
500 print_r2p_header ("RDR_to_PC_Escape", msg
, msglen
);
503 printf (" buffer[9] .........: %02X\n", msg
[9]);
504 print_pr_data (msg
, msglen
, 10);
509 print_r2p_datarate (const unsigned char *msg
, size_t msglen
)
511 print_r2p_header ("RDR_to_PC_DataRate", msg
, msglen
);
516 printf (" dwClockFrequency ..: %u\n", convert_le_u32 (msg
+10));
517 printf (" dwDataRate ..... ..: %u\n", convert_le_u32 (msg
+14));
518 print_pr_data (msg
, msglen
, 18);
521 print_pr_data (msg
, msglen
, 10);
526 print_r2p_unknown (const unsigned char *msg
, size_t msglen
)
530 snprintf (buf
, sizeof buf
, "Unknown RDR_to_PC command 0x%02X",
532 print_r2p_header (buf
, msg
, msglen
);
535 printf (" bMessageType ......: %02X\n", msg
[0]);
536 printf (" buffer[9] .........: %02X\n", msg
[9]);
537 print_pr_data (msg
, msglen
, 10);
542 print_r2p (const unsigned char *msg
, size_t msglen
)
544 switch (msglen
? msg
[0]:0)
546 case RDR_to_PC_DataBlock
:
547 print_r2p_datablock (msg
, msglen
);
549 case RDR_to_PC_SlotStatus
:
550 print_r2p_slotstatus (msg
, msglen
);
552 case RDR_to_PC_Parameters
:
553 print_r2p_parameters (msg
, msglen
);
555 case RDR_to_PC_Escape
:
556 print_r2p_escape (msg
, msglen
);
558 case RDR_to_PC_DataRate
:
559 print_r2p_datarate (msg
, msglen
);
562 print_r2p_unknown (msg
, msglen
);
572 if (!databuffer
.count
)
576 printf ("Address: %s\n", databuffer
.address
);
577 if (databuffer
.is_bi
)
579 print_r2p (databuffer
.data
, databuffer
.count
);
584 print_p2r (databuffer
.data
, databuffer
.count
);
586 databuffer
.count
= 0;
590 collect_data (char *hexdata
, const char *address
, unsigned int lineno
)
597 is_bi
= (*address
&& address
[1] == 'i');
599 if (databuffer
.is_bi
!= is_bi
|| strcmp (databuffer
.address
, address
))
601 databuffer
.is_bi
= is_bi
;
602 if (strlen (address
) >= sizeof databuffer
.address
)
603 die ("address field too long");
604 strcpy (databuffer
.address
, address
);
606 length
= databuffer
.count
;
607 for (s
=hexdata
; *s
; s
++ )
609 if (ascii_isspace (*s
))
613 err ("invalid hex digit in line %u - line skipped", lineno
);
616 value
= xtoi_1 (*s
) * 16;
620 err ("invalid hex digit in line %u - line skipped", lineno
);
623 value
+= xtoi_1 (*s
);
625 if (length
>= sizeof (databuffer
.data
))
627 err ("too much data at line %u - can handle only up to % bytes",
628 lineno
, sizeof (databuffer
.data
));
631 databuffer
.data
[length
++] = value
;
633 databuffer
.count
= length
;
638 parse_line (char *line
, unsigned int lineno
)
641 char *event_type
, *address
, *data
, *status
, *datatag
;
644 printf ("line[%u] =`%s'\n", lineno
, line
);
646 p
= strtok (line
, " ");
648 die ("invalid line %d (no URB)");
649 p
= strtok (NULL
, " ");
651 die ("invalid line %d (no timestamp)");
652 event_type
= strtok (NULL
, " ");
654 die ("invalid line %d (no event type)");
655 address
= strtok (NULL
, " ");
657 die ("invalid line %d (no address");
658 if (usb_bus
|| usb_dev
)
662 p
= strchr (address
, ':');
664 die ("invalid line %d (invalid address");
669 die ("invalid line %d (invalid address");
673 if ((usb_bus
&& usb_bus
!= bus
) || (usb_dev
&& usb_dev
!= dev
))
674 return; /* We don't want that one. */
676 if (*address
!= 'B' || (address
[1] != 'o' && address
[1] != 'i'))
677 return; /* We only want block in and block out. */
678 status
= strtok (NULL
, " ");
681 if (!strchr ("-0123456789", *status
))
682 return; /* Setup packet. */
683 /* We don't support "Z[io]" types thus we don't need to check here. */
684 p
= strtok (NULL
, " ");
686 return; /* No data length. */
688 datatag
= strtok (NULL
, " ");
689 if (datatag
&& *datatag
== '=')
691 data
= strtok (NULL
, "");
692 collect_data (data
?data
:"", address
, lineno
);
698 parse_line_sniffusb (char *line
, unsigned int lineno
)
703 printf ("line[%u] =`%s'\n", lineno
, line
);
705 p
= strtok (line
, " \t");
708 p
= strtok (NULL
, " \t");
711 p
= strtok (NULL
, " \t");
715 if (hexdigitp (p
[0]) && hexdigitp (p
[1])
716 && hexdigitp (p
[2]) && hexdigitp (p
[3])
717 && p
[4] == ':' && !p
[5])
722 length
= databuffer
.count
;
723 while ((p
=strtok (NULL
, " \t")))
725 if (!hexdigitp (p
[0]) || !hexdigitp (p
[1]))
727 err ("invalid hex digit in line %u (%s)", lineno
,p
);
730 value
= xtoi_1 (p
[0]) * 16 + xtoi_1 (p
[1]);
732 if (length
>= sizeof (databuffer
.data
))
734 err ("too much data at line %u - can handle only up to % bytes",
735 lineno
, sizeof (databuffer
.data
));
738 databuffer
.data
[length
++] = value
;
740 databuffer
.count
= length
;
743 else if (!strcmp (p
, "TransferFlags"))
747 *databuffer
.address
= 0;
748 while ((p
=strtok (NULL
, " \t(,)")))
750 if (!strcmp (p
, "USBD_TRANSFER_DIRECTION_IN"))
752 databuffer
.is_bi
= 1;
755 else if (!strcmp (p
, "USBD_TRANSFER_DIRECTION_OUT"))
757 databuffer
.is_bi
= 0;
767 parse_input (FILE *fp
)
771 unsigned int lineno
= 0;
773 while (fgets (line
, sizeof (line
), fp
))
776 length
= strlen (line
);
777 if (length
&& line
[length
- 1] == '\n')
780 err ("line number %u too long or last line not terminated", lineno
);
781 if (length
&& line
[length
- 1] == '\r')
784 parse_line_sniffusb (line
, lineno
);
786 parse_line (line
, lineno
);
790 err ("error reading input at line %u: %s", lineno
, strerror (errno
));
795 main (int argc
, char **argv
)
803 while (argc
&& last_argc
!= argc
)
806 if (!strcmp (*argv
, "--"))
811 else if (!strcmp (*argv
, "--version"))
813 fputs (PGM
" (GnuPG) " PACKAGE_VERSION
"\n", stdout
);
816 else if (!strcmp (*argv
, "--help"))
818 puts ("Usage: " PGM
" [BUS:DEV]\n"
819 "Parse the output of usbmod assuming it is CCID compliant.\n\n"
820 " --skip-escape do not show escape packets\n"
821 " --sniffusb Assume output from Sniffusb.exe\n"
822 " --verbose enable extra informational output\n"
823 " --debug enable additional debug output\n"
824 " --help display this help and exit\n\n"
825 "Report bugs to " PACKAGE_BUGREPORT
".");
828 else if (!strcmp (*argv
, "--verbose"))
833 else if (!strcmp (*argv
, "--debug"))
838 else if (!strcmp (*argv
, "--skip-escape"))
843 else if (!strcmp (*argv
, "--sniffusb"))
850 if (argc
&& sniffusb
)
851 die ("no arguments expected when using --sniffusb\n");
853 die ("usage: " PGM
" [BUS:DEV] (try --help for more information)\n");
857 const char *s
= strchr (argv
[0], ':');
859 usb_bus
= atoi (argv
[0]);
861 usb_dev
= atoi (s
+1);
862 if (usb_bus
< 1 || usb_bus
> 999 || usb_dev
< 1 || usb_dev
> 999)
863 die ("invalid bus:dev specified");
867 signal (SIGPIPE
, SIG_IGN
);
871 return any_error
? 1:0;
877 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"