1/* 2 parse.c: parse CCID structure 3 Copyright (C) 2003-2010 Ludovic Rousseau 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 51 17 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18*/ 19 20/* 21 * $Id: parse.c 6633 2013-05-22 14:11:37Z rousseau $ 22 */ 23 24#include <stdio.h> 25#include <string.h> 26# ifdef S_SPLINT_S 27# include <sys/types.h> 28# endif 29#include <errno.h> 30 31#include "defs.h" 32#include "ccid.h" 33 34/* define DISPLAY_EXTRA_VALUES to display the extra (invalid) values 35 * returned by bNumClockSupported and bNumDataRatesSupported */ 36#undef DISPLAY_EXTRA_VALUES 37 38#ifndef TRUE 39#define TRUE 1 40#define FALSE 0 41#endif 42 43#define BLUE "\33[34m" 44#define RED "\33[31m" 45#define BRIGHT_RED "\33[01;31m" 46#define GREEN "\33[32m" 47#define MAGENTA "\33[35m" 48#define NORMAL "\33[0m" 49 50/* global variables used in ccid_usb.c but defined in ifdhandler.c */ 51int LogLevel = 1+2+4+8; /* full debug */ 52int DriverOptions = 0; 53 54static int ccid_parse_interface_descriptor(libusb_device_handle *handle, 55 struct libusb_device_descriptor desc, 56 struct libusb_config_descriptor *config_desc, 57 int num, 58 const struct libusb_interface *usb_interface); 59 60 61/***************************************************************************** 62 * 63 * main 64 * 65 ****************************************************************************/ 66int main(int argc, char *argv[]) 67{ 68 libusb_device **devs, *dev; 69 int nb = 0, r, i; 70 unsigned char buffer[256]; 71 char class_ff = FALSE; 72 ssize_t cnt; 73 74 if ((argc > 1) && (0 == strcmp(argv[1], "-p"))) 75 class_ff = TRUE; 76 77 r = libusb_init(NULL); 78 if (r < 0) 79 { 80 (void)printf("libusb_init() failed\n"); 81 return r; 82 } 83 84 cnt = libusb_get_device_list(NULL, &devs); 85 if (cnt < 0) 86 { 87 (void)printf("libusb_get_device_list() failed\n"); 88 return (int)cnt; 89 } 90 91 /* for every device */ 92 i = 0; 93 while ((dev = devs[i++]) != NULL) 94 { 95 struct libusb_device_descriptor desc; 96 struct libusb_config_descriptor *config_desc; 97 struct libusb_device_handle *handle; 98 const struct libusb_interface *usb_interface = NULL; 99#ifndef __APPLE__ 100 int interface; 101#endif 102 int num = 0; 103 104 r = libusb_open(dev, &handle); 105 if (r < 0) 106 { 107 (void)fprintf(stderr, "Can't libusb_open(): %s\n", strerror(errno)); 108 if (getuid()) 109 { 110 (void)fprintf(stderr, 111 BRIGHT_RED "Please, restart the command as root\n" NORMAL); 112 return 1; 113 } 114 continue; 115 } 116 117 r = libusb_get_device_descriptor(dev, &desc); 118 if (r < 0) 119 { 120 (void)fprintf(stderr, 121 BRIGHT_RED "failed to get device descriptor" NORMAL); 122 return 1; 123 } 124 125 (void)fprintf(stderr, 126 "Parsing USB bus/device: %04X:%04X (bus %d, device %d)\n", 127 desc.idVendor, desc.idProduct, 128 libusb_get_bus_number(dev), libusb_get_device_address(dev)); 129 130 (void)fprintf(stderr, " idVendor: 0x%04X", desc.idVendor); 131 r = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, 132 buffer, sizeof(buffer)); 133 if (r < 0) 134 { 135 (void)fprintf(stderr, " Can't get iManufacturer string\n"); 136 if (getuid()) 137 { 138 (void)fprintf(stderr, 139 BRIGHT_RED "Please, restart the command as root\n" NORMAL); 140 return 1; 141 } 142 } 143 else 144 (void)fprintf(stderr, 145 " iManufacturer: " BLUE "%s\n" NORMAL, buffer); 146 147 (void)fprintf(stderr, " idProduct: 0x%04X", desc.idProduct); 148 r = libusb_get_string_descriptor_ascii(handle, desc.iProduct, 149 buffer, sizeof(buffer)); 150 if (r < 0) 151 (void)fprintf(stderr, " Can't get iProduct string\n"); 152 else 153 (void)fprintf(stderr, " iProduct: " BLUE "%s\n" NORMAL, buffer); 154 155again: 156 /* check if the device has bInterfaceClass == 11 */ 157 r = libusb_get_active_config_descriptor(dev, &config_desc); 158 if (r < 0) 159 { 160 (void)fprintf(stderr, " Can't get config descriptor: %d\n", r); 161 (void)libusb_close(handle); 162 continue; 163 } 164 165 usb_interface = get_ccid_usb_interface(config_desc, &num); 166 if (NULL == usb_interface) 167 { 168 (void)libusb_close(handle); 169 /* only if we found no CCID interface */ 170 if (0 == num) 171 (void)fprintf(stderr, RED " NOT a CCID/ICCD device\n" NORMAL); 172 continue; 173 } 174 if (!class_ff && (0xFF == usb_interface->altsetting->bInterfaceClass)) 175 { 176 (void)libusb_close(handle); 177 (void)fprintf(stderr, MAGENTA " Found a possibly CCID/ICCD device (bInterfaceClass = 0xFF). Use %s -p\n" NORMAL, argv[0]); 178 continue; 179 } 180 (void)fprintf(stderr, 181 GREEN " Found a CCID/ICCD device at interface %d\n" NORMAL, num); 182 183 /* now we found a free reader and we try to use it */ 184#if 0 185 if (NULL == dev->config) 186 { 187 (void)libusb_close(handle); 188 (void)fprintf(stderr, "No dev->config found for %s/%s\n", 189 bus->dirname, dev->filename); 190 continue; 191 } 192#endif 193 194#ifndef __APPLE__ 195 interface = usb_interface->altsetting->bInterfaceNumber; 196 r = libusb_claim_interface(handle, interface); 197 if (r < 0) 198 { 199 (void)fprintf(stderr, 200 "Can't claim interface (bus %d, device %d): %s\n", 201 libusb_get_bus_number(dev), libusb_get_device_address(dev), 202 strerror(errno)); 203 (void)libusb_close(handle); 204 205 if (EBUSY == errno) 206 { 207 (void)fprintf(stderr, 208 BRIGHT_RED " Please, stop pcscd and retry\n\n" NORMAL); 209 210 if (class_ff) 211 /* maybe the device with Class = 0xFF is NOT a CCID 212 * reader */ 213 continue; 214 else 215 return TRUE; 216 } 217 continue; 218 } 219#endif 220 221 (void)ccid_parse_interface_descriptor(handle, desc, config_desc, num, 222 usb_interface); 223 nb++; 224 225#ifndef __APPLE__ 226 (void)libusb_release_interface(handle, interface); 227#endif 228 /* check for another CCID interface on the same device */ 229 num++; 230 goto again; 231 } 232 233 if ((0 == nb) && (0 != geteuid())) 234 (void)fprintf(stderr, 235 "Can't find any CCID device.\nMaybe you must run parse as root?\n"); 236 237 libusb_exit(NULL); 238 239 return 0; 240} /* main */ 241 242 243/***************************************************************************** 244 * 245 * Parse a CCID USB Descriptor 246 * 247 ****************************************************************************/ 248static int ccid_parse_interface_descriptor(libusb_device_handle *handle, 249 struct libusb_device_descriptor desc, 250 struct libusb_config_descriptor *config_desc, 251 int num, 252 const struct libusb_interface *usb_interface) 253{ 254 const struct libusb_interface_descriptor *usb_interface_descriptor; 255 const unsigned char *device_descriptor; 256 unsigned char buffer[256*sizeof(int)]; /* maximum is 256 records */ 257 int r; 258 259 /* 260 * Vendor/model name 261 */ 262 (void)printf(" idVendor: 0x%04X\n", desc.idVendor); 263 r = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, 264 buffer, sizeof(buffer)); 265 if (r < 0) 266 { 267 (void)printf(" Can't get iManufacturer string\n"); 268 if (getuid()) 269 { 270 (void)fprintf(stderr, 271 BRIGHT_RED "Please, restart the command as root\n\n" NORMAL); 272 return TRUE; 273 } 274 } 275 else 276 (void)printf(" iManufacturer: %s\n", buffer); 277 278 (void)printf(" idProduct: 0x%04X\n", desc.idProduct); 279 r = libusb_get_string_descriptor_ascii(handle, desc.iProduct, 280 buffer, sizeof(buffer)); 281 if (r < 0) 282 (void)printf(" Can't get iProduct string\n"); 283 else 284 (void)printf(" iProduct: %s\n", buffer); 285 286 (void)printf(" bcdDevice: %X.%02X (firmware release?)\n", 287 desc.bcdDevice >> 8, desc.bcdDevice & 0xFF); 288 289 usb_interface_descriptor = get_ccid_usb_interface(config_desc, &num)->altsetting; 290 291 (void)printf(" bLength: %d\n", usb_interface_descriptor->bLength); 292 293 (void)printf(" bDescriptorType: %d\n", usb_interface_descriptor->bDescriptorType); 294 295 (void)printf(" bInterfaceNumber: %d\n", usb_interface_descriptor->bInterfaceNumber); 296 297 (void)printf(" bAlternateSetting: %d\n", usb_interface_descriptor->bAlternateSetting); 298 299 (void)printf(" bNumEndpoints: %d\n", usb_interface_descriptor->bNumEndpoints); 300 switch (usb_interface_descriptor->bNumEndpoints) 301 { 302 case 0: 303 (void)printf(" Control only\n"); 304 break; 305 case 1: 306 (void)printf(" Interrupt-IN\n"); 307 break; 308 case 2: 309 (void)printf(" bulk-IN and bulk-OUT\n"); 310 break; 311 case 3: 312 (void)printf(" bulk-IN, bulk-OUT and Interrupt-IN\n"); 313 break; 314 default: 315 (void)printf(" UNKNOWN value\n"); 316 } 317 318 (void)printf(" bInterfaceClass: 0x%02X", usb_interface_descriptor->bInterfaceClass); 319 if (usb_interface_descriptor->bInterfaceClass == 0x0b) 320 (void)printf(" [Chip Card Interface Device Class (CCID)]\n"); 321 else 322 { 323 (void)printf("\n NOT A CCID DEVICE\n"); 324 if (usb_interface_descriptor->bInterfaceClass != 0xFF) 325 return TRUE; 326 else 327 (void)printf(" Class is 0xFF (proprietary)\n"); 328 } 329 330 (void)printf(" bInterfaceSubClass: %d\n", 331 usb_interface_descriptor->bInterfaceSubClass); 332 if (usb_interface_descriptor->bInterfaceSubClass) 333 (void)printf(" UNSUPPORTED SubClass\n"); 334 335 (void)printf(" bInterfaceProtocol: %d\n", 336 usb_interface_descriptor->bInterfaceProtocol); 337 switch (usb_interface_descriptor->bInterfaceProtocol) 338 { 339 case 0: 340 (void)printf(" bulk transfer, optional interrupt-IN (CCID)\n"); 341 break; 342 case 1: 343 (void)printf(" ICCD Version A, Control transfers, (no interrupt-IN)\n"); 344 break; 345 case 2: 346 (void)printf(" ICCD Version B, Control transfers, (optional interrupt-IN)\n"); 347 break; 348 default: 349 (void)printf(" UNSUPPORTED InterfaceProtocol\n"); 350 } 351 352 r = libusb_get_string_descriptor_ascii(handle, usb_interface_descriptor->iInterface, 353 buffer, sizeof(buffer)); 354 if (r < 0) 355 (void)printf(" Can't get iInterface string\n"); 356 else 357 (void)printf(" iInterface: %s\n", buffer); 358 359 device_descriptor = get_ccid_device_descriptor(usb_interface); 360 if (NULL == device_descriptor) 361 { 362 (void)printf("\n NOT A CCID DEVICE\n"); 363 return TRUE; 364 } 365 366 /* 367 * CCID Class Descriptor 368 */ 369 (void)printf(" CCID Class Descriptor\n"); 370 371 (void)printf(" bLength: 0x%02X\n", device_descriptor[0]); 372 if (device_descriptor[0] != 0x36) 373 { 374 (void)printf(" UNSUPPORTED bLength\n"); 375 return TRUE; 376 } 377 378 (void)printf(" bDescriptorType: 0x%02X\n", device_descriptor[1]); 379 if (device_descriptor[1] != 0x21) 380 { 381 if (0xFF == device_descriptor[1]) 382 (void)printf(" PROPRIETARY bDescriptorType\n"); 383 else 384 { 385 (void)printf(" UNSUPPORTED bDescriptorType\n"); 386 return TRUE; 387 } 388 } 389 390 (void)printf(" bcdCCID: %X.%02X\n", device_descriptor[3], device_descriptor[2]); 391 (void)printf(" bMaxSlotIndex: 0x%02X\n", device_descriptor[4]); 392 (void)printf(" bVoltageSupport: 0x%02X\n", device_descriptor[5]); 393 if (device_descriptor[5] & 0x01) 394 (void)printf(" 5.0V\n"); 395 if (device_descriptor[5] & 0x02) 396 (void)printf(" 3.0V\n"); 397 if (device_descriptor[5] & 0x04) 398 (void)printf(" 1.8V\n"); 399 400 (void)printf(" dwProtocols: 0x%02X%02X 0x%02X%02X\n", device_descriptor[9], device_descriptor[8], 401 device_descriptor[7], device_descriptor[6]); 402 if (device_descriptor[6] & 0x01) 403 (void)printf(" T=0\n"); 404 if (device_descriptor[6] & 0x02) 405 (void)printf(" T=1\n"); 406 407 (void)printf(" dwDefaultClock: %.3f MHz\n", dw2i(device_descriptor, 10)/1000.0); 408 (void)printf(" dwMaximumClock: %.3f MHz\n", dw2i(device_descriptor, 14)/1000.0); 409 (void)printf(" bNumClockSupported: %d%s\n", device_descriptor[18], 410 device_descriptor[18] ? "" : " (will use whatever is returned)"); 411 { 412 int n; 413 414 /* See CCID 3.7.2 page 25 */ 415 n = libusb_control_transfer(handle, 416 0xA1, /* request type */ 417 0x02, /* GET CLOCK FREQUENCIES */ 418 0x00, /* value */ 419 usb_interface_descriptor->bInterfaceNumber, /* interface */ 420 buffer, 421 sizeof(buffer), 422 2 * 1000); 423 424 /* we got an error? */ 425 if (n <= 0) 426 { 427 (void)(void)printf(" IFD does not support GET CLOCK FREQUENCIES request: %s\n", strerror(errno)); 428 if (EBUSY == errno) 429 { 430 (void)fprintf(stderr, 431 BRIGHT_RED " Please, stop pcscd and retry\n\n" NORMAL); 432 return TRUE; 433 } 434 } 435 else 436 if (n % 4) /* not a multiple of 4 */ 437 (void)printf(" wrong size for GET CLOCK FREQUENCIES: %d\n", n); 438 else 439 { 440 int i; 441 442 /* we do not get the expected number of data rates */ 443 if ((n != device_descriptor[18]*4) && device_descriptor[18]) 444 { 445 (void)printf(" Got %d clock frequencies but was expecting %d\n", 446 n/4, device_descriptor[18]); 447 448 /* we got more data than expected */ 449#ifndef DISPLAY_EXTRA_VALUES 450 if (n > device_descriptor[18]*4) 451 n = device_descriptor[18]*4; 452#endif 453 } 454 455 for (i=0; i<n; i+=4) 456 (void)printf(" Support %d kHz\n", dw2i(buffer, i)); 457 } 458 } 459 (void)printf(" dwDataRate: %d bps\n", dw2i(device_descriptor, 19)); 460 (void)printf(" dwMaxDataRate: %d bps\n", dw2i(device_descriptor, 23)); 461 (void)printf(" bNumDataRatesSupported: %d%s\n", device_descriptor[27], 462 device_descriptor[27] ? "" : " (will use whatever is returned)"); 463 { 464 int n; 465 466 /* See CCID 3.7.3 page 25 */ 467 n = libusb_control_transfer(handle, 468 0xA1, /* request type */ 469 0x03, /* GET DATA RATES */ 470 0x00, /* value */ 471 usb_interface_descriptor->bInterfaceNumber, /* interface */ 472 buffer, 473 sizeof(buffer), 474 2 * 1000); 475 476 /* we got an error? */ 477 if (n <= 0) 478 (void)printf(" IFD does not support GET_DATA_RATES request: %s\n", 479 strerror(errno)); 480 else 481 if (n % 4) /* not a multiple of 4 */ 482 (void)printf(" wrong size for GET_DATA_RATES: %d\n", n); 483 else 484 { 485 int i; 486 487 /* we do not get the expected number of data rates */ 488 if ((n != device_descriptor[27]*4) && device_descriptor[27]) 489 { 490 (void)printf(" Got %d data rates but was expecting %d\n", n/4, 491 device_descriptor[27]); 492 493 /* we got more data than expected */ 494#ifndef DISPLAY_EXTRA_VALUES 495 if (n > device_descriptor[27]*4) 496 n = device_descriptor[27]*4; 497#endif 498 } 499 500 for (i=0; i<n; i+=4) 501 (void)printf(" Support %d bps\n", dw2i(buffer, i)); 502 } 503 } 504 (void)printf(" dwMaxIFSD: %d\n", dw2i(device_descriptor, 28)); 505 (void)printf(" dwSynchProtocols: 0x%08X\n", dw2i(device_descriptor, 32)); 506 if (device_descriptor[32] & 0x01) 507 (void)printf(" 2-wire protocol\n"); 508 if (device_descriptor[32] & 0x02) 509 (void)printf(" 3-wire protocol\n"); 510 if (device_descriptor[32] & 0x04) 511 (void)printf(" I2C protocol\n"); 512 513 (void)printf(" dwMechanical: 0x%08X\n", dw2i(device_descriptor, 36)); 514 if (device_descriptor[36] == 0) 515 (void)printf(" No special characteristics\n"); 516 if (device_descriptor[36] & 0x01) 517 (void)printf(" Card accept mechanism\n"); 518 if (device_descriptor[36] & 0x02) 519 (void)printf(" Card ejection mechanism\n"); 520 if (device_descriptor[36] & 0x04) 521 (void)printf(" Card capture mechanism\n"); 522 if (device_descriptor[36] & 0x08) 523 (void)printf(" Card lock/unlock mechanism\n"); 524 525 (void)printf(" dwFeatures: 0x%08X\n", dw2i(device_descriptor, 40)); 526 if (dw2i(device_descriptor, 40) == 0) 527 (void)printf(" No special characteristics\n"); 528 if (device_descriptor[40] & 0x02) 529 (void)printf(" ....02 Automatic parameter configuration based on ATR data\n"); 530 if (device_descriptor[40] & 0x04) 531 (void)printf(" ....04 Automatic activation of ICC on inserting\n"); 532 if (device_descriptor[40] & 0x08) 533 (void)printf(" ....08 Automatic ICC voltage selection\n"); 534 if (device_descriptor[40] & 0x10) 535 (void)printf(" ....10 Automatic ICC clock frequency change according to parameters\n"); 536 if (device_descriptor[40] & 0x20) 537 (void)printf(" ....20 Automatic baud rate change according to frequency and Fi, Di params\n"); 538 if (device_descriptor[40] & 0x40) 539 (void)printf(" ....40 Automatic parameters negotiation made by the CCID\n"); 540 if (device_descriptor[40] & 0x80) 541 (void)printf(" ....80 Automatic PPS made by the CCID\n"); 542 if (device_descriptor[41] & 0x01) 543 (void)printf(" ..01.. CCID can set ICC in clock stop mode\n"); 544 if (device_descriptor[41] & 0x02) 545 (void)printf(" ..02.. NAD value other than 00 accepted (T=1)\n"); 546 if (device_descriptor[41] & 0x04) 547 (void)printf(" ..04.. Automatic IFSD exchange as first exchange (T=1)\n"); 548 if (device_descriptor[41] & 0x08) 549 (void)printf(" ..08.. Unknown (ICCD?)\n"); 550 switch (device_descriptor[42] & 0x07) 551 { 552 case 0x00: 553 (void)printf(" 00.... Character level exchange\n"); 554 break; 555 556 case 0x01: 557 (void)printf(" 01.... TPDU level exchange\n"); 558 break; 559 560 case 0x02: 561 (void)printf(" 02.... Short APDU level exchange\n"); 562 break; 563 564 case 0x04: 565 (void)printf(" 04.... Short and Extended APDU level exchange\n"); 566 break; 567 } 568 if (device_descriptor[42] & 0x10) 569 (void)printf(" 10.... USB Wake up signaling supported on card insertion and removal\n"); 570 571 (void)printf(" dwMaxCCIDMessageLength: %d bytes\n", dw2i(device_descriptor, 44)); 572 (void)printf(" bClassGetResponse: 0x%02X\n", device_descriptor[48]); 573 if (0xFF == device_descriptor[48]) 574 (void)printf(" echoes the APDU class\n"); 575 (void)printf(" bClassEnvelope: 0x%02X\n", device_descriptor[49]); 576 if (0xFF == device_descriptor[49]) 577 (void)printf(" echoes the APDU class\n"); 578 (void)printf(" wLcdLayout: 0x%04X\n", (device_descriptor[51] << 8)+device_descriptor[50]); 579 if (device_descriptor[51]) 580 (void)printf(" %2d lines\n", device_descriptor[51]); 581 if (device_descriptor[50]) 582 (void)printf(" %2d characters per line\n", device_descriptor[50]); 583 (void)printf(" bPINSupport: 0x%02X\n", device_descriptor[52]); 584 if (device_descriptor[52] & 0x01) 585 (void)printf(" PIN Verification supported\n"); 586 if (device_descriptor[52] & 0x02) 587 (void)printf(" PIN Modification supported\n"); 588 (void)printf(" bMaxCCIDBusySlots: %d\n", device_descriptor[53]); 589 590 return FALSE; 591} /* ccid_parse_interface_descriptor */ 592 593