我花了一些时间在这个问题上我的项目,所以即使它是一个老问题,我会添加一些信息,也许它可以帮助别人。 我也有同样的问题;我的证书(没有SAN属性)在mosquito客户端上工作得很好,在我的android应用程序上使用org.eclipse.paho.client.mqttv3-1.2.0.jar,但在这个库的新版本上就不行了。 我理解了为什么它可以和1.2.0一起工作:这个版本有一个问题,主机名没有经过验证(参见CVE-2019-11777。 在1.2.1或更高版本中,主机名经过了很好的验证,因此您将遇到MQTT: javax.net.ssl.SSLHandshakeException: No subjectAltNames on the certificate match问题。 我不知道为什么,但在Android中,主机名只使用SAN属性进行验证,而不是CN。这是okhttp OkHostnameVerifier.java中的自定义Android更改。(编辑:使用CN进行主机名验证已被弃用,请参阅@hardillb注解。这就是Android不再使用它的原因。) 对我来说,有两个解决方案: 1.始终添加一个SAN属性,匹配证书中的CN(最佳解决方案) 1.如果你真的需要一个没有SAN属性的证书:使用自定义的主机名验证器(使用MqttConnectOptions#setSSLHostnameVerifier方法)你可以使用OkHostnameVerifier.java并重新添加注解部分:
/**
* Returns true if {@code certificate} matches {@code hostName}.
*/
private boolean verifyHostName(String hostName, X509Certificate certificate) {
hostName = hostName.toLowerCase(Locale.US);
boolean hasDns = false;
List<String> altNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
for (int i = 0, size = altNames.size(); i < size; i++) {
hasDns = true;
if (verifyHostName(hostName, altNames.get(i))) {
return true;
}
}
// BEGIN Android-removed: Ignore common name in hostname verification. http://b/70278814
if (!hasDns) {
X500Principal principal = certificate.getSubjectX500Principal();
// RFC 2818 advises using the most specific name for matching.
String cn = new DistinguishedNameParser(principal).findMostSpecific("cn");
if (cn != null) {
return verifyHostName(hostName, cn);
}
}
// END Android-removed: Ignore common name in hostname verification. http://b/70278814
return false;
}
3条答案
按热度按时间ldioqlga1#
虽然这不是一个好的做法,但如果你信任你的代理,不想验证它的身份,你可以建立一个假的信任管理器,如下所示,它什么也不验证(在客户端没有ca证书使用),客户端连接到代理没有任何例外(尽管通信保持加密)。
字符串
这类似于Chrome的警告“您的连接不是私有的。“和我们的操作“继续(不安全)"。
41ik7eoe2#
这个错误与Paho或MQTT无关。
这意味着代理提供的证书与用于连接它的主机名不匹配。
您需要为代理获取一个新证书,该证书与用于连接到代理的所有主机名相匹配,或者确保您使用的主机名包含在证书的SAN部分中。
bis0qfac3#
我花了一些时间在这个问题上我的项目,所以即使它是一个老问题,我会添加一些信息,也许它可以帮助别人。
我也有同样的问题;我的证书(没有
SAN
属性)在mosquito客户端上工作得很好,在我的android应用程序上使用org.eclipse.paho.client.mqttv3-1.2.0.jar
,但在这个库的新版本上就不行了。我理解了为什么它可以和
1.2.0
一起工作:这个版本有一个问题,主机名没有经过验证(参见CVE-2019-11777。在
1.2.1
或更高版本中,主机名经过了很好的验证,因此您将遇到MQTT: javax.net.ssl.SSLHandshakeException: No subjectAltNames on the certificate match
问题。我不知道为什么,但在Android中,主机名只使用
SAN
属性进行验证,而不是CN
。这是okhttp OkHostnameVerifier.java中的自定义Android更改。(编辑:使用CN
进行主机名验证已被弃用,请参阅@hardillb注解。这就是Android不再使用它的原因。)对我来说,有两个解决方案:
1.始终添加一个
SAN
属性,匹配证书中的CN
(最佳解决方案)1.如果你真的需要一个没有
SAN
属性的证书:使用自定义的主机名验证器(使用MqttConnectOptions#setSSLHostnameVerifier方法)你可以使用OkHostnameVerifier.java并重新添加注解部分:字符串