关于SSLServerSocket.setWantClientAuth :
如果设置为true
,如果客户选择不发送谈判继续证书。
我也注意到,如果客户端发送一个证书,但不是truststore.The谈判在这种情况下没有任何失败的一部分,这也正好。
那么,什么是该设置的使用情况?
关于SSLServerSocket.setWantClientAuth :
如果设置为true
,如果客户选择不发送谈判继续证书。
我也注意到,如果客户端发送一个证书,但不是truststore.The谈判在这种情况下没有任何失败的一部分,这也正好。
那么,什么是该设置的使用情况?
(多编辑,下面的一些评论。)
setWantClientAuth
用于请求客户端证书验证,但保持连接,如果没有提供认证。 setNeedClientAuth
用于请求并要求客户证书验证:如果没有合适的客户端证书被呈现在连接将被终止。
你可以找到更多关于这个主题的TLS规范的客户端证书部分 。 对于一些历史:
在1.2版本中,它说:“ 如果没有合适的证书是可用的,客户端必须发送包含没有证书的证书信息。” 在此之前,这只是一个“应该”,但孙JSSE客户要送出一个空列表这种情况。
1.2版还增加了:
此外,如果证书链的某些方面是不可接受的(例如,它不是由一个已知的签署,信任的CA),服务器可自行决定是继续握手(考虑客户未认证)或发送致命警报。
这使得关于何时发送一个不可接受的证书做一定的灵活性。 该JSSE选择发送致命警报。 ( setWantAuth
原则上可以进行与无效的证书,但不能治疗同伴的身份验证,因为如果没有客户端证书发送,但事实并非如此。)
在TLS规范的早期版本说,“ 如果服务器要求客户端身份验证的握手继续,它可能会致命的握手失败响应警报。” 这是需要或希望作为JSSE实现之间的区别:使用“需要”,该服务器具有致命的握手失败响应,而使用“希望”,服务器的连接进行,但不把它当作认证。
我最初不过,当你使用“需要”您的客户端未发送其证书。 事实上,大多数客户不会发送客户端证书在所有的,如果他们无法找到由在CA名称中列出的发行人之一发布了其请求期间由服务器发送(或客户端证书,如果客户端不能建链本身,这是一个常见的问题 )。 默认情况下,JSSE使用CA的信任库构建列表。 出于这个原因,你的客户可能不会如果有合适的发行人是不是在服务器的信任发送客户端证书都没有。
您可以检查客户端证书是否使用Wireshark的发送。 如果你不能正常使用SSL使用的端口上运行/ TLS,你需要右键点击一个包,然后选择“解码为... - >交通运输 - > SSL”。
在那里,你会看到一个Certificate Request
来自服务器的消息。 (出于某种原因,当我使用默认的JRE信任与Wireshark的,看来,消息为“加密握手消息”,只是“服务器密钥交换”消息后,但是,它不加密的:你可以清楚地看到了一些CA的名字,如果你看一下在底部面板包的ASCII渲染。也许这是因为这个消息是太长了,我不知道。)用更短的列表,例如,信托商店与单一CA ,Wireshark的您正确解码此作为Certificate Request
消息,您应该看到“专有名称”一节中公认的CA列表。
你也应该看到Certificate
消息从客户端(而不是一个来自服务器,当然)到来。 如果服务器请求(与希望或需要)的证书,你应该总是看到从客户此消息呢。
假设你有机会获得测试CA(与由CA颁发的客户端证书),你可以试试下面的实验。
如果您设置的信任存储与测试CA证书,使用setWantClientAuth(true)
,客户端将发送其客户端证书,并且连接将继续进行。 然后,服务器可以从获取客户端证书SSLSession
,符合市场预期。
如果使用默认的信任存储区(不包含测试CA证书),使用setWantClientAuth(true)
,则CA DN将不会在Certificate Request
。 客户端会发送一个Certificate
信息,但证书列表是空的( Certificates Length: 0
在Wireshark的)。 在这里,客户端实际上没有发送客户端证书,即使其密钥库配置这样做,只是因为它无法找到合适的匹配。 该连接将继续(如果你尝试读取从对等证书可能会得到一个异常SSLSession
在服务器上,但是这不是致命的)。 这是用例为setWantClientAuth(true)
; setNeedClientAuth(true)
会立即终止连接。
对于这个实验的目的,你可以通过假Java中的服务器发送的DN的列表。
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);
在这种情况下, Certificate Request
由服务器发送的消息应该包含您的测试CA的DN。 但是,CA实际上并不信任管理器,它仍然使用默认值信赖。
客户端将发送其证书,但服务器将拒绝它,说:“javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径验证失败”,这将结束连接。 这是至少使用SunJSSE提供商的执行情况,使用PKIX或SunX509信任管理器。 这也符合一贯的信任管理器的JSSE规格 :“ 在的TrustManager的主要职责是确定提交认证证书是否应该信任如果证书不被信任,连接将被终止。”
这里的关键是,如果你在一个位置,您可以通过客户端证书是SSLSession
,该证书应该由信托管理者认证(通过我的意思了SSLSession
你得到一次握手已经完成, SSLSocket.getSession()
你不使用握手过程中得到一个getHandshakeSession()
在Java 7中引入)。
你似乎在你使用其他JSSE供应商,您的客户端是无论如何发送客户端证书,CA证书是否是在服务器的信任存储的话来表明,因为你也有另一种不同的CA证书在您的信任具有相同主题DN存储。 假设这两个CA证书具有不同的密钥(否则他们将有效地同CA),这将是一个相当严重的错误:使用客户端证书身份验证有权期望的客户端证书已被信任管理器验证的应用程序(作为JSSE参考指南中规定)。 如果你使用Apache Tomcat,一旦获得客户端证书,远程连接被认为与此证书进行认证。 如果在这一点上的servlet能够使用不能被验证的客户端证书,没有认证实际上已经做出,这将是一个严重的缺陷。
它被用来当你想知道客户端凭证,如果他送他们,但你不想停止沟通,如果他没有。 与“needClientAuth”在那里,如果他不给他们握手失败对比。