PCSC API spy for GNU systems

Executive summary


  1. Copy the file ltrace.conf to ~/.ltrace.conf
  2. Use with: ltrace -l/usr/lib/libpcsclite.so your_application

Discussion


It may be difficult to debug a PC/SC application. You can ask pcscd to generate logs using --debug but these logs are mainly to trace problems at the reader level, not at the application level.

ltrace


ltrace (wikipedia)
ltrace is a debugging utility in Linux to monitor the library calls used by a program and all the signals it receives. It can also show system calls, used by a program.

It is easy to use ltrace to trace a program. I will use the testpcsc program included in pcsc-lite as a PC/SC sample code:
$ ltrace .libs/testpcsc


__libc_start_main(0x8048c5a, 1, 0xbfdfadb4, 0x8049dc0, 0x8049db0 
puts("\nMUSCLE PC/SC Lite unitary test "...
MUSCLE PC/SC Lite unitary test Program

)     = 41
puts("\033[35mTHIS PROGRAM IS NOT DESIGNE"...THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL FOR END USERS!
)   = 67
printf("Do NOT use it unless you really "...Do NOT use it unless you really know what you do.

)    = 55
printf("Testing SCardEstablishContext\t:"...)    = 32
SCardEstablishContext(2, 0, 0, 0xbfdfacd8, 0)    = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xb778780d, 0xb7764ff4, 0) = 0xb778c340
puts("Command successful."Testing SCardEstablishContext : Command successful.
)                      = 20
printf("Testing SCardIsValidContext\t: ")        = 30
SCardIsValidContext(0x103a3a0, 0x103a3a0, 0, 0xbfdfacd8, 0) = 0
pcsc_stringify_error(0, 0, 0xbfdfa568, 0xb77855ce, 0x103a3a0) = 0xb778c340
puts("Command successful."Testing SCardIsValidContext : Command successful.
)                      = 20
printf("Testing SCardIsValidContext\t: ")        = 30
SCardIsValidContext(0x103a3a1, 0x103a3a0, 0, 0xbfdfacd8, 0) = 0x80100003
pcsc_stringify_error(0x80100003, 0, 0xbfdfa568, 0xb77855ce, 0xbfdfa574) = 0xb778c340
printf("\033[34m%s (don't panic)\n\033[0"..., "Invalid handle."Testing SCardIsValidContext : Invalid handle. (don't panic)
) = 39
printf("Testing SCardListReaderGroups\t:"...)    = 32
SCardListReaderGroups(0x103a3a0, 0xbfdfac08, 0xbfdfac04, 0xbfdfacd8, 0) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfac08, 0xb7764ff4, 0) = 0xb778c340
puts("Command successful."Testing SCardListReaderGroups : Command successful.
)                      = 20
printf("\033[32mGroup %02d: %s\n\033[0m", 1, "SCard$DefaultReaders"Group 01: SCard$DefaultReaders
) = 40
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea0f8, 0x96ea0f8, 0xbfdfacd8, 0) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0x96ea0f8, 0xb77855e0, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Testing SCardListReaders\t: ")           = 27
SCardListReaders(0x103a3a0, 0, 0, 0xbfdfac88, 0) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0, 0xb7764ff4, 0) = 0xb778c340
puts("Command successful."Testing SCardListReaders : Command successful.
)                      = 20
printf("Testing SCardListReaders\t: ")           = 27
SCardListReaders(0x103a3a0, 0, 0xbfdfac80, 0xbfdfac88, 0) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0xbfdfac88, 0) = 0xb778c340
puts("Command successful."Testing SCardListReaders : Command successful.
)                      = 20
printf("\033[32mReader %02d: %s\n\033[0m", 1, "Lenovo Integrated Smart Card Rea"...Reader 01: Lenovo Integrated Smart Card Reader 00 00
) = 62
printf("Waiting for card insertion\t: ")         = 29
fflush(0xb77654c0Waiting for card insertion : )                               = 0
SCardGetStatusChange(0x103a3a0, -1, 0xbfdfaca0, 1, 0) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfaca0, 0xbfdfac88, 0) = 0xb778c340
puts("Command successful."Command successful.
)                      = 20
printf("Testing SCardConnect\t\t: ")             = 24
SCardConnect(0x103a3a0, 0x96ea118, 2, 3, 0xbfdfacdc) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfacdc, 0xbfdfac88, 0) = 0xb778c340
puts("Command successful."Testing SCardConnect  : Command successful.
)                      = 20
printf("Select file:")                           = 12
memcpy(0xbfdfaaa8, "", 7)                        = 0xbfdfaaa8
printf(" %02X", 0)                               = 3
printf(" %02X", 0xa4)                            = 3
printf(" %02X", 0)                               = 3
printf(" %02X", 0)                               = 3
printf(" %02X", 0x2)                             = 3
printf(" %02X", 0x3f)                            = 3
printf(" %02X", 0)                               = 3
putchar(10, 0, 7, 3, 0xbfdfacdcSelect file: 00 A4 00 00 02 3F 00
)                 = 10
printf("Testing SCardTransmit\t\t: ")            = 25
SCardTransmit(105074, 0xbfdfabb0, 0xbfdfaaa8, 7, 0xbfdfabb8) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfabb0, 0xbfdfac88, 0) = 0xb778c340
puts("Command successful."Testing SCardTransmit  : Command successful.
)                      = 20
printf(" card response:\033[32m")                = 20
printf(" %02X", 0x6f)                            = 3
printf(" %02X", 0x14)                            = 3
printf(" %02X", 0x84)                            = 3
printf(" %02X", 0xd)                             = 3
printf(" %02X", 0x70)                            = 3
printf(" %02X", 0x3c)                            = 3
printf(" %02X", 0x71)                            = 3
printf(" %02X", 0xb7)                            = 3
printf(" %02X", 0x6c)                            = 3
printf(" %02X", 0x3a)                            = 3
printf(" %02X", 0x8)                             = 3
printf(" %02X", 0x9)                             = 3
printf(" %02X", 0x2f)                            = 3
printf(" %02X", 0x2d)                            = 3
printf(" %02X", 0x73)                            = 3
printf(" %02X", 0xb7)                            = 3
printf(" %02X", 0xff)                            = 3
printf(" %02X", 0xa5)                            = 3
printf(" %02X", 0x3)                             = 3
printf(" %02X", 0x88)                            = 3
printf(" %02X", 0x1)                             = 3
printf(" %02X", 0)                               = 3
printf(" %02X", 0x90)                            = 3
printf(" %02X", 0)                               = 3
printf("\n\033[0m" card response: 6F 14 84 0D 70 3C 71 B7 6C 3A 08 09 2F 2D 73 B7 FF A5 03 88 01 00 90 00
)                              = 5
printf("Testing SCardControl\t\t: ")             = 24
SCardControl(105074, 0x42000001, 0xbfdfa598, 1, 0xbfdfa598) = 0x80100016
pcsc_stringify_error(0x80100016, 0xb77b73a0, 0xbfdfa598, 0xbfdfa598, 0) = 0xb778c340
printf("\033[34m%s (don't panic)\n\033[0"..., "Transaction failed."Testing SCardControl  : Transaction failed. (don't panic)
) = 43
printf("Testing SCardGetAttrib\t\t: ")           = 26
SCardGetAttrib(105074, 0x7fff0003, 0xbfdfac10, 0xbfdfac0c, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfac10, 0xbfdfa598, 0) = 0xb778c340
puts("Command successful."Testing SCardGetAttrib  : Command successful.
)                      = 20
printf("SCARD_ATTR_DEVICE_FRIENDLY_NAME:"...SCARD_ATTR_DEVICE_FRIENDLY_NAME: Lenovo Integrated Smart Card Reader 00 00
)    = 84
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea198, 1, 0xbfdfac0c, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0x8049fbe, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Testing SCardGetAttrib\t\t: ")           = 26
SCardGetAttrib(105074, 590595, 0xbfdfac10, 0xbfdfac0c, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0xbfdfa598, 0) = 0xb778c340
puts("Command successful."Testing SCardGetAttrib  : Command successful.
)                      = 20
printf("SCARD_ATTR_ATR_STRING length: \033"...SCARD_ATTR_ATR_STRING length: 23
)  = 42
printf("SCARD_ATTR_ATR_STRING: \033[32m")        = 28
printf("%02X ", 0x3b)                            = 3
printf("%02X ", 0x9f)                            = 3
printf("%02X ", 0x95)                            = 3
printf("%02X ", 0x81)                            = 3
printf("%02X ", 0x31)                            = 3
printf("%02X ", 0xfe)                            = 3
printf("%02X ", 0x9f)                            = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0x65)                            = 3
printf("%02X ", 0x46)                            = 3
printf("%02X ", 0x53)                            = 3
printf("%02X ", 0x5)                             = 3
printf("%02X ", 0x30)                            = 3
printf("%02X ", 0x6)                             = 3
printf("%02X ", 0x71)                            = 3
printf("%02X ", 0xdf)                            = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0x81)                            = 3
printf("%02X ", 0x61)                            = 3
printf("%02X ", 0x16)                            = 3
printf("%02X ", 0xc0)                            = 3
printf("\n\033[0m"SCARD_ATTR_ATR_STRING: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 16 C0 
)                              = 5
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea198, 1, 0xbfdfac0c, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0x8049fbe, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Testing SCardGetAttrib\t\t: ")           = 26
SCardGetAttrib(105074, 65794, 0xbfdfac18, 0xbfdfac14, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0xbfdfa598, 0) = 0xb778c340
puts("Command successful."Testing SCardGetAttrib  : Command successful.
)                      = 20
printf("Vendor IFD version\t\t: \033[32m"...Vendor IFD version  : 0x0103000D
)    = 42
printf("Testing SCardGetAttrib\t\t: ")           = 26
SCardGetAttrib(105074, 499719, 0xbfdfac18, 0xbfdfac14, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0xbfdfa598, 0) = 0xb778c340
puts("Command successful."Testing SCardGetAttrib  : Command successful.
)                      = 20
printf("Max message length\t\t: \033[32m"..., 261Max message length  : 261
) = 35
printf("Testing SCardGetAttrib\t\t: ")           = 26
SCardGetAttrib(105074, 65792, 0xbfdfac18, 0xbfdfac14, 0xbfdfa598) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0xbfdfa598, 0) = 0xb778c340
puts("Command successful."Testing SCardGetAttrib  : Command successful.
)                      = 20
printf("Vendor name\t\t\t: \033[32m%s\n\033"..., "Ludovic Rousseau"Vendor name : Ludovic Rousseau
) = 42
printf("Testing SCardSetAttrib\t\t: ")           = 26
SCardSetAttrib(105074, 590595, 0x804a2ab, 1, 0xbfdfa598) = 0x80100016
pcsc_stringify_error(0x80100016, 0x804a2ab, 0xbfdfa57c, 0xb77867a0, 105074) = 0xb778c340
printf("\033[34m%s (don't panic)\n\033[0"..., "Transaction failed."Testing SCardSetAttrib  : Transaction failed. (don't panic)
) = 43
printf("Testing SCardStatus\t\t: ")              = 23
SCardStatus(105074, 0xbfdfac84, 0xbfdfac9c, 0xbfdfac98, 0xbfdfac94) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfac84, 0xbfdfac90, 0) = 0xb778c340
puts("Command successful."Testing SCardStatus  : Command successful.
)                      = 20
printf("Current Reader Name\t\t: \033[32"..., "Lenovo Integrated Smart Card Rea"...Current Reader Name  : Lenovo Integrated Smart Card Reader 00 00
) = 74
printf("Current Reader State\t\t: \033[3"...Current Reader State  : 0x10034
)    = 41
printf("Current Reader Protocol\t\t: T=\033"...Current Reader Protocol  : T=1
) = 40
printf("Current Reader ATR Size\t\t: \033"...Current Reader ATR Size  : 23 bytes
)   = 45
printf("Current Reader ATR Value\t: \033"...)    = 32
printf("%02X ", 0x3b)                            = 3
printf("%02X ", 0x9f)                            = 3
printf("%02X ", 0x95)                            = 3
printf("%02X ", 0x81)                            = 3
printf("%02X ", 0x31)                            = 3
printf("%02X ", 0xfe)                            = 3
printf("%02X ", 0x9f)                            = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0x65)                            = 3
printf("%02X ", 0x46)                            = 3
printf("%02X ", 0x53)                            = 3
printf("%02X ", 0x5)                             = 3
printf("%02X ", 0x30)                            = 3
printf("%02X ", 0x6)                             = 3
printf("%02X ", 0x71)                            = 3
printf("%02X ", 0xdf)                            = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0)                               = 3
printf("%02X ", 0x81)                            = 3
printf("%02X ", 0x61)                            = 3
printf("%02X ", 0x16)                            = 3
printf("%02X ", 0xc0)                            = 3
puts("\033[0m"Current Reader ATR Value : 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 16 C0 
)                                  = 5
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea198, 0, 0xbfdfac98, 0xbfdfac94) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0x8049fbe, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea0f8, 0, 0xbfdfac98, 0xbfdfac94) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0x8049fbe, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Press enter: ")                          = 13
getchar(0x804a396, 0x103a3a0, 0, 0xbfdfac98, 0xbfdfac94Press enter: 
) = 10
printf("Testing SCardReconnect\t\t: ")           = 26
SCardReconnect(105074, 2, 3, 2, 0xbfdfac8c)      = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfac8c, 0xbfdfac90, 0) = 0xb778c340
puts("Command successful."Testing SCardReconnect  : Command successful.
)                      = 20
printf("Testing SCardDisconnect\t\t: ")          = 27
SCardDisconnect(105074, 2, 0, 2, 0xbfdfac8c)     = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfa4b4, 0xbfdfac90, 0) = 0xb778c340
puts("Command successful."Testing SCardDisconnect  : Command successful.
)                      = 20
printf("Testing SCardFreeMemory\t\t: ")          = 27
SCardFreeMemory(0x103a3a0, 0x96ea118, 0, 2, 0xbfdfac8c) = 0
pcsc_stringify_error(0, 0xb7669260, 0xb77654c0, 0x8049fbe, 0xb77855e9) = 0xb778c340
puts("Command successful."Testing SCardFreeMemory  : Command successful.
)                      = 20
printf("Testing SCardReleaseContext\t: ")        = 30
SCardReleaseContext(0x103a3a0, 0x103a3a0, 0, 2, 0xbfdfac8c) = 0
pcsc_stringify_error(0, 0xb77b73a0, 0xbfdfa4b4, 0xbfdfac90, 0) = 0xb778c340
puts("Command successful."Testing SCardReleaseContext : Command successful.
)                      = 20
putchar(10, 0x103a3a0, 0, 2, 0xbfdfac8c
)         = 10
puts("PC/SC Test Completed Successfull"...PC/SC Test Completed Successfully !
)      = 36
+++ exited (status 0) +++

Limitations


By default ltrace lists all the calls from all the libraries. You can restrict the tracing to one specific library using: -l/usr/lib/libpcsclite.so

The PC/SC API calls are not really useful. You have to parse the argument by hand. It is not easy to know what SCardConnect(0x103a3a0, 0x96ea118, 2, 3, 0xbfdfacdc) = 0 is really doing.

ltrace PCSC configuration file


ltrace can use a configuration file to parse the arguments of the functions and display a (more) human readable version.

The configuration file uses a very simple format. For example for SCardConnect I used:
scarderror SCardConnect(scardcontext, string, share_mode, protocol, +scardhandle*, +protocol*);

A ltrace configuration file is now included in the pcsc-lite project in the new contrib/ directory. Just copy the file to ~/.ltrace.conf.

Example with the configuration file


$ ltrace -l/usr/lib/libpcsclite.so .libs/testpcsc


MUSCLE PC/SC Lite unitary test Program

THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL FOR END USERS!
Do NOT use it unless you really know what you do.

SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, 0x103d6cb) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardEstablishContext : Command successful.
SCardIsValidContext(0x103d6cb)                   = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardIsValidContext : Command successful.
SCardIsValidContext(0x103d6cc)                   = SCARD_E_INVALID_HANDLE
pcsc_stringify_error(SCARD_E_INVALID_HANDLE)     = "Invalid handle."
Testing SCardIsValidContext : Invalid handle. (don't panic)
SCardListReaderGroups(0x103d6cb, "SCard$DefaultReaders", 22) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardListReaderGroups : Command successful.
Group 01: SCard$DefaultReaders
SCardFreeMemory(0x103d6cb, 0x09eb70f8)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
SCardListReaders(0x103d6cb, NULL, NULL, 43)      = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardListReaders : Command successful.
SCardListReaders(0x103d6cb, NULL, "Lenovo Integrated Smart Card Rea"..., 43) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardListReaders : Command successful.
Reader 01: Lenovo Integrated Smart Card Reader 00 00
Waiting for card insertion : SCardGetStatusChange(0x103d6cb, -1, { "Lenovo Integrated Smart Card Rea"..., 0x00000001, 16, 34, 23, [ ';', '\237', '\225', '\201'... ] }, 1) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Command successful.
SCardConnect(0x103d6cb, "Lenovo Integrated Smart Card Rea"..., SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0_SCARD_PROTOCOL_T1, 126261, SCARD_PROTOCOL_T1) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardConnect  : Command successful.
Select file: 00 A4 00 00 02 3F 00
SCardTransmit(126261, { SCARD_PROTOCOL_T1, 8 }, [ '\000', '\244', '\000', '\000'... ], 7, { 0xbfe04130, -1216591178 }, 'o', 24) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardTransmit  : Command successful.
 card response: 6F 14 84 0D 70 3C 71 B7 6C 3A 08 09 2F 2D 73 B7 FF A5 03 88 01 00 90 00
SCardControl(126261, 1107296257, [ '\002' ], 1, [ '\002', '\000', '\000', '\000'... ], 1024, 0) = SCARD_E_NOT_TRANSACTED
pcsc_stringify_error(SCARD_E_NOT_TRANSACTED)     = "Transaction failed."
Testing SCardControl  : Transaction failed. (don't panic)
SCardGetAttrib(126261, SCARD_ATTR_DEVICE_FRIENDLY_NAME, [  ], 42) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardGetAttrib  : Command successful.
SCARD_ATTR_DEVICE_FRIENDLY_NAME: Lenovo Integrated Smart Card Reader 00 00
SCardFreeMemory(0x103d6cb, 0x09eb7198)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
SCardGetAttrib(126261, SCARD_ATTR_ATR_STRING, [  ], 23) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardGetAttrib  : Command successful.
SCARD_ATTR_ATR_STRING length: 23
SCARD_ATTR_ATR_STRING: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 16 C0 
SCardFreeMemory(0x103d6cb, 0x09eb7198)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
SCardGetAttrib(126261, SCARD_ATTR_VENDOR_IFD_VERSION, [  ], 4) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardGetAttrib  : Command successful.
Vendor IFD version  : 0x0103000D
SCardGetAttrib(126261, SCARD_ATTR_MAXINPUT, [  ], 4) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardGetAttrib  : Command successful.
Max message length  : 261
SCardGetAttrib(126261, SCARD_ATTR_VENDOR_NAME, [  ], 17) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardGetAttrib  : Command successful.
Vendor name   : Ludovic Rousseau
SCardSetAttrib(126261, SCARD_ATTR_ATR_STRING, , 1) = SCARD_E_NOT_TRANSACTED
pcsc_stringify_error(SCARD_E_NOT_TRANSACTED)     = "Transaction failed."
Testing SCardSetAttrib  : Transaction failed. (don't panic)
SCardStatus(126261, "Lenovo Integrated Smart Card Rea"..., 42, 52, SCARD_PROTOCOL_T1, [ '\370', 'p', '\353', '\t'... ], 23) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardStatus  : Command successful.
Current Reader Name  : Lenovo Integrated Smart Card Reader 00 00
Current Reader State  : 0x0034
Current Reader Protocol  : T=1
Current Reader ATR Size  : 23 bytes
Current Reader ATR Value : 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 16 C0 
SCardFreeMemory(0x103d6cb, 0x09eb7198)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
SCardFreeMemory(0x103d6cb, 0x09eb70f8)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
Press enter: 
SCardReconnect(126261, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0_SCARD_PROTOCOL_T1, SCARD_UNPOWER_CARD, SCARD_PROTOCOL_T1) = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardReconnect  : Command successful.
SCardDisconnect(126261, SCARD_UNPOWER_CARD)      = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardDisconnect  : Command successful.
SCardFreeMemory(0x103d6cb, 0x09eb7118)           = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardFreeMemory  : Command successful.
SCardReleaseContext(0x103d6cb)                   = SCARD_S_SUCCESS
pcsc_stringify_error(SCARD_S_SUCCESS)            = "Command successful."
Testing SCardReleaseContext : Command successful.

PC/SC Test Completed Successfully !
+++ exited (status 0) +++

  • Call to other libraries (lib C in particular) are no more displayed
  • PCSC functions arguments are displayed in a human form

If I reuse the same SCardConnect example we now have:
SCardConnect(0x103d6cb, "Lenovo Integrated Smart Card Rea"..., SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0_SCARD_PROTOCOL_T1, 126261, SCARD_PROTOCOL_T1) = SCARD_S_SUCCESS

We get:
  • Connection context to the PC/SC Resource Manager. It is just a random numeric value: 0x103d6cb
  • Reader name to connect to: "Lenovo Integrated Smart Card Rea"...
  • Mode of connection type: exclusive or shared. SCARD_SHARE_SHARED
  • Desired protocol use: SCARD_PROTOCOL_T0_SCARD_PROTOCOL_T1
  • Handle to this connection: 126261
  • Established protocol to this connection: SCARD_PROTOCOL_T1
  • Return code: SCARD_S_SUCCESS

Conclusion


I discovered the use of ltrace very recently. The configuration file may contain bugs. But I hope it will be useful.

My blog messages license

To make things clear I added a license to the messages I post on this blog. The license is Creative Common Attribution-NonCommercial-ShareAlike 4.0 International.

You are free to:

  •  Share — to copy, distribute and transmit the work
  •  Remix — to adapt the work

Under the following conditions:


  •  Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

  •  NonCommercial — You may not use this work for commercial purposes.
  •  Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
You will find more information on the Creative Common web site for by-nc-sa.


[Update October 2023] upgrade from "CC BY-NC-SA 3.0 Deed" to "CC BY-NC-SA 4.0 Deed" as suggested by https://creativecommons.org/licenses/by-nc-sa/3.0/.

New CCID 1.4.0 and card movement notification mechanism

Card movement detection in the ancient times

Before the mechanism I will describe in this blog post was implemented and used, the only way pcsc-lite detected a card movement (card insertion or removal) was to poll the driver every 200ms to ask if a card was present or not in the reader and to compare with the previous state.

Advantages

Every driver (i.e. the old ones) implements the IFDHICCPresence function:
This function returns the status of the card inserted in the reader/slot specified by Lun.

Problems

Active polling

The driver is then continuously asking the reader. This is host CPU "intensive" and will prevent the CPU to go in sleep state to limit its power consumption. You can use the powertop tool to see that. This is BAD.

Performances

Another problem is that the pcscd is notified up to 200ms after the card status has changed. So if your application is waiting for a card insertion you can waste up to 200ms between the card insertion and the application being notified.

libccid 1.4.0

4 days ago I released a new version 1.4.0 of my CCID driver (libccid).

Changes

1.4.0 - 4 August 2010, Ludovic Rousseau

  • add support of Kingtrust Multi-Reader, Dectel CI692, Todos CX00,
    C3PO LTC36, ACS AET65, Broadcom 5880, Tianyu Smart Card Reader,
    Gemalto Hybrid Smartcard Reader
  • Add support of the SCM SDI 010 again. At least the contact
    interface can be used.
  • Use libusb-1.0 instead of libusb-0.1
  • add support of TAG_IFD_STOP_POLLING_THREAD and use of the asynchronous libusb API to be able to stop a transfer.
  • Request pcsc-lite 1.6.2 minimum (instead of 1.6.0) to have TAG_IFD_STOP_POLLING_THREAD defined
  • The O2MICRO OZ776 patch (for OZ776, OZ776_7772, REINER_SCT and BLUDRIVEII_CCID) is no more supported with libusb-1.0
  • correctly get the IFSC from the ATR (ATR parsing was not always correct)
  • some minor bugs removed

The change that will interest us here is the support of TAG_IFD_STOP_POLLING_THREAD. This is used so that pcscd can ask the driver to stop its polling function.

But the support of TAG_IFD_STOP_POLLING_THREAD has only be included in pcsc-lite 1.6.2. This is why you need pcsc-lite 1.6.2 to compile libccid 1.4.0.

pcsc-lite 1.6.2

The same day of the libcid 1.4.0 release I also released pcsc-lite 1.6.2.

Changes

pcsc-lite-1.6.2: Ludovic Rousseau
4 August 2010
  • implement a "Forced suicide" mechanism. After 3 Ctrl-C without much reaction from pcscd (in fact the drivers) we force the suicide. Sometimes libusb is blocked in a kind of dead-lock and kill -9 was the only option.
  • Add support of TAG_IFD_STOP_POLLING_THREAD to request the stop of the driver polling function.
  • Avoid a division by 0. Closes [#312555] "simclist bug in pcsc-lite"
  • if pcscd is started by libpcsclite then close all file handles except stdin, stdout and stderr so that pcscd does not confiscate resources allocated by the application
  • in case of auto exit create a new session so that Ctrl-C on the application will not also quit pcscd
  • src/hotplug_libusb.c: port from libusb-0.1 to libusb-1.0
  • default configuration is now $sysconfdir/reader.conf.d
  • fix crash with empty config dir
  • src/PCSC/winscard.h: Remove definitions of SCARD_READERSTATE_A PSCARD_READERSTATE_A and LPSCARD_READERSTATE_A types
  • some other minor improvements and bug corrections

Card movement notification

How does the card movement notification works with the CCID protocol?

USB interrupt end point

Some readers (but not all) provides an interrupt endpoint at the USB level. This endpoint is used to signal a card movement to the host even if the host does not send a CCID command to be notified. The host just has to read the interrupt endpoint.

From the CCID specification 1.1 § 5.2.3 Interrupt-IN Endpoint:
The interrupt pipe is mandatory for a CCID that supports ICC insertion/removal. It is optional for a CCID with ICCs that are always inserted and are not removable. If there is an Interrupt-In endpoint, then the RDR_to_PC_NotifySlotChange message is required and all other messages are optional.

RDR_to_PC_NotifySlotChange message

The first byte is bMessageType and its value is 0x50 indicating RDR_to_PC_NotifySlotChange.

The next bytes are bmSlotICCState:
This field is reported on byte granularity.
The size is ( 2 bits * number of slots ) rounded up to the nearest byte.
Each slot has 2 bits. The least significant bit reports the current state of the slot (0b = no ICC present, 1b = ICC present). The most significant bit reports whether the slot has changed state since the last RDR_to_PC_NotifySlotChange message was sent (0b = no change, 1b = change).
If no slot exists for a given location, the field returns 00b in those 2 bits.
Example: A 3 slot CCID reports a single byte with the following format:
Bit 0 = Slot 0 current state
Bit 1 = Slot 0 changed status
Bit 2 = Slot 1 current state
Bit 3 = Slot 1 changed status
Bit 4 = Slot 2 current state
Bit 5 = Slot 2 changed status
Bit 6 = 0b
Bit 7 = 0b

In short, and if the reader has only one slot, you will receive 0x50 0x03 when a card is removed and 0x50 0x02 when a card is inserted.

libusb

libusb-0.1

The use of an interrupt end point is already supported in libusb-0.1 but I had many issues when using this feature. The main issue is that libusb-0.1 calls are synchronous and it is not possible to (cleanly) interrupt a usb_interrupt_read call. It is then impossible to cleanly stop the driver when pcscd exits.

One hack I used is to make the usb_interrupt_read call timeout after 2 seconds. But it is still a kind of polling, even if the period is now 2 seconds instead of 200 ms.

libusb-1.0

libusb-1.0 has a new API and, in particular, an asynchronous API. Using the asynchronous API it is possible to cancel an ongoing call. This is exactly what is done when TAG_IFD_STOP_POLLING_THREAD is requested by pcscd to the driver.

But libusb-1.0 is relatively new and has bugs. The latest stable version 1.0.8 is not yet bug free and I found some bugs in particular cases. Bugs have been reported to the libusb project and most are already corrected.

Conclusion

pcscd when used with my CCID driver is now a good citizen regarding the computer CPU use. All the internal active polling loops have been removed and pcsc-lite is now completely event managed.

pcsc-lite for limited (embedded) systems

Limited or embedded systems


Since Linux is working everywhere some of this everywhere is connected to a smart card reader. And of course pcsc-lite is used.

Example of embedded systems


I am not aware of any projects using pcsc-lite. I will just give two examples.


  • Android: see the seek for android project trying to bring a Smartcard API for Android
  • GCR5500: It is a health care reader for doctors, etc. It is also possible to connect a USB smart card reader and pcsc-lite is used to manage this external reader.
  • Many set top boxes (ADSL modem, home routers, etc.) are using Linux. Some of the boxes have a smart card reader.

Memory optimisations


Starting with pcsc-lite 1.6.0 I worked on memory optimizations. The work is not yet finished since I have other ideas.

Disable unused interfaces


I added --disable-serial and --disable-usb options to remove code that will not be used.

  • --disable-serial removes support of /etc/reader.conf.

    gain: 8.0kB of .text (12%) and 160 bytes of .bss (4%) for pcscd
  • --disable-usb removes support of USB hotplug

    gain: 9.7kB of .text (14%) and 960 bytes of .bss (23%) for pcscd

If you use both options (and use a static driver configuration) gain:
17.7kB of .text (26%) and 1152 bytes of .bss (28%) for pcscd

No logs


Since the embedded systems are not supposed to be directly administered having logs in /var/log/syslog is not useful.

  • Minimal pcsc_stringify_error()

    If NO_LOG is defined a minimal pcsc_stringify_error() is used. The function is still available but only the error code in hex is displayed in this case.

    Gain: 2kB of .text (10%) for libpcsclite

  • No log function

    If NO_LOG is defined then no log are displayed. The log functions are defined (they are also used by the drivers) but are empty.

    With NO_LOG defined we gain 26% (17 kB) for the .text segment of pcscd and 15% (4 kB) for the .text segment of libpcsclite.so (for i386)

One option to activate the embedded mode


Just use the --enable-embedded (default is no) configure option to build pcsc-lite for an embedded system. This will activate the NO_LOG option to disable logging and limit RAM and disk consumption.

Results

If --enable-embedded is used and you disable the communication interface you do not use (serial or USB) you can expect a gain of 40% on the code size and then a reduced disk/flash space and memory used.

To be followed...

New version of pcsc-perl: 1.4.9

I just released a new version of pcsc-perl to fix a compilation bug.

The problem


pcsc-lite defined some error codes specific to pcsc-lite. One is SCARD_W_INSERTED_CARD.

This error code is never returned by pcsc-lite and has been removed in pcsc-lite revision 4574 included in pcsc-lite 1.6.0.

Solution


Do not reference this error code any more. The side effect is that if your Perl program uses SCARD_W_INSERTED_CARD it will fail and has to be corrected.

Thanks


Thanks to Olivier Huber for reporting the problem.

See also


A previous blog entry about this Perl PCSC wrapper: PCSC sample in Perl.

PyKCS11 history

This article is not part of the serie initiated by PC/SC sample in different languages. We will not use the PCSC API but the PKCS#11 API.

You can find the other articles in this serie from the first one: PyKCS11 introduction.

PKCS#11 (Cryptographic Token Interface Standard) is an API used to talk to cryptographic tokens like smart cards (but not only).

The PKCS#11 API is in C language but a wrapper for Python call pykcs11 also exists. We will use this wrapper. The project has a ohloh page.

History


The wrapper uses SWIG.
"SWIG is an interface compiler that connects programs written in C and C++ with scripting languages such as Perl, Python, Ruby, and Tcl. It works by taking the declarations found in C/C++ header files and using them to generate the wrapper code that scripting languages need to access the underlying C/C++ code. In addition, SWIG provides a variety of customization features that let you tailor the wrapping process to suit your application."

The wrapper is initialy written by Giuseppe Amato (started in 2004). But the API was very low level: one Python function for one PKCS#11 C function. This API was not really Python friendly. When I discovered the project, in 2006, I started writting a higher level API more Python oriented, object oriented and easier to use.

The project is still active. The latest version is 1.2.2 from June 2010.

Since I started this serie on PyKCS I added new methods and improved the wrapper to make it even easier to use.

PyKCS11 introduction

I will start a new serie about PyKCS11.

What is it?


PyKCS11 is a Python wrapper above the PKCS#11 API. PKCS#11 is a "Cryptographic Token Interface Standard" defined by RSA and used by smart cards (but not only).

If you are a user of PyKCS11 please add a comment. If you have requests about PyKCS11 please also add a comment.

Articles in the serie



Update on pcsc-lite security advisory CVE-2010-0407

I would like to update the status about the security issue of pcsc-lite also known as CVE-2010-0407. I presented the problem in pcsc-lite security advisory CVE-2010-0407

2 new CVE numbers


The fix in upstream revision 4208 was bogus. A fix of the fix is available in upstream revision 4334 and is included in pcsc-lite 1.5.5.

So even if pcsc-lite 1.5.4 do not have the security issue this version has a broken SCardControl() function. See Debian bug #585791 "Upgrading from pcscd_1.4.102-1_i386.deb to pcscd_1.4.102-1+lenny1_i386.deb broke my bankid application (digital signing internetbanking)".

CVE-2009-4901
The MSGFunctionDemarshall function in winscard_svc.c in the PC/SC Smart Card daemon (aka PCSCD) in MUSCLE PCSC-Lite before 1.5.4 might allow local users to cause a denial of service (daemon crash) via crafted SCARD_SET_ATTRIB message data, which is improperly demarshalled and triggers a buffer over-read, a related issue to CVE-2010-0407.

CVE-2009-4902

Buffer overflow in the MSGFunctionDemarshall function in winscard_svc.c in the PC/SC Smart Card daemon (aka PCSCD) in MUSCLE PCSC-Lite 1.5.4 and earlier might allow local users to gain privileges via crafted SCARD_CONTROL message data, which is improperly demarshalled. NOTE: this vulnerability exists because of an incorrect fix for CVE-2010-0407.

Debian


Debian should have a fixed fixed version named 1.4.102-1+lenny3 soon.

Red Hat


The Red Hat bug 596426 indicates that:


Others


Still no news about Ubuntu, SUSE Linux and the other GNU/Linux, *BSD or Unix distributions.

PCSC sample in Java

Here is the PCSC sample in Java language I promised in PC/SC sample in different languages.

Installation


Since Java 1.6 the JRE includes the package javax.smartcardio which was defined in the JSR 268. No need to compile additional source code.

For the example I used Eclipse Galileo and the Java 1.6 provided by Apple on a Mac OS X Snow Leopard (10.6.4).

Source code


import java.util.List;
import javax.smartcardio.*;

public class Blog {
 public static void main(String[] args) {
  try {
   // Display the list of terminals
   TerminalFactory factory = TerminalFactory.getDefault();
   List<CardTerminal> terminals = factory.terminals().list();
   System.out.println("Terminals: " + terminals);

   // Use the first terminal
   CardTerminal terminal = terminals.get(0);

   // Connect wit hthe card
   Card card = terminal.connect("*");
   System.out.println("card: " + card);
   CardChannel channel = card.getBasicChannel();

   // Send Select Applet command
   byte[] aid = {(byte)0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01};
   ResponseAPDU answer = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, 0x00, aid));
   System.out.println("answer: " + answer.toString());

   // Send test command
   answer = channel.transmit(new CommandAPDU(0x00, 0x00, 0x00, 0x00));
   System.out.println("answer: " + answer.toString());
   byte r[] = answer.getData();
   for (int i=0; i<r.length; i++)
    System.out.print((char)r[i]);
   System.out.println();

   // Disconnect the card
   card.disconnect(false);
  } catch(Exception e) {
   System.out.println("Ouch: " + e.toString());
  }
 }
}


Output



Terminals: [PC/SC terminal Gemplus GemPC Twin 00 00]
card: PC/SC card in Gemplus GemPC Twin 00 00, protocol T=1, state OK
answer: ResponseAPDU: 2 bytes, SW=9000
answer: ResponseAPDU: 14 bytes, SW=9000
Hello world!

Conclusion


Nothing special to add. The major advantage here is that the wrapper is included in the runtime. So you do not have to install much on a system before you can use your program, just the JRE :-)

pcsc-lite security advisory CVE-2010-0407

The problem


It is possible to trigger a buffer overflow in old versions of pcsc-lite, and possibly gain root access.

The bug is present in version 1.4.102 of pcsc-lite and has been corrected in revision 4208 (May 14 2009). This revision was included in pcsc-lite 1.5.4.

Debian


Debian published a DSA (Debian Security Advisory) DSA-2059-1 pcsc-lite -- buffer overflow about a vulnerability in pcsc-lite present in Debian stable.

Ubuntu


Ubuntu has not yet published a usn (Ubuntu security notices). Maybe because pcscd is part of universe and not main. But libpcsclite is part of main. Note that Ubuntu is vulnerable even in the latest version 10.04 LTS "Lucid Lynx"

Red Hat


Red Hat has an entry for the CVE on their security web site and on their bug tracking tool as bug 596426. Maybe a new package will be available soon.

SUSE Linux


I could not find information on the novell.com site. I don't even know what versions of pcsc-lite SUSE Linux Enterprise 11 is providing.

Other distributions


There are too many Unix distributions to mention them all. If you have pointers for a Unix system just add a comment and I will update the blog.