#include #include #include #include #include #include #include #include "usb.h" #define CCID_MAX_PACKET_SIZE 64 /* * BULK_OUT messages from PC to Reader * Defined in CCID Rev 1.1 6.1 (page 26) */ #define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62 #define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63 #define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65 #define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f #define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c #define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d #define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61 #define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b #define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e #define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a #define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69 #define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71 #define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72 #define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73 /* * BULK_IN messages from Reader to PC * Defined in CCID Rev 1.1 6.2 (page 48) */ #define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80 #define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81 #define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82 #define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83 #define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84 /* * INTERRUPT_IN messages from Reader to PC * Defined in CCID Rev 1.1 6.3 (page 56) */ #define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50 #define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51 /* * Endpoints for CCID - addresses are up to us to decide. * To support slot insertion and removal we must have an interrupt in ep * in addition we need a bulk in and bulk out ep * 5.2, page 20 */ #define CCID_INT_IN_EP (1 | 0x80) #define CCID_BULK_IN_EP (2 | 0x80) #define CCID_BULK_OUT_EP (3) typedef struct __attribute__((packed)) CCID_Header { uint8_t bMessageType; uint32_t dwLength; uint8_t bSlot; uint8_t bSeq; } CCID_Header; typedef struct __attribute__((packed)) CCID_BULK_IN { CCID_Header hdr; uint8_t bStatus; /* Only used in BULK_IN */ uint8_t bError; /* Only used in BULK_IN */ } CCID_BULK_IN; typedef struct __attribute__((packed)) CCID_SlotStatus { CCID_BULK_IN b; uint8_t bClockStatus; } CCID_SlotStatus; int main(int argc, char *argv[]) { int len, xlen, pos, xfered, rc; uint8_t buf[CCID_MAX_PACKET_SIZE]; CCID_Header *hdr = (void*)&buf; CCID_SlotStatus *slot = (void*)&buf; find_device("smartcard reader", 0x08e6, 0x4433); fprintf(stderr, "init ok\n"); sleep(1); /* ------------------------------------------------------------ */ fprintf(stderr, "checking slot status ...\n"); memset(buf, 0, sizeof(buf)); hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus; hdr->dwLength = len = 10; rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP, buf, len, &xfered, 1000); if (rc != 0) { fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc); exit(1); } fprintf(stderr, "slot-status out %d/%d\n", xfered, len); memset(buf, 0, sizeof(buf)); len = sizeof(CCID_SlotStatus); rc = libusb_bulk_transfer(hdev, CCID_BULK_IN_EP, buf, len, &xfered, 1000); if (rc != 0) { fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc); exit(1); } fprintf(stderr, "slot-status out %d/%d\n", xfered, len); fprintf(stderr, "status: 0x%x, error: 0x%x\n", slot->b.bStatus, slot->b.bError); if (slot->b.bStatus != 0x00 || slot->b.bError != 0x00) { fprintf(stderr, "bad slot status (no card?)\n"); exit(1); } fprintf(stderr, "... ok\n"); /* ------------------------------------------------------------ */ fprintf(stderr, "sending extra large apdu\n"); memset(buf, 0, sizeof(buf)); hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU; hdr->dwLength = len = 1024 * 1024; pos = 0; while (pos < len) { xlen = (len - pos); if (xlen > CCID_MAX_PACKET_SIZE) xlen = CCID_MAX_PACKET_SIZE; rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP, buf, xlen, &xfered, 1000); if (rc != 0) { fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc); exit(1); } pos += xfered; fprintf(stderr, "\r%d/%d ", pos, len); memset(buf, 0xaa, sizeof(buf)); } fprintf(stderr, "done\n"); exit(0); }