[英]How to set mutual authentication using SSL in Java SE
我是第一次在Java中使用SSL,试图创建一个echo服务器。 当只有服务器需要进行身份验证时,我设法让它工作(在设置属性指向适当的KeyStore和TrustStore之后):
服务器端:
SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(bancoPort);
String [] supported = serverSocketFactory.getSupportedCipherSuites();
serverSocket.setEnabledCipherSuites(supported);
serverSocket.setEnabledProtocols(new String[]{"TLSv1"});
SSLSocket s = (SSLSocket) serverSocket.accept();
客户端:
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket bancoSocket = (SSLSocket) socketFactory.createSocket(bancoIP, bancoPort);
String[] suites = bancoSocket.getSupportedCipherSuites();
bancoSocket.setEnabledCipherSuites(suites);
由于调试模式,我知道用于身份验证的密码套件是TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
main, READ: TLSv1 Handshake, length = 215
*** ClientHello, TLSv1
RandomCookie: GMT: 1399451465 bytes = { 177, 86, 70, 228, 7, 0, 109, 56, 245, 8, 243, 18, 122, 186, 159, 138, 76, 99, 65, 224, 21, 100, 1, 90, 20, 109, 241, 216 }
Session ID: {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_ECDH_anon_WITH_RC4_128_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_anon_WITH_NULL_SHA, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
%% Initialized: [Session-1, SSL_NULL_WITH_NULL_NULL]
%% Negotiating: [Session-1, TLS_ECDH_anon_WITH_AES_128_CBC_SHA]
*** ServerHello, TLSv1
RandomCookie: GMT: 1399451466 bytes = { 252, 63, 206, 222, 115, 40, 143, 4, 55, 11, 88, 196, 5, 10, 114, 159, 76, 144, 181, 27, 73, 248, 196, 71, 169, 136, 228, 82 }
Session ID: {83, 106, 239, 74, 65, 85, 23, 110, 97, 151, 196, 61, 224, 79, 140, 15, 11, 132, 208, 66, 112, 216, 122, 85, 27, 159, 194, 255, 104, 171, 81, 220}
Cipher Suite: TLS_ECDH_anon_WITH_AES_128_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
Cipher suite: TLS_ECDH_anon_WITH_AES_128_CBC_SHA
如果我添加到服务器代码行
serverSocket.setNeedClientAuth(true);
一切都崩溃了。 然后使用的套件是TLS_KRB5_WITH_RC4_128_MD5,但是客户端显然没有准备好使用Kerberos,因为这是在发送第一条要回显的消息时在客户端弹出的错误:
may 08, 2014 3:31:30 AM echoclient.EchoClientSSL main
Grave: null
java.io.IOException: Invalid service principal name: host/desk-linux
at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.getServiceTicket(KerberosClientKeyExchangeImpl.java:307)
at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.init(KerberosClientKeyExchangeImpl.java:112)
at sun.security.ssl.KerberosClientKeyExchange.init(KerberosClientKeyExchange.java:122)
at sun.security.ssl.KerberosClientKeyExchange.<init>(KerberosClientKeyExchange.java:80)
at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:873)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:285)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
at java.io.DataOutputStream.write(DataOutputStream.java:107)
at java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
at java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
at echoclient.EchoClientSSL.main(EchoClientSSL.java:45)
Caused by: KrbException: Cannot locate default realm
at sun.security.krb5.PrincipalName.<init>(PrincipalName.java:367)
at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.getServiceTicket(KerberosClientKeyExchangeImpl.java:302)
... 15 more
Caused by: KrbException: Cannot locate default realm
at sun.security.krb5.Config.getDefaultRealm(Config.java:1181)
at sun.security.krb5.PrincipalName.<init>(PrincipalName.java:365)
... 16 more
Caused by: KrbException: Generic error (description in e-text) (60) - Unable to locate Kerberos realm
at sun.security.krb5.Config.getRealmFromDNS(Config.java:1277)
at sun.security.krb5.Config.getDefaultRealm(Config.java:1162)
... 17 more
我试图在客户端中将setEnabledCipherSuite设置为我认识的工作(TLS_ECDH_anon_WITH_AES_128_CBC_SHA),而不是整个允许的密码套件,但如果我这样做,我在服务器上获得异常“javax.net.ssl.SSLHandshakeException:no cipher共同的套房“。 日志:
main, READ: TLSv1 Handshake, length = 114
*** ClientHello, TLSv1
RandomCookie: GMT: 1399451199 bytes = { 43, 248, 163, 155, 250, 241, 124, 194, 33, 46, 197, 27, 122, 1, 148, 254, 255, 71, 219, 220, 213, 91, 180, 178, 126, 242, 166, 82 }
Session ID: {}
Cipher Suites: [TLS_ECDH_anon_WITH_AES_128_CBC_SHA]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Initialized: [Session-1, SSL_NULL_WITH_NULL_NULL]
%% Invalidated: [Session-1, SSL_NULL_WITH_NULL_NULL]
main, SEND TLSv1 ALERT: fatal, description = handshake_failure
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common
may 08, 2014 3:38:56 AM echoserver.EchoServerSSL main
Grave: null
javax.net.ssl.SSLHandshakeException: no cipher suites in common
服务器和客户端都在同一台机器上运行,因此我不知道在尝试验证客户端时,用于验证服务器的密码套件是如何失败的。
String [] supported = serverSocketFactory.getSupportedCipherSuites();
serverSocket.setEnabledCipherSuites(supported);
和
String[] suites = bancoSocket.getSupportedCipherSuites();
bancoSocket.setEnabledCipherSuites(suites);
不要乱用启用的密码套件。 取出代码并重新测试。 您已经启用了匿名套件,在这两个套件中,任何方向都没有任何身份验证。
Cipher Suites: [TLS_ECDH_anon_WITH_AES_128_CBC_SHA]
正如@EJP所说,这些线路适得其反,需要将其删除。 问题不在于代码,而在于如何创建密钥库和信任库中的证书。
一旦我按照这里的说明一切正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.