Wednesday, March 17, 2021

Accessing a lot of smart cards?

In "A lot of readers connected to a computer..." I presented a problem you can have when accessing many USB smart card readers.

It is possible to access a lot of smart cards with a limited number of readers.


Multislots readers

As I explained in the previous article:

One possible solution is to use a CCID reader that can handle many smart cards. The CCID specification defines a feature called "slot". A CCID smart card reader can support up to 256 slots or 256 smart cards.

The number of slots of a CCID reader is available in the bMaxSlotIndex field. See "CCID descriptor statistics: bMaxSlotIndex". Many readers, 92.91% (in 2013 when I wrote the article), only have one slot.

Readers may have 2 or more slots but not all the slots can be used at the same time. The maximum number of slots that are usable at the same time is available in the bMaxCCIDBusySlots field. See "CCID descriptor statistics: bMaxCCIDBusySlots". And 98.82% of the readers (again in 2013) are able to handle only 1 slot at a time.

As of today, only 9 readers (1.53%) have bMaxCCIDBusySlots≥2 so can use 2 or more slots at the same time. But the situation changed since 2013.


8 slots

A smart card reader with 8 slots already exists. It is the sysmoOCTSIM I presented in "sysmoOCTSIM: 8 slots reader". This reader has 8 slots. So you can access 8 smart cards with the same USB device (using only 3 USB endpoints). And more importantly, you can access all the 8 slots at the same time.

192 slots?

Sysmocom also has the project to build the sysmoSIMBANK-96 and sysmoSIMBANK-192 units with 96 and 192 slots, respectively.

One limitation is that you have to use Mini-SIM (2FF) format smart cards. But if you plan to use as many as 192 smart cards maybe you can use the adequate form factor for the smart card.


Multi access performances

Since I have a sysmoOCTSIM reader I wanted to make some performance tests using my usim_read.py Python program I presented in "Reading a SIM card phone book in Python". One benefit of using Python is that the PC/SC Python wrapper is available for GNU/Linux, macOS and Windows. So no need to port or recompile a program.

I wanted to make tests on the reference platform for PC/SC and CCID i.e. Windows. I connect the sysmoOCTSIM reader and... nothing. The Windows CCID driver does not recognize the reader, not even the first slot. I am (again) very disappointed by Windows.

So I will use a Debian GNU/Linux system.

3 independent readers

First I start with 3 independent "normal" USB readers:

With the Cherry reader I get:

$ time ./usim_read.py 1
Available readers:
- Gemalto PC Twin Reader 00 00
- Cherry GmbH CHERRY SECURE BOARD 1.0 [CHERRY SECURE BOARD 1.0] (00000002JS0405948M3DOGKTHA) 01 00
- Gemalto PC Twin Reader 02 00
Using: Cherry GmbH CHERRY SECURE BOARD 1.0 [CHERRY SECURE BOARD 1.0] (00000002JS0405948M3DOGKTHA) 01 00
Select MF
Select DF Telecom
Select EF ADN
Get Response
1: Name: Gilles Georges Aime, phone: 1216240521
2: Name: Lucienne Aimee Bert, phone: 6613167868
[...]
249: Name: Loup Regis Laurent., phone: 6056648470

real	0m6,068s
user	0m0,103s
sys	0m0,038s

A total time of 6.068 seconds.

With the Gemalto reader I get:

$ time ./usim_read.py 0
Available readers:
- Gemalto PC Twin Reader 00 00
- Cherry GmbH CHERRY SECURE BOARD 1.0 [CHERRY SECURE BOARD 1.0] (00000002JS0405948M3DOGKTHA) 01 00
- Gemalto PC Twin Reader 02 00
Using: Gemalto PC Twin Reader 00 00
Select MF
Select DF Telecom
Select EF ADN
Get Response
1: Name: Juliette Claire Fra, phone: 0574007144
2: Name: Luc Nicolas Regis.., phone: 3864760137
[...]
249: Name: Solange Marguerite , phone: 0569846150

real	0m5,564s
user	0m0,093s
sys	0m0,046s

A total time of 5.564 seconds.

The Cherry reader is a bit slower (0.5 s) than the Gemalto reader. This can be explained by the different clock frequencies.
The Gemalto default clock is: dwDefaultClock: 4.000 MHz
The Cherry default clock is: dwDefaultClock: 3.685 MHz

From the CCID driver logs you can see the different communication speeds used.

For the Gemalto reader we have:

00000012 [140389477558016] ifdhandler.c:847:IFDHSetProtocolParameters() Set speed to 250000 bauds

For the Cherry reader we have:

00000012 [140389477558016] ifdhandler.c:847:IFDHSetProtocolParameters() Set speed to 230312 bauds

A difference of 8.5% in clock speed generates a difference of 8.5% in communication baud rate, and a difference of ~9% in execution time.

The Cherry reader has a maximum clock speed of: dwMaximumClock: 14.320 MHz
The Gemalto reader has a maximum clock speed of: dwMaximumClock: 4.000 MHz

So the Cherry reader could be much faster. But the CCID driver does not yet support changing the clock speed. If you are interested by this change please contact me.


Mixing accesses

We now need to be able to run the usim_read.py program in parallel on the 3 readers. One very easy way to do that is to use the make command with this Makefile file:

CMD=./usim_read.py

all: 0.test 1.test 2.test

%.test:
	${CMD} $(@:.test=)

Calling make 0.test will run ./usim_read 0. Calling make will run the 3 targets 0.test, 1.test and 2.test.

By default make will run the 3 targets sequentially. But if you use make -j the 3 executions will be started in parallel.

 

Results

number of readers sequential exe parallel exe
1 5.564s 5.564s
2 11.099s 5.533s
3 17.083s 6.049s

 

As expected the time grows linearly in the sequential execution, but stays constant in the parallel execution.


sysmoOCTSIM

My CCID driver for Unix do support multi-slot readers. But only one slot can be used at the same time. It is a limitation of the driver.

Supporting accesses to 2 or more slots in parallel would imply a change from synchronous USB communication to asynchronous USB communication. That is a possible change but not an easy one.


Results

number of slots sequential exe parallel exe
1 5.126s 5.126s
2 10.273s 10.030s
3 15.321s 14.944s

The performance is a bit better on the sysmoOCTSIM reader (5.126s) than on the Gemalto reader (5.564s). I guess the reader is using a slightly higher clock frequency.

You may note that in the case of parallel execution we have a linear growth. As I explained before only one slot can be used at the same time. So pcsc-lite (the PC/SC resource manager) has to serialize the accesses to the different slots from the different executions.

The parallel execution is a bit more efficient than the sequential execution because part of the execution can be executed in parallel. But not so much.

 

Improving the CCID driver

It is possible to access all the slots at the same time for the sysmoOCTSIM reader. But the CCID driver needs to be updated.

If you need to access lots of SIM format smart card at the same time please contact me.


Conclusion

Connecting many smart cards to a single computer is possible.

You can connect many readers but the USB architecture may limit you. Or you can use one or more multi-slot readers to limit the requirements on the USB bus.

Friday, March 12, 2021

A lot of readers connected to a computer...

I had planed to write about possible issues when connecting many readers and a new request "Connect 54 tokens in a usb hub" gives me the occasion to write this article.

pcsc-lite limitation

By default pcsc-lite is limited to 16 PC/SC readers. It is a known limitation, see "use a list instead of a fixed size array for 16 reader states".

It is easy to change the value of PCSCLITE_MAX_READERS_CONTEXTS from 16 to whatever you want and rebuild pcsc-lite.


libccid limitation

By default my CCID driver also is limited to 16 slots. It is a known limitation, see "use a list instead of a fixed size array for 16 reader states".

It is easy to change the value of CCID_DRIVER_MAX_READERS from 16 to whatever you want and rebuild libccid.


USB hardware limitation

The software limitations are easy to fix. Both pcsc-lite and libccid projects are Free Software for a good reason. You can adapt the software to your needs, within the respect of the software licence.

The problem now is that the hardware is also limited. Thanks to Harald Welte for mentioning this limitation to me. I am not a PC compatible hardware specialist but I found some interesting information.

From https://community.intel.com/t5/Embedded-Intel-Core-Processors/Hardware-limitations-on-USB-endpoints-XHCI/td-p/264556 "Hardware limitations on USB endpoints (XHCI)":

I have spoken to the Linux kernal developers and they state that "Intel Ivy Bridge system xhci host, the 64 endpoint is a hardware limitation."

From https://acroname.com/blog/how-many-usbs-can-i-connect-acroname "Why Can't I Connect More Usb 3.0 Devices To My System?":

The XHCI specification allows for a massive 7,906 enpoints! However, common implementations of the XHCI controllers impose their own limit on the total number of endpoints to 96. The most notorious of these Intel's series 8 architectures. This means that the maximum number of common devices which use 3 endpoints able to be attached to an Intel series 8 XHCI host controller is actually 96 endpoints / 3 endpoints per device = 32 devices. This is a known limitation of Intel-based XHCI controllers.

To make matters worse, USB 3.0 buses live in a strange dual existence with USB 2.0 devices. That is, they live in the similar yet separate tree architecture in parallel with USB 2.0 devices, but they share the same endpoints on XHCI controllers. USB 3.0 devices may implement endpoints on  both the USB 3.0 and 2.0 buses. This will even further reduce the number of devices which can be attached to a single XHCI host controller.

So the real problem is with the USB controller you use.

A CCID device uses 3 endpoints: Bulk IN, Bulk OUT and interrupt. If your xHCI controller can only handle 96 endpoints in total you can use a maximum of 96 / 3 = 32 readers. But I guess your computer do not have 32 USB ports available. So you will use one or more USB hubs. A USB hub consumes 4 or 5 endpoints for itself then you can use even less than 32 readers.

In fact, the limitation to 16 readers in pcsc-lite and libccid is reasonable compared to the hardware limitation of USB controllers.


Possible solutions

Special CCID reader

One possible solution is to use a CCID reader that can handle many smartcards. The CCID specification define a feature called "slot". A CCID smartcard reader can support up to 256 slots or 256 smartcards.

A CCID reader with support of a high number of slot exists. I plan to write about it in another blog article.

 

Enlarge your number of USB ports

Another solution to the hardware limitation may be to add PCI cards with 4 (or more) USB ports.

The description of such PCI card does not indicate the number of additional endpoints supported. So maybe you will find the controller supports even less than 96 endpoints.

 

Conclusion

I regularly get requests to support a "huge" number of smartcard readers. This article will serve as an answer now.

If you have other solutions please share them.

Friday, March 5, 2021

Reader Selection: new field "section", new operator "≠"

In 2015 I presented the service Reader selection in the article "Reader Selection: find the smart card reader you search".

This service allows you to selected specific readers my list of 589 CCID readers.


Field "section"

It is now possible to select readers according to the field "section". This field can have 4 values: supported, shouldwork, unsupported, disabled. It will restrict the search to readers in the selected section.

For example if you want to list all the readers that can do PIN verification (pinpad readers) and that are in the supported list you use https://ccid.apdu.fr/select_readers/?section=supported&features=PIN%20Verification and you will get the 18 (as of now) readers that match these 2 criteria.


Operator "≠"

Previously, the possible operators were:

  • = strict equality (for number or string)
  • ~ match the head of a string
  • ≤ lesser or equal
  • ≥ greater or equal

I added a new operator "≠" for different.

For example if you want to list all the readers that can do PIN verification (pinpad readers) and that are NOT in the supported list you use https://ccid.apdu.fr/select_readers/?section%E2%89%A0supported&features=PIN%20Verification and you will get the 65 (as of now) readers that match these 2 criteria.

 

Combination

As before you can combine more than once the same selection field. If you want to list the pinpad readers that are NOT in the supported list and that are also NOT in the disabled list you use https://ccid.apdu.fr/select_readers/?section%E2%89%A0supported&features=PIN%20Verification&section%E2%89%A0disabled and you get the pinpad readers that are in the shouldwork list OR in the unsupported list.

This "≠" operator is a way to get an OR combination that is otherwise not possible. If you have 4 values A, B, C or D and you want to use (A or B) then you can use (NOT C AND NOT D).


Conclusion

This service is very useful to select readers will a particularity. Of course you need to know what you are looking for.

If you want to know more about each of the USB CCID fields I suggest you have a look at my articles from "CCID descriptor statistics". You will learn what each CCID field is used for.

Wednesday, February 24, 2021

Writing a SIM card phone book in Python

In the previous article "Reading a SIM card phone book in Python" I presented a program to read the phone book from a SIM card. I will now present the writing part.

 

Source code

The source code is in 2 parts: usim.py and usim_write.py files.

usim.py is the exact same file as in the previous article.

usim_write.py is:

#!/usr/bin/env python3

from smartcard.util import toBytes, padd
import random
import usim


def get_name():
    # List of firstnames from https://www.data.gouv.fr/fr/datasets/liste-de-prenoms/
    with open(random.choice(['f', 'm'])) as fd:
        lines = list(map(str.strip, fd.readlines()))
    return " ".join([random.choice(lines), random.choice(lines),
                    random.choice(lines)])


def get_number():
    numbers = "0123456789"
    phone = list()
    phone.append(random.choice(numbers) + random.choice(numbers))
    phone.append(random.choice(numbers) + random.choice(numbers))
    phone.append(random.choice(numbers) + random.choice(numbers))
    phone.append(random.choice(numbers) + random.choice(numbers))
    phone.append(random.choice(numbers) + random.choice(numbers))
    return " ".join(phone)


def new_record(size):
    # size-14 characters for the name
    name = get_name()[0:size-14]
    phone = get_number()
    print("name:", name)
    print("phone:", phone)
    record = padd(list(map(ord, name)), size-14) \
        + padd(toBytes("06 A1 " + phone), 14)
    return record


def usim_write(reader_nb):
    # Select the EF ADN
    (size, connection) = usim.usim(reader_nb)

    for nbr in range(1, 250):
        record = new_record(size)
        #  Update record
        header = [0xA0, 0xDC]
        record_idx = nbr
        cmd = header + [record_idx, 0x04, size] + record
        data, sw1, sw2 = connection.transmit(cmd)
        if (sw1, sw2) != (0x90, 0x00):
            return


if __name__ == "__main__":
    import sys
    if 2 == len(sys.argv):
        reader_nb = int(sys.argv[1])
    else:
        reader_nb = 0
    usim_write(reader_nb)


Comments

I wanted to have reasonable names and phone numbers in my phone book. So I generate names by randomly selecting 3 first names from 2 lists: the 50 first (by frequency of use) male first names in French stored in the m file, and the 50 first female first names in French stored in the f file. I got the data from https://www.data.gouv.fr/fr/datasets/liste-de-prenoms/. The original list also contains first names from other languages.

The first 10 lines of m are:

Pierre
Juste
Julien
Olivier
Henri
Jacques
Philippe
Nicolas
Aime
Antoine
[...]

The first 10 lines of f are:

Marie
Victoire
Claire
Marine
Reine
Virginie
Vienne
Solange
Jolie
Marguerite
[...]

For the phone number I just select a random 10-digits number.

Maybe the entries I created are non functional in a real phone. First check it works for you if you want to reuse this code. Also if you plan to reuse my source code you must read "My blog source code license" first.


Output

$ ./usim_write.py 
Available readers:
- Gemalto PC Twin Reader
Using: Gemalto PC Twin Reader
connecting to Gemalto PC Twin Reader
Select MF
> A0 A4 00 00 02 3F 00
<  [] 9F 22
Select DF Telecom
> A0 A4 00 00 02 7F 10
<  [] 9F 22
Select EF ADN
> A0 A4 00 00 02 6F 3A
<  [] 9F 0F
Get Response
> A0 C0 00 00 0F
< 00 00 21 34 6F 3A 04 00 11 FF 22 01 02 01 22 90 00
name: Juliette Claire Fran
phone: 50 47 00 17 44
> A0 DC 01 04 22 4A 75 6C 69 65 74 74 65 20 43 6C 61 69 72 65 20 46 72 61 6E 06 A1 50 47 00 17 44 FF FF FF FF FF FF FF
<  [] 90 00
name: Luc Nicolas Regis
phone: 83 46 67 10 73
> A0 DC 02 04 22 4C 75 63 20 4E 69 63 6F 6C 61 73 20 52 65 67 69 73 FF FF FF 06 A1 83 46 67 10 73 FF FF FF FF FF FF FF
<  [] 90 00
name: Julien Jeremie Serge
phone: 89 07 17 20 07
> A0 DC 03 04 22 4A 75 6C 69 65 6E 20 4A 65 72 65 6D 69 65 20 53 65 72 67 65 06 A1 89 07 17 20 07 FF FF FF FF FF FF FF
<  [] 90 00
[...]

The output is truncated. I do not want to include all the 255 phone numbers.

If I use usim_read.py (with debug disabled) I get:

$ ./usim_read.py 
Available readers:
- Gemalto PC Twin Reader
Using: Gemalto PC Twin Reader
Select MF
Select DF Telecom
Select EF ADN
Get Response
1: Name: Juliette Claire Fra, phone: 0574007144
2: Name: Luc Nicolas Regis.., phone: 3864760137
3: Name: Julien Jeremie Serg, phone: 9870710270
[...]

Note that the phone numbers are reversed by group of 2 digits. 50 47 00 17 44 becomes 0574007144.


Conclusion

It is as easy to write than to read a SIM phone book.

My goal here was to be able to write "realistic" phone book entries so that the usim_read.py has "real" data to read and display.

usim_read.py will be used again in the next episode.

Monday, February 22, 2021

Reading a SIM card phone book in Python

I already wrote a SIM phone book dumper program in 2004. This first version was in Perl and was presented in "SIM card phone book listing".

You can also find more advanced tools in articles with the SIM label, like cardpeek, monosim or PSSI.

I now present a version in Python using the PySCard wrapper

 

Source code

The source code is in 2 parts: usim.py and usim_read.py files.

usim.py is:

#!/usr/bin/env python3

from smartcard.System import readers
from smartcard.util import toBytes
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver

debug = True

def usim(reader_nb):
    # get all the available readers
    r = readers()
    print("Available readers:")
    for reader in r:
        print("-", reader)

    reader = r[reader_nb]
    print("Using:", reader)

    connection = reader.createConnection()
    if debug:
        observer = ConsoleCardConnectionObserver()
        connection.addObserver(observer)
    connection.connect()

    SELECT = "A0 A4 00 00 02 "
    GET_RESPONSE = "A0 C0 00 00 "

    # Select MF
    print("Select MF")
    data, sw1, sw2 = connection.transmit(toBytes(SELECT + "3F 00"))
    if sw1 != 0x9F:
        raise(Exception("Error"))

    # Select DF Telecom
    print("Select DF Telecom")
    data, sw1, sw2 = connection.transmit(toBytes(SELECT + "7F 10"))
    if sw1 != 0x9F:
        raise(Exception("Error"))

    # Select EF ADN
    print("Select EF ADN")
    data, sw1, sw2 = connection.transmit(toBytes(SELECT + "6F 3A"))
    if (sw1, sw2) != (0x9F, 0x0F):
        raise(Exception("Error"))

    # Get Response
    print("Get Response")
    data, sw1, sw2 = connection.transmit(toBytes(GET_RESPONSE) + [sw2])
    if (sw1, sw2) != (0x90, 0x00):
        raise(Exception("Error"))

    size = data[-1]

    pin = None
    if pin:
        print(pin)
        pin = list(map(ord, pin))
        padd(pin, 8)

        # Verify CHV
        VERIFY = "A0 20 00 01 08"
        cmd = toBytes(VERIFY) + pin
        data, sw1, sw2 = connection.transmit(cmd)
        if (sw1, sw2) != (0x90, 0x00):
            raise(Exception("Wrong PIN:" + pin))

    return size, connection


if __name__ == "__main__":
    usim(0)

usim_read.py is:

#!/usr/bin/env python3

from smartcard.util import toBytes, toASCIIString
import usim


def decode_record(record):
    """
    decode_record(toBytes("43 75 73 74 6F 6D 65 72 20 43 61 72 65 FF 06 A1 80 00 07 70 00 FF FF FF FF FF FF FF"))
    >> ['Customer Care', '0800700700']
    """
    X = len(record) - 14
    name = toASCIIString(record[0:X - 1]).replace("ΓΏ", "")
    # number of bytes for the phone number
    tel_size = record[X]
    phone = record[X + 2:X + tel_size + 1]

    decoded = ""
    for n in phone:
        hex = "%02X" % n
        high = hex[0]
        low = hex[1]
        decoded += low + high
    # if the number of digits is odd we suppress the padding
    if decoded[-1] == "F":
        decoded = decoded[:-1]
    phone = decoded

    return name, phone


def usim_read(reader_nb):
    # Select the EF ADN
    (size, connection) = usim.usim(reader_nb)

    for nbr in range(1, 250):
        #  Read record
        header = [0xA0, 0xB2]
        record_idx = nbr
        cmd = header + [record_idx, 0x04, size]
        data, sw1, sw2 = connection.transmit(cmd)
        if (sw1, sw2) != (0x90, 0x00):
            return

        name, phone = decode_record(data)
        if name != "":
            print(f"{record_idx}: Name: {name}, phone: {phone}")


if __name__ == "__main__":
    import sys
    if 2 == len(sys.argv):
        reader_nb = int(sys.argv[1])
    else:
        reader_nb = 0
    usim_read(reader_nb)


Comments

The debug is enabled. So you can see the communication between the application and the card.
You ned to change only one line to remove the APDU log if needed. 

The phone book record size is not fixed for all the SIM cards. The record size is returned in the last byte of the GET RESPONSE command after the SELECT EF (Elementary File) ADN (Abbreviated dialling numbers).

You can get more details about the EF ADN and the record coding in the document ETSI TS 131 102 V16.6.0 (2021-01) chapter "4.4.2.3 EF_ADN (Abbreviated dialling numbers)". It is important to note that ETSI (European Telecommunications Standards Institute) standards are public and free.

By default the first PC/SC reader is used. But you can select another reader by passing a number as argument to the program. We will use this feature later.

No PIN is defined and verified. I am using a sysmocom sysmoUSIM-SJS1 card. This card has the user PIN disabled by default.
You can enable PIN verification by defining a PIN in usim.py. The code is already present.

USIM (Universal Subscriber Identity Module) is a new application introduced for GSM version 3 (3G) to replace/improve the SIM (subscriber identity/identification) application. The code should work the same with a SIM card or a USIM card (but untested).

Output

$ ./usim_read.py 
Available readers:
- Gemalto PC Twin Reader
Using: Gemalto PC Twin Reader
connecting to Gemalto PC Twin Reader
Select MF
> A0 A4 00 00 02 3F 00
<  [] 9F 22
Select DF Telecom
> A0 A4 00 00 02 7F 10
<  [] 9F 22
Select EF ADN
> A0 A4 00 00 02 6F 3A
<  [] 9F 0F
Get Response
> A0 C0 00 00 0F
< 00 00 21 34 6F 3A 04 00 11 FF 22 01 02 01 22 90 00
> A0 B2 01 04 22
< 4C 61 75 72 65 20 46 72 61 6E E7 6F 69 73 65 20 59 76 6F 6E 06 A1 24 66 85 10 22 FF FF FF FF FF FF FF 90 00
1: Name: Laure Francoise Yvo, phone: 4266580122
> A0 B2 02 04 22
< 4C 75 63 69 65 6E 6E 65 20 48 65 6C 65 6E 65 20 4C 75 63 69 06 A1 76 45 65 28 77 FF FF FF FF FF FF FF 90 00
2: Name: Lucienne Helene Luc, phone: 6754568277
> A0 B2 03 04 22
< 55 72 62 61 69 6E 20 47 69 6C 6C 65 73 20 4A 75 73 74 65 FF 06 A1 80 38 74 16 54 FF FF FF FF FF FF FF 90 00
3: Name: Urbain Gilles Juste, phone: 0883476145
> A0 B2 04 04 22
< 4A 65 72 6F 6D 65 20 50 61 73 63 61 6C 20 46 65 72 6E 61 6E 06 A1 80 53 42 10 86 FF FF FF FF FF FF FF 90 00
4: Name: Jerome Pascal Ferna, phone: 0835240168
[...]

The output is truncated. I do not want to include all the 255 phone numbers. 

Note that the names and numbers are random. More on that later.


Conclusion

It is easy to dump the phone book from a SIM card.

The SIM phone book is very limited (no birthday, no email address). The real phone book is, in general, in the phone itself and synchronised using CardDav with a server like Nextcloud.

Wednesday, February 17, 2021

GitHub Sponsors: first year

In January 2020 I engaged in the GitHub Sponsors project. I got my first payment in May 2020. After a full year I think it is time for a public status. 

 

Results

My gains give a total of 296,82€ for 12 months. Of course I will have to pay some French taxes (employee and employer social security contributions URSSAF) of around 25% and also some income taxes.

Description
Revenue 296,82 €
Social Contributions
-74,20 €
Remaining
225,62 €

That is 18,55€/month.

 

Bills

That is not much (I can't live with that yet) but enough to pay some of the infrastructure used by my smart card projects: a Virtual Private Server to host the web sites and the domain name for https://muscle.apdu.fr/, https://pcsclite.apdu.fr/ and https://ccid.apdu.fr/.

Description
Virtual Private Server 100,66 €
Domain name .apdu.fr
8,39 €
Total
109,05 €

That is 9,09€/month.

 

Conclusion

Thank you to the generous sponsors.

Tuesday, February 16, 2021

New version of pcsc-lite: 1.9.1

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

 Changes:

1.9.1: Ludovic Rousseau
16 February 2021

  • Do not (possibly) lock a reader if allocating hCard fails
  • Fix a hang in SCardTransmit()
  • Do not report an error if the wrong interface is used by the driver
  • Update reader state when a card is removed during an exchange
  • readerfactory: Make sure a freed Reader Context is not accessed
  • PHSetProtocol(): supports T=0&1 cards on T=0 reader
  • hotplug-libusb:
    • support CCIDCLASSDRIVER
    • add interface name to reader name
    • remove obsolete libhal scheme
  • Some other minor improvements