pcsc-lite 2.3.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
38#include "config.h"
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "pcsclite.h"
44#include "winscard.h"
45#include "reader.h"
46
47#define PANIC 0
48#define DONT_PANIC 1
49
50#define USE_AUTOALLOCATE
51
52#define BLUE "\33[34m"
53#define RED "\33[31m"
54#define BRIGHT_RED "\33[01;31m"
55#define GREEN "\33[32m"
56#define NORMAL "\33[0m"
57#define MAGENTA "\33[35m"
58
59static void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic)
60{
61 if (rv != SCARD_S_SUCCESS)
62 {
63 if (dont_panic)
64 printf(BLUE "%s (don't panic)\n" NORMAL, pcsc_stringify_error(rv));
65 else
66 {
67 printf(RED "%s\n" NORMAL, pcsc_stringify_error(rv));
68 (void)SCardReleaseContext(hContext);
69 exit(-1);
70 }
71 }
72 else
73 (void)puts(pcsc_stringify_error(rv));
74}
75
76int main(/*@unused@*/ int argc, /*@unused@*/ char **argv)
77{
78 SCARDHANDLE hCard;
79 SCARDCONTEXT hContext;
80 SCARD_READERSTATE rgReaderStates[1];
81 DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
82 DWORD dwPref, dwReaders = 0;
83 char *pcReader = NULL, *mszReaders;
84#ifdef USE_AUTOALLOCATE
85 unsigned char *pbAtr = NULL;
86#else
87 unsigned char pbAtr[MAX_ATR_SIZE];
88#endif
89 union {
90 unsigned char as_char[100];
91 DWORD as_DWORD;
92 uint32_t as_uint32_t;
93 } buf;
94 DWORD dwBufLen;
95 unsigned char *pbAttr = NULL;
96 DWORD pcbAttrLen;
97 char *mszGroups;
98 DWORD dwGroups = 0;
99 long rv;
100 DWORD i;
101 int p, iReader;
102 int iList[16] = {0};
103 SCARD_IO_REQUEST ioRecvPci = *SCARD_PCI_T0; /* use a default value */
104 const SCARD_IO_REQUEST *pioSendPci;
105 unsigned char bSendBuffer[MAX_BUFFER_SIZE];
106 unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
107 DWORD send_length, length;
108
109 (void)argc;
110 (void)argv;
111
112 printf("\nMUSCLE PC/SC Lite unitary test Program\n\n");
113
114 printf(MAGENTA "THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL FOR END USERS!\n");
115 printf("Do NOT use it unless you really know what you do.\n\n" NORMAL);
116
117 printf("Testing SCardEstablishContext\t: ");
118 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
119 test_rv(rv, hContext, PANIC);
120
121 printf("Testing SCardIsValidContext\t: ");
122 rv = SCardIsValidContext(hContext);
123 test_rv(rv, hContext, PANIC);
124
125 printf("Testing SCardIsValidContext\t: ");
126 rv = SCardIsValidContext(hContext+1);
127 test_rv(rv, hContext, DONT_PANIC);
128
129 printf("Testing SCardListReaderGroups\t: ");
130#ifdef USE_AUTOALLOCATE
131 dwGroups = SCARD_AUTOALLOCATE;
132 rv = SCardListReaderGroups(hContext, (LPSTR)&mszGroups, &dwGroups);
133#else
134 rv = SCardListReaderGroups(hContext, NULL, &dwGroups);
135 test_rv(rv, hContext, PANIC);
136
137 printf("Testing SCardListReaderGroups\t: ");
138 mszGroups = calloc(dwGroups, sizeof(char));
139 rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups);
140#endif
141 test_rv(rv, hContext, PANIC);
142
143 /*
144 * Have to understand the multi-string here
145 */
146 p = 0;
147 for (i = 0; i+1 < dwGroups; i++)
148 {
149 ++p;
150 printf(GREEN "Group %02d: %s\n" NORMAL, p, &mszGroups[i]);
151 while (mszGroups[++i] != 0) ;
152 }
153
154#ifdef USE_AUTOALLOCATE
155 printf("Testing SCardFreeMemory\t\t: ");
156 rv = SCardFreeMemory(hContext, mszGroups);
157 test_rv(rv, hContext, PANIC);
158#else
159 free(mszGroups);
160#endif
161
162wait_for_card_again:
163 mszGroups = NULL;
164 printf("Testing SCardListReaders\t: ");
165 rv = SCardListReaders(hContext, mszGroups, NULL, &dwReaders);
166 test_rv(rv, hContext, DONT_PANIC);
168 {
169 printf("Testing SCardGetStatusChange \n");
170 printf("Please insert a working reader\t: ");
171 (void)fflush(stdout);
172 rgReaderStates[0].szReader = "\\\\?PnP?\\Notification";
173 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
174
175 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
176 test_rv(rv, hContext, PANIC);
177 }
178
179 printf("Testing SCardListReaders\t: ");
180#ifdef USE_AUTOALLOCATE
181 dwReaders = SCARD_AUTOALLOCATE;
182 rv = SCardListReaders(hContext, mszGroups, (LPSTR)&mszReaders, &dwReaders);
183#else
184 rv = SCardListReaders(hContext, mszGroups, NULL, &dwReaders);
185 test_rv(rv, hContext, PANIC);
186
187 printf("Testing SCardListReaders\t: ");
188 mszReaders = calloc(dwReaders, sizeof(char));
189 rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders);
190#endif
191 test_rv(rv, hContext, PANIC);
192
193 /*
194 * Have to understand the multi-string here
195 */
196 p = 0;
197 for (i = 0; i+1 < dwReaders; i++)
198 {
199 ++p;
200 printf(GREEN "Reader %02d: %s\n" NORMAL, p, &mszReaders[i]);
201 iList[p] = i;
202 while (mszReaders[++i] != 0) ;
203 }
204
205 if (p > 1)
206 {
207 int again = 0;
208
209 do
210 {
211 char input[80];
212 char *r;
213
214 printf("Enter the reader number\t\t: ");
215 r = fgets(input, sizeof(input), stdin);
216 if (NULL == r)
217 iReader = -1;
218 else
219 iReader = atoi(input);
220
221 if (iReader > p || iReader <= 0)
222 {
223 printf("Invalid Value - try again\n");
224 again = 1;
225 }
226 }
227 while (again);
228 }
229 else
230 iReader = 1;
231
232 rgReaderStates[0].szReader = &mszReaders[iList[iReader]];
233 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
234
235 printf("Waiting for card insertion\t: ");
236 (void)fflush(stdout);
237 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
238 test_rv(rv, hContext, PANIC);
239 if (rgReaderStates[0].dwEventState & SCARD_STATE_UNKNOWN)
240 {
241 printf("\nA reader has been connected/disconnected\n");
242 goto wait_for_card_again;
243 }
244
245 printf("Testing SCardConnect\t\t: ");
246 rv = SCardConnect(hContext, &mszReaders[iList[iReader]],
248 &hCard, &dwPref);
249 test_rv(rv, hContext, PANIC);
250
251 switch(dwPref)
252 {
254 pioSendPci = SCARD_PCI_T0;
255 break;
257 pioSendPci = SCARD_PCI_T1;
258 break;
260 pioSendPci = SCARD_PCI_RAW;
261 break;
262 default:
263 printf("Unknown protocol\n");
264 return -1;
265 }
266
267 /* APDU select file */
268 printf("Select file:");
269 send_length = 7;
270 memcpy(bSendBuffer, "\x00\xA4\x00\x00\x02\x3F\x00", send_length);
271 for (i=0; i<send_length; i++)
272 printf(" %02X", bSendBuffer[i]);
273 printf("\n");
274 length = sizeof(bRecvBuffer);
275
276 printf("Testing SCardTransmit\t\t: ");
277 rv = SCardTransmit(hCard, pioSendPci, bSendBuffer, send_length,
278 &ioRecvPci, bRecvBuffer, &length);
279 test_rv(rv, hContext, PANIC);
280 printf(" card response:" GREEN);
281 for (i=0; i<length; i++)
282 printf(" %02X", bRecvBuffer[i]);
283 printf("\n" NORMAL);
284
285 printf("Testing SCardControl\t\t: ");
286 {
287 char buffer[1024] = { 0x02 };
288 DWORD cbRecvLength = sizeof(buffer);
289
290 rv = SCardControl(hCard, SCARD_CTL_CODE(1), buffer, 1, buffer,
291 sizeof(buffer), &cbRecvLength);
292 if (cbRecvLength && (SCARD_S_SUCCESS == rv))
293 {
294 for (i=0; i<cbRecvLength; i++)
295 printf("%c", buffer[i]);
296 printf(" ");
297 }
298 }
299 test_rv(rv, hContext, DONT_PANIC);
300
301 printf("Testing SCardGetAttrib\t\t: ");
302#ifdef USE_AUTOALLOCATE
303 pcbAttrLen = SCARD_AUTOALLOCATE;
304 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, (unsigned char *)&pbAttr,
305 &pcbAttrLen);
306#else
307 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, NULL, &pcbAttrLen);
308 test_rv(rv, hContext, DONT_PANIC);
309 if (rv == SCARD_S_SUCCESS)
310 {
311 printf("SCARD_ATTR_DEVICE_FRIENDLY_NAME length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
312 pbAttr = malloc(pcbAttrLen);
313 }
314
315 printf("Testing SCardGetAttrib\t\t: ");
316 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME, pbAttr, &pcbAttrLen);
317#endif
318 test_rv(rv, hContext, DONT_PANIC);
319 if (rv == SCARD_S_SUCCESS)
320 printf("SCARD_ATTR_DEVICE_FRIENDLY_NAME: " GREEN "%s\n" NORMAL, pbAttr);
321
322#ifdef USE_AUTOALLOCATE
323 printf("Testing SCardFreeMemory\t\t: ");
324 rv = SCardFreeMemory(hContext, pbAttr);
325 test_rv(rv, hContext, PANIC);
326#else
327 if (pbAttr)
328 free(pbAttr);
329#endif
330
331 printf("Testing SCardGetAttrib\t\t: ");
332#ifdef USE_AUTOALLOCATE
333 pcbAttrLen = SCARD_AUTOALLOCATE;
334 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, (unsigned char *)&pbAttr,
335 &pcbAttrLen);
336#else
337 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &pcbAttrLen);
338 test_rv(rv, hContext, DONT_PANIC);
339 if (rv == SCARD_S_SUCCESS)
340 {
341 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
342 pbAttr = malloc(pcbAttrLen);
343 }
344
345 printf("Testing SCardGetAttrib\t\t: ");
346 rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAttr, &pcbAttrLen);
347#endif
348 test_rv(rv, hContext, DONT_PANIC);
349 if (rv == SCARD_S_SUCCESS)
350 {
351 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld\n" NORMAL, pcbAttrLen);
352 printf("SCARD_ATTR_ATR_STRING: " GREEN);
353 for (i = 0; i < pcbAttrLen; i++)
354 printf("%02X ", pbAttr[i]);
355 printf("\n" NORMAL);
356 }
357
358#ifdef USE_AUTOALLOCATE
359 printf("Testing SCardFreeMemory\t\t: ");
360 rv = SCardFreeMemory(hContext, pbAttr);
361 test_rv(rv, hContext, PANIC);
362#else
363 if (pbAttr)
364 free(pbAttr);
365#endif
366
367 printf("Testing SCardGetAttrib\t\t: ");
368 dwBufLen = sizeof(buf);
369 rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_IFD_VERSION, buf.as_char, &dwBufLen);
370 test_rv(rv, hContext, DONT_PANIC);
371 if (rv == SCARD_S_SUCCESS)
372 {
373 int valid = 1; /* valid value by default */
374 long value;
375 printf("Vendor IFD version\t\t: ");
376 if (dwBufLen == sizeof(DWORD))
377 value = buf.as_DWORD;
378 else
379 {
380 if (dwBufLen == sizeof(uint32_t))
381 value = buf.as_uint32_t;
382 else
383 {
384 printf(RED "Unsupported size\n" NORMAL);
385 valid = 0; /* invalid value */
386 }
387 }
388
389 if (valid)
390 {
391 int M = (value & 0xFF000000) >> 24; /* Major */
392 int m = (value & 0x00FF0000) >> 16; /* Minor */
393 int b = (value & 0x0000FFFF); /* build */
394 printf(GREEN "%d.%d.%d\n" NORMAL, M, m, b);
395 }
396 }
397
398 printf("Testing SCardGetAttrib\t\t: ");
399 dwBufLen = sizeof(buf);
400 rv = SCardGetAttrib(hCard, SCARD_ATTR_MAXINPUT, buf.as_char, &dwBufLen);
401 test_rv(rv, hContext, DONT_PANIC);
402 if (rv == SCARD_S_SUCCESS)
403 {
404 if (dwBufLen == sizeof(uint32_t))
405 printf("Max message length\t\t: " GREEN "%d\n" NORMAL,
406 buf.as_uint32_t);
407 else
408 printf(RED "Wrong size" NORMAL);
409 }
410
411 printf("Testing SCardGetAttrib\t\t: ");
412 dwBufLen = sizeof(buf);
413 rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_NAME, buf.as_char, &dwBufLen);
414 test_rv(rv, hContext, DONT_PANIC);
415 if (rv == SCARD_S_SUCCESS)
416 printf("Vendor name\t\t\t: " GREEN "%s\n" NORMAL, buf.as_char);
417
418 printf("Testing SCardSetAttrib\t\t: ");
419 rv = SCardSetAttrib(hCard, SCARD_ATTR_ATR_STRING, (LPCBYTE)"", 1);
420 test_rv(rv, hContext, DONT_PANIC);
421
422 printf("Testing SCardStatus\t\t: ");
423
424#ifdef USE_AUTOALLOCATE
425 dwReaderLen = SCARD_AUTOALLOCATE;
426 dwAtrLen = SCARD_AUTOALLOCATE;
427 rv = SCardStatus(hCard, (LPSTR)&pcReader, &dwReaderLen, &dwState, &dwProt,
428 (LPBYTE)&pbAtr, &dwAtrLen);
429#else
430 dwReaderLen = 100;
431 pcReader = malloc(sizeof(char) * 100);
432 dwAtrLen = MAX_ATR_SIZE;
433
434 rv = SCardStatus(hCard, pcReader, &dwReaderLen, &dwState, &dwProt,
435 pbAtr, &dwAtrLen);
436#endif
437 test_rv(rv, hContext, PANIC);
438
439 printf("Current Reader Name\t\t: " GREEN "%s\n" NORMAL, pcReader);
440 printf("Current Reader State\t\t: " GREEN "0x%.4lx\n" NORMAL, dwState);
441 printf("Current Reader Protocol\t\t: T=" GREEN "%ld\n" NORMAL, dwProt - 1);
442 printf("Current Reader ATR Size\t\t: " GREEN "%ld" NORMAL " bytes\n",
443 dwAtrLen);
444 printf("Current Reader ATR Value\t: " GREEN);
445
446 for (i = 0; i < dwAtrLen; i++)
447 {
448 printf("%02X ", pbAtr[i]);
449 }
450 printf(NORMAL "\n");
451
452#ifdef USE_AUTOALLOCATE
453 printf("Testing SCardFreeMemory\t\t: ");
454 rv = SCardFreeMemory(hContext, pcReader);
455 test_rv(rv, hContext, PANIC);
456 printf("Testing SCardFreeMemory\t\t: ");
457 rv = SCardFreeMemory(hContext, pbAtr);
458 test_rv(rv, hContext, PANIC);
459#else
460 if (pcReader)
461 free(pcReader);
462#endif
463
464 printf("Press enter: ");
465 (void)getchar();
466 printf("Testing SCardReconnect\t\t: ");
467 rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
469 test_rv(rv, hContext, PANIC);
470
471 printf("Testing SCardDisconnect\t\t: ");
472 rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
473 test_rv(rv, hContext, PANIC);
474
475#ifdef USE_AUTOALLOCATE
476 printf("Testing SCardFreeMemory\t\t: ");
477 rv = SCardFreeMemory(hContext, mszReaders);
478 test_rv(rv, hContext, PANIC);
479#else
480 free(mszReaders);
481#endif
482
483 printf("Testing SCardReleaseContext\t: ");
484 rv = SCardReleaseContext(hContext);
485 test_rv(rv, hContext, PANIC);
486
487 printf("\n");
488 printf("PC/SC Test Completed Successfully !\n");
489
490 return 0;
491}
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.