繁体   English   中英

Java SSLServerSocket:请求客户端证书允许任何客户端证书

[英]Java SSLServerSocket: Request client certificate allowing ANY client certificate

我跟随这些线程和其他类似的例子:

我已经为客户端和服务器使用任何本地生成的自签名证书实现了一个客户端/服务器简单的 Java 程序。 顺便说一句,我看到他们协商 TLS 1.3 而不是 1.2。 那挺好的。

但我看到他们只使用服务器证书(客户端配置为接受任何,好的)。 我希望他们也要求客户端进行身份验证。 并允许客户端证书是任何自签名的,而不是由任何 CA 签名的 所以我尝试服务器使用sslServerSocket.setNeedClientAuth(true)或访问客户端证书信息。 然后我得到这样的错误:

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at java.base/sun.security.ssl.SSLSessionImpl.getPeerPrincipal(SSLSessionImpl.java:1122)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)

所以我一直在使用这些工具来测试我的实现的双方:

  • ncat --ssl
  • ncat --ssl --listen
  • openssl s_client
  • openssl s_server

我的结论是我的客户端运行良好,需要时在其他服务器上进行身份验证。 但是我的服务器需要向客户端提供基本 CA(我不想要这个),或者只接受没有客户端身份验证的任何客户端(这就是我现在拥有的,这不是我的目标)。

我希望我的服务器需要客户端证书并接受任何证书。 我怎样才能做到这一点? 谢谢!

动机:我想使用 Java 而不是 Go 来实现一些Syncthing有据可查的特性。 他们在连接的两端使用自定义证书身份验证。

所以现在它正在工作。

首先,我只在客户端强制握手。 似乎没问题,但在服务器端添加它会产生更好的错误消息。

所以我在接受连接后在服务器端添加了最后一行(Groovy 代码):

ss.setNeedClientAuth(true)
SSLSocket socket = ss.accept() as SSLSocket
socket.startHandshake()

然后,当客户到达时,我得到了一个更指示性的错误:

Exception in thread "main" javax.net.ssl.SSLException: Cannot read the array length because "caCerts" is null
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
at java.base/sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1702)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:465)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:421)
at javax.net.ssl.SSLSocket$startHandshake.call(Unknown Source)

所以过了一会儿,我在接受来自任何证书的连接的代码中发现了一些可疑的东西:

def x509TrustAllCerts = new X509TrustManager() {
        X509Certificate[] getAcceptedIssuers() {
            return null // <--- SUSPICIOUS!!
        }
        void checkClientTrusted(X509Certificate[] certs, String authType) { }
        void checkServerTrusted(X509Certificate[] certs, String authType) { }
    }
TrustManager[] trustAllCerts = new TrustManager[] { x509TrustAllCerts }

所以我做了最简单的修复,将null更改为空数组:

def x509TrustAllCerts = new X509TrustManager() {
        X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0] // <-- FIX
        }
        void checkClientTrusted(X509Certificate[] certs, String authType) { }
        void checkServerTrusted(X509Certificate[] certs, String authType) { }
    }
TrustManager[] trustAllCerts = new TrustManager[] { x509TrustAllCerts }

现在它正在按照我的预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM