PKCS#11 Smartcard getting error: javax.net.ssl.SSLHandshakeException due to java.security.InvalidKeyException: The RSA asymmetric cipher
PKCS#11 Smartcard getting error: javax.net.ssl.SSLHandshakeException due to java.security.InvalidKeyException: The RSA asymmetric cipher
情况
我正在做一个项目,我们必须让智能卡在 Linux 中工作。该卡由制造商 Izenpe 提供。每次与服务器进行 SSL 握手时,我都会收到 javax.net.ssl.SSLHandshakeException
。
我使用这些代码加载 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();
它加载证书以在 table 中显示,我可以继续从服务器的响应中获取 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 握手中获取卡中的 unextractable 私钥以签署质询时失败,因为 PKCS#11 私钥不是 supported/recognized 有效。
通过将这一行添加到我的代码中,我得到了很多行关于 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 .......f...@E.A.
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 JA.......JV@.2.S
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
,禁用选项jdk.tls.disabledAlgorithms=SSLv3, TLSv1.1
中的TLSv1.2
和SSLv3
,只留下TLSv1.1
因为这是服务器的选择,没有用。
我用来加载Provider的驱动来自Izenpe网站。从我在 Eclipse 的控制台中得到的信息来看,它正在工作。
我的想法:
可能是提供商 SunPKCS11
失败了。我这样说是因为当我们使用 SunMSCAPI
时,原始代码在 Windows 中有效。 SunMSCAPI
的一些内部机制为我们签署了挑战。但现在我们必须将项目调整为multi-platformed,在Linux中我们别无选择,只能SunPKCS11
。 Java 6 和 Java 8 的 JAR sunpkcs11.jar
都失败了。 (在 Java 7 中不存在。)
本意是让(几乎)所有的智能卡都可以在我的APP中进行身份验证,但目前只需要Izenpe和DNIe(西班牙电子身份证,OpenSC支持)工作。
虽然我不太精通 PKCS#11(当我想到它时也不精通 SSL),但根据您的描述和日志文件,以下项目引起了我的注意并让我思考:
考虑到上面抛出的 InvalidKeyException 和突出显示的算法(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),我倾向于认为密钥是椭圆曲线密钥,而不是 RSA(在屏幕截图中,它声明安全性由TLS_ECDHE 等于使用 2048 位的 RSA 得到的)。
因此,在此过程中的某个地方,以编程方式或格式错误的证书选择了错误的签名提供程序(RSA 而不是 ECDSA)。
希望对您有所帮助。
看起来像 Java JCE 的 SSL 连接,正在使用 Entrust Provider。
如果您查看堆栈跟踪:
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)
此错误是由 Entrust JCE 提供程序引发的。它可能只需要 Java 的 RSA 密钥,但正在向它发送一个它可能无法处理的 PKCS11 密钥。
因此,请尝试同时删除 'Entrust' 提供程序。
如果这不起作用,请尝试将 SunPKCS11 provider
实例传递给 SSLContext,无论您在哪里使用它来启动安全连接。
情况
我正在做一个项目,我们必须让智能卡在 Linux 中工作。该卡由制造商 Izenpe 提供。每次与服务器进行 SSL 握手时,我都会收到 javax.net.ssl.SSLHandshakeException
。
我使用这些代码加载 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();
它加载证书以在 table 中显示,我可以继续从服务器的响应中获取 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 握手中获取卡中的 unextractable 私钥以签署质询时失败,因为 PKCS#11 私钥不是 supported/recognized 有效。
通过将这一行添加到我的代码中,我得到了很多行关于 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 .......f...@E.A.
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 JA.......JV@.2.S
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
,禁用选项jdk.tls.disabledAlgorithms=SSLv3, TLSv1.1
中的TLSv1.2
和SSLv3
,只留下TLSv1.1
因为这是服务器的选择,没有用。我用来加载Provider的驱动来自Izenpe网站。从我在 Eclipse 的控制台中得到的信息来看,它正在工作。
我的想法:
可能是提供商
SunPKCS11
失败了。我这样说是因为当我们使用SunMSCAPI
时,原始代码在 Windows 中有效。SunMSCAPI
的一些内部机制为我们签署了挑战。但现在我们必须将项目调整为multi-platformed,在Linux中我们别无选择,只能SunPKCS11
。 Java 6 和 Java 8 的 JARsunpkcs11.jar
都失败了。 (在 Java 7 中不存在。)本意是让(几乎)所有的智能卡都可以在我的APP中进行身份验证,但目前只需要Izenpe和DNIe(西班牙电子身份证,OpenSC支持)工作。
虽然我不太精通 PKCS#11(当我想到它时也不精通 SSL),但根据您的描述和日志文件,以下项目引起了我的注意并让我思考:
考虑到上面抛出的 InvalidKeyException 和突出显示的算法(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),我倾向于认为密钥是椭圆曲线密钥,而不是 RSA(在屏幕截图中,它声明安全性由TLS_ECDHE 等于使用 2048 位的 RSA 得到的)。 因此,在此过程中的某个地方,以编程方式或格式错误的证书选择了错误的签名提供程序(RSA 而不是 ECDSA)。
希望对您有所帮助。
看起来像 Java JCE 的 SSL 连接,正在使用 Entrust Provider。
如果您查看堆栈跟踪:
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)
此错误是由 Entrust JCE 提供程序引发的。它可能只需要 Java 的 RSA 密钥,但正在向它发送一个它可能无法处理的 PKCS11 密钥。
因此,请尝试同时删除 'Entrust' 提供程序。
如果这不起作用,请尝试将 SunPKCS11 provider
实例传递给 SSLContext,无论您在哪里使用它来启动安全连接。