PKCS # 11 Ошибка получения смарт-карты: javax.net.ssl.SSLHandshakeException из-за java.security.InvalidKeyException: асимметричный шифр RSA

Ситуация

Я работаю над проектом, в котором мы должны заставить смарт-карту работать в Linux. Карта от производителя Izenpe. Я получаю javax.net.ssl.SSLHandshakeException каждый раз, когда устанавливаю SSL-соединение с сервером.

Я загружаю драйвер Izenpe с этим кодом:

private final static String config_path3 = "name=IZENPE\nlibrary=/usr/lib/libbit4ipki.so";

...

String config = config_path3;
Provider provider = new SunPKCS11(new ByteArrayInputStream(config.getBytes()));
Security.removeProvider("IAIK");
Security.insertProviderAt(provider, 1);
try {
    keystore = KeyStore.getInstance("PKCS11", provider);
} catch (KeyStoreException e) {
    throw e;
}
KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", provider, 
        new KeyStore.CallbackHandlerProtection(new UtilTarjetas(). new callback()));
keystore = builder.getKeyStore();

Он загружает сертификаты для отображения в таблице, и я могу перейти к части, чтобы получить OutputStream из ответа сервера, где он не работает, когда мы выполняем рукопожатие SSL (подписывая запрос). Полные трассировки стека ниже:

javax.net.ssl.SSLHandshakeException: Error signing certificate verify
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1904)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:279)
    at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1054)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:341)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:901)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:837)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1023)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1092)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
    at gestores.comunicacion.gisscide.HTTPS_TGSS.doHTTP_Get(HTTPS_TGSS.java:470)
    at gestores.comunicacion.Gestor_Comunicaciones$RecibeMensajesSSL.descargaMsgHTTPS(Gestor_Comunicaciones.java:1284)
    at gestores.comunicacion.Gestor_Comunicaciones$RecibeMensajesSSL.run(Gestor_Comunicaciones.java:1852)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.security.InvalidKeyException: The RSA asymmetric cipher only operates with RSA keys; unsupported key found (sun.security.pkcs11.P11Key$P11PrivateKey)
    at com.entrust.toolkit.security.provider.RSA.a(Unknown Source)
    at com.entrust.toolkit.security.provider.RSA.engineGetKeySize(Unknown Source)
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052)
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1010)
    at javax.crypto.Cipher.init(Cipher.java:1209)
    at java.security.Signature$CipherAdapter.engineInitSign(Signature.java:1254)
    at java.security.Signature$Delegate.init(Signature.java:1128)
    at java.security.Signature$Delegate.chooseProvider(Signature.java:1085)
    at java.security.Signature$Delegate.engineInitSign(Signature.java:1158)
    at java.security.Signature.initSign(Signature.java:529)
    at sun.security.ssl.RSASignature.engineInitSign(RSASignature.java:125)
    at java.security.Signature$Delegate.engineInitSign(Signature.java:1156)
    at java.security.Signature.initSign(Signature.java:529)
    at sun.security.ssl.HandshakeMessage$CertificateVerify.<init>(HandshakeMessage.java:1556)
    at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1049)
    ... 15 more

Похоже, что получение не извлекаемого закрытого ключа на карту для подписания запроса в SSL-рукопожатии завершается ошибкой, потому что закрытый ключ PKCS # 11 не поддерживается / не распознается как действительный.

Добавляя эту строку в свой код, я получаю много строк журналов о SSL.

Properties systemProps = System.getProperties();
systemProps.put("javax.net.debug", "all");          
System.setProperties(systemProps);

В конце я вижу вот это:

SESSION KEYGEN:
PreMaster Secret:
0000: A5 F7 9C 89 A4 B5 B4 66   D4 DC CC 40 45 C8 41 07  [email protected].
0010: 0E F1 E9 5C 99 36 C8 84   06 B0 6B 95              ...\.6....k.
CONNECTION KEYGEN:
Client Nonce:
0000: 58 07 74 02 CD 8B 65 BB   E0 03 8D 53 95 C4 87 8C  X.t...e....S....
0010: EE 95 B2 92 C1 DF E8 CA   B0 7D E4 AD 16 B7 31 D2  ..............1.
Server Nonce:
0000: 4A 41 AA 83 DD 1D 9C DE   84 4A 56 40 A3 32 F7 53  [email protected]
0010: 18 48 32 BD 7A E2 3A 1D   19 AD 67 6E DD E1 3B 20  .H2.z.:...gn..; 
Master Secret:
0000: 72 58 C0 3D 90 67 2E 3B   B2 AE D4 54 15 AB 18 AA  rX.=.g.;...T....
0010: 95 73 91 9A DA AE EF 3D   77 A1 CD 7A 68 8B 37 56  .s.....=w..zh.7V
0020: 0F 05 64 EB DD 93 AF 6C   C4 C2 8A 75 A7 C2 CA 06  ..d....l...u....
Client MAC write Secret:
0000: 30 2C D3 A0 4C 2D 3F 67   ED B9 64 B8 3B 81 47 0E  0,..L-?g..d.;.G.
0010: D1 7B 75 A9                                        ..u.
Server MAC write Secret:
0000: 4B 22 25 8E 81 D1 55 6D   B9 40 0F 2A A2 26 49 F5  K"%...Um.@.*.&I.
0010: 66 6A 91 AE                                        fj..
Client write key:
0000: 72 BD C0 56 3C 1A E5 61   90 2C A6 AE AA FE B9 71  r..V<..a.,.....q
Server write key:
0000: C6 CE F4 C6 CE A4 E3 55   F6 2D 29 D6 2E 4C CA 7A  .......U.-)..L.z
Client write IV:
0000: 7D DB C8 17 F4 18 72 33   A1 DC 03 D6 2F 87 65 F1  ......r3..../.e.
Server write IV:
0000: 58 B1 4E BE 1A 90 0C B3   0D AE 5C 5B CD 36 74 4D  X.N.......\[.6tM
%% Invalidated:  [Session-3, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA]
Thread-7, SEND TLSv1 ALERT:  fatal, description = handshake_failure
Thread-7, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 28                               ......(
Thread-7, called closeSocket()
Thread-7, handling exception: javax.net.ssl.SSLHandshakeException: Error signing certificate verify
Finalizer, called close()
Finalizer, called closeInternal(true)

Я не знаю, актуально ли это, но при тестировании моего серверного сайта на www.ssllabs.com я обнаружил, что TLSv1.2 поддерживается, а TLSv1.1 - нет. И алгоритм, выбранный здесь в журнале, не указан в предпочтительном списке сервера:

введите здесь описание изображения

Итак, в чем может быть причина?

  • Я изменил $JAVA_HOME/jre/lib/security/java.security, отключив TLSv1.2 и SSLv3 в опции jdk.tls.disabledAlgorithms=SSLv3, TLSv1.1, оставив только TLSv1.1, потому что это выбор сервера, но безрезультатно.

  • Драйвер, который я использовал для загрузки провайдера, взят с сайта Izenpe. Судя по тому, что я получил в консоли Eclipse, он работает.

Моя мысль об этом:

  • Что не удается, возможно, провайдер SunPKCS11. Я говорю это, потому что исходный код работает в Windows, когда мы используем SunMSCAPI. Какой-то внутренний механизм SunMSCAPI помог нам подписать вызов. Но теперь, когда мы должны адаптировать проект к многоплатформенности, в Linux у нас нет другого выбора, кроме SunPKCS11. Не удалось выполнить JAR sunpkcs11.jar Java 6 и Java 8. (В Java 7 этого нет.)

  • Первоначальное намерение - сделать (почти) все смарт-карты доступными для аутентификации в моем приложении, но на данный момент мы хотим, чтобы работали только Izenpe и DNIe (испанская электронная идентификационная карта, поддерживаемая OpenSC).



person WesternGun    schedule 19.10.2016    source источник


Ответы (2)


Похоже, для SSL-соединения Java JCE используется Entrust Provider.

Если вы посмотрите в stacktrace:

Вызвано: java.security.InvalidKeyException: асимметричный шифр RSA работает только с ключами RSA; обнаружен неподдерживаемый ключ (sun.security.pkcs11.P11Key $ P11PrivateKey) в com.entrust.toolkit.security.provider.RSA.a (неизвестный источник) в com.entrust.toolkit.security .provider.RSA.engineGetKeySize (неизвестный источник) в javax.crypto.Cipher.passCryptoPermCheck (Cipher.java:1052)

Эта ошибка выдается поставщиком Entrust JCE. Он может ожидать только ключи RSA Java, но ему отправляется ключ PKCS11, который он не может обработать.

Итак, попробуйте удалить также поставщика Entrust.

Если это не сработает, попробуйте передать экземпляр SunPKCS11 provider в SSLContext, где бы вы ни использовали его для инициирования защищенного соединения.

person always_a_rookie    schedule 04.11.2016
comment
Спасибо. Я только что заметил, что перед установкой соединения существует способ изменить порядок поставщиков, поместив IAIK и Entrust в последний из списка поставщиков. Достаточно? Другое дело, как передать SSLContext провайдера SunPKCS11? - person WesternGun; 07.11.2016
comment
Если вы можете подключиться к URL-адресу https (т. Е. Сертификат является доверенным), не беспокойтесь о SSLContext. Похоже, в вашем случае сертификат доверенный. Если после переупорядочивания поставщиков вы по-прежнему получаете ту же ошибку, попробуйте удалить поставщика. Вы можете добавить их обратно после завершения подключения. - person always_a_rookie; 07.11.2016
comment
Спасибо, я попробовал, и это в основном причина, хотя я изменил много кодов и использовал NSS, и я не уверен, но то же исключение больше не появляется. Просто сомневаюсь, что где действительно находится этот провайдер Entrust? - person WesternGun; 09.11.2016
comment
Он должен быть из банка Entrust JCE. Возможно, вы добавляете поставщика с помощью Security.addProvider(...) или можете использовать его собственный API. - person always_a_rookie; 09.11.2016

Хотя я не слишком разбираюсь в PKCS # 11 (ни в SSL, когда я думаю об этом), из вашего описания и файлов журнала следующие элементы привлекли мое внимание и заставили меня задуматься:

Учитывая созданное выше исключение InvalidKeyException и выделенный алгоритм (TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), я склонен полагать, что ключ является ключом эллиптической кривой, а не RSA (на снимке экрана указано, что безопасность, обеспечиваемая TLS_ECDHE, равна той, которую вы получаете с помощью RSA. с 2048 битами). Следовательно, где-то по пути выбирается неправильный поставщик подписи (RSA вместо ECDSA) либо программно, либо с помощью искаженного сертификата.

Надеюсь, это поможет.

person ALe    schedule 25.10.2016
comment
Я проверил карту, и она показывает, что открытый ключ - RSA. Думаю, приватный ключ тоже RSA? Кроме того, при установлении связи SSL в Windows 10, той же карте и с поставщиком Microsoft Windows (Windows-MY) он хорошо работает с TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA. Так что, думаю, причина не в этом (подлежит подтверждению). - person WesternGun; 26.10.2016