MQTT:javax.net.ssl.SSLHandshakeException:证书上没有匹配的subjectAltNames

jqjz2hbq  于 5个月前  发布在  Java
关注(0)|答案(3)|浏览(180)

我正在尝试通过paho客户端连接服务器(我使用的版本是org.eclipse.paho.client.mqttv3-1.2.1.jar
当我尝试连接时,我得到:
“MQTT:javax.net.ssl.SSLHandshakeException:证书上没有匹配的subjectAltNames”
但我在org.eclipse.paho.client.mqttv3-1.2.0.jar中没有得到这个问题
下面是蚊子的日志
“sslv3警报证书未知”

ldioqlga

ldioqlga1#

虽然这不是一个好的做法,但如果你信任你的代理,不想验证它的身份,你可以建立一个假的信任管理器,如下所示,它什么也不验证(在客户端没有ca证书使用),客户端连接到代理没有任何例外(尽管通信保持加密)。

private fun fakeSocketFactory() : SocketFactory {
    val trustManager = object: X509TrustManager {
        override fun checkClientTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) {}
        override fun checkServerTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) {}
        override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf()
    }
    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, arrayOf(trustManager), SecureRandom())
    return sslContext.socketFactory
}

override fun connect() {
    val options = MqttConnectOptions()
        ...
    options.socketFactory = fakeSocketFactory()
    client.connect(options,null,object:IMqttActionListener{
        ...
    })
}

字符串
这类似于Chrome的警告“您的连接不是私有的。“和我们的操作“继续(不安全)"。

41ik7eoe

41ik7eoe2#

这个错误与Paho或MQTT无关。
这意味着代理提供的证书与用于连接它的主机名不匹配。
您需要为代理获取一个新证书,该证书与用于连接到代理的所有主机名相匹配,或者确保您使用的主机名包含在证书的SAN部分中。

bis0qfac

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并重新添加注解部分:

/**
   * 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;
  }

字符串

相关问题