我正在实现一个协议,该协议将TLS1.2
指定为传输层,并且需要客户端服务器身份验证,通过将连接的客户端套接字的主机名值与其证书中服务器指示的值进行比较,以验证服务器的主机名>类型subjectAltName
的扩展名。
我创建了一个测试,将该值放入服务器的证书中,客户端似乎完全忽略了它,但是我想确定一下。我是否必须在实现of dNSName
中对此检查进行编码,还是可以通过一些晦涩的属性将其启用? reference guide在此问题上保持沉默。
协议规范(我正在实现的规范)还提到通配符可以用作证书中值的前缀。
“ *”通配符可以用作最左边的名称
证书中的组件。例如,*。example.com将
匹配a.example.com,foo.example.com等,但不匹配
example.com。
但是,当我尝试使用X509ExtendedTrustManager.checkServerTrusted(X509Certificate[], String, Socket)
创建这样的扩展名时,它拒绝这样做。这是怎么回事?
“ C:\ Program Files \ Java \ jdk1.7.0_51 \ bin \ keytool.exe” -genkeypair-别名服务器-keyalg RSA -validity 365 -ext san = dns:*。example.com -keystore mykeystore
...
keytool错误:java.lang.RuntimeException:java.io.IOException:DNSName组件必须以字母开头
最佳答案
Java 7提供了一种自动验证SSLSocket
或SSLEngine
上的主机名的方法,但是不会自动启用它(Java 6中不存在)。该实现可以使用LDAP或HTTPS的命名规范,而不是更通用的RFC 6125(至少现在还没有)。在大多数情况下,对于其他协议,使用HTTPS规范的这一部分应该很好,当然总比没有好。
您可以如下使用它:
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
sslSocket.setSSLParameters(sslParams); // or SSLEngine
您可以找到以下参考:
在
SSLParameters.setEndpointIdentificationAlgorithm(...)
文档中,通过在JSSE Reference Guide中搜索“端点标识”,
在JSSE Ref Guide section on
X509ExtendedTrustManager
中(“ X509ExtendedTrustManager类还支持算法约束和SSL层主机名验证”),通过向下滚动到Standard Names section of the Java™ Cryptography Architecture.Standard Algorithm Name Documentation中的最后一个表
您遇到的第二个问题似乎是
keytool
的问题,无法生成这样的证书。这不会影响如何验证提供给Java客户端的此类证书。如有必要,您可以使用其他工具来生成带有通配符的证书。编辑:
请注意,要使其正常工作,您需要使用使用
SSLSocket
的方法创建String host
(以便它知道主机名),或者使用SSLEngine
创建SSLContext.createSSLEngine(String peerHost, int peerPort)
。这样便可以知道要在证书中尝试匹配的主机名。 (对于SNI,使用名称也很有用。)