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.