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, September 29, 2017

macOS High Sierra and smart cards status

macOS High Sierra (macOS 10.13) is now available since 25th September, 2017.


API Differences between 10.12 and 10.13

The differences are listed in the developer page macOS Sierra 10.13. The page only documents big changes. No changes related to smart card are listed.

PC/SC

Since Yosemite (10.10) the PC/SC layer is no more a fork of pcsc-lite. So comparing versions with pcsc-lite is useless.

$ cat /System/Library/Frameworks/PCSC.framework/Versions/A/Resources/version.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>BuildAliasOf</key>
 <string>CryptoTokenKit</string>
 <key>BuildVersion</key>
 <string>3</string>
 <key>CFBundleShortVersionString</key>
 <string>8.0</string>
 <key>CFBundleVersion</key>
 <string>1</string>
 <key>ProjectName</key>
 <string>SmartCardServices</string>
 <key>SourceVersion</key>
 <string>281001001000000</string>
</dict>
</plist>

The BuildVersion moved from 65 in Sierra 10.12.0 to 3 in High Sierra 10.13.0. I guess this number is not a good indicator since it is decreasing.

The SourceVersion moved from 196001003000000 in Sierra 10.12.0 to 281001001000000 in High Sierra 10.13.0. I have no idea how to parse or use this information.

PC/SC Bugs fixed

These bugs were found in El Capitan or latter and are now fixed in Sierra:
  1. SCARD_W_RESET_CARD not returned by SCardTransmit()
  2. PC/SC SCardTransmit() silently truncates the smart card response (bug #30868184)
  3. Command "security smartcards token -d" command does not work as documented? (bug #31010575)

Some (minor) bugs reported on El Capitan are still present in High Sierra. I updated the page "OS X El Capitan and smart cards: known bugs".

CryptoTokenKit

CryptoTokenKit is the native smart card API since the complete rewrite in macOS Yosemite 10.10 (OS X Yosemite BETA and smart cards status).

$ strings /System/Library/Frameworks/CryptoTokenKit.framework/CryptoTokenKit | grep BuildRoot
/BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.1.1/CryptoTokenKit/TKToken.m
/BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.1.1/CryptoTokenKit/TKSmartCard.m
/BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.1.1/CryptoTokenKit/TKTokenSession.m

In High Sierra CryptoTokenKit source code is at version 281.1.1. In Sierra it was at version 196.60.1. Since the source code is not available I can't write much more than that.

Card events

It is not easy to compare the state of CyptoTokenKit since the source code is not public. Nonetheless I could find changes in the com.apple.ifdreader process (this process loads and use the IFDHandler, i.e. the smart card reader driver like the CCID driver).

It looks like Apple has worked on moving from active polling to eventing to manage smart card events (card insertion and removal). I reported it as a feature request: OS X El Capitan missing feature: add support of TAG_IFD_POLLING_THREAD_WITH_TIMEOUT.

I compared the result of the strings(1) Unix command on the binary from Sierra and the binary from High Sierra. In High Sierra new symbols are available:
$ strings /System/Library/CryptoTokenKit/com.apple.ifdreader.slotd/Contents/MacOS/com.apple.ifdreader | grep -i Poll
getPollingFunction:
getStopPollingFunction:
isPollingThreadKillable:
setupPolling
getPollingFunction
polling:
stopPolling
_pollingStarted
_pollingThread
PollingTimeout
Failed to create polling thread: %d
'IFDHPolling' failed %ld
%{public}@: got sleep request, stop polling card, close the channel

They are all new strings in High Sierra except the last one that was already present in Sierra.

Since my bug #24009313 was closed as a duplicate of #17534485 I don't know if the bug is fixed, or not, in High Sierra. This will need some debug logs from a driver. The Terminal command "log stream --debug | grep CryptoTokenKit" gives a lot of details regarding the smart card activity but not enough to know how the card events are generated.

CCID driver

Driver version 1.4.27. Sierra had: 1.4.24 in 10.12.0 and 1.4.25 in 10.12.6.
$ grep -A 1 CFBundleShortVersionString /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
 <key>CFBundleShortVersionString</key>
 <string>1.4.27</string>
You can have a look at the CCID README file to know what changes between version 1.4.25 and version 1.4.27.

Note that the CCID driver version 1.4.27 provided in macOS High Sierra is the latest version available (as I write this blog). version 1.4.27 has been released in May 2017 (4 months ago only).

Conclusion

You can compare with the status I made for Sierra in "macOS Sierra and smart cards status".

It looks like High Sierra has not seen many changes regarding smart card.

Tuesday, September 26, 2017

Use a pinpad reader with macOS CryptoTokenKit: TKSmartCardUserInteractionForPINOperation

The API proposed by Apple to use a smart card and a smart card reader is CryptoTokenKit. I already wrote about this API in:
CryptoTokenKit is an equivalent of the PC/SC API defined by the PC/SC workgroup and implemented by Microsoft in Windows and by pcsc-lite for Unixes. The PC/SC API is also known as WinSCard.

Pinpad reader

The idea of a pinpad reader it so submit the user secret PIN code to the card without entering it on the computer. The PIN is entered on the smart card reader and is sent directly to the smart card inserted in the smart card reader. The computer (PC, Mac, whatever) never has access to the PIN code.

A pinpad reader is often used with banking applications. Even if your system is compromised the PIN is safe.

You can have a list of pinpad readers at my Reader selection page.

I will use a Gemalto Ezio Bluetooth reader in USB mode for the demo.


TKSmartCardUserInteractionForPINOperation

Apple provides a way to use a pinpad reader using CryptoTokenKit with the class TKSmartCardUserInteractionForPINOperation.

In the example I will use the subclass TKSmartCardUserInteractionForSecurePINVerification and the method userInteractionForSecurePINVerificationWithPINFormat:APDU:PINByteOffset:.

The parameter PINFormat of class TKSmartCardPINFormat offers services similar to what can be found in PC/SC version 2 Part 10 for using a pinpad reader but with a better interface design.

Source code

#import <Foundation/Foundation.h>
#import <CryptoTokenKit/CryptoTokenKit.h>

int main(int argc, const char * argv[]) {
    TKSmartCardSlotManager * mngr;
    mngr = [TKSmartCardSlotManager defaultManager];

    // Use the first reader/slot found
    if ([mngr.slotNames count] == 0)
    {
        NSLog(@"No reader found");
        return -1;
    }

    NSString *slotName = (NSString *)mngr.slotNames[0];
    NSLog(@"slotName: %@", slotName);

    dispatch_semaphore_t sem = dispatch_semaphore_create(0);

    // connect to the slot
    [mngr getSlotWithName:slotName reply:^(TKSmartCardSlot *slot)
     {
         // connect to the card
         TKSmartCard *card = [slot makeSmartCard];
         if (nil == card)
         {
             NSLog(@"No card found");

             // signals end of getSlotWithName block
             dispatch_semaphore_signal(sem);

             return;
         }

         // begin a session
         [card beginSessionWithReply:^(BOOL success, NSError *error)
          {
              if (success)
              {
                  NSData *response;
                  UInt16 sw;
                  TKSmartCardPINFormat *PINFormat;
                  TKSmartCardUserInteractionForSecurePINVerification *userInter;
                  NSData *APDUTemplate;

                  // explicitly set the CLA byte even if 0 is already the default value
                  card.cla = 0x00;

                  // send select applet APDU
                  uint8_t aid[] = {0xA0, 0x00, 0x00, 0x00, 0x18, 0xFF, 0x01};
                  NSData *data = [NSData dataWithBytes:aid length:sizeof aid];

                  response = [card sendIns:0xA4 p1:0x04 p2:0x00 data:data le:nil sw:&sw error:&error];

                  if (nil == response)
                  {
                      NSLog(@"sendIns error: %@", error);
                      [card endSession];

                      // signals end of beginSessionWithReply block
                      dispatch_semaphore_signal(sem);

                      return;
                  }

                  NSLog(@"Response select applet: %@ 0x%04X", response, sw);

                  const UInt8 template[] = {card.cla, 0x20, 0x00, 0x80, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                  APDUTemplate = [NSData dataWithBytes:template length:sizeof(template)];
                  PINFormat = [[TKSmartCardPINFormat alloc] init];
                  PINFormat.PINBitOffset = 0;

                  // VerifyPIN
                  data = [NSData dataWithBytes:template length:sizeof template];
                  userInter = [card userInteractionForSecurePINVerificationWithPINFormat:PINFormat APDU:data PINByteOffset:0];

                  if (nil == userInter)
                  {
                      NSLog(@"userInteractionForSecurePINVerificationWithPINFormat returned nil. Are you using a pinpad reader?");

                      [card endSession];

                      // signals end of beginSessionWithReply block
                      dispatch_semaphore_signal(sem);
                  }
                  else
                  {
                      NSLog(@"Enter the PIN on the pinpad");
                      [userInter runWithReply:^(BOOL success, NSError *error)
                       {
                           if (success)
                           {
                               NSLog(@"success");

                               // give some time to the reader to display a message before the next APDU
                               sleep(1);

                               NSLog(@"resultData: %@", [userInter resultData]);
                               NSLog(@"resultSW: %04X", [userInter resultSW]);

                               UInt16 sw;

                               // send PIN dump
                               uint8_t param[] = {0x09};
                               NSData *data = [NSData dataWithBytes:param length:sizeof param];
                            
                               NSData *response = [card sendIns:0x40 p1:0x00 p2:0x00 data:data le:@0 sw:&sw error:&error];
                            
                               if (nil == response)
                                   NSLog(@"sendIns error: %@", error);
                               else
                                   NSLog(@"Response PIN dump: %@ 0x%04X", response, sw);
                            
                               [card endSession];
                            
                               // signals end of beginSessionWithReply block
                               dispatch_semaphore_signal(sem);
                           }
                           else
                           {
                               NSLog(@"Error: %@", error);
                            
                               [card endSession];
                            
                               // signals end of beginSessionWithReply block
                               dispatch_semaphore_signal(sem);
                           }
                       }];
                  }
              }
              else
              {
                  NSLog(@"Session error: %@", error);
                
                  // signals end of getSlotWithName block
                  dispatch_semaphore_signal(sem);
              }
          }];
     }];

    // wait for the asynchronous blocks to finish
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}

Output

slotName: Gemalto Ezio Shield
 Response select applet: <> 0x9000
 Enter the PIN on the pinpad
 success
 resultData: <>
 resultSW: 9000
 Response PIN dump: <00200080 08313233 34353637 38> 0x9000

At the beginning



Application started


PIN code entered in the reader


PIN code validated by the card


This last picture is out of focus. I am sorry for that. Note that it is not easy to hold the smartphone, validate on the pinpad and take the picture with only two hands.

Comments

Source code auto documented

I will not comment the code here. Comments are already present in the source code.

Entitlements

Do not forget to create an .entitlements file in Xcode (enable App Sandbox). Then add the com.apple.security.smartcard property and set it to YES.

If you do not do that access to the CryptoTokenKit API will be denied and your output will be something like:
[smartcard] ctk: connecting to slot registration server failed
 No reader found
 [smartcard] connection to slot registration server failed

Without a pinpad reader

If you do not use a reader that support PIN verification using a pinpad then the method userInteractionForSecurePINVerificationWithPINFormat: will return nil instead of a TKSmartCardUserInteractionForSecurePINVerification object.

Be careful to check the returned value.

Test applet

I use a smart card with a specific test applet. The Java applet source code is available.

From the execution Output you can see the line:
Response PIN dump: <00200080 08313233 34353637 38> 0x9000
This is a special debug command I use to check what exactly the reader has sent to the card. The PIN may have many different formats and padding. Here you see the PIN "12345678" (Oops, it is no more a secret) has been sent as the ASCII codes for "1" (0x31), "2" (0x32), etc.

Your may need a different coding or padding. Have a look at the different TKSmartCardPINFormat parameters like charset, minPINLength, maxPINLength, PINJustification, PINBitOffset, etc.

Asynchronous runWithReply:

The runWithReply: method is asynchronous. So be careful to not end the card session before the user has entered its PIN. In the code I use a semaphore but you can use something else, or nothing, depending on your application.

Non-CCID readers?

Because of a bug in, I think, CryptoTokenKit I was not able to use the Gemalto Ezio Bluetooth reader in Bluetooth mode. The reader is not detected as a pinpad reader. This reader works fine with the PC/SC API on macOS and the pinpad feature can be used in Bluetooth mode.

My guess is that CryptoTokenKit detects that a reader is a pinpad reader by reading the bPINSupport byte directly from the CCID USB descriptor instead of using the driver IFDHControl(CM_IOCTL_GET_FEATURE_REQUEST, ...) call to check if FEATURE_VERIFY_PIN_DIRECT is supported. So only CCID pinpad readers may be supported.

I opened a bug at Apple "CryptoTokenKit does not detect my Bluetooth smart card reader as a pinpad reader" #34648641.

Source code and blog licence

If you do plan to reuse (part of) my code please read the blog licence bellow and be sure it is OK for you to conform with it, or contact me. See also My blog messages license.

Conclusion

I do not know many applications that use CryptoTokenKit to interact with a smart card. When I was debugging my code I searched for examples of use of TKSmartCardUserInteractionForPINOperation but could not find any.

I would not be surprised if my code is the first public example of CryptoTokenKit to use a pinpad reader.

Monday, September 25, 2017

ATR statistics: TA3 - Specific to T after T from 0 to 14 in TDi–1

Article from the series "ATR statistics".

TA3 - Specific to T after T from 0 to 14 in TDi–1

The ISO 7816-3 specification is not public. So I can't copy/paste part of the text. I will use Wikipedia instead.

For T = 1: maximum block size the card can receive. Encodes IFSC.
If T = 15: supported supply voltages and low power modes

TA3#%
137966.55 %
0xFE38818.73 %
0xC71095.26 %
0xC3351.69 %
0x80241.16 %
0x20190.92 %
0x43140.68 %
0x3C90.43 %
0x4780.39 %
0x8670.34 %
0xA070.34 %
0x0060.29 %
0x0360.29 %
0x5060.29 %
0x4250.24 %
0xC650.24 %
0x4040.19 %
0x6040.19 %
0x7040.19 %
0x6630.14 %
0x9030.14 %
0xFC30.14 %
0xFF30.14 %
0x4620.10 %
0x7620.10 %
0xF020.10 %
0xFA20.10 %
0xFB20.10 %
0x0710.05 %
0x2610.05 %
0x3A10.05 %
0x3D10.05 %
0x5210.05 %
0x6410.05 %
0x7C10.05 %
0x8310.05 %
0x8710.05 %
0xC210.05 %
0xEF10.05 %



The interpretation of TA3 depends on the protocol in use.

19% of ATRs have TA3 = 0xFE :

IFSC

The IFSC repartition is as follows:
IFSC#%
25436675,78 %
128214,35 %
32193,93 %
6091,86 %
13471,45 %
16071,45 %
8061,24 %
051,04 %
6440,83 %
9640,83 %
11240,83 %
6630,62 %
10230,62 %
14430,62 %
25230,62 %
25530,62 %
7020,41 %
11820,41 %
24020,41 %
25020,41 %
25120,41 %
3810,21 %
5810,21 %
8210,21 %
10010,21 %
12410,21 %
23910,21 %



With a logarithmic scale:


75% of ATRs with a IFSC defined in TA3 (so T=1 cards only) defines IFSC = 254.

Supported supply voltages

It is also possible to get the repartition of the class:
Class#%
A 5V B 3V C 1.8V11449,57 %
A 5V B 3V10646,09 %
B 3V C 1.8V52,17 %
B 3V31,30 %
B 3V C 1.8V D RFU E RFU20,87 %



50% of ATRs defining the class supports the 3 classes: A, B and C for 5 Volts, 3 Volts and 1.8 Volt.

46% of ATRs defining the class supports the classes A and B but not C.

2 cards declare the support of classes D and E that are RFU. They are 3B D9 18 00 C0 09 10 FE 54 59 46 4F 4E 45 00 00 00 and 3B DD 96 00 80 10 FE 80 31 80 63 01 FF C0 73 B3 21 1B 81 05. It may be a bug in the parsing since the class is defined only after T=15 protocol. But in the two examples the latest defined protocol is T=0. The ATRs may not be valid.

ATR statistics: TD2 - Structural, encodes Y3 and T

Article from the series "ATR statistics"

TD2 - Structural, encodes Y3 and T

The ISO 7816-3 specification is not public. So I can't copy/paste part of the text. I will use Wikipedia instead.

Refer to TD1 - Structural, encodes Y2 and T since the definition of TD2 is identical to TD1.

TD2#%
112354.20 %
0x3139318.97 %
0x0125012.07 %
0x1F1788.59 %
0x71502.41 %
0xB1482.32 %
0x91100.48 %
0x2160.29 %
0x3F50.24 %
0xF150.24 %
0x1020.10 %
0x1120.10 %



TD2 (as the other TDi bytes) is structural and indicates:
  • How to interpret the other ATR bytes
  • What communication protocol the card wants to use

For 54% of the ATRs no TD2 is present. So no other TA3, TB3, TC3 or TD3 is present and no new protocol is defined so the protocol defined by TD1 (if any) will be used.

For 19% of the ATRs TD2 = 0x31. The high nibble is 0011b so TA3, TB3 are present and T=1 protocol is defined. One such ATR is 3B 82 81 31 76 43 C0 02 C5.

For 12% of ATRs TD2 = 0x01. The high nibble is 0000b so no other TA3, TB3, TC3 or TD3 is present and T=1 protocol is defined. One such ATR is 3B 84 80 01 00 00 90 00 95.

0.10% of cards have TD2 = 0x10 and so (re)define the use of T=0. In fact what is important here is the high nibble of TD2 0001b that defines that TA3 is present. One such ATR is 3B DD 96 00 80 10 FE 80 31 80 63 01 FF C0 73 B3 21 1B 81 05.

I will not document all the other cases. I let this exercise to the reader.

Thursday, August 17, 2017

macOS Sierra bug: PC/SC transactions can't be nested

This is the second new PC/SC bug I report for macOS Sierra (first one was "macOS Sierra bug: SCardTransmit() silently truncates the card response").
I imagine this bug is also present in El Capitan and Yosemite but I have not checked.

SCardEndTransaction() ends all the transactions

SCardEndTransaction() does not work as it should, at least it does not work as the pcsc-lite version on GNU/Linux.
If you start a new PC/SC transaction inside a PC/SC transaction you expect the card to be available to another application only after all the transactions have ended.

For example if, in one application, you do:
A. SCardBeginTransaction()
  B. SCardBeginTransaction()
  C. SCardEndTransaction()
D. SCardEndTransaction()
You may expect that the card is available again for another application after the transaction is ended in step D.

What happens on macOS Sierra is that the transaction is ended at step C instead. So all the card APDU exchanges between steps C and D are not protected by the PC/SC transaction and can be mixed with APDU exchanges from any other applications.

It looks like PC/SC on macOS does not include a nested transaction counter. The first call to SCardEndTransaction() will end the transaction.

The sample code above is very simple and may seem stupid. But maybe the steps B and C are executed in another function of your application and then more hidden.

The macOS Sierra behaviour may produce very bad side effects. Imagine you use transactions to restrict access to the card private key after verifying the card PIN code. Then another application could also use the private key (between steps C and D) before the PIN is unverified just before step D.

See also

Apple bug report #33940052 "Smart card PC/SC transactions can't be nested"
Closed by Apple as a duplicate of #33752531.

Sample code


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

#define pcsc_error(fct) printf(fct ": %s 0x%08lX\n", pcsc_stringify_error(err), (long)err)

int main(void)
{
    LPSTR mszReaders;
    DWORD err, cchReaders = 0;
    SCARDCONTEXT hContext = 0;
    SCARDHANDLE hCard = 0;

    err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardEstablishedContext");
        return -1;
    }

    err = SCardListReaders(hContext, NULL, NULL, &cchReaders);
    if (err != 0) {
        pcsc_error("ScardListReaders");
        return -1;
    }
    mszReaders = calloc(cchReaders, sizeof(char));
    if (!mszReaders) {
        printf("calloc\n");
        return -1;
    }
    err = SCardListReaders(hContext,NULL, mszReaders, &cchReaders);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardListReaders");
        return -1;
    }

    printf("Using reader: %s\n", mszReaders);

    DWORD dwActiveProtocol;
    printf("connect\n");
    err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("SCardConnect");
        return 0;
    }

    printf("transaction 1\n");
    err = SCardBeginTransaction(hCard);
    if (err != SCARD_S_SUCCESS)
        pcsc_error("SCardBeginTransaction");

    printf("transaction 2\n");
    err = SCardBeginTransaction(hCard);
    if (err != SCARD_S_SUCCESS)
        pcsc_error("SCardBeginTransaction");

    printf("release transaction 2\n");
    err = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
    if (err != SCARD_S_SUCCESS)
        pcsc_error("SCardBeginTransaction");

    printf("Start me again and press enter\n");
    getchar();

    printf("release transaction 1\n");
    err = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
    if (err != SCARD_S_SUCCESS)
        pcsc_error("SCardBeginTransaction");

    err = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    if (err != SCARD_S_SUCCESS)
        pcsc_error("SCardDisconnect");

    SCardReleaseContext(hContext);

    return 0;
}

Result (on Sierra)

$ CFLAGS="-framework PCSC" make main
cc -framework PCSC    main.c   -o main

First execution:
$ ./main_Mac
Using reader: Gemalto PC Twin Reader
connect
transaction 1
transaction 2
release transaction 2
Start me again and press enter

Second execution in another window:
$ ./main_Mac 
Using reader: Gemalto PC Twin Reader
connect
transaction 1
transaction 2
release transaction 2
Start me again and press enter

Expected result (on Debian)

$ CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main
cc -pthread -I/usr/include/PCSC    -lpcsclite    main.c   -o main

First execution:
$ ./main_Linux 
Using reader: Gemalto PC Twin Reader 00 00
connect
transaction 1
transaction 2
release transaction 2
Start me again and press enter

Second execution in another window:
$ ./main_Linux 
Using reader: Gemalto PC Twin Reader 00 00
connect

Here you notice that the second execution is blocked at the "connect" step. Once you press "Enter" for the first execution then the transaction is released and the second execution can continue.

Known workaround

None. Do not use nested PC/SC transactions.

Update: 8th January 2018

The bug is fixed in macOS High Sierra 10.13.2.

Saturday, June 24, 2017

New PyKCS11 1.4.3 available

I just released a new version of PyKCS11, a Python wrapper above the PKCS#11 API.

Changes:
1.4.3 - June 2017, Ludovic Rousseau
  • Add support of CKM_RSA_PKCS_PSS mechanism
  • fix CKM_AES_CBC issue with Python 3
  • add Unitary Tests (make tests)
  • add tox support (automate and standardize testing in Python)
  • add coverage support (measuring code coverage of Python programs)
  • add Travis-CI configuration (automatic build and tests)
  • some minor improvements

Source code available on:

Results available on:

Saturday, June 17, 2017

New version of pcsc-lite: 1.8.22

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

Changes:
1.8.22: Ludovic Rousseau
17 June 2017
  • SCardCancel() was broken in 1.8.21. The call was blocking.
  • Enable use of info level logging for pcscd using -i/--info