Saturday, September 26, 2015

PCSC sample in Swift

To continue the list of PC/SC wrappers initiated in 2010 with "PC/SC sample in different languages" I now present a sample in Swift using the Apple Crypto Token Kit API.

Crypto Token Kit API

See my previous article "PCSC sample in Objective-C" to know more about Crypto Token Kit API.

Source code

Create a new Swift application in Xcode. You need to enable the App Sandbox and add/set the com.apple.security.smartcard entitlement to YES.

This code is just a, more or less direct, conversion of the Objective-C source code to Swift.

I used Xcode 7.0 that implements Swift version 2.1.

Swift is a language not yet known by my colorization tool: source-highlight. The colors may not be great.
import CryptoTokenKit

let mngr = TKSmartCardSlotManager.defaultManager()

// Use the first reader/slot found
let slotName = mngr!.slotNames[0]
print("slotName:", slotName)

// connect to the slot
mngr?.getSlotWithName(slotName, reply: {
    (slot: TKSmartCardSlot?) in
    // connect to the card
    let card = slot?.makeSmartCard()
    if (card != nil)
    {
        // begin a session
        card?.beginSessionWithReply({
            (success: Bool, error: NSError?) in
            if (success)
            {
                // send 1st APDU
                let aid : [UInt8] = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01]
                let data = NSData(bytes: aid, length: aid.count)
                card?.sendIns(0xA4, p1: 0x04, p2: 0x00, data: data, le: 0, reply: {
                    (data: NSData?, sw: UInt16, error: NSError?) in
                    if (error != nil)
                    {
                        print("sendIns error:", error!)
                    }
                    else
                    {
                        print("Response:", data!, String(sw, radix: 16))

                        // send 2nd APDU
                        let data = NSData(bytes: nil, length: 0)
                        card?.sendIns(0x0, p1: 0x00, p2: 0x00, data: data, le: 200, reply: {
                            (data: NSData?, sw: UInt16, error: NSError?) in
                            if (error != nil)
                            {
                                print("sendIns error:", error!)
                            }
                            else
                            {
                                print("Response:", data!, String(sw, radix: 16))
                                let newString = NSString(bytes: data!.bytes, length: data!.length, encoding: NSASCIIStringEncoding)
                                print(newString!)
                            }
                        })
                    }
                })
            }
            else
            {
                print("Session error:", error)
            }
        })
    }
    else
    {
        print("No card found")
    }
})

// wait for the asynchronous blocks to finish
sleep(1)

Output

slotName: Gemalto PC Twin Reader
Response: <> 9000
Response: <48656c6c 6f20776f 726c6421> 9000
Hello world!

Comments

See the previous article "PCSC sample in Objective-C" for comments about the Crypto Token Kit API.

Swift may be easier to learn and use than Objective-C. Using the Crypto Token Kit API is not different if you use Objective-C or Swift.

It looks like I am the first to provide a public code sample using the Crypto Token Kit API in Swift. Great! I hope that is a good Swift sample, I am not a Swift expert.

Conclusion

As I wrote in "PCSC framework will stay in Mac OS X 10.11 El Capitan" the PC/SC API is not available from Swift. So the only option (for now) to use a smart card from Swift is to use the Crypto Token Kit API.

[Update 5 Oct 2015]

The sample code was not correct in the error treatment.

I then discovered that if the card returns an "error" code then the sendIns method returns an error in the error parameter. Here is the execution output of the program with a card that does not contain the applet:
slotName: Gemalto PC Twin Reader
sendIns error: Error Domain=CryptoTokenKit Code=-3 "SmartCard returned error 6a82" UserInfo=0x600000060940 {NSLocalizedDescription=SmartCard returned error 6a82}
The card returns 0x6A82 (Wrong parameter(s) P1-P2, File not found) in SW (Status Word).

It may be difficult to differentiate errors at the card/reader communication level from "errors" returned  by the card.  A SW different from 0x9000 may be completely valid and expected by the application in some cases.

Friday, September 25, 2015

PCSC sample in Objective-C

To continue the list of PC/SC wrappers initiated in 2010 with "PC/SC sample in different languages" I now present a sample in Objective-C using the Apple Crypto Token Kit API.

Crypto Token Kit API

In Yosemite (Mac OS X 10.10) Apple introduced a new API to access smart cards. See OS X Yosemite and smart cards status.
This API is not a wrapper above PC/SC. It is the native API to be used on Mac OS X. You do not need to install it, it comes with the OS.

Source code

Create a new Cocoa application in Xcode. You need to enable the App Sandbox and add/set the com.apple.security.smartcard entitlement to yes.

My sample HellloWorld application does not use Cocoa. It is a text only application.


#import <CryptoTokenKit/CryptoTokenKit.h>

int main(int argc, const char * argv[])
{
    TKSmartCardSlotManager * mngr;
    mngr = [TKSmartCardSlotManager defaultManager];
    
    // Use the first reader/slot found
    NSString *slotName = (NSString *)mngr.slotNames[0];
    NSLog(@"slotName: %@", slotName);
    
    // connect to the slot
    [mngr getSlotWithName:slotName reply:^(TKSmartCardSlot *slot)
     {
         // connect to the card
         TKSmartCard *card = [slot makeSmartCard];
         if (card)
         {
             // begin a session
             [card beginSessionWithReply:^(BOOL success, NSError *error)
              {
                  if (success)
                  {
                      // send 1st APDU
                      uint8_t aid[] = {0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01};
                      NSData *data = [NSData dataWithBytes: aid length: sizeof aid];
                      [card sendIns:0xA4 p1:0x04 p2:0x00 data:data le:nil
                              reply:^(NSData *replyData, UInt16 sw, NSError *error)
                       {
                           if (error)
                           {
                               NSLog(@"sendIns error: %@", error);
                           }
                           else
                           {
                               NSLog(@"Response: %@ 0x%04X", replyData, sw);

                               // send 2nd APDU
                               NSData *data = [NSData dataWithBytes: nil length: 0];
                               [card sendIns:0x00 p1:0x00 p2:0x00 data:data le:@200
                                       reply:^(NSData *replyData, UInt16 sw, NSError *error)
                                {
                                    if (error)
                                    {
                                        NSLog(@"sendIns error: %@", error);
                                    }
                                    else
                                    {
                                        NSLog(@"Response: %@ 0x%04X", replyData, sw);
                                        NSString *newString = [[NSString alloc] initWithData:replyData encoding:NSASCIIStringEncoding];
                                        NSLog(@"%@", newString);
                                    }
                                }];
                           }
                       }];
                  }
                  else
                  {
                      NSLog(@"Session error: %@", error);
                  }
              }];
         } else
         {
             NSLog(@"No card found");
         }
     }];
    
    // wait for the asynchronous blocks to finish
    sleep(1);
    
    return 0;
}


Output

2015-09-25 14:24:19.552 HelloWorld[1578:141676] slotName: Gemalto PC Twin Reader
2015-09-25 14:24:19.668 HelloWorld[1578:141740] Response: <> 0x9000
2015-09-25 14:24:19.681 HelloWorld[1578:141740] Response: <48656c6c 6f20776f 726c6421> 0x9000
2015-09-25 14:24:19.681 HelloWorld[1578:141740] Hello world!

Comments

The method SendIns is asynchronous. The result is executed in a block. It is similar to a callback in the JavaScript example PCSC sample in JavaScript (Node.js).

With the method SendIns you do not specify the class byte. If needed you can use the lower level transmitRequest method instead.

The method SendIns takes a parameter that contains the data sent to the card. I get a compiler warning if I use nil to indicate that I have no data to transmit. I have to create a NSData structure of 0 bytes and use it as argument. It is perfectly valid to send no data and the API should allow a simpler code.

My code is a very simple example. The code does not explicitly wait for the asynchronous blocks to finish. I use sleep(1) instead. Without this delay the main function would return before the asynchronous blocks are executed.

Conclusion

I have seen very few source codes using this new Crypto Token Kit API one year after it is available.
The only API documentation I found is comments contained in the .h header files with no sample code. That does not help.

Maybe the situation will evolve with El Capitan (Mac OS X 10.11) that should be available in the next few days.

[UPDATE 26 Sept 2015]

It is in fact possible to specify the class byte CLA of an APDU. This byte is stored in the cla property of the TKSmartCard class. The default value is 0x00.

[UPDATE 31 March 2017]

See also ""PC/SC" sample in Objective-C (synchronous)".

Wednesday, September 2, 2015

Reader Selection: find the smart card reader you search

I now provide a web interface to access and filter the amazing list of 353 readers supported by my CCID driver.

Filter

You can filter the list using any field from the USB CCID descriptor. I presented each field from the descriptor in the articles "CCID descriptor statistics" in 2013 and 2014.

It is also possible to filter using the "features" field. This field is not available from the descriptor. It documents the features of the reader, like "contactless".

Combination of filters

It is possible to filter the results according to more than one field. The result is a AND combination. The readers must match according to field1 AND according to field2.

Demo

The web site is available at https://pcsclite.alioth.debian.org/select_readers/

By default no filer is used and you get the complete list of 353 readers.


Add a filter

To add a filer click on the "Add a match on..." drop down menu and select a field. For example "iManufacturer".
Then enter a manufacturer name like "NXP" in the value field.

Change the relation operator

You can use different relation operators:
  • = strict equality (for number or string)
  • ~ match the head of a string
  • ≤ lesser or equal
  • ≥ greater or equal
For example you can use the relation "~" with the value "a" and you get all the readers with the iManufacturer field starting with "a" or "A".

Share your results

You can share your selection by clicking on the "Get URL" button. A link will be displayed. Just use this URL and you will get the same selection again.

Examples:

Source code

The Javascript + HTML source code is available at https://anonscm.debian.org/cgit/pcsclite/website.git/tree/select_readers.

The code is Free Software and licensed under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

The project uses Bootstrap and jQuery.

Conclusion

Please propose new ideas, user experience improvements, design modifications, bug fixes, etc.
You can use the MUSCLE list for discussion.