Accessing javax.smartcardio from Linux 64 bits
Asked Answered
G

7

24

I'm trying to load the smartcard terminals using the javax.smartcardio API with the following code:

public CardTerminal getReadyCardTerminal() throws CardException {

    TerminalFactory factory = TerminalFactory.getDefault();
    CardTerminals terminals = factory.terminals();
    List<CardTerminal> list = terminals.list(State.CARD_PRESENT);

    while (list.isEmpty()) {
        terminals.waitForChange(1000);
        list = terminals.list(State.CARD_PRESENT);
    }
    CardTerminal cardTerminal = list.get(0);
    return cardTerminal;
}

... and I always get the following exception:

java.lang.IllegalStateException: no terminals
at javax.smartcardio.TerminalFactory$NoneCardTerminals.waitForChange(TerminalFactory.java:145)

On Windows Vista/7 everything works fine, but I can't get it to work on Linux. I'm using Ubuntu 12.04 64 bits.

I installed the pcscd service using the following command:

sudo apt-get install libccid pcscd libpcsclite-dev libpcsclite1
sudo service pcscd start

And the pcsc_scan command prints this:

PC/SC device scanner
V 1.4.18 (c) 2001-2011, Ludovic Rousseau <[email protected]>
Compiled with PC/SC lite version: 1.7.4
Using reader plug'n play mechanism
Scanning present readers...
0: OMNIKEY CardMan 3x21 00 00

Tue Sep 11 15:44:49 2012
Reader 0: OMNIKEY CardMan 3x21 00 00
  Card state: Card inserted, 
  ATR: <some hexa codes>
  ...

So everything looks ok, but the smartcardio just doesn't work. I'm trying with both Oracle and OpenJDK 1.7.0_05, 32 and 64 bits.

The code runs ok with OpenJDK (but not with Oracle JDK, don't know really why) on a Ubuntu 32 bits environment. So I think it is a problem with the 64 bits bridge from Java to the PC/SC library.

Any ideas?

Thanks.

Gillies answered 11/9, 2012 at 19:2 Comment(2)
By the way, the pcsc_scan command is from the pcsc-tools package.Gillies
Good question. I did solve it myself on my Ubuntu box, but it's good that it is now logged somewhere it can be found.Stedt
F
38

I think I found a workaround for this as I just had a similar problem. In a bugreport from ubuntu it says that the javax.smartcardio library searches for the PC/SC library in the wrong directory.

By specifying the path to the PC/SC library on my machine, like the bugreport mentions, I got it working.

The paths in the bugreport are wrong for me, I'm on 64 bit fedora, where the pc/sc library are installed at /usr/lib64/libpcsclite.so.1

So the workaround for me is to specify the library path to java like this:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

Depending on your Linux distribution, the location of libpcsclite.so.1 actually might differ, it could also be at /lib/x86_64-linux-gnu/libpcsclite.so.1 (i.e. Kubuntu 15.04). In that case, call it like this:

java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1
Fukien answered 12/9, 2012 at 10:55 Comment(8)
Thank you man! That solved the problem. On Ubuntu, the path is /usr/lib/libpcsclite.so.1Gillies
Newbie here, just to be clear, i can run this: "java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1" in terminal or where?Seemaseeming
Yes, when you start your program with the java command. Like "java -Dsun.secu... -jar yourprogram.jar".Fukien
It works also with Java 1_8_25 on debian wheezy (in this case: -Dsun.security.smartcardio.library=/usr/lib/libpcsclite.so.1 )Kurtiskurtosis
Life saver. Thanks.Maribeth
@JosteinStuhaug I am stuck right here with correct path and still its giving java.lang.IllegalStateException: no terminalsKoester
Is there a way to set this for the system Java? What if a program invokes java from a shell script, where it's not as easy to add a -D parameter?Goober
An answer further down has a solution for that it seems: https://mcmap.net/q/544192/-accessing-javax-smartcardio-from-linux-64-bitsFukien
I
9

i'm using raspberry with debian arm version

find the location of libpcsclite first with:

$ ldd -r /usr/bin/pcsc_scan

and then use the libpcsclite location with:

java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
Itinerancy answered 30/12, 2013 at 3:53 Comment(1)
i have manage to get the cardreader working, is there any way to fix the problem? right now every time i try to run the program i need to java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1 Test.jar ir order to work correctly..if i do java -jar Test.jar it gives me error main class not found..Inspiratory
E
6

You need to give the path to the libpcsclite.so.1 when calling your program as follows

java -Dsun.security.smartcardio.library=/path/to/libpcsclite.so.1

If you don't know the path to the library, use the following command

find /usr/lib -name libpcsclite.so.1

This usually shows you the path on your machine. I used it on both Ubuntu 10 (32bit) and Ubuntu 15(32bit and 64bit)

If you're lazy like me, what you can do is include this part of code in your program before you use the javax.smartcardio library

      try {
            String comm[] = { "find", "/usr", "/lib", "-name",
                    "libpcsclite.so.1" };
            Process p = Runtime.getRuntime().exec(comm);

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));

            while ((line = reader.readLine()) != null && !line.equals("")) {
                if (line.contains("libpcsclite.so.1")) {
                System.setProperty("sun.security.smartcardio.library",line);
                    break;
                }

            }
            p.waitFor();

        } catch (Exception e) {

            e.printStackTrace();
        }

Now you can run your code from as usual without including the path to libpcsclite.so.1

Eldest answered 14/6, 2016 at 5:24 Comment(3)
Hi, May I know what is this line ? It's an undefined object here. line = reader.readLine()Russ
Its been a while since I used this, but I think you can define line to be an empty String before reader.readLine() is calledEldest
Ok :-) Thank youRuss
D
4

For anyone else struggling with this on Ubuntu 14 with a 64 bit machine. I found the .so file is actually located in the following directory

/usr/lib/x86_64-linux-gnu/libpcsclite.so

So running my app with the setting as below worked for me

-Dsun.security.smartcardio.library=/usr/lib/x86_64-linux-gnu/libpcsclite.so

Dishtowel answered 3/3, 2015 at 12:28 Comment(1)
My Path to libpcsclite.so is -Dsun.security.smartcardio.library=/usr/lib/libpcsclite.so.1 which is valid, but still not getting any list of terminal. Can you give some details of your implementation ?Koester
A
2

Addition to the solution with supplying the path as a parameter like this:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

If you don't want to supply this every time you call the JVM, set it in the environment variables _JAVA_OPTIONS and/or JAVA_OPTS:

export _JAVA_OPTIONS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"
export JAVA_OPTS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"

Since this is a workaround for bug that affects the entire system, it makes sense IMHO to apply this workaround systemwide as well.

JAVA_OPTS has local scope and has to be evaluated by scripts running your code; _JAVA_OPTIONS is supposed to be evaluated automatically by the JRE.

Administration answered 10/7, 2015 at 12:47 Comment(0)
E
1

Yet another approach (my favorite) is to make some symbolic links.

It has the advantage that it works system-wide (no jvm arguments, no environment variables).

For my (beloved) debian jessie amd64:

ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so libpcsclite.so
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1 libpcsclite.so.1
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0 libpcsclite.so.1.0.0

Note: This will probably require superuser access.

Extragalactic answered 24/9, 2015 at 19:24 Comment(0)
R
1

Complementing @AshanPerera answer, as sometimes searching each time can be slow, you can search it at the first time, and them store the location in a file, and read it from then on:

        try {

        String filename = "libpcsclite.location"; 
        File propertyFile = new File(filename);
        if(propertyFile.createNewFile()) 
        {   
            String commandWithArguments[] = { "find", "/usr", "/lib", "-name","libpcsclite.so.1" };
            Process searchProcess = Runtime.getRuntime().exec(commandWithArguments);
            BufferedReader searchReader = new BufferedReader(new InputStreamReader(searchProcess.getInputStream()));
            String propertyValue;
            while ( (propertyValue = searchReader.readLine()) != null && !propertyValue.equals("")) 
            {
                if (propertyValue.contains("libpcsclite.so.1")) {
                    BufferedWriter propertyWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertyFile)));
                    propertyWriter.write(propertyValue);
                    propertyWriter.close();
                    System.setProperty("sun.security.smartcardio.library",propertyValue);
                    break;
                }
            }
            searchProcess.waitFor();
        }
        else 
        {  
            BufferedReader propertyReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertyFile)));                 
            String propertyValue = propertyReader.readLine(); 
            System.setProperty("sun.security.smartcardio.library",propertyValue);       
        }
    } catch (Exception e) {

        e.printStackTrace();
    }
Rianna answered 15/10, 2018 at 20:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.