Friday, August 27, 2010

RAM and CPU improvements in pcsc-lite 1.6.x

Between pcsc-lite 1.5.x and pcsc-lite 1.6.x I improved many aspects regarding resources consumption: CPU and memory.

System used


For the measures I used an embedded Linux on an ARM9 CPU. This is a typical embedded system. The relative gains are comparable on a desktop PC even if the numbers are different.

The CCID driver is the standard one with support of 159 readers. Only this driver is installed.

Note that pcscd is compiled to use libusb instead of the default libhal. The targeted system does not have libhal available. So the libusb-1.0 code is shared between pcscd and libccid.

CPU consumption


Start up time


From 13193049 µs (13 s) to 258262 µs (0.3 s) ⇒ factor x51 or 5008%

pcsc-lite 1.5.x (and previous versions) used a complexity exponential with the number of readers supported in a Info.plist file.

pcsc-lite 1.6.x now has a complexity linear with the number of readers supported in a Info.plist file.

No more polling


In previous versions the sources of polling were:
  • SCardGetStatusChange

    This function is used by an application to detect card events or readers events. In the previous implementation the client library libpcsclite regularly asked the daemon the list of connected readers and card status.

  • Reader hotplug

    If libusb is used by pcsc-lite the USB bus is scanned every 1 second. It is no more the case with libhal.

  • Card events

    The card status is asked by pcscd to the card driver every 200ms. If the driver supports TAG_IFD_POLLING_THREAD then it is no more the case. My CCID driver supports this feature.

In version 1.6.x no polling is done by pcsc-lite. So if nothing happens with the reader(s) then the CPU activity of pcsc-lite is 0%.

RAM consumption of pcscd


Global


Numbers are from the VSZ field from ps(1)

With no reader connected:
From 1516 kB to 976 kB ⇒ gain 36% or 540 kB

With one reader connected:
From 1688 kB to 1180 kB ⇒ gain 30% or 508 kB

text


From 76 kB to 88 kB ⇒ loss 15%
The code has grow. Mainly because of the use of a list management library.

heap


With no reader connected:
From 624 kB to 84 kB ⇒ gain 86% or 540 kB

With one reader connected:
From 652 kB to 132 kB ⇒; gain 80% or 520 kB

RAM consumption with optimization for embedded systems


As described in a previous article "pcsc-lite for limited (embedded) systems" it is possible to limit the RAM consumption by disabling features.

--enable-embedded


Both pcsc-lite and libccid supports the --enable-embedded flag.

Global consumption with one reader connected and compared to version 1.6.x:
From 1180 kB to 1152 kB ⇒ gain 2% or 28 kB

--enable-embedded and --disable-serial


Compared to the previous case:
From 1152 kB to 1144 kB ⇒ gain 1% or 8 kB

Compared to the normal case:
From 1180 kB to 1144 kB ⇒ gain 3% or 36 kB

RAM consumption repartition


The graphic bellow gives the repartition (sorted by size) of RAM used by the different parts of a running pcscd with a CCID reader connected.



If I separate the different libraries used from pcscd + libpcsclite + heap + stack we have:



The code I have an impact on (pcsc-lite and libccid) is only 34% of the total RAM consumed. So any further improvement will be rather limited.

But the libraries uClibc, libpthread, libgcc and libdl may also be used by other applications and be present only once in memory and shared. So the real RAM consumption is more complex than shown in the graphics.

RAM consumption of libpcsclite.so


Measures are done using the testpcsc sample program.

libpcsclite text


Without --enable-embedded:
From 36 kB to 32 kB ⇒ gain 11% or 4 kB

With --enable-embedded:
From 36 kB to 24 kB ⇒ gain 33% or 12 kB

libpcsclite data


The communication between pcscd and libpcsclite do not use a shared memory segment any more. So the pcscd.pub RAM mapped file is no more used and 64 kB of RAM are saved.

Conclusion


The start up speed has greatly been improved. This is even more important now that we can start pcscd automatically when needed from libpcsclite.

The use of lists instead of static arrays has decreased the RAM consumed in normal cases and allowed to use much more contexts.


Flattr this

Friday, August 20, 2010

PCSC sample in Ada

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

Installation


The PCSC/Ada project is hosted at http://www.nongnu.org/pcscada.

PCSC/Ada is available as package in Debian testing/unstable and Ubuntu
10.04.

Debian squeeze (testing at time of writing this article)


To install the PCSC/Ada development package type:

$ sudo apt-get install libpcscada1-dev

Debian Lenny (stable)


If you use Debian stable (Lenny), an unofficial backport is also
available from codelabs.ch. To install the backport package, perform the
following steps:

Add this line to /etc/apt/sources.list:

deb http://www.codelabs.ch/debian lenny-backports main contrib non-free

Then, execute the following commands:

$ sudo apt-get update
$ sudo apt-get install debian-codelabs-archive-keyring
$ sudo apt-get update

To install the PCSC/Ada development package type:

$ sudo apt-get install libpcscada1-dev

If you want to compile PCSC/Ada from source, see the distributed README
file for details.

API


The API documentation is available online at
http://www.nongnu.org/pcscada/api/index.html.


Source code


Makefile


all: ada_sample

ada_sample:
 @gnatmake -p -Ppcscada_sample

clean:
 @rm -rf obj

pcscada_sample.gpr


with "pcscada";

project PCSCAda_Sample is

   for Object_Dir use "obj";
   for Source_Dirs use (".");
   for Main use ("ada_sample.adb");

   Compiler_Switches := ("-gnaty3aAbcdefhiIklnprStuxM80o",
                         "-gnatVa",
                         "-gnat05",
                         "-gnatwal",
                         "-gnatf",
                         "-fstack-check",
                         "-gnato",
                         "-g");

   package Compiler is
      for Default_Switches ("ada") use Compiler_Switches;
   end Compiler;

   package Binder is
      for Default_Switches ("ada") use ("-E");
   end Binder;

end PCSCAda_Sample;


ada_sample.adb


with Ada.Text_IO;

with PCSC.SCard.Utils;

use PCSC;

procedure Ada_Sample is

   package SCU renames SCard.Utils;

   My_Context : SCard.Context;
   First_Card : SCard.Card;
   Readers    : SCard.Reader_ID_Set;
   Recv_PCI   : SCard.IO_Request;
   Recv_Len   : Natural := 0;

   APDU_Select  : constant SCard.Byte_Set :=
     (16#00#, 16#A4#, 16#04#, 16#00#, 16#0A#,
      16#A0#, 16#00#, 16#00#, 16#00#, 16#62#,
      16#03#, 16#01#, 16#0C#, 16#06#, 16#01#);
   APDU_Command : constant SCard.Byte_Set :=
     (16#00#, 16#00#, 16#00#, 16#00#);

begin

   --  Establish context

   SCard.Establish_Context (Context => My_Context,
                            Scope   => SCard.Scope_System);

   --  List readers

   Readers := SCard.List_Readers (Context => My_Context);
   Ada.Text_IO.Put_Line ("Readers found:");
   SCU.For_Every_Reader (Readers => Readers,
                         Call    => SCU.Print_ReaderID'Access);

   --  Connect with the card in first reader

   SCard.Connect (Context => My_Context,
                  Card    => First_Card,
                  Reader  => Readers.First_Item,
                  Mode    => SCard.Share_Shared);

   --  Send APDUs

   Send_Select_Applet_APDU :
   declare
      Recv_Buffer : SCard.Byte_Set (1 .. 128);
   begin
      SCard.Transmit (Card        => First_Card,
                      Send_Buffer => APDU_Select,
                      Recv_Pci    => Recv_PCI,
                      Recv_Buffer => Recv_Buffer,
                      Recv_Len    => Recv_Len);
      Ada.Text_IO.Put_Line
        ("Select applet: " & SCU.To_Hex_String
         (Given => Recv_Buffer,
          Len   => 2 * Recv_Len));
   end Send_Select_Applet_APDU;

   Send_Command_APDU :
   declare
      Recv_Buffer : SCard.Byte_Set (1 .. 32);
   begin
      SCard.Transmit (Card        => First_Card,
                      Send_Buffer => APDU_Command,
                      Recv_Pci    => Recv_PCI,
                      Recv_Buffer => Recv_Buffer,
                      Recv_Len    => Recv_Len);
      Ada.Text_IO.Put_Line
        ("Command      : "
         & SCU.To_String (Given => Recv_Buffer (1 .. Recv_Len)));
   end Send_Command_APDU;

   --  Disconnect the card

   SCard.Disconnect (Card   => First_Card,
                     Action => SCard.Unpower_Card);

   --  Release context

   SCard.Release_Context (Context => My_Context);

exception
   when others =>
      Ada.Text_IO.Put_Line ("OOPS - got an exception:");
      if SCard.Is_Valid (Context => My_Context) then
         SCard.Release_Context (Context => My_Context);
      end if;

      raise;
end Ada_Sample;

Compilation


Just type make.


$ make
object directory "/home/rousseau/blog/pcscada_sample/obj" created
gcc-4.4 -c -gnaty3aAbcdefhiIklnprStuxM80o -gnatVa -gnat05 -gnatwal -gnatf -fstack-check -gnato -g -I- -gnatA /home/rousseau/blog/pcscada_sample/ada_sample.adb
gnatbind -shared -E -I- -x /home/rousseau/blog/pcscada_sample/obj/ada_sample.ali
gnatlink /home/rousseau/blog/pcscada_sample/obj/ada_sample.ali -shared-libgcc -L/usr/lib -lpcscada -o /home/rousseau/blog/pcscada_sample/obj/ada_sample


The generated binary is ./obj/ada_sample.

Output


$ ./obj/ada_sample
Readers found:
Gemalto GemPC Twin 00 00
Select applet: 9000
Command : Hello world!�


Conclusion


I do not use Ada myself so I can't really say more. This wrapper should do the job if you do use Ada.

Thanks a lot to Reto Buerki, the author of the Ada wrapper, for writing the sample code for me.


Flattr this

Thursday, August 19, 2010

How to help my projects?

I am now a member of flattr.com. Go see the web site if you do not know flattr yet.

The idea is to give money to the people doing things you like. So if you like this blog or my smart card project you can say so by clicking the flattr icon
on the right just above my picture.

Thanks


Flattr this

pcsc-lite 1.6.x breaks some programs at compilation

Minor API change


pcsc-lite 1.6.x makes the compilation of some badly written programs to fail. Badly written programs include my owns: pcsc-tools and pcsc-perl.

SCARD_READERSTATE_A


Windows uses two versions for the SCARD_READERSTATE structure:
  • SCARD_READERSTATE_W

    If UNICODE is defined and the szReader field is a LPCWSTR using wide characters
  • SCARD_READERSTATE_A

    If UNICODE is not define and the szReader field is a LPCSTR using normal characters

Since Unix uses UTF-8 instead of UTF-16 we do not need those stupid wide characters. Every string (ASCII or Unicode or what ever encoding) is a char [].

The problem is that the Windows winscard API only uses SCARD_READERSTATE externally and programs should never use SCARD_READERSTATE_W or SCARD_READERSTATE_A.

pcsc-lite 1.6.2 removed the definition of SCARD_READERSTATE_A PSCARD_READERSTATE_A and LPSCARD_READERSTATE_A types

LPSCARD_READERSTATE


This type was missing and has been added in pcsc-lite 1.6.3. pcsc-lite up to 1.6.1 defined LPSCARD_READERSTATE_A instead and we have seen why it was a bad idea.


SCARD_W_INSERTED_CARD


The SCARD_W_INSERTED_CARD error code was specific to pcsc-lite and was never used. I removed its declaration.

If your code uses it just remove the line.

No ABI change


Only the compilation of some programs will fail. The execution should not fail. The ABI (Application Binary Interface) has not changed.


Flattr this

Sunday, August 15, 2010

ATR not (yet) in my database

If you are using my online ATR parsing I presented in Parsing an ATR you may have used an ATR of a card I do not know. You then get a:

Possibly identified card: UNKNOWN

Now a new "Enter the card description" link is added to allow you to file a card description. The form looks like:



Remarks


  • To avoid spam and abuse you first have to login using a google account.
  • The design is really minimalistic (I am not a web designer). If you have ideas to improve the look-n-feel just contact me.
  • I still have to manually edit a file to add your ATR. So do not be impatient and do not resubmit the same ATR.


Flattr this

Friday, August 13, 2010

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.


Flattr this

Tuesday, August 10, 2010

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 3.0.

You are free:

  • to Share — to copy, distribute and transmit the work
  • to 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.



Flattr this

Friday, August 6, 2010

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.


Flattr this