Ситуация
Я работаю над проектом, в котором мы должны заставить смарт-карту работать в 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
. Не удалось выполнить JARsunpkcs11.jar
Java 6 и Java 8. (В Java 7 этого нет.)Первоначальное намерение - сделать (почти) все смарт-карты доступными для аутентификации в моем приложении, но на данный момент мы хотим, чтобы работали только Izenpe и DNIe (испанская электронная идентификационная карта, поддерживаемая OpenSC).