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.

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)".

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://ccid.apdu.fr/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.

How to get my GPG public key?

On the MUSCLE mailing list we got the following question:

From: Jessie Frazelle
Subject: GPG Key

I swear I looked all over the website and downloads page [1]. But I
cannot find what key the tarballs are signed with to import to verify.
I am so sorry for bothering a mailing list with such noise, especially
because as much as I try I know they have to be somewhere and I am
just missing it.

Thanks in advance.


[1] https://alioth.debian.org/frs/?group_id=30105

Check the signature

Let try with the CCID driver. Download the 2 files: ccid-1.4.20.tar.bz2 and ccid-1.4.20.tar.bz2.asc and try to verify the signature.

$ gpg2 ccid-1.4.20.tar.bz2.asc
gpg: assuming signed data in 'ccid-1.4.20.tar.bz2'
gpg: Signature made Wed Aug  5 13:23:24 2015 CEST using RSA key ID E8F9C57E
gpg: Can't check signature: No public key

The signing key ID is E8F9C57E. We need to find this public key.

Fetch the public GPG key

You can use your web search engine for "E8F9C57E". It will return many results, including the public key you are looking for.

One way to get the key is to ask a key server using:
$ gpg2 --keyserver pgp.mit.edu --recv-key E8F9C57E
gpg: requesting key E8F9C57E from hkp server pgp.mit.edu
gpg: key E8F9C57E: public key "Ludovic Rousseau " imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

I used pgp.mit.edu as key server but you can use another one.

Check the signature, again

Then we can verify the signature:
$ gpg2 ccid-1.4.20.tar.bz2.asc
gpg: assuming signed data in 'ccid-1.4.20.tar.bz2'
gpg: Signature made Wed Aug  5 13:23:24 2015 CEST using RSA key ID E8F9C57E
gpg: Good signature from "Ludovic Rousseau " [unknown]
gpg:                 aka "Ludovic Rousseau " [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: F5E1 1B9F FE91 1146 F41D  953D 78A1 B4DF E8F9 C57E

The signature is correct. But the key is not trusted.

Trust the public key?

Then you can verify that the public key ID E8F9C57E is really my public key. You will need to use the web of trust for that.
Maybe you trust one of the keys that signed my public key (level 1)?
Or maybe you trust a key that signed a key that signed my key (level 2)?
etc.

My GPG public key is also available from my web page at http://ludovic.rousseau.free.fr/

PySCard 1.9.0 released

I just released a new official pyscard version 1.9.0 of pyscard. pyscard is a python module adding smart cards support (PC/SC) to python.

The PySCard project is available at:


Changes:

The main change is the support of Python3. I would not be surprised if some Python3 issues are still present.
After some more testing, stress test and bug fix (if needed) on Python3 I will move the version number to 2.0.0.

1.9.0 (August 2015)
  • add Python3 support (Python2 is still supported)
  • fix a lot of pylint warnings
  • smartcard/test/* replace deprecated assert calls
  • add tox support and coverage reports, run test suite on Travis
  • add Travis CI support to automatically build on Unix
  • add AppVeyor support to automatically build on Windows
  • minor bugs fixed
  • Big thank you to Alex Willmer for his work on pyscard

See also my previous article: PySCard 1.7.0 released

New version of libccid: 1.4.20

I just released a version 1.4.20 of libccid the Free Software CCID class smart card reader driver.

Direct download here.

Changes:
1.4.20 - 5 August 2015, Ludovic Rousseau

  • Add support of
    • ACS ACR1251 Dual Reader
    • Access IS NFC Smart Module
    • BIFIT iToken
    • BLUTRONICS BLUDRIVE II CCID (idProduct: 0x1079)
    • Generic MultiCard Device
    • NXP Pegoda 2 N
    • SafeNet eToken 5100
    • SafeNet eToken 7300
    • Yubico Yubikey 4 CCID
    • Yubico Yubikey 4 OTP+CCID
    • Yubico Yubikey 4 OTP+U2F+CCID
    • Yubico Yubikey 4 U2F+CCID
  • Depends on libusb version 1.0.9 instead of 1.0.8
  • The O2 Micro Oz776 reader only supports 9600 bps
  • Change installation directory for Mac OS X El Capitan 10.11

New version of pcsc-lite: 1.8.14

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

Changes:
1.8.14: Ludovic Rousseau
5 August 2015

  • Threading: lock the PC/SC context in a safe way
  • Threading: lock the card context in a safe way
  • SCardGetStatusChange(): fix card movement rare bug
  • Doxygen:
    • SCardTransmit() may return SCARD_E_INSUFFICIENT_BUFFER
    • SCardEndTransaction() The disposition is used and the dwDisposition parameter has an effect.
    • SCardReconnect() do not release locks
    • fix typos
  • Move the source code repository from subversion to git
  • Use asprintf(3) instead of strlcat(3) and strlcpy(3)
  • Allow to use pcscd in a remote session (polkit issue)
  • Some other minor improvements and bug corrections

OS X Yosemite bug: SCardConnect blocks in SCARD_SHARE_SHARED mode

This is part of the series: "OS X Yosemite and smart cards: known bugs".

SCardConnect(..., SCARD_SHARE_SHARED, ...)

SCardConnect() do not work correctly on Yosemite in a multi application context.

SCardConnect(..., SCARD_SHARE_SHARED, ...) will block its execution until SCardDisconnect() is called in the other application using the card or the card is removed.

The SCARD_SHARE_SHARED flag indicates that the connection shall be shared by different applications. Different application should be able to use the card at the same time. An application can use SCardBeginTransaction()/SCardEndTransaction() to get a temporary exclusive access to the card.

This can be really problematic if an application is not correctly written and SCardDisconnect() is not called. The concurrent application would be blocked forever on SCardConnect().

When SCardConnect() is unblocked by a card removal it will return the error code SCARD_E_NO_SMARTCARD.

This bug is present in Yosemite version 10.10.4. I have not verified if the bug is also present in previous Yosemite versions. Maybe it is a bug introduced in 10.10.4?

See also

Apple bug report #21703315 "PC/SC SCardConnect() blocks in SCARD_SHARE_SHARED mode"

Sample code

Thanks to Mounir for the initial sample code.

The sample application does:
  1. wait for a card insertion
  2. SCardConnect() to the card
  3. sleep for 3 seconds
  4. SCardDisconnect() from the card
  5. go to step 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

SCARDCONTEXT hContext;
SCARD_READERSTATE state;

#define CHECK_ERROR(text) \
    if (err != SCARD_S_SUCCESS) \
        printf("\033[0;31m" text ": %s (0x%08x)\033[00m\n",pcsc_stringify_error(err),err); \
    else \
        timed_log(text ": OK\n");

#define CHECK_EXIT(text) \
    CHECK_ERROR(text) \
    if (err != SCARD_S_SUCCESS) return -1;

static void timed_log(const char *msg)
{
    static struct timeval old_tp;
    struct timeval tp, r;

    gettimeofday(&tp, NULL);

    r.tv_sec = tp.tv_sec - old_tp.tv_sec;
    r.tv_usec = tp.tv_usec - old_tp.tv_usec;
    if (r.tv_usec < 0)
    {
        r.tv_sec--;
        r.tv_usec += 1000000;
    }

    printf("%ld.%.6d %s", r.tv_sec, r.tv_usec, msg);
    old_tp = tp;
}

static int WaitForCardEvent(void)
{
    int insert = 0;

    DWORD err;
    while (1)
    {
        timed_log("Waiting for event...\n");
        err = SCardGetStatusChange(hContext, INFINITE, &state, 1);
        CHECK_EXIT("SCardGetStatusChange")

        timed_log("event detected\n");
        state.dwCurrentState = state.dwEventState;

        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            if (! (state.dwEventState & SCARD_STATE_MUTE))
            {
                timed_log("card inserted\n");
                if (insert)
                    return 1;
            }
            else
                timed_log("card is mute\n");
        }
        else
        {
            timed_log("card removed\n");
            insert = 1;
        }
    }

    return 0;
}

static int UseCard(const char *mszReaders)
{
    DWORD dwActiveProtocol;
    SCARDHANDLE hCard = 0;

    timed_log("calling SCardConnect\n");
    DWORD err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
        SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
    CHECK_EXIT("SCardConnect")
    timed_log("connected\n");

    sleep(3);

#if 1
    timed_log("calling SCardDisconnect\n");
    err = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    CHECK_ERROR("SCardDisconnect")
#endif

    return 1;
}

int main(void)
{
    LPSTR mszReaders;
    DWORD err, cchReaders;

    err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    CHECK_EXIT("SCardEstablishContext")
    cchReaders = 0;

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

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

    memset(&state, 0, sizeof state);
    state.szReader = mszReaders;
    err = SCardGetStatusChange(hContext, 0, &state, 1);
    CHECK_EXIT("SCardGetStatusChange")

    while (1)
    {
        WaitForCardEvent();

        UseCard(mszReaders);
    }

    SCardReleaseContext(hContext);


    return 0;
}

You need to open 2 terminal windows and run the application concurrently in the 2 terminals.

Result (on Yosemite)

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

Terminal 1

$ ./main
1436274783.304010 SCardEstablishContext: OK
0.000163 SCardListReaders: OK
0.000108 SCardListReaders: OK
Using Reader: Dell Dell Smart Card Reader Keyboard
0.000971 SCardGetStatusChange: OK
0.000004 Waiting for event...
0.000540 SCardGetStatusChange: OK
0.000005 event detected
0.000001 card removed
0.000001 Waiting for event...

42.709172 SCardGetStatusChange: OK
0.000010 event detected
0.000002 card inserted
0.000001 calling SCardConnect
0.042665 SCardConnect: OK
0.000010 connected
3.000132 calling SCardDisconnect
0.000339 SCardDisconnect: OK
0.000006 Waiting for event...
0.000825 SCardGetStatusChange: OK
0.000006 event detected
0.000001 card inserted
0.000001 Waiting for event...
3.001277 SCardGetStatusChange: OK
0.000008 event detected
0.000001 card inserted
0.000001 Waiting for event...

Terminal 2

$ ./main
1436274812.713724 SCardEstablishContext: OK
0.000145 SCardListReaders: OK
0.000091 SCardListReaders: OK
Using Reader: Dell Dell Smart Card Reader Keyboard
0.001038 SCardGetStatusChange: OK
0.000005 Waiting for event...
0.000717 SCardGetStatusChange: OK
0.000006 event detected
0.000001 card removed
0.000001 Waiting for event...

13.299278 SCardGetStatusChange: OK
0.000007 event detected
0.000001 card inserted
0.000001 calling SCardConnect
3.043707 SCardConnect: OK
0.000014 connected
3.000740 calling SCardDisconnect
0.000396 SCardDisconnect: OK
0.000007 Waiting for event...

Description

I added a newline in the traces just before the card insertion. The number in front of each line is the time that passed since the previous log line. So if you see "1.23 foo" then "foo" happened 1.23 second after the previous log.

In this execution the application in terminal 1 got the card connection in the first place. You can see that SCardConnect() returns after 0.042665 seconds. The state was "connected" for 3.000132 seconds. Then SCardDisconnect() is called.

In terminal 2 we note that SCardConnect() returns after 3.043707 seconds. The application is blocked during the 3 seconds used by the the first application.

Also note that in terminal 1 SCardGetStatusChange() returns after 3.001277 seconds. This is because the card was used by the application in terminal 2 and the card state changed. The bit SCARD_STATE_INUSE changed from 1 (card in use) to 0 (card not used).

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

Terminal 1

$ ./main1436274912.852172 SCardEstablishContext: OK
0.000144 SCardListReaders: OK
0.000134 SCardListReaders: OK
Using Reader: Gemalto PC Twin Reader (70D7E2EE) 00 00
0.000138 SCardGetStatusChange: OK
0.000012 Waiting for event...
0.000089 SCardGetStatusChange: OK
0.000020 event detected
0.000003 card removed
0.000002 Waiting for event...

11.780610 SCardGetStatusChange: OK
0.000014 event detected
0.000002 card inserted
0.000002 calling SCardConnect
0.033486 SCardConnect: OK
0.000013 connected
3.000073 calling SCardDisconnect
0.000125 SCardDisconnect: OK
0.000016 Waiting for event...

Terminal 2

$ ./main 
1436274916.659394 SCardEstablishContext: OK
0.000163 SCardListReaders: OK
0.000149 SCardListReaders: OK
Using Reader: Gemalto PC Twin Reader (70D7E2EE) 00 00
0.000144 SCardGetStatusChange: OK
0.000033 Waiting for event...
0.000108 SCardGetStatusChange: OK
0.000023 event detected
0.000019 card removed
0.000007 Waiting for event...

7.973306 SCardGetStatusChange: OK
0.000025 event detected
0.000009 card inserted
0.000007 calling SCardConnect
0.033451 SCardConnect: OK
0.000028 connected
3.000083 calling SCardDisconnect
0.000215 SCardDisconnect: OK
0.000025 Waiting for event...

Description

On Linux you can see that the 2 applications run at the same time concurrently. No application is blocked by the other.

Known workaround

None known.

Some ideas that should help:
  • Do not forget to call SCardDisconnect() when you no longer use the card, or another application may be blocked for a long time.
  • Connect to a card for short periods of time if possible. Another application would then get a chance to access the card.

Update

This bug is now fixed in Mac OS X El Capitan 10.11.0.

PySCard 1.7.0 released

Release 1.7.0

I just released a new official pyscard version 1.7.0 of pyscard. pyscard is a python module adding smart cards support (PC/SC) to python.

Changes:

1.7.0 (June 2015)
  • PCSCCardConnection: Fix a problem with mode=SCARD_SHARE_DIRECT
  • add support of cygwin as a build platform
  • Fix a problem with Windows Remote Desktop
  • Switch from distutils to setuptools
  • dropped support for Python 2.5 and earlier (Alex Willmer)
  • dropped support for OS X 10.5 (Leopard) and earlier (Alex Willmer)
  • minor bugs fixed

Provided software

The source code archive pyscard-1.7.0.tar.gz is of course provided.

I also provide a binary installer pyscard-1.7.0.macosx-10.10-intel.tar.gz for Mac OS X 10.10 Yosemite and Python 2.7.

Continuous Integration

The PySCard project now uses two continuous integration platforms:

Windows installers?

Maybe AppVeyor can be used to provide binary installers for Windows. Your help is welcome on this task because I am not a Windows user.