JDK-7200271 : javax.smartcardio.CardTerminal.isCardPresent always returns false
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.smartcardio
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: os_x
  • CPU: x86
  • Submitted: 2012-09-21
  • Updated: 2014-05-23
  • Resolved: 2013-04-12
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_06-ea"
Java(TM) SE Runtime Environment (build 1.7.0_06-ea-b08)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Mac OS X only

EXTRA RELEVANT SYSTEM CONFIGURATION :
Smart Card reader attached to an OS X system along with a smart card.

A DESCRIPTION OF THE PROBLEM :
7195480, but I can't find a way to add more details.

CardTerminal.isCardPresent() always returns false.



REGRESSION.  Last worked in version 6u31

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this code on OS X with Oracle Java 7
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
CardTerminal terminal = terminals.get(0);
System.out.println(terminal.isCardPresent()); // Always false

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Returns true when a card is present, false otherwise
ACTUAL -
CardTerminal.isCardPresent() always returns false.

The main issue here is the native layer in Java is reading the wrong part of the struct SCARD_READERSTATE after calling SCardGetStatusChange.

  From Java_sun_security_smartcardio_PCSC_SCardGetStatusChange after the malloc call:

(gdb) c
Continuing.

Breakpoint 3, 0x000000010aa225b2 in Java_sun_security_smartcardio_PCSC_SCardGetStatusChange ()
3: x/8xw 4300546608
0x100552230:	0x00554aa0	0x00000001	0x00000000	0x00000000
0x100552240:	0x00000000	0x00000022	0x00000013	0x0096db3b
                                  ^^^^^^^^        ^^^^^^^^
                                     |               +--- Number of bytes in ATR
                                     +--- Event State
2: /x $rax = 0x0
1: x/i $rip  0x10aa225b2 <Java_sun_security_smartcardio_PCSC_SCardGetStatusChange+265>:	mov %rax,-0x50(%rbp)
(gdb) set {int}0x100552248 = 0xdeadbeef
(gdb) display
3: x/8xw 4300546608
0x100552230:	0x00554aa0	0x00000001	0x00000000	0x00000000
0x100552240:	0x00000000	0x00000022	0xdeadbeef	0x0096db3b
                                  ^^^^^^^^        ^^^^^^^^
                                     |               +--- Number of bytes in ATR
                                     +--- Event State
2: /x $rax = 0x0
1: x/i $rip  0x10aa225b2 <Java_sun_security_smartcardio_PCSC_SCardGetStatusChange+265>:	mov %rax,-0x50(%rbp)
(gdb) c
Continuing.
deadbeef <-- Printed from the JVM, the result of directly calling SCardGetStatusChange via reflection
^^^^^^^^
   |
   +---- Now in the JVM from a direct reflection call to SCardGetStatusChange
  Program exited normally.
(gdb)



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
CardTerminal terminal = terminals.get(0);
System.out.println(terminal.isCardPresent()); // Always false
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Since in OS X the method returns the number of bytes in the ATR rather than the event state, the main workaround is to test if the number of ATR bytes is non-zero.

  To do so, code must be written that restricts its execution to Java versions after 1.7 and OS X only. The code must use reflection to directly call SCardGetStatusChange and check the value of the returned ATR size.