JDK-7195480 : javax.smartcardio does not detect cards on Mac OS X
  • Type: Bug
  • Status: Closed
  • Resolution: Fixed
  • Component: security-libs
  • Sub-Component: javax.smartcardio
  • Priority: P3
  • Affected Version: 7
  • OS: os_x
  • CPU: x86
  • Submit Date: 2012-08-31
  • Updated Date: 2016-06-13
  • Resolved Date: 2014-05-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
JDK 7 JDK 8 JDK 9
7u72Fixed 8u20Resolved 9 b15Fixed
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Mac OS X 10.8.1
Darwin lambda.local 12.1.0 Darwin Kernel Version 12.1.0: Tue Aug 14 13:29:55 PDT 2012; root:xnu-2050.9.2~1/RELEASE_X86_64 x86_64

EXTRA RELEVANT SYSTEM CONFIGURATION :
Connected a ACR38U smartcardreader (CCID)
Inserted a Belgian eID card in the reader.

A DESCRIPTION OF THE PROBLEM :
Smartcards inserted in a smartcardreader are not detected by Oracle's Java 7 for Mac. It detects the reader, but not the card.

REGRESSION.  Last worked in version 6u31

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
connect a reader and insert a smartcard. Then basically do this in Java:

TerminalFactory factory = TerminalFactory.getDefault();
CardTerminals cardTerminals = factory.terminals();
List<CardTerminal> cardTerminalList;
cardTerminalList = cardTerminals.list();
for (CardTerminal cardTerminal : cardTerminalList){
    System.out.println(cardTerminal.getName());
    if (cardTerminal.isCardPresent()) {
    // not getting here
   }
}


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected to detect the card. This works in Mac OS X's own Java 6 VM.
ACTUAL -
The card is not detected. The VM acts as if the reader is empty.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.smartcardio.*;
import java.util.List;

public class SmartCardBug {

    public static void main(String[] args) {
        TerminalFactory factory = TerminalFactory.getDefault();

        CardTerminals cardTerminals = factory.terminals();
        List<CardTerminal> cardTerminalList;
        try {
            cardTerminalList = cardTerminals.list();
            for (CardTerminal cardTerminal : cardTerminalList) {
                System.out.println(cardTerminal.getName());
                cardTerminal.waitForCardPresent(10000);
                if (cardTerminal.isCardPresent()) {
                    Card card;
                    try {

                        card = cardTerminal.connect("T=0");

                        card.beginExclusive();
                    } catch (CardException e) {
                        System.err.println("could not connect to card: "
                                + e.getMessage());
                        continue;
                    }
                    ATR atr = card.getATR();

                    byte[] atrBytes = atr.getBytes();
                    StringBuffer atrStringBuffer = new StringBuffer();
                    for (byte atrByte : atrBytes) {
                         atrStringBuffer.append(Integer
                                    .toHexString(atrByte & 0xff));
                    }
                    System.out.println("ATR= "
                                        + atrStringBuffer);

                    card.endExclusive();
                    card.disconnect(true);
                }
            }

        } catch (CardException e) {
            System.err.println("error on card terminals list: "
                    + e.getMessage());
            System.err.println("no card readers connected?");
            Throwable cause = e.getCause();
            if (null != cause) {
                System.err.println("cause: " + cause.getMessage());
                System.err.println("cause type: "
                        + cause.getClass().getName());
            }
        }
    }

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
We currently recommend our customers to deinstall Oracle's Java version and to stick with Apple's Java version.

Comments
Please note that currently many other tests from jdk/test/sun/security/smartcardio/ are failing on Mac OS X too, but I suggest handling these problems one by one.
2014-05-16

The fix can be tested with the already existing test jdk/test/sun/security/smartcardio/TestPresent.java. The test is manual, but it seems this can hardly be automated unless we have a virtual reader/smartcard set up.
2014-05-16

I confirm that fixing the type of named above fields solves the issue. The structure SCARD_READERSTATE_A must also be packed, so that the fields will be aligned on the correct boundary. The total size of the structure SCARD_READERSTATE_A on Mac is therefore 61 byte (opposite to 80 on Solaris/Linux).
2014-05-15

Hmm, it looks like the problem is due to different structure declarations between Mac OS and Solaris. On Solaris, the fields 'dwCurrentState', 'dwEventState', and 'cbAtr' are declared to be long vs the uint32 on Mac OS. This leads to incorrect value being read for dwEventState which is used to determine if a card is present or not. We have to correct the declaration for Mac OS so that the read is done correctly.
2014-04-24