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 thecom.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 methodSendIns
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 thecla
property of the TKSmartCard
class. The default value is 0x00.