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  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. 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.
18 3. 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 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS 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 #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 
60 static 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 
77 int 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 
163 wait_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  {
255  case SCARD_PROTOCOL_T0:
256  pioSendPci = SCARD_PCI_T0;
257  break;
258  case SCARD_PROTOCOL_T1:
259  pioSendPci = SCARD_PCI_T1;
260  break;
261  case SCARD_PROTOCOL_RAW:
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 }
#define SCARD_ATTR_ATR_STRING
Answer to reset (ATR) string.
Definition: reader.h:91
#define SCARD_ATTR_DEVICE_FRIENDLY_NAME
Reader's display name.
Definition: reader.h:111
#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_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:298
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:271
This keeps a list of defines shared between the driver and the application.
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:202
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:243
#define SCARD_PCI_T0
protocol control information (PCI) for T=0
Definition: pcsclite.h:95
#define SCARD_PCI_RAW
protocol control information (PCI) for RAW protocol
Definition: pcsclite.h:97
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:280
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:269
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:234
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_SHARE_SHARED
Shared mode only.
Definition: pcsclite.h:250
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:242
#define SCARD_ATTR_MAXINPUT
FIXME.
Definition: reader.h:97
#define SCARD_PCI_T1
protocol control information (PCI) for T=1
Definition: pcsclite.h:96
#define SCARD_UNPOWER_CARD
Power down on close.
Definition: pcsclite.h:255
This keeps a list of defines for pcsc-lite.
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:244
#define SCARD_CTL_CODE(code)
Provide source compatibility on different platforms.
Definition: reader.h:118
Protocol Control Information (PCI)
Definition: pcsclite.h:79
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_ATTR_VENDOR_NAME
Vendor name.
Definition: reader.h:58
#define MAX_ATR_SIZE
Maximum ATR size.
Definition: pcsclite.h:59
#define SCARD_SCOPE_SYSTEM
Scope in system.
Definition: pcsclite.h:237
This handles smart card reader communications.