1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#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);
}
|