barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

среда, 9 сентября 2015 г.

JCP + ruToken: ошибка "java.io.IOException: Can't connect to Aktiv Co. ruToken 0"

Проблема

Используется JCP + ruToken для вычисления ЭЦП. При попытке получить ключ с токена падает ошибка:
Caused by: java.security.UnrecoverableKeyException: Can't connect to Aktiv Co. ruToken 0
at ru.CryptoPro.JCP.KeyStore.s.e(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.engineGetKey(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.JCPKeyStore.engineGetKey(Unknown Source)
at java.security.KeyStore.getKey(KeyStore.java:792)
...
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
Решение

Текст ошибки не особо содержателен, и по нему совершенно неочевидно, в чем именно проблема. Из того же JCP-шного ControlPane я великолепно вижу Aktiv Co. ruToken 0, включая ключ и сертификат на нем.
Декомпилируем rtjlib.JCP.RutokenReader (rtjlib.jar в jre/lib/ext того JDK, который используется для подписывания). Там IOException с таким текстом кидается в 2 местах, и если в одном он кидается просто в коде после неудачного коннекта, то вот во втором применен замечательный подход "проглатывания исключения":
try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str);
    }
Добавляем в бросаемое исключение исходный localException1:
    try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str, localException1);
    }
Перекомпилируем класс RutokenReader, подкладываем в целевой JDK. Получаем более развернутую ошибку:
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:38)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
... 25 more
Caused by: java.lang.Exception: Establish context failed with 0x8010001d
at rtjlib.nativeAPI.SCardEstablishContext(Native Method)
at rtjlib.readerImpl.nativeWinJavaReader.getAtr(Unknown Source)
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:34)
... 28 more
Гуглим код 0x8010001d, узнаем, что расшифровывается он как "SCARD_E_NO_SERVICE - "The Smart card resource manager is not running." (http://blogs.msdn.com/b/alejacma/archive/2011/05/19/scardestablishcontext-fails-with-scard-e-no-service-error.aspx). Гугл же подсказывает и возможную причину: ошибка может быть вызвана нехваткой прав к событию "Global\Microsoft Smart Card Resource Manager Started". На это событие есть права только у интерактивных пользователей, SYSTEM и LOCAL SERVICE. В моем же случае ошибка падала в службе, запускающейся из-под обычного пользователя (но т.к. вход не интерактивный - прав не хватало). Запустили целевую программу в интерактивном режиме (из командной строки) вместо запуска в качестве службы - ошибка ушла. Пока такое решение устроило.

Комментариев нет:

Отправить комментарий