pcsc-lite 2.5.0
testpcsc.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2004-2022
7 * Ludovic Rousseau <ludovic.rousseau@free.fr>
8 *
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
183. The name of the author may not be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
37
38#include "config.h"
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <stdbool.h>
43
44#include "pcsclite.h"
45#include "winscard.h"
46#include "reader.h"
47
48#define PANIC 0
49#define DONT_PANIC 1
50
51#define USE_AUTOALLOCATE
52
53#define BLUE "\33[34m"
54#define RED "\33[31m"
55#define BRIGHT_RED "\33[01;31m"
56#define GREEN "\33[32m"
57#define NORMAL "\33[0m"
58#define MAGENTA "\33[35m"
59
60static void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic)
61{
62 if (rv != SCARD_S_SUCCESS)
63 {
64 if (dont_panic)
65 printf(BLUE "%s (don't panic)\n" NORMAL, pcsc_stringify_error(rv));
66 else
67 {
68 printf(RED "%s\n" NORMAL, pcsc_stringify_error(rv));
69 (void)SCardReleaseContext(hContext);
70 exit(-1);
71 }
72 }
73 else
74 (void)puts(pcsc_stringify_error(rv));
75}
76
77int main(/*@unused@*/ int argc, /*@unused@*/ char **argv)
78{
79 SCARDHANDLE hCard;
80 SCARDCONTEXT hContext = -1;
81 SCARD_READERSTATE rgReaderStates[1];
82 DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
83 DWORD dwPref = -1, dwReaders = 0;
84 char *pcReader = NULL, *mszReaders;
85#ifdef USE_AUTOALLOCATE
86 unsigned char *pbAtr = NULL;
87#else
88 unsigned char pbAtr[MAX_ATR_SIZE];
89#endif
90 union {
91 unsigned char as_char[100];
92 DWORD as_DWORD;
93 uint32_t as_uint32_t;
94 } buf;
95 DWORD dwBufLen;
96 unsigned char *pbAttr = NULL;
97 DWORD pcbAttrLen;
98 char *mszGroups = NULL;
99 DWORD dwGroups = 0;
100 long rv;
101 DWORD i;
102 int p, iReader;
103 int iList[512] = {0};
104 SCARD_IO_REQUEST ioRecvPci = *SCARD_PCI_T0; /* use a default value */
105 const SCARD_IO_REQUEST *pioSendPci;
106 unsigned char bSendBuffer[MAX_BUFFER_SIZE];
107 unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
108 DWORD send_length, length;
109
110 (void)argc;
111 (void)argv;
112
113 printf("\nMUSCLE PC/SC Lite unitary test Program\n\n");
114
115 printf(MAGENTA "THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL FOR END USERS!\n");
116 printf("Do NOT use it unless you really know what you do.\n\n" NORMAL);
117
118 printf("Testing SCardEstablishContext\t: ");
119 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
120 test_rv(rv, hContext, PANIC);
121
122 printf("Testing SCardIsValidContext\t: ");
123 rv = SCardIsValidContext(hContext);
124 test_rv(rv, hContext, PANIC);
125
126 printf("Testing SCardIsValidContext\t: ");
127 rv = SCardIsValidContext(hContext+1);
128 test_rv(rv, hContext, DONT_PANIC);
129
130 printf("Testing SCardListReaderGroups\t: ");
131#ifdef USE_AUTOALLOCATE
132 dwGroups = SCARD_AUTOALLOCATE;
133 rv = SCardListReaderGroups(hContext, (LPSTR)&mszGroups, &dwGroups);
134#else
135 rv = SCardListReaderGroups(hContext, NULL, &dwGroups);
136 test_rv(rv, hContext, PANIC);
137
138 printf("Testing SCardListReaderGroups\t: ");
139 mszGroups = calloc(dwGroups, sizeof(char));
140 rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups);
141#endif
142 test_rv(rv, hContext, PANIC);
143
144 /*
145 * Have to understand the multi-string here
146 */
147 p = 0;
148 for (i = 0; i+1 < dwGroups; i++)
149 {
150 ++p;
151 printf(GREEN "Group %02d: %s\n" NORMAL, p, &mszGroups[i]);
152 while (mszGroups[++i] != 0) ;
153 }
154
155#ifdef USE_AUTOALLOCATE
156 printf("Testing SCardFreeMemory\t\t: ");
157 rv = SCardFreeMemory(hContext, mszGroups);
158 test_rv(rv, hContext, PANIC);
159#else
160 free(mszGroups);
161#endif
162
163wait_for_card_again:
164 mszGroups = NULL;
165 printf("Testing SCardListReaders\t: ");
166 rv = SCardListReaders(hContext, mszGroups, NULL, &dwReaders);
167 test_rv(rv, hContext, DONT_PANIC);
169 {
170 printf("Testing SCardGetStatusChange \n");
171 printf("Please insert a working reader\t: ");
172 (void)fflush(stdout);
173 rgReaderStates[0].szReader = "\\\\?PnP?\\Notification";
174 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
175
176 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
177 test_rv(rv, hContext, PANIC);
178 }
179
180 printf("Testing SCardListReaders\t: ");
181#ifdef USE_AUTOALLOCATE
182 dwReaders = SCARD_AUTOALLOCATE;
183 rv = SCardListReaders(hContext, mszGroups, (LPSTR)&mszReaders, &dwReaders);
184#else
185 rv = SCardListReaders(hContext, mszGroups, NULL, &dwReaders);
186 test_rv(rv, hContext, PANIC);
187
188 printf("Testing SCardListReaders\t: ");
189 mszReaders = calloc(dwReaders, sizeof(char));
190 rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders);
191#endif
192 test_rv(rv, hContext, PANIC);
193
194 /*
195 * Have to understand the multi-string here
196 */
197 p = 0;
198 for (i = 0; i+1 < dwReaders; i++)
199 {
200 ++p;
201 printf(GREEN "Reader %02d: %s\n" NORMAL, p, &mszReaders[i]);
202 iList[p] = i;
203 while (mszReaders[++i] != 0) ;
204 }
205
206 if (p > 1)
207 {
208 bool again = false;
209
210 do
211 {
212 char input[80];
213 char *r;
214
215 again = false;
216 printf("Enter the reader number\t\t: ");
217 r = fgets(input, sizeof(input), stdin);
218 if (NULL == r)
219 iReader = -1;
220 else
221 iReader = atoi(input);
222
223 if (iReader > p || iReader <= 0)
224 {
225 printf("Invalid Value - try again\n");
226 again = true;
227 }
228 }
229 while (again);
230 }
231 else
232 iReader = 1;
233
234 rgReaderStates[0].szReader = &mszReaders[iList[iReader]];
235 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
236
237 printf("Waiting for card insertion\t: ");
238 (void)fflush(stdout);
239 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
240 test_rv(rv, hContext, PANIC);
241 if (rgReaderStates[0].dwEventState & SCARD_STATE_UNKNOWN)
242 {
243 printf("\nA reader has been connected/disconnected\n");
244 goto wait_for_card_again;
245 }
246
247 printf("Testing SCardConnect\t\t: ");
248 rv = SCardConnect(hContext, &mszReaders[iList[iReader]],
250 &hCard, &dwPref);
251 test_rv(rv, hContext, PANIC);
252
253 switch(dwPref)
254 {
256 pioSendPci = SCARD_PCI_T0;
257 break;
259 pioSendPci = SCARD_PCI_T1;
260 break;
262 pioSendPci = SCARD_PCI_RAW;
263 break;
264 default:
265 printf("Unknown protocol\n");
266 return -1;
267 }
268
269 /* APDU select file */
270 printf("Select file:");
271 send_length = 7;
272 memcpy(bSendBuffer, "\x00\xA4\x00\x00\x02\x3F\x00", send_length);
273 for (i=0; i<send_length; i++)
274 printf(" %02X", bSendBuffer[i]);
275 printf("\n");
276 length = sizeof(bRecvBuffer);
277
278 printf("Testing SCardTransmit\t\t: ");
279 rv = SCardTransmit(hCard, pioSendPci, bSendBuffer, send_length,
280 &ioRecvPci, bRecvBuffer, &length);
281 test_rv(rv, hContext, PANIC);
282 printf(" card response:" GREEN);
283 for (i=0; i<length; i++)
284 printf(" %02X", bRecvBuffer[i]);
285 printf("\n" NORMAL);
286
287 printf("Testing SCardControl\t\t: ");
288 {
289 char buffer[1024] = { 0x02 };
290 DWORD cbRecvLength = sizeof(buffer);
291
292 rv = SCardControl(hCard, SCARD_CTL_CODE(1), buffer, 1, buffer,
293 sizeof(buffer), &cbRecvLength);
294 if (cbRecvLength && (SCARD_S_SUCCESS == rv))
295 {
296 for (i=0; i<cbRecvLength; i++)
297 printf("%c", buffer[i]);
298 printf(" ");
299 }
300 }
301 test_rv(rv, hContext, DONT_PANIC);
302
303 printf("Testing SCardGetAttrib\t\t: ");
304#ifdef USE_AUTOALLOCATE
305 pcbAttrLen = SCARD_AUTOALLOCATE;
306 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, (unsigned char *)&pbAttr,
307 &pcbAttrLen);
308#else
309 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, NULL, &pcbAttrLen);
310 test_rv(rv, hContext, DONT_PANIC);
311 if (rv == SCARD_S_SUCCESS)
312 {
313 printf("SCARD_ATTR_DEVICE_FRIENDLY_NAME length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
314 pbAttr = malloc(pcbAttrLen);
315 }
316
317 printf("Testing SCardGetAttrib\t\t: ");
318 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, pbAttr, &pcbAttrLen);
319#endif
320 test_rv(rv, hContext, DONT_PANIC);
321 if (rv == SCARD_S_SUCCESS)
322 printf("SCARD_ATTR_DEVICE_FRIENDLY_NAME: " GREEN "%s\n" NORMAL, pbAttr);
323
324#ifdef USE_AUTOALLOCATE
325 printf("Testing SCardFreeMemory\t\t: ");
326 rv = SCardFreeMemory(hContext, pbAttr);
327 test_rv(rv, hContext, PANIC);
328#else
329 if (pbAttr)
330 free(pbAttr);
331#endif
332
333 printf("Testing SCardGetAttrib\t\t: ");
334#ifdef USE_AUTOALLOCATE
335 pcbAttrLen = SCARD_AUTOALLOCATE;
336 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, (unsigned char *)&pbAttr,
337 &pcbAttrLen);
338#else
339 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &pcbAttrLen);
340 test_rv(rv, hContext, DONT_PANIC);
341 if (rv == SCARD_S_SUCCESS)
342 {
343 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
344 pbAttr = malloc(pcbAttrLen);
345 }
346
347 printf("Testing SCardGetAttrib\t\t: ");
348 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAttr, &pcbAttrLen);
349#endif
350 test_rv(rv, hContext, DONT_PANIC);
351 if (rv == SCARD_S_SUCCESS)
352 {
353 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
354 printf("SCARD_ATTR_ATR_STRING: " GREEN);
355 for (i = 0; i < pcbAttrLen; i++)
356 printf("%02X ", pbAttr[i]);
357 printf("\n" NORMAL);
358 }
359
360#ifdef USE_AUTOALLOCATE
361 printf("Testing SCardFreeMemory\t\t: ");
362 rv = SCardFreeMemory(hContext, pbAttr);
363 test_rv(rv, hContext, PANIC);
364#else
365 if (pbAttr)
366 free(pbAttr);
367#endif
368
369 printf("Testing SCardGetAttrib\t\t: ");
370 dwBufLen = sizeof(buf);
371 rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_IFD_VERSION, buf.as_char, &dwBufLen);
372 test_rv(rv, hContext, DONT_PANIC);
373 if (rv == SCARD_S_SUCCESS)
374 {
375 int valid = 1; /* valid value by default */
376 long value;
377 printf("Vendor IFD version\t\t: ");
378 if (dwBufLen == sizeof(DWORD))
379 value = buf.as_DWORD;
380 else
381 {
382 if (dwBufLen == sizeof(uint32_t))
383 value = buf.as_uint32_t;
384 else
385 {
386 printf(RED "Unsupported size\n" NORMAL);
387 valid = 0; /* invalid value */
388 }
389 }
390
391 if (valid)
392 {
393 int M = (value & 0xFF000000) >> 24; /* Major */
394 int m = (value & 0x00FF0000) >> 16; /* Minor */
395 int b = (value & 0x0000FFFF); /* build */
396 printf(GREEN "%d.%d.%d\n" NORMAL, M, m, b);
397 }
398 }
399
400 printf("Testing SCardGetAttrib\t\t: ");
401 dwBufLen = sizeof(buf);
402 rv = SCardGetAttrib(hCard, SCARD_ATTR_MAXINPUT, buf.as_char, &dwBufLen);
403 test_rv(rv, hContext, DONT_PANIC);
404 if (rv == SCARD_S_SUCCESS)
405 {
406 if (dwBufLen == sizeof(uint32_t))
407 printf("Max message length\t\t: " GREEN "%d\n" NORMAL,
408 buf.as_uint32_t);
409 else
410 printf(RED "Wrong size" NORMAL);
411 }
412
413 printf("Testing SCardGetAttrib\t\t: ");
414 dwBufLen = sizeof(buf);
415 rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_NAME, buf.as_char, &dwBufLen);
416 test_rv(rv, hContext, DONT_PANIC);
417 if (rv == SCARD_S_SUCCESS)
418 printf("Vendor name\t\t\t: " GREEN "%s\n" NORMAL, buf.as_char);
419
420 printf("Testing SCardSetAttrib\t\t: ");
421 rv = SCardSetAttrib(hCard, SCARD_ATTR_ATR_STRING, (LPCBYTE)"", 1);
422 test_rv(rv, hContext, DONT_PANIC);
423
424 printf("Testing SCardStatus\t\t: ");
425
426#ifdef USE_AUTOALLOCATE
427 dwReaderLen = SCARD_AUTOALLOCATE;
428 dwAtrLen = SCARD_AUTOALLOCATE;
429 rv = SCardStatus(hCard, (LPSTR)&pcReader, &dwReaderLen, &dwState, &dwProt,
430 (LPBYTE)&pbAtr, &dwAtrLen);
431#else
432 dwReaderLen = 100;
433 pcReader = malloc(sizeof(char) * 100);
434 dwAtrLen = MAX_ATR_SIZE;
435
436 rv = SCardStatus(hCard, pcReader, &dwReaderLen, &dwState, &dwProt,
437 pbAtr, &dwAtrLen);
438#endif
439 test_rv(rv, hContext, PANIC);
440
441 printf("Current Reader Name\t\t: " GREEN "%s\n" NORMAL, pcReader);
442 printf("Current Reader State\t\t: " GREEN "0x%.4lx\n" NORMAL, dwState);
443 printf("Current Reader Protocol\t\t: T=" GREEN "%ld\n" NORMAL, dwProt - 1);
444 printf("Current Reader ATR Size\t\t: " GREEN "%ld" NORMAL " bytes\n",
445 dwAtrLen);
446 printf("Current Reader ATR Value\t: " GREEN);
447
448 for (i = 0; i < dwAtrLen; i++)
449 {
450 printf("%02X ", pbAtr[i]);
451 }
452 printf(NORMAL "\n");
453
454#ifdef USE_AUTOALLOCATE
455 printf("Testing SCardFreeMemory\t\t: ");
456 rv = SCardFreeMemory(hContext, pcReader);
457 test_rv(rv, hContext, PANIC);
458 printf("Testing SCardFreeMemory\t\t: ");
459 rv = SCardFreeMemory(hContext, pbAtr);
460 test_rv(rv, hContext, PANIC);
461#else
462 if (pcReader)
463 free(pcReader);
464#endif
465
466 printf("Press enter: ");
467 (void)getchar();
468 printf("Testing SCardReconnect\t\t: ");
469 rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
471 test_rv(rv, hContext, PANIC);
472
473 printf("Testing SCardDisconnect\t\t: ");
474 rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
475 test_rv(rv, hContext, PANIC);
476
477#ifdef USE_AUTOALLOCATE
478 printf("Testing SCardFreeMemory\t\t: ");
479 rv = SCardFreeMemory(hContext, mszReaders);
480 test_rv(rv, hContext, PANIC);
481#else
482 free(mszReaders);
483#endif
484
485 printf("Testing SCardReleaseContext\t: ");
486 rv = SCardReleaseContext(hContext);
487 test_rv(rv, hContext, PANIC);
488
489 printf("\n");
490 printf("PC/SC Test Completed Successfully !\n");
491
492 return 0;
493}
PCSC_API const char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition error.c:82
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition pcsclite.h:202
This keeps a list of defines for pcsc-lite.
#define SCARD_SCOPE_SYSTEM
Scope in system.
Definition pcsclite.h:237
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition pcsclite.h:243
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition pcsclite.h:242
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition pcsclite.h:234
#define SCARD_UNPOWER_CARD
Power down on close.
Definition pcsclite.h:255
#define SCARD_SHARE_SHARED
Shared mode only.
Definition pcsclite.h:250
#define MAX_ATR_SIZE
Maximum ATR size.
Definition pcsclite.h:59
#define SCARD_PCI_RAW
protocol control information (PCI) for RAW protocol
Definition pcsclite.h:97
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition pcsclite.h:269
#define INFINITE
Infinite timeout.
Definition pcsclite.h:280
#define SCARD_STATE_EMPTY
Card removed.
Definition pcsclite.h:271
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition pcsclite.h:244
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition pcsclite.h:298
#define SCARD_PCI_T1
protocol control information (PCI) for T=1
Definition pcsclite.h:96
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define SCARD_PCI_T0
protocol control information (PCI) for T=0
Definition pcsclite.h:95
This keeps a list of defines shared between the driver and the application.
#define SCARD_ATTR_VENDOR_IFD_VERSION
Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version,...
Definition reader.h:60
#define SCARD_ATTR_DEVICE_FRIENDLY_NAME
Reader's display name.
Definition reader.h:111
#define SCARD_ATTR_MAXINPUT
FIXME.
Definition reader.h:97
#define SCARD_CTL_CODE(code)
Provide source compatibility on different platforms.
Definition reader.h:118
#define SCARD_ATTR_VENDOR_NAME
Vendor name.
Definition reader.h:58
#define SCARD_ATTR_ATR_STRING
Answer to reset (ATR) string.
Definition reader.h:91
Protocol Control Information (PCI).
Definition pcsclite.h:80
This handles smart card reader communications.