Подтвердить что ты не робот

Доступ к javax.smartcardio из Linux 64 бит

Я пытаюсь загрузить терминалы смарт-карт с помощью javax.smartcardio API со следующим кодом:

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;
}

... и я получаю следующее исключение:

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

В Windows Vista/7 все работает отлично, но я не могу заставить его работать в Linux. Я использую Ubuntu 12.04 64 бит.

Я установил службу pcscd, используя следующую команду:

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

И команда pcsc_scan печатает это:

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

Итак, все выглядит нормально, но смарткардио просто не работает. Я пытаюсь как с Oracle, так и с OpenJDK 1.7.0_05, 32 и 64 бит.

Код работает нормально с OpenJDK (но не с Oracle JDK, не знаю, почему) в среде 32 бит Ubuntu. Поэтому я думаю, что это проблема с 64-битным мостом от Java до библиотеки ПК /SC.

Любые идеи?

Спасибо.

4b9b3361

Ответ 1

Я думаю, что нашел обходной путь для этого, поскольку у меня была аналогичная проблема. В bugreport из ubuntu говорится, что библиотека javax.smartcardio ищет библиотеку ПК /SC в неправильном каталоге.

Указав путь к библиотеке ПК /SC на моей машине, как упоминается в bugreport, я получил ее работу.

Пути в bugreport неверны для меня, я на 64-битной Fedora, где библиотека pc/sc установлена ​​на/usr/lib64/libpcsclite.so.1

Итак, обходной путь для меня заключается в том, чтобы указать путь библиотеки к java следующим образом:

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

В зависимости от вашего дистрибутива Linux расположение libpcsclite.so.1 на самом деле может отличаться, оно также может быть в /lib/x86_64-linux-gnu/libpcsclite.so.1 (т.е. Kubuntu 15.04). В этом случае вызовите его так:

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

Ответ 2

Я использую малину с версией debian arm

найдите местоположение libpcsclite сначала с помощью

$ ldd -r /usr/bin/pcsc_scan

а затем используйте расположение libpcsclite с помощью:

java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1

Ответ 3

Для всех, кто борется с этим на Ubuntu 14 с 64-битной машиной. Я нашел файл .so на самом деле расположен в следующем каталоге

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

Итак, запуск моего приложения с настройкой, как показано ниже, работал у меня

-Dsun.security.smartcardio.library =/USR/Library/x86_64-Linux-ГНУ/libpcsclite.so

Ответ 4

Вам нужно указать путь к libpcsclite.so.1 при вызове вашей программы следующим образом

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

Если вы не знаете путь к библиотеке, используйте следующую команду

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

Обычно это показывает путь на вашем компьютере. Я использовал его как на Ubuntu 10 (32 бит), так и на Ubuntu 15 (32 бит и 64 бит)

Если вы ленивы, как и я, то вы можете включить эту часть кода в свою программу, прежде чем использовать библиотеку javax.smartcardio

      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();
        }

Теперь вы можете запускать свой код, как обычно, без указания пути к libpcsclite.so.1

Ответ 5

Дополнение к решению с поставкой пути в качестве параметра следующим образом:

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

Если вы не хотите предоставлять это при каждом вызове JVM, установите его в переменных среды _JAVA_OPTIONS и/или 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"

Так как это обходной путь для ошибки, которая затрагивает всю систему, имеет смысл ИМХО применять это обходное решение в масштабах всей системы.

JAVA_OPTS имеет локальную область действия и должен оцениваться скриптами, запускающими ваш код; _JAVA_OPTIONS предполагается автоматически оценивать JRE.

Ответ 6

Еще один подход (мой любимый) - сделать некоторые символические ссылки.

Преимущество состоит в том, что он работает в общесистемной среде (нет аргументов jvm, нет переменных среды).

Для моего (любимого) 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

Примечание. Для этого, вероятно, потребуется доступ к суперпользователю.