Java SSL服务器套接字需要身份验证选项
关于:Java SSL服务器套接字需要身份验证选项,java,security,sockets,ssl,jsse,Java,Security,Sockets,Ssl,Jsse,关于: 如果设置为true如果客户端选择不发送证书,协商将继续。 我还注意到,如果客户机发送一个证书,但不是信任库的一部分,也会发生这种情况。在这种情况下,协商也不会失败 那么这个设置的用例是什么呢?(多个编辑,后面有许多注释。) setWantClientAuth用于请求客户端证书身份验证,但如果未提供身份验证,则保持连接setNeedClientAuth用于请求和要求客户端证书身份验证:如果没有提供合适的客户端证书,连接将终止 您可以在中找到有关此主题的更多信息。回顾一下历史: 在版本1.
如果设置为
true
如果客户端选择不发送证书,协商将继续。我还注意到,如果客户机发送一个证书,但不是信任库的一部分,也会发生这种情况。在这种情况下,协商也不会失败 那么这个设置的用例是什么呢?(多个编辑,后面有许多注释。)
setWantClientAuth
用于请求客户端证书身份验证,但如果未提供身份验证,则保持连接setNeedClientAuth
用于请求和要求客户端证书身份验证:如果没有提供合适的客户端证书,连接将终止
您可以在中找到有关此主题的更多信息。回顾一下历史:
- 在版本1.2中,它说“如果没有合适的证书可用,客户端必须发送不包含证书的证书消息。”。在此之前,它只是一个“应该”,但Sun JSSE客户端无论如何都会发送一个空列表
- 版本1.2还添加了:
此外,如果证书链的某些方面不可接受(例如。,
它没有由已知的、受信任的CA签名),服务器可能会在
决定是否继续握手(考虑客户)
未经验证)或发送致命警报
这在发送不可接受的证书时提供了一些灵活性。JSSE选择发送致命警报。(
原则上可以处理无效证书,但不能将对等方视为已验证,就好像没有发送客户端证书一样,但事实并非如此。) TLS规范的早期版本说,“如果服务器需要客户端身份验证才能继续握手,它可能会发出致命的握手失败警报。”。这就是JSSE中实现的“需要”和“想要”之间的区别:使用“需要”,服务器会以致命的握手失败来响应,而使用“想要”,服务器会继续连接,但不会将其视为已验证setWantAuth
证书请求
消息。(出于某种原因,当我使用Wireshark的默认JRE信任库时,该消息显示为“加密握手消息”,就在“服务器密钥交换”之后)消息。但是,它不是加密的:如果查看底部面板中数据包的ASCII呈现,您可以清楚地看到许多CA名称。这可能是因为此消息太长,我不确定。)使用较短的列表,例如,具有单个CA的信任存储,Wireshark将其正确解码为证书请求
消息,您应该在“可分辨名称”部分中看到已接受CA的列表
您还应该看到来自客户机的证书
消息(当然不是来自服务器的消息)。如果服务器请求(想要或需要)证书,您应该始终从客户端看到此消息
假设您有权访问测试CA(使用该CA颁发的客户端证书),您可以尝试以下实验
- 如果使用该测试CA证书设置信任存储,请使用
,客户端将发送其客户端证书,连接将继续。然后,服务器可以按预期从setWantClientAuth(true)
获取客户端证书SSLSession
- 如果使用默认信任存储(不包含测试CA证书),请使用
,CA DN将不在setWantClientAuth(true)
证书请求中。客户端将发送一条
消息,但证书列表将为空(Certificate
在Wireshark中)。在这里,客户机实际上没有发送客户机证书,即使其密钥库被配置为发送客户机证书,这仅仅是因为它找不到合适的匹配项。连接将继续(如果尝试从服务器上的Certificates Length:0
读取对等证书,可能会出现异常,但这不是致命的)。这是SSLSession
的用例setWantClientAuth(true)
会立即结束连接setNeedClientAuth(true)
- 为了进行此实验,可以用Java伪造服务器发送的DNs列表
在这种情况下,服务器发送的KeyManagerFactory kmf = //... Initialise a KMF with your server's keystore TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore) null); // Use the default trust store TrustManager[] trustManagers = tmf.getTrustManagers(); final X509TrustManager origTrustManager = (X509TrustManager) trustManagers[0]; final X509Certificate caCert = // Load your test CA certificate here. X509TrustManager fakeTrustManager = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // Key the behaviour of the default trust manager. origTrustManager.checkClientTrusted(chain, authType); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // Key the behaviour of the default trust manager. origTrustManager.checkServerTrusted(chain, authType); } public X509Certificate[] getAcceptedIssuers() { // This is only used for sending the list of acceptable CA DNs. return new X509Certificate[] { caCert }; } }; trustManagers = new X509TrustManager[] { fakeTrustManager }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), trustManagers, null);
消息应该包含测试CA的DN。但是,信任管理器实际上并不信任该CA,它仍然使用默认值 客户端将发送其证书,但服务器将拒绝它,并说“javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径验证失败”,这将结束连接。这至少是使用SunJSSE提供程序、使用PKIX或SunX509信任管理器的实现。这也与“TrustManager的主要职责是确定所提供的身份验证凭据是否应被信任证书请求