java.security.cert.CertificateException:找不到与IP地址x.x.x.x匹配的使用者替代名称

时间:2019-05-05 19:03:12

标签: java ssl

我有一个Java程序,试图从ip地址下载文件。假设IP地址为10.2.14.35。因此,该文件位于https://10.2.14.35/path/to/the/file/myfile.txt。我具有以下旨在下载该文件的功能:

for chunk in iter(lambda: input_stream.read(BUFFER_SIZE), b''):
    dostuff(chunk)

并将函数用作:

public static void downloadFile(String uri, String localFileName) { try { URL url = new URL(uri); ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream()); FileOutputStream fileOutputStream = new FileOutputStream(localFileName); fileOutputStream .getChannel() .transferFrom(readableByteChannel, 0 /* position */, Long.MAX_VALUE /* count */); fileOutputStream.close(); readableByteChannel.close(); } catch (IOException e) { throw new AgentException(ErrorProto.Type.kIOError, e.getMessage()); } }

我收到错误downloadFile(" https://10.2.14.35/path/to/the/file/myfile.txt", "/tmp/myfile.txt")。我发现有人在SO上提出了一些问题(JAVA - No subject alternative names matching IP addressSSLHandshakeException: No subject alternative names presentHow are SSL certificate server names resolved/Can I add alternative names using keytool?),但它们都没有起作用(或者也许我在某处做错了。)

我从浏览器尝试下载该文件,并下载了该文件。但是,这表明该站点不安全,因为证书无效。我不确定是否由于此原因无法通过Java程序下载文件。在阅读时,我遇到了cacerts的概念,我必须让JRE理解可以连接到10.2.14.35。为此,我需要创建证书并将其导入cacerts。我这样做了,但是没用,因为也许我错过了一些东西。有人可以帮我指出错误吗?

2 个答案:

答案 0 :(得分:1)

TLDR

您看到的错误与名为Subject Alternative Name的特定证书扩展有关,而没有将10.2.14.35指定为有效的IP地址。

该错误还表明证书CA已受信任。如果不信任CA,则证书验证可能会更早失败并给出另一个错误,例如

  

PKIX路径构建失败:   sun.security.provider.certpath.SunCertPathBuilderException:无法执行   找到到所请求目标的有效认证路径


由于我无权访问您的特定证书,因此我将尝试使用example.com的服务器证书进行说明。

要查看证书,我将使用openssl,但还有其他多种工具可用-例如,大多数浏览器都可以显示证书详细信息。

我将删除不需要的输出来说明我想要的

$ openssl s_client -connect example.com:443 -showcerts | openssl x509 -noout -text
[...]
Subject: C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, OU = Technology, CN = www.example.org
[...]
    X509v3 Subject Alternative Name: 
       DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net

Subject字段包含不同类型的信息,但是CN(通用名称)值为www.example.com。以前,大多数或所有浏览器都使用此命令来验证是否为与浏览器连接的服务器颁发了证书。但是,最近(Chrome浏览器(我认为是Firefox))完全忽略了Subject字段中的信息,而完全忽略了relies on the Subject Alternative Name

  

对于Chrome 58及更高版本,仅subjectAlternativeName扩展名,   不是commonName,用于匹配域名和站点证书。   证书使用者备用名称可以是域名或IP   地址。如果证书不正确   subjectAlternativeName扩展名,用户获得一个   NET :: ERR_CERT_COMMON_NAME_INVALID错误,让他们知道   连接不是私人的。

因此,您的错误源于10.2.14.35所提供的服务器证书不包含您要连接的IP地址的事实。使用openssl查看证书,服务器提供的证书必须至少具有Subject Alternative Name,并且必须至少包含IP Address:10.2.14.35。一个构造的最小示例看起来像这样。

$ openssl s_client -connect 10.2.14.35:443 -showcerts | openssl x509 -noout -text
[...]
Subject: CN = 10.2.14.35
[...]
    X509v3 Subject Alternative Name: 
        IP Address:10.2.14.35

答案 1 :(得分:0)

  

但是,这表明该站点不安全,因为证书无效。我不确定是不是因为这个原因而无法通过Java程序下载文件。

虽然您未提供浏览器的详细错误消息,但可能由于Java表示证书无效的相同原因而抱怨,例如,由于IP地址未包含在证书的主题备用名称扩展名中(必须以IP地址而不是DNS的形式给出)。唯一的不同是,您可以单击使浏览器忽略此错误,而您需要调整程序以忽略该错误。