我正在使用SSLEngine
与NIO
进行非阻止TLS通信。
引擎运行正常,可以验证CA信任,即服务器证书的有效期。
但我缺少的是验证证书主题名称与我正在连接的服务器名称相匹配。
考虑所有SSL扩展程序(如subject alternative names等),实施它的最佳方法是什么?
我只是尝试检查主题名称,但即使使用google.nl
它也不起作用,证书中的主题为google.com
,而google.nl
只能在{{1}}中找到替代名称扩展。
答案 0 :(得分:0)
再次回答我自己的问题......
到目前为止,我能够接受这个。它仅限于Sun JSSE实现。不确定这是否是一个完整的解决方案。
void checkServerName(String serverName, SSLSession session) throws IOException {
String name;
boolean matches = false;
X509CertImpl cert = (X509CertImpl)session.getPeerCertificates()[0];
SubjectAlternativeNameExtension altNames = cert.getSubjectAlternativeNameExtension();
if (altNames != null) {
GeneralNames names = (GeneralNames) altNames.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
for (GeneralName genName : names.names()) {
switch (genName.getType()) {
case GeneralNameInterface.NAME_DNS:
name = ((DNSName)genName.getName()).getName();
break;
case GeneralNameInterface.NAME_IP:
name = ((IPAddressName)genName.getName()).getName();
break;
case GeneralNameInterface.NAME_RFC822:
name = ((RFC822Name)genName.getName()).getName();
break;
case GeneralNameInterface.NAME_ANY:
DerValue derValue = new DerValue(((OtherName)genName.getName()).getNameValue());
name = derValue.getData().getUTF8String();
break;
default:
continue;
}
if (name.startsWith("*"))
matches |= serverName.endsWith(name.substring(1).toLowerCase());
else
matches |= serverName.equals(name.toLowerCase());
if (matches)
break;
}
}
name = ((X500Name)cert.getSubjectDN()).getCommonName();
if (!matches)
matches = serverName.equals(name.toLowerCase());
if (!matches)
throw new SSLPeerUnverifiedException("server name mismatch, certificate issued to: " + name);
}