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 <https://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"
49 # define GNUPG_NAME "GnuPG"
55 static int skip_escape;
56 static int usb_bus, usb_dev;
74 RDR_to_PC_NotifySlotChange= 0x50,
75 RDR_to_PC_HardwareError = 0x51,
77 PC_to_RDR_SetParameters = 0x61,
78 PC_to_RDR_IccPowerOn = 0x62,
79 PC_to_RDR_IccPowerOff = 0x63,
80 PC_to_RDR_GetSlotStatus = 0x65,
81 PC_to_RDR_Secure = 0x69,
82 PC_to_RDR_T0APDU = 0x6a,
83 PC_to_RDR_Escape = 0x6b,
84 PC_to_RDR_GetParameters = 0x6c,
85 PC_to_RDR_ResetParameters = 0x6d,
86 PC_to_RDR_IccClock = 0x6e,
87 PC_to_RDR_XfrBlock = 0x6f,
88 PC_to_RDR_Mechanical = 0x71,
89 PC_to_RDR_Abort = 0x72,
90 PC_to_RDR_SetDataRate = 0x73,
92 RDR_to_PC_DataBlock = 0x80,
93 RDR_to_PC_SlotStatus = 0x81,
94 RDR_to_PC_Parameters = 0x82,
95 RDR_to_PC_Escape = 0x83,
96 RDR_to_PC_DataRate = 0x84
100 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
101 #define hexdigitp(a) (digitp (a) \
102 || (*(a) >= 'A' && *(a) <= 'F') \
103 || (*(a) >= 'a' && *(a) <= 'f'))
104 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
105 #define xtoi_1(p) ((p) <= '9'? ((p)- '0'): \
106 (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
110 /* Print diagnostic message and exit with failure. */
112 die (const char *format, ...)
117 fprintf (stderr, "%s: ", PGM);
119 va_start (arg_ptr, format);
120 vfprintf (stderr, format, arg_ptr);
128 /* Print diagnostic message. */
130 err (const char *format, ...)
137 fprintf (stderr, "%s: ", PGM);
139 va_start (arg_ptr, format);
140 vfprintf (stderr, format, arg_ptr);
146 /* Convert a little endian stored 4 byte value into an unsigned
149 convert_le_u32 (const unsigned char *buf)
151 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | ((unsigned int)buf[3] << 24);
155 /* Convert a little endian stored 2 byte value into an unsigned
158 convert_le_u16 (const unsigned char *buf)
160 return buf[0] | (buf[1] << 8);
167 print_pr_data (const unsigned char *data, size_t datalen, size_t off)
172 for (; off < datalen; off++)
174 if (!(off % 16) || first)
178 printf (" [%04lu] ", (unsigned long)off);
180 printf (" %02X", data[off]);
190 print_p2r_header (const char *name, const unsigned char *msg, size_t msglen)
192 printf ("%s:\n", name);
195 printf (" dwLength ..........: %u\n", convert_le_u32 (msg+1));
196 printf (" bSlot .............: %u\n", msg[5]);
197 printf (" bSeq ..............: %u\n", msg[6]);
202 print_p2r_iccpoweron (const unsigned char *msg, size_t msglen)
204 print_p2r_header ("PC_to_RDR_IccPowerOn", msg, msglen);
207 printf (" bPowerSelect ......: 0x%02x (%s)\n", msg[7],
209 msg[7] == 1? "5.0 V":
210 msg[7] == 2? "3.0 V":
211 msg[7] == 3? "1.8 V":"");
212 print_pr_data (msg, msglen, 8);
217 print_p2r_iccpoweroff (const unsigned char *msg, size_t msglen)
219 print_p2r_header ("PC_to_RDR_IccPowerOff", msg, msglen);
220 print_pr_data (msg, msglen, 7);
225 print_p2r_getslotstatus (const unsigned char *msg, size_t msglen)
227 print_p2r_header ("PC_to_RDR_GetSlotStatus", msg, msglen);
228 print_pr_data (msg, msglen, 7);
233 print_p2r_xfrblock (const unsigned char *msg, size_t msglen)
237 print_p2r_header ("PC_to_RDR_XfrBlock", msg, msglen);
240 printf (" bBWI ..............: 0x%02x\n", msg[7]);
241 val = convert_le_u16 (msg+8);
242 printf (" wLevelParameter ...: 0x%04x%s\n", val,
243 val == 1? " (continued)":
244 val == 2? " (continues+ends)":
245 val == 3? " (continues+continued)":
246 val == 16? " (DataBlock-expected)":"");
247 print_pr_data (msg, msglen, 10);
252 print_p2r_getparameters (const unsigned char *msg, size_t msglen)
254 print_p2r_header ("PC_to_RDR_GetParameters", msg, msglen);
255 print_pr_data (msg, msglen, 7);
260 print_p2r_resetparameters (const unsigned char *msg, size_t msglen)
262 print_p2r_header ("PC_to_RDR_ResetParameters", msg, msglen);
263 print_pr_data (msg, msglen, 7);
268 print_p2r_setparameters (const unsigned char *msg, size_t msglen)
270 print_p2r_header ("PC_to_RDR_SetParameters", msg, msglen);
273 printf (" bProtocolNum ......: 0x%02x\n", msg[7]);
274 print_pr_data (msg, msglen, 8);
279 print_p2r_escape (const unsigned char *msg, size_t msglen)
283 print_p2r_header ("PC_to_RDR_Escape", msg, msglen);
284 print_pr_data (msg, msglen, 7);
289 print_p2r_iccclock (const unsigned char *msg, size_t msglen)
291 print_p2r_header ("PC_to_RDR_IccClock", msg, msglen);
294 printf (" bClockCommand .....: 0x%02x\n", msg[7]);
295 print_pr_data (msg, msglen, 8);
300 print_p2r_to0apdu (const unsigned char *msg, size_t msglen)
302 print_p2r_header ("PC_to_RDR_T0APDU", msg, msglen);
305 printf (" bmChanges .........: 0x%02x\n", msg[7]);
306 printf (" bClassGetResponse .: 0x%02x\n", msg[8]);
307 printf (" bClassEnvelope ....: 0x%02x\n", msg[9]);
308 print_pr_data (msg, msglen, 10);
313 print_p2r_secure (const unsigned char *msg, size_t msglen)
317 print_p2r_header ("PC_to_RDR_Secure", msg, msglen);
320 printf (" bBMI ..............: 0x%02x\n", msg[7]);
321 val = convert_le_u16 (msg+8);
322 printf (" wLevelParameter ...: 0x%04x%s\n", val,
323 val == 1? " (continued)":
324 val == 2? " (continues+ends)":
325 val == 3? " (continues+continued)":
326 val == 16? " (DataBlock-expected)":"");
327 print_pr_data (msg, msglen, 10);
332 print_p2r_mechanical (const unsigned char *msg, size_t msglen)
334 print_p2r_header ("PC_to_RDR_Mechanical", msg, msglen);
337 printf (" bFunction .........: 0x%02x\n", msg[7]);
338 print_pr_data (msg, msglen, 8);
343 print_p2r_abort (const unsigned char *msg, size_t msglen)
345 print_p2r_header ("PC_to_RDR_Abort", msg, msglen);
346 print_pr_data (msg, msglen, 7);
351 print_p2r_setdatarate (const unsigned char *msg, size_t msglen)
353 print_p2r_header ("PC_to_RDR_SetDataRate", msg, msglen);
356 print_pr_data (msg, msglen, 7);
361 print_p2r_unknown (const unsigned char *msg, size_t msglen)
365 snprintf (buf, sizeof buf, "Unknown PC_to_RDR command 0x%02X",
367 print_p2r_header (buf, msg, msglen);
370 print_pr_data (msg, msglen, 0);
375 print_p2r (const unsigned char *msg, size_t msglen)
377 switch (msglen? msg[0]:0)
379 case PC_to_RDR_IccPowerOn:
380 print_p2r_iccpoweron (msg, msglen);
382 case PC_to_RDR_IccPowerOff:
383 print_p2r_iccpoweroff (msg, msglen);
385 case PC_to_RDR_GetSlotStatus:
386 print_p2r_getslotstatus (msg, msglen);
388 case PC_to_RDR_XfrBlock:
389 print_p2r_xfrblock (msg, msglen);
391 case PC_to_RDR_GetParameters:
392 print_p2r_getparameters (msg, msglen);
394 case PC_to_RDR_ResetParameters:
395 print_p2r_resetparameters (msg, msglen);
397 case PC_to_RDR_SetParameters:
398 print_p2r_setparameters (msg, msglen);
400 case PC_to_RDR_Escape:
401 print_p2r_escape (msg, msglen);
403 case PC_to_RDR_IccClock:
404 print_p2r_iccclock (msg, msglen);
406 case PC_to_RDR_T0APDU:
407 print_p2r_to0apdu (msg, msglen);
409 case PC_to_RDR_Secure:
410 print_p2r_secure (msg, msglen);
412 case PC_to_RDR_Mechanical:
413 print_p2r_mechanical (msg, msglen);
415 case PC_to_RDR_Abort:
416 print_p2r_abort (msg, msglen);
418 case PC_to_RDR_SetDataRate:
419 print_p2r_setdatarate (msg, msglen);
422 print_p2r_unknown (msg, msglen);
429 print_r2p_header (const char *name, const unsigned char *msg, size_t msglen)
431 printf ("%s:\n", name);
434 printf (" dwLength ..........: %u\n", convert_le_u32 (msg+1));
435 printf (" bSlot .............: %u\n", msg[5]);
436 printf (" bSeq ..............: %u\n", msg[6]);
437 printf (" bStatus ...........: %u\n", msg[7]);
439 printf (" bError ............: %u\n", msg[8]);
444 print_r2p_datablock (const unsigned char *msg, size_t msglen)
446 print_r2p_header ("RDR_to_PC_DataBlock", msg, msglen);
450 printf (" bChainParameter ...: 0x%02x%s\n", msg[9],
451 msg[9] == 1? " (continued)":
452 msg[9] == 2? " (continues+ends)":
453 msg[9] == 3? " (continues+continued)":
454 msg[9] == 16? " (XferBlock-expected)":"");
455 print_pr_data (msg, msglen, 10);
460 print_r2p_slotstatus (const unsigned char *msg, size_t msglen)
462 print_r2p_header ("RDR_to_PC_SlotStatus", msg, msglen);
465 printf (" bClockStatus ......: 0x%02x%s\n", msg[9],
466 msg[9] == 0? " (running)":
467 msg[9] == 1? " (stopped-L)":
468 msg[9] == 2? " (stopped-H)":
469 msg[9] == 3? " (stopped)":"");
470 print_pr_data (msg, msglen, 10);
475 print_r2p_parameters (const unsigned char *msg, size_t msglen)
477 print_r2p_header ("RDR_to_PC_Parameters", msg, msglen);
481 printf (" protocol ..........: T=%d\n", msg[9]);
482 if (msglen == 17 && msg[9] == 1)
485 printf (" bmFindexDindex ....: %02X\n", msg[10]);
486 printf (" bmTCCKST1 .........: %02X\n", msg[11]);
487 printf (" bGuardTimeT1 ......: %02X\n", msg[12]);
488 printf (" bmWaitingIntegersT1: %02X\n", msg[13]);
489 printf (" bClockStop ........: %02X\n", msg[14]);
490 printf (" bIFSC .............: %d\n", msg[15]);
491 printf (" bNadValue .........: %d\n", msg[16]);
494 print_pr_data (msg, msglen, 10);
499 print_r2p_escape (const unsigned char *msg, size_t msglen)
503 print_r2p_header ("RDR_to_PC_Escape", msg, msglen);
506 printf (" buffer[9] .........: %02X\n", msg[9]);
507 print_pr_data (msg, msglen, 10);
512 print_r2p_datarate (const unsigned char *msg, size_t msglen)
514 print_r2p_header ("RDR_to_PC_DataRate", msg, msglen);
519 printf (" dwClockFrequency ..: %u\n", convert_le_u32 (msg+10));
520 printf (" dwDataRate ..... ..: %u\n", convert_le_u32 (msg+14));
521 print_pr_data (msg, msglen, 18);
524 print_pr_data (msg, msglen, 10);
529 print_r2p_unknown (const unsigned char *msg, size_t msglen)
533 snprintf (buf, sizeof buf, "Unknown RDR_to_PC command 0x%02X",
535 print_r2p_header (buf, msg, msglen);
538 printf (" bMessageType ......: %02X\n", msg[0]);
539 printf (" buffer[9] .........: %02X\n", msg[9]);
540 print_pr_data (msg, msglen, 10);
545 print_r2p (const unsigned char *msg, size_t msglen)
547 switch (msglen? msg[0]:0)
549 case RDR_to_PC_DataBlock:
550 print_r2p_datablock (msg, msglen);
552 case RDR_to_PC_SlotStatus:
553 print_r2p_slotstatus (msg, msglen);
555 case RDR_to_PC_Parameters:
556 print_r2p_parameters (msg, msglen);
558 case RDR_to_PC_Escape:
559 print_r2p_escape (msg, msglen);
561 case RDR_to_PC_DataRate:
562 print_r2p_datarate (msg, msglen);
565 print_r2p_unknown (msg, msglen);
575 if (!databuffer.count)
579 printf ("Address: %s\n", databuffer.address);
580 if (databuffer.is_bi)
582 print_r2p (databuffer.data, databuffer.count);
587 print_p2r (databuffer.data, databuffer.count);
589 databuffer.count = 0;
593 collect_data (char *hexdata, const char *address, unsigned int lineno)
600 is_bi = (*address && address[1] == 'i');
602 if (databuffer.is_bi != is_bi || strcmp (databuffer.address, address))
604 databuffer.is_bi = is_bi;
605 if (strlen (address) >= sizeof databuffer.address)
606 die ("address field too long");
607 strcpy (databuffer.address, address);
609 length = databuffer.count;
610 for (s=hexdata; *s; s++ )
612 if (ascii_isspace (*s))
616 err ("invalid hex digit in line %u - line skipped", lineno);
619 value = xtoi_1 (*s) * 16;
623 err ("invalid hex digit in line %u - line skipped", lineno);
626 value += xtoi_1 (*s);
628 if (length >= sizeof (databuffer.data))
630 err ("too much data at line %u - can handle only up to % bytes",
631 lineno, sizeof (databuffer.data));
634 databuffer.data[length++] = value;
636 databuffer.count = length;
641 parse_line (char *line, unsigned int lineno)
644 char *event_type, *address, *data, *status, *datatag;
647 printf ("line[%u] ='%s'\n", lineno, line);
649 p = strtok (line, " ");
651 die ("invalid line %d (no URB)");
652 p = strtok (NULL, " ");
654 die ("invalid line %d (no timestamp)");
655 event_type = strtok (NULL, " ");
657 die ("invalid line %d (no event type)");
658 address = strtok (NULL, " ");
660 die ("invalid line %d (no address");
661 if (usb_bus || usb_dev)
665 p = strchr (address, ':');
667 die ("invalid line %d (invalid address");
672 die ("invalid line %d (invalid address");
676 if ((usb_bus && usb_bus != bus) || (usb_dev && usb_dev != dev))
677 return; /* We don't want that one. */
679 if (*address != 'B' || (address[1] != 'o' && address[1] != 'i'))
680 return; /* We only want block in and block out. */
681 status = strtok (NULL, " ");
684 if (!strchr ("-0123456789", *status))
685 return; /* Setup packet. */
686 /* We don't support "Z[io]" types thus we don't need to check here. */
687 p = strtok (NULL, " ");
689 return; /* No data length. */
691 datatag = strtok (NULL, " ");
692 if (datatag && *datatag == '=')
694 data = strtok (NULL, "");
695 collect_data (data?data:"", address, lineno);
701 parse_line_sniffusb (char *line, unsigned int lineno)
706 printf ("line[%u] ='%s'\n", lineno, line);
708 p = strtok (line, " \t");
711 p = strtok (NULL, " \t");
714 p = strtok (NULL, " \t");
718 if (hexdigitp (p+0) && hexdigitp (p+1)
719 && hexdigitp (p+2) && hexdigitp (p+3)
720 && p[4] == ':' && !p[5])
725 length = databuffer.count;
726 while ((p=strtok (NULL, " \t")))
728 if (!hexdigitp (p+0) || !hexdigitp (p+1))
730 err ("invalid hex digit in line %u (%s)", lineno,p);
733 value = xtoi_1 (p[0]) * 16 + xtoi_1 (p[1]);
735 if (length >= sizeof (databuffer.data))
737 err ("too much data at line %u - can handle only up to % bytes",
738 lineno, sizeof (databuffer.data));
741 databuffer.data[length++] = value;
743 databuffer.count = length;
746 else if (!strcmp (p, "TransferFlags"))
750 *databuffer.address = 0;
751 while ((p=strtok (NULL, " \t(,)")))
753 if (!strcmp (p, "USBD_TRANSFER_DIRECTION_IN"))
755 databuffer.is_bi = 1;
758 else if (!strcmp (p, "USBD_TRANSFER_DIRECTION_OUT"))
760 databuffer.is_bi = 0;
770 parse_input (FILE *fp)
774 unsigned int lineno = 0;
776 while (fgets (line, sizeof (line), fp))
779 length = strlen (line);
780 if (length && line[length - 1] == '\n')
783 err ("line number %u too long or last line not terminated", lineno);
784 if (length && line[length - 1] == '\r')
787 parse_line_sniffusb (line, lineno);
789 parse_line (line, lineno);
793 err ("error reading input at line %u: %s", lineno, strerror (errno));
798 main (int argc, char **argv)
806 while (argc && last_argc != argc )
809 if (!strcmp (*argv, "--"))
814 else if (!strcmp (*argv, "--version"))
816 fputs (PGM " (" GNUPG_NAME ") " PACKAGE_VERSION "\n", stdout);
819 else if (!strcmp (*argv, "--help"))
821 puts ("Usage: " PGM " [BUS:DEV]\n"
822 "Parse the output of usbmod assuming it is CCID compliant.\n\n"
823 " --skip-escape do not show escape packets\n"
824 " --sniffusb Assume output from Sniffusb.exe\n"
825 " --verbose enable extra informational output\n"
826 " --debug enable additional debug output\n"
827 " --help display this help and exit\n\n"
828 "Report bugs to " PACKAGE_BUGREPORT ".");
831 else if (!strcmp (*argv, "--verbose"))
836 else if (!strcmp (*argv, "--debug"))
841 else if (!strcmp (*argv, "--skip-escape"))
846 else if (!strcmp (*argv, "--sniffusb"))
853 if (argc && sniffusb)
854 die ("no arguments expected when using --sniffusb\n");
856 die ("usage: " PGM " [BUS:DEV] (try --help for more information)\n");
860 const char *s = strchr (argv[0], ':');
862 usb_bus = atoi (argv[0]);
864 usb_dev = atoi (s+1);
865 if (usb_bus < 1 || usb_bus > 999 || usb_dev < 1 || usb_dev > 999)
866 die ("invalid bus:dev specified");
870 signal (SIGPIPE, SIG_IGN);
874 return any_error? 1:0;
880 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"