【问题标题】:Java SSL handshake failure - no client certificateJava SSL 握手失败 - 没有客户端证书
【发布时间】:2016-01-18 01:22:30
【问题描述】:

我正在使用带有内置 ssl 客户端的第三方库对 PKCS#7 签名执行 CRL 检查。

我创建了一个密钥库和一个信任库,并将服务器的 CA 放在我的信任库中。

查看下面的调试,证书颁发机构和证书链是空的。我的客户没有发回他的证书。

你能解释一下这是怎么回事吗?

编辑

感谢下面的cmets,我明白了客户端的“空CA”不是问题。

问题是服务器要求提供客户端证书,但我的客户端没有将其发送到服务器。

为什么客户不发送他的证书?

keyStore is : [...]
keyStore type is : jks
keyStore provider is : 
init keystore
init keymanager of type SunX509
***
found key for : [...]
chain [0] = [
...
]
***
trustStore is: [...]
trustStore type is : jks
trustStore provider is : 
init truststore
adding as trusted cert:
[...]

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
[...]
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(10000) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1445266954 bytes = { 44, 84, 229, 125, 84, 33, 145, 120, 170, 228, 77, 65, 146, 200, 227, 227, 48, 200, 116, 240, 140, 55, 227, 162, 119, 75, 116, 47 }
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_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, 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, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
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 server_name, server_name: [host_name: ...]
***
[write] MD5 and SHA1 hashes:  len = 176
[...]
main, WRITE: TLSv1 Handshake, length = 176
[Raw write]: length = 181
[...]
[Raw read]: length = 5
[...]
[Raw read]: length = 85
[...]
main, READ: TLSv1 Handshake, length = 85
*** ServerHello, TLSv1
RandomCookie:  GMT: 1929314415 bytes = { 133, 174, 213, 209, 239, 104, 185, 151, 182, 150, 87, 234, 171, 201, 244, 45, 171, 118, 159, 20, 148, 138, 19, 5, 1, 44, 188, 76 }
Session ID:  {144, 227, 198, 123, 46, 241, 49, 85, 156, 181, 102, 130, 42, 23, 39, 17, 11, 64, 23, 39, 166, 11, 119, 139, 12, 51, 60, 252, 170, 105, 23, 161}
Cipher Suite: SSL_RSA_WITH_3DES_EDE_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
Extension server_name, server_name: 
***
%% Initialized:  [Session-1, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
** SSL_RSA_WITH_3DES_EDE_CBC_SHA
[read] MD5 and SHA1 hashes:  len = 85
[...]
[Raw read]: length = 5
[...]
[Raw read]: length = 1024
[...]
main, READ: TLSv1 Handshake, length = 1024
*** Certificate chain
chain [0] = [
[
 [...]
]
  Algorithm: [SHA1withRSA]
  Signature:
[...]

]
***
Found trusted certificate:
[
[...]
]
[read] MD5 and SHA1 hashes:  len = 1024
[...]
[Raw read]: length = 5
[...]
[Raw read]: length = 8
[...]
main, READ: TLSv1 Handshake, length = 8
*** CertificateRequest
Cert Types: RSA
Cert Authorities:
<Empty>
[read] MD5 and SHA1 hashes:  len = 8
[...]
[Raw read]: length = 5
[...]
[Raw read]: length = 4
[...]
main, READ: TLSv1 Handshake, length = 4
*** ServerHelloDone
[read] MD5 and SHA1 hashes:  len = 4
[...]
*** Certificate chain
***
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
[write] MD5 and SHA1 hashes:  len = 269
[...]
main, WRITE: TLSv1 Handshake, length = 269
[Raw write]: length = 274
[...]
SESSION KEYGEN:
PreMaster Secret:
[...]
CONNECTION KEYGEN:
Client Nonce:
[...]
Server Nonce:
[...]
Master Secret:
[...]
Client MAC write Secret:
[...]
Server MAC write Secret:
[...]
Client write key:
[...]
Server write key:
[...]
Client write IV:
[...]
Server write IV:
[...]
main, WRITE: TLSv1 Change Cipher Spec, length = 1
[Raw write]: length = 6
[...]
*** Finished
verify_data:  { 212, 27, 4, 13, 87, 128, 70, 120, 43, 97, 111, 135 }
***
[write] MD5 and SHA1 hashes:  len = 16
[...]
Padded plaintext before ENCRYPTION:  len = 40
[...]
main, WRITE: TLSv1 Handshake, length = 40
[Raw write]: length = 45
[...]
[Raw read]: length = 5
[...]
[Raw read]: length = 2
[...]
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-1, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

【问题讨论】:

  • 我很惊讶做 CRL 检查的东西(在 PKCS#7 或其他任何东西上)正在建立任何 SSL/TLS 连接。 CRL fetch 和 OCSP 的最佳实践是使用纯 HTTP 或其他类似 LDAP 的东西,以避免无限循环。 数据(CRL 或 OCSP 正文)已签名,不需要进一步的完整性或通常的任何机密性。
  • Certificate chain 消息中ServerHelloDone 之后是否有任何内容(不确定您是否删除了某些行)。
  • 证书链为空。
  • 密钥库中证书的密钥类型是什么? (我假设您在顶部的缩写输出中确实存在一个密钥库,其中包含具有匹配私钥的证书)

标签: java ssl sslhandshakeexception


【解决方案1】:

证书颁发机构和证书链为空。

这意味着服务器信任库中没有受信任的 CA 证书。

我的客户没有扔回他的证书。

没有发回他的证书。抛出异常,而不是证书。不要滥用标准术语。除非服务器在 CertificateRequest 消息中表示他信任的 CA 之一信任他的证书,否则不允许他发送证书。

【讨论】:

  • 但是如果服务器不信任任何人,我仍然可以建立 SSL 连接吗?这是我的问题吗?
  • 我已经编辑了我的帖子以纠正我的术语错误。很抱歉。
  • 如果服务器不信任任何人,则没有人可以通过客户端证书进行身份验证。然而,您的服务器正在请求一个,并在没有得到一个时中止连接。您只需要决定是否需要客户端证书,如果需要,您将信任哪个颁发者。
  • Empty CAlist 不一定说明服务器信任库; tools.ietf.org/html/rfc5246#section-7.4.4 允许服务器发送一个空列表,客户端发送它想要的任何证书,并且在我使用默认 SunX509KeyManagerImpl 测试 JSSE 客户端时,它会发送它为任何请求的类型(算法)找到的第一个。我不知道任何只请求类型为 RSA 的堆栈,如此处所示,但如果我使用 OpenSSL
  • 如果服务器发送空的 CAlist,我使用的浏览器(IE、FF、Chrome)都会提示用户选择私钥(如果存在)。显然,如果用户或像 JSSE 这样的代码选择/猜测服务器不信任的证书,那就太糟糕了,所以如果服务器确实发送了它实际想要的 CAlist,那就更好了,但是不需要。
【解决方案2】:

我错过了客户端的证书必须由服务器通过证书签名请求 (CSR) 生成的事实。

过程是:

  1. 生成密钥对(通过 keytool -genkey)
  2. 生成 PKCS#10 CSR(通过 keytool -certreq)
  3. 将 CSR 发送给相关机构
  4. 取回 SSL 证书

感谢 cmets 帮助我提高了对 ssl 的理解。

【讨论】:

    【解决方案3】:

    客户端不发送任何证书意味着两件事: 1.服务器没有请求任何证书(所以没有CertificateRequest) 2. 服务器已请求证书,但您的密钥库没有请求证书。

    【讨论】:

      【解决方案4】:

      只是想为此投入 2 美分。我在控制台日志中看到了这个确切的错误。经过大量搜索和尝试,我终于弄清楚了错误是什么。我的密钥库的密码不正确。此错误从未显示在日志中,它只是默默地失败并导致大量 ssl 错误发生。

      【讨论】:

        猜你喜欢
        • 2018-05-15
        • 2019-02-28
        • 2016-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多