当前位置: 代码迷 >> 综合 >> httpClient,Certificate for ip/域名 doesn't match any of the subject altinative names: []问题处理
  详细解决方案

httpClient,Certificate for ip/域名 doesn't match any of the subject altinative names: []问题处理

热度:53   发布时间:2023-12-13 19:22:55.0

在做https双向认证通信类开发的时候,遇到一个问题,错误信息是:javax.net.ssl.SSLPeerUnverifiedException: Certificate for <我请求的IP地址> doesn't match any of the subject alternative names: []

遇到这种情况,先查看你安装的Certificate证书的subject alternative name(SAN)是否有设置,设置的记录是否包含你请求的IP/域名,如果没有设置即报此错误。(关于SAN的科普建议百度)

百度的证书举例:

一个证书保护N多个域名,而我所请求的服务器的证书没有设置SAN,所以在做https请求时,走到SSLSocketConnectionFactory的connectSocketFactory时,verifyHostname抛异常,见代码。

SSLSocketConnectionFactory:

    @Overridepublic Socket connectSocket(final int connectTimeout,final Socket socket,final HttpHost host,final InetSocketAddress remoteAddress,final InetSocketAddress localAddress,final HttpContext context) throws IOException {Args.notNull(host, "HTTP host");Args.notNull(remoteAddress, "Remote address");final Socket sock = socket != null ? socket : createSocket(context);if (localAddress != null) {sock.bind(localAddress);}try {if (connectTimeout > 0 && sock.getSoTimeout() == 0) {sock.setSoTimeout(connectTimeout);}if (this.log.isDebugEnabled()) {this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);}sock.connect(remoteAddress, connectTimeout);} catch (final IOException ex) {try {sock.close();} catch (final IOException ignore) {}throw ex;}// Setup SSL layering if necessaryif (sock instanceof SSLSocket) {final SSLSocket sslsock = (SSLSocket) sock;this.log.debug("Starting handshake");sslsock.startHandshake();verifyHostname(sslsock, host.getHostName());return sock;} else {return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);}}

verifyHostname实现细节截取:

  final Certificate[] certs = session.getPeerCertificates();final X509Certificate x509 = (X509Certificate) certs[0];final X500Principal peer = x509.getSubjectX500Principal();this.log.debug(" peer principal: " + peer.toString());final Collection<List<?>> altNames1 = x509.getSubjectAlternativeNames();if (altNames1 != null) {final List<String> altNames = new ArrayList<String>();for (final List<?> aC : altNames1) {if (!aC.isEmpty()) {altNames.add((String) aC.get(1));}}this.log.debug(" peer alternative names: " + altNames);}

后面会将从证书里获取到的altNames和所请求的host做比对,如果没有和host所匹配的,则抛如题的异常了。

            if (!this.hostnameVerifier.verify(hostname, session)) {final Certificate[] certs = session.getPeerCertificates();final X509Certificate x509 = (X509Certificate) certs[0];final List<SubjectName> subjectAlts = DefaultHostnameVerifier.getSubjectAltNames(x509);throw new SSLPeerUnverifiedException("Certificate for <" + hostname + "> doesn't match any " +"of the subject alternative names: " + subjectAlts);}

解决办法

1. 修改请求的域名/ip,使证书可以覆盖到。

2. 设置证书的SAN,覆盖到请求的域名/ip。

3. 从代码上关闭https请求的主机认证,代码:

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,NoopHostnameVerifier.INSTANCE);//暂时关闭hostnameVerify
//                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

 

问题解决。

  相关解决方案