Important!

Blog moved to https://blog.apdu.fr/

I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...

Friday, May 20, 2022

ATR parsing in JSON

I updated my ATR parsing web site at https://smartcard-atr.apdu.fr/ to add the option to get the result not in an HTML page but as a JSON document.

If you do not yet know this service you can read "Parsing an ATR: new web site URL" to get some history. 


JSON

The URL for the JSON service is https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3BFF9700008131FE4380318065B0846160FB120FFD8290000D.

It is the same as for the HTML output https://smartcard-atr.apdu.fr/parse?ATR=3BFF9700008131FE4380318065B0846160FB120FFD8290000D except you replace "parse" by "V1/parse2json" in the URL.

Of course you update the ATR parameter value to use the ATR value you want to parse.

Examples

You can use it to get the description of a particular field by piping the result in the jq command.

jq is a lightweight and flexible command-line JSON processor.

For example to get the meaning of the TA1 byte you can use:

$ curl -s https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3B12953606 | jq '.TA."1"'
{
  "description": "Fi=512, Di=16, 32 cycles/ETU (125000 bits/s at 4.00 MHz, 156250 bits/s for fMax=5 MHz)",
  "value": 149
}

Or for just the TA1 description:

$ curl -s https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3B90160187 | jq '.TA."1".description'
"Fi=372, Di=32, 11.625 cycles/ETU (344086 bits/s at 4.00 MHz, 430107 bits/s for fMax=5 MHz)"

 

Card matching

I also added the possibility to get the cards matching a given ATR.

For example: https://smartcard-atr.apdu.fr/V1/match?ATR=3B8F800180318065B0850300EF120FFE82900072

$ curl -s https://smartcard-atr.apdu.fr/V1/match?ATR=3B8F800180318065B0850300EF120FFE82900072 | jq
{
  "3B 8F 80 01 80 31 80 65 B0 .. .. .. .. 12 0F FE 82 90 00 ..": [
    "IDPrime MD 3810 T=Contactless (Prox DU)"
  ],
  "3B 8F 80 01 80 31 80 65 B0 85 03 00 EF 12 0F FE 82 90 00 72": [
    "Gemalto IDPrime MD 3840",
    "http://www.gemalto.com/dwnld/6891_IDPrimeMD3840_Product_Datasheet_May14.pdf"
  ]
}

Because of the joker mechanism using the character '.' it is possible that one ATR matches more than one "card".


Conclusion

If you have ideas how to improve the service just tell me.

Saturday, May 14, 2022

SCardListReaders() and non-initialized pcchReaders parameter

Sample C sample

We start with the following sample.c program:

01: #include <stdio.h>
02: #include <stdlib.h>
03: #include <winscard.h>
04: 
05: #define CHECK(f, rv) \
06:  if (SCARD_S_SUCCESS != rv) \
07:  { \
08:   printf(f ": %s\n", pcsc_stringify_error(rv)); \
09:   return -1; \
10:  }
11: 
12: int main(void)
13: {
14:     LONG rv;
15: 
16:     SCARDCONTEXT hContext;
17:     LPTSTR mszReaders;
18:     DWORD dwReaders;
19: 
20:     rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
21:     CHECK("SCardEstablishContext", rv)
22: 
23:     rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
24:     CHECK("SCardListReaders", rv)
25: 
26:     mszReaders = calloc(dwReaders, sizeof(char));
27:     rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
28:     CHECK("SCardListReaders", rv)
29:     printf("1st reader name: %s\n", mszReaders);
30: 
31:     free(mszReaders);
32: 
33:     rv = SCardReleaseContext(hContext);
34:     CHECK("SCardReleaseContext", rv)
35: 
36:     return 0;
37: }
38: 

Makefile

I used this Makefile

# Linux
PCSC_CFLAGS := $(shell pkg-config --cflags libpcsclite)
LDLIBS := $(shell pkg-config --libs libpcsclite)

CFLAGS = $(PCSC_CFLAGS) -g

sample: sample.c

clean:
	rm -f sample

Output

Compilation and execution give:

$ make
cc -pthread -I/usr/include/PCSC -g   sample.c  -lpcsclite -o sample
$ ./sample 
1st reader name: Alcor Micro AU9540 00 00

It looks like everything is correct.

But can you find the problem?

 

Valgrind is your friend

valgrind is a very nice tool to debug issues.

Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tools.

valgrind sees a problem:

$ valgrind --track-origins=yes ./sample 
==99878== Memcheck, a memory error detector
==99878== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==99878== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==99878== Command: ./sample
==99878== 
==99878== Conditional jump or move depends on uninitialised value(s)
==99878==    at 0x486E02E: SCardListReaders (in /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0)
==99878==    by 0x109210: main (sample.c:23)
==99878==  Uninitialised value was created by a stack allocation
==99878==    at 0x109199: main (sample.c:13)
==99878== 
1st reader name: Alcor Micro AU9540 00 00
==99878== 
==99878== HEAP SUMMARY:
==99878==     in use at exit: 112 bytes in 4 blocks
==99878==   total heap usage: 10 allocs, 6 frees, 1,434 bytes allocated
==99878== 
==99878== LEAK SUMMARY:
==99878==    definitely lost: 0 bytes in 0 blocks
==99878==    indirectly lost: 0 bytes in 0 blocks
==99878==      possibly lost: 0 bytes in 0 blocks
==99878==    still reachable: 112 bytes in 4 blocks
==99878==         suppressed: 0 bytes in 0 blocks
==99878== Rerun with --leak-check=full to see details of leaked memory
==99878== 
==99878== For lists of detected and suppressed errors, rerun with: -s
==99878== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Using uninitialized variables is bad. It creates bugs that declare at random time and are not easy to find.


SCardListReaders

The problem is at line 23 which is:

23:     rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);

If we read the documentation for SCardListReaders() we have:

Returns a list of currently available readers on the system.

mszReaders is a pointer to a character string that is allocated by the application. If the application sends mszGroups and mszReaders as NULL then this function will return the size of the buffer needed to allocate in pcchReaders.

If *pcchReaders is equal to SCARD_AUTOALLOCATE then the function will allocate itself the needed memory. Use SCardFreeMemory() to release it.

Parameters
[in] hContext Connection context to the PC/SC Resource Manager.
[in] mszGroups List of groups to list readers (not used).
[out] mszReaders Multi-string with list of readers.
[in,out] pcchReaders Size of multi-string buffer including NULL's.

You can note that the parameter pcchReaders is in and out. This is because the value is compared to SCARD_AUTOALLOCATE. So the value of pcchReaders shall be set before calling SCardListReaders().

The fix is simple. Just update line 18 like this:

18: DWORD dwReaders = 0;

 

Looking for problems

What happens if we initialize dwReaders to the special value SCARD_AUTOALLOCATE instead of 0?

18: DWORD dwReaders = SCARD_AUTOALLOCATE;

We build and run the sample:

$ ./sample 
SCardListReaders: Invalid parameter given.

The execution of SCardListReaders() fails.

23:     rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);

This is because we are asking SCardListReaders() to allocate and store the result in the parameter mszReaders. But in our sample this parameter is NULL. pcsc-lite has a check for that and returns an error code.

Instead of using NULL we could use something else like 0x1234.

23:     rv = SCardListReaders(hContext, NULL, 0x1234, &dwReaders);

This time we have a nice crash:

$ ./sample 
Segmentation fault

This is because we asked SCardListReaders() to write at the address 0x1234. This address is, in general, not valid.

This problem could happen if you use something like:

23:     rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);

And both variables mszReaders and dwReaders are uninitialized, and by a total lack of luck dwReaders has the value SCARD_AUTOALLOCATE (i.e. -1).

 

GnuPG

The problem was found in by oddlama and reported to PCSC at "pcscd fails to read future yubikeys after removing a yubikey, until restarted #125".

The problem is not in pcsc-lite but in GnugPG. So I reported the problem at "SCardListReaders: Conditional jump or move depends on uninitialised value(s)".


WinSCard API

macOS does not support (yet) the value SCARD_AUTOALLOCATE. But pcsc-lite and Windows WinSCard do.

I agree the API to use SCARD_AUTOALLOCATE is ugly. We pass the address of a buffer pointer in a parameter that is a buffer pointer. We have to cast the variable like I did in the C sample like:

  dwReaders = SCARD_AUTOALLOCATE;
  rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);

This feature is a Microsoft extension that is not present in the PCSC workgroup specification.


Conclusion

I think the problem is not very known and should be better documented. That was my motivation for writting this blog article.

Morality: in C language, always initialize your variables to a known/safe value (like 0).

Friday, May 13, 2022

New version of pcsc-lite: 1.9.7

I just released a new version of pcsc-lite 1.9.7.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for Unix systems. 

 

 Changes

1.9.7: Ludovic Rousseau
13 May 2022

  • disable strict compilation by default
  • fix 3 warnings


Issues with strict compilation

In the previous version (1.9.6) I enabled a strict compilation option by default. The compiler was configured to use the -Werror argument. The effect is to transform warnings into errors. The compilation would fail instead of just displaying a warning.

On my side I had no warnings so I was confident.

But some build systems use a different set of default compilation arguments. For example Arch Linux or openSUSE Tumbleweed use the argument -flto=auto to perform some link-time optimizer.

This option generated 3 warnings. The warnings are minor but since the compilation used -Werror they were treated as errors and the compilation failed.

Sorry for generating the problem. Thanks to Axel Braun and frederik for reporting the failure.

Wednesday, May 11, 2022

New version of pcsc-lite: 1.9.6

I just released a new version of pcsc-lite 1.9.6.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for Unix systems. 

 

Changes:

1.9.6: Ludovic Rousseau
11 May 2022
  • do not fail reader removal in some specific cases (USB/Thunderbolt port)
  • improve documentation regarding /etc/reader.conf.d/
  • SCardGetStatusChange: speedup the case DISABLE_AUTO_POWER_ON
  • configure:
    • add --disable-strict option
      By default the compiler arguments are now:
      -Wall -Wextra -Wno-unused-parameter -Werror ${CFLAGS}
    • fail if flex is not found
  • fix different data races
  • pcscdaemon: -v displays internal constants values: MAX_READERNAME & PCSCLITE_MAX_READERS_CONTEXTS
  • Some other minor improvements

 

Reader removal issue

The problem with reader removal is that, with some hardware configurations, the USB bus is removed when the USB device is disconnected. You can see that using the libusb command.

Before connecting the device:

Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam
Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard
Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

After connecting the Yubikey token

Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam
Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard
Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The new lines are: 

  • Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
  • Bus 003 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
  • Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

2 new USB buses are created 003 & 004. The Yubikey token is connected on the bus 003.

After removing the Yubikey

Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam
Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard
Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The USB buses 3 & 4 have disappeared. This confused pcsc-lite. The token was not removed for pcsc-lite and caused the generation of log errors. This is now fixed.

    It looks like the problem occurred with a USB-C + Thunderbolt port and was reported in "pcscd fails to read future yubikeys after removing a yubikey, until restarted #125" and "Yubikey 5c Reader "stuck" #57".