Java Paho TLS验证: No subject alternative names present

介绍

在使用Java Paho库进行TLS验证时,有时会遇到"No subject alternative names present"的错误。这个错误通常是由于服务器的TLS证书中没有包含主机的Subject Alternative Names字段所引起的。本文将介绍如何解决这个问题,并提供代码示例。

什么是Subject Alternative Names?

Subject Alternative Names(SAN)是TLS证书中的一个扩展字段,用于指定证书的有效主体名称。该字段允许证书同时适用于多个主机,而不仅仅是一个。

为什么会出现"No subject alternative names present"错误?

当使用Java Paho库进行TLS验证时,它会检查服务器的TLS证书中的Subject Alternative Names字段是否包含与主机匹配的名称。如果服务器的TLS证书没有包含这个字段,Java Paho库就会报错"No subject alternative names present"。

解决方案

要解决"No subject alternative names present"错误,有两种方法:

方法一:在服务器的TLS证书中添加Subject Alternative Names字段

这是最常用的解决方法。可以使用openssl命令生成一个新的TLS证书,并在生成证书时添加Subject Alternative Names字段。以下是一个示例openssl命令:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj '/CN=example.com' -addext 'subjectAltName=DNS:example.com,DNS:www.example.com'

上述命令将生成一个新的TLS证书,其中包含了两个主机名:example.com和www.example.com。

方法二:禁用主机名验证

如果无法修改服务器的TLS证书,可以通过禁用主机名验证来解决这个问题。以下是一个示例代码:

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class MqttClientExample {
    public static void main(String[] args) {
        String broker = "ssl://example.com:8883";
        String clientId = "JavaExample";
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] { new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
                public X509Certificate[] getAcceptedIssuers() { return null; }
            } }, null);
            
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
            
            MqttClient client = new MqttClient(broker, clientId, persistence);
            MqttConnectOptions options = new MqttConnectOptions();
            options.setSocketFactory(socketFactory);
            
            client.connect(options);
            
            // 连接成功后的操作
            // ...
            
            client.disconnect();
        } catch (MqttException | java.security.NoSuchAlgorithmException | java.security.KeyManagementException e) {
            e.printStackTrace();
        }
    }
}

上述代码中,我们创建了一个自定义的X509TrustManager,用于禁用证书验证。然后,我们使用这个自定义的TrustManager来创建一个SSLContext,并将其设置为MqttConnectOptions的socketFactory。

请注意,禁用主机名验证可能会导致安全问题,因为它允许连接到未经验证的主机。在生产环境中,应该尽量避免使用这种方法。

总结

"No subject alternative names present"错误是由服务器的TLS证书中缺少Subject Alternative Names字段引起的。为了解决这个问题,可以在服务器的TLS证书中添加Subject Alternative Names字段,或者禁用主机名验证。然而,在生产环境中,最好使用第一种方法来修复这个问题,以确保连接的安全性。

希望本文能够帮助你解决"No subject alternative names present"错误,并成功使用Java Paho库进行TLS验证。

参考资料

  • [Java Paho](
  • [Java SE Documentation](