繁体   English   中英

使用自签名证书在 SSL 上使用 Mosquitto 设置 Java MQTT 客户端

[英]Setup Java MQTT client with Mosquitto over SSL with a self signed certificate

我想在 Java 中创建一个客户端,它通过 SSL 连接到我的 mosquitto 代理。我的 Java 代码如下所示:

    public void connect(String protocol, String hostname, int port) throws MqttException {
            client = new MqttAsyncClient(String.format("%s://%s:%d", protocol, hostname, port), UUID.randomUUID());
            client.setCallback(new BaseMqttCallback(id, hostname, mqttEventPublisher));

            client.connect(mqttConnectOptions()).waitForCompletion(WAIT_DELAY);
        } else {
            throw new MqttException(MqttException.REASON_CODE_CLIENT_CONNECTED);
        }
    private MqttConnectOptions mqttConnectOptions() {
        MqttConnectOptions options = new MqttConnectOptions();
        // The library will automatically try to reconnect to the server in the event of a network failure
        options.setAutomaticReconnect(false);
        // It will discard unsent messages from a previous run
        options.setCleanSession(true);
        // Connection timeout is set to 5 seconds
        options.setConnectionTimeout(5);

        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null,null);
            var file = new FileInputStream("/etc/mosquitto/ca_certificates/ca.crt");
            trustStore.setCertificateEntry("Custom CA", CertificateFactory.getInstance("X509")
                .generateCertificate(file));

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            TrustManager[] trustManagers = tmf.getTrustManagers();

            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, null);
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            
            options.setSocketFactory(sslSocketFactory);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        // options.setUserName(null);
        // options.setPassword(null);
        return options;
    }

这是我使用以下命令时证书的 output: openssl x509 -text -noout -in ca.crt

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            64:a8:04:ac:51:3f:7f:f6:fa:b5:21:12:6e:c4:e3:fb:94:f1:47:40
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = GD, L = SZ, O = "Acme, Inc.", CN = Acme Root CA
        Validity
            Not Before: Sep 27 11:04:02 2021 GMT
            Not After : Sep 27 11:04:02 2022 GMT
        Subject: C = CN, ST = GD, L = SZ, O = "Acme, Inc.", CN = Acme Root CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:ba:ad:39:a5:c2:03:e7:ef:58:b0:fb:26:bd:e1:
                    d4:36:8e:63:38:8b:65:c4:03:c5:44:96:c5:1e:2f:
                    0f:60:32:c7:33:7c:58:0d:4a:b6:a5:61:dd:0b:55:
                    f5:69:fc:d0:f0:82:c7:d8:b5:13:61:ef:ca:27:07:
                    ec:88:f5:2c:85:c8:34:cf:16:5c:80:db:ff:79:66:
                    91:7c:2d:32:8e:78:27:40:f2:b1:1b:fe:b3:b4:9e:
                    62:2f:f5:a3:5a:05:f5:3d:e9:bc:ed:e0:f1:6b:b0:
                    56:f4:41:4e:3b:6b:df:1e:17:4c:50:00:c5:ff:eb:
                    3d:d3:68:e0:9a:30:ba:ba:a9:0b:41:9b:6a:2f:b4:
                    95:e3:39:c7:c6:a3:95:59:cb:e0:b6:32:98:7e:eb:
                    35:6b:95:44:f7:c2:48:b0:8f:90:f8:d5:9e:af:ff:
                    fa:84:b7:ec:79:e4:cf:a6:8f:fd:58:b4:1f:73:9c:
                    2e:6f:ab:cf:2f:be:31:88:de:c8:b1:2d:16:db:d4:
                    72:3e:33:4c:33:ec:e4:3d:4c:6e:61:e4:a7:09:73:
                    80:ad:6f:24:f2:71:1a:96:49:63:3b:36:f6:93:f4:
                    07:7a:de:d4:b3:46:79:8d:2d:a0:9f:37:30:41:9e:
                    68:42:9e:eb:b4:df:0e:f5:da:83:df:4b:bb:96:18:
                    64:83
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                04:A1:92:4E:AC:B4:90:59:2F:97:3A:CE:0C:2F:0C:7E:53:63:81:82
            X509v3 Authority Key Identifier: 
                keyid:04:A1:92:4E:AC:B4:90:59:2F:97:3A:CE:0C:2F:0C:7E:53:63:81:82

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         9b:bc:c3:bc:21:71:da:ba:2d:b7:d4:dd:b4:a2:1c:3c:52:ca:
         30:c0:f9:cb:9f:46:29:f5:9f:a7:b5:de:0b:ed:19:6d:6d:6b:
         6b:40:20:87:3e:35:71:95:01:b8:03:4f:1e:5a:86:17:34:ed:
         44:28:9c:6d:6c:b6:e4:b4:8e:5c:34:c2:b1:cf:a1:08:54:3b:
         97:ce:98:64:f0:6e:a8:39:6a:3b:21:8a:d1:20:d4:f2:02:b3:
         8d:2c:50:0e:51:72:74:d4:12:a0:52:4d:f6:7b:ff:0d:6d:7c:
         db:39:ea:e1:20:26:74:49:0a:a0:c3:d5:49:be:9a:5d:ea:03:
         fb:04:c9:46:ff:8b:1e:09:51:3e:ae:85:0b:12:21:da:7b:62:
         44:ff:1d:c9:7a:9e:61:c5:d5:f8:a1:20:7d:70:3e:ac:ca:8b:
         6e:4b:9f:0e:cf:28:8f:b3:80:65:55:dd:bf:1c:eb:75:73:d3:
         f6:00:52:c2:6c:43:97:a8:d5:26:46:8e:e6:22:62:a3:cc:8a:
         02:e7:78:a5:8a:74:54:76:5e:92:e8:05:9a:80:33:28:04:78:
         47:12:7b:03:b6:3a:f9:31:0b:12:20:10:3f:01:0d:f9:38:55:
         b7:fb:25:41:0b:e3:4b:fe:40:c2:09:99:c6:54:b5:5d:18:f5:
         a9:99:49:27

这是我的 server.crt 的样子:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2a:79:1a:8b:53:b4:c9:c1:91:e9:f0:fe:1e:eb:5d:5a:f3:a5:67:8a
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = GD, L = SZ, O = "Acme, Inc.", CN = Acme Root CA
        Validity
            Not Before: Sep 27 11:05:27 2021 GMT
            Not After : Sep 27 11:05:27 2022 GMT
        Subject: C = CN, ST = GD, L = SZ, O = "Acme, Inc.", CN = *127.0.0.1
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:da:8c:86:4e:77:f3:a3:5c:31:3f:8b:5a:c1:23:
                    1e:03:53:6a:0e:13:6d:7a:64:1d:db:86:5a:92:fa:
                    e9:88:e4:45:4a:e0:cf:29:0c:6f:eb:bd:81:c1:04:
                    e8:40:af:9f:63:61:07:1c:f8:2e:fa:9f:1b:98:86:
                    2f:3f:bf:c3:d0:f8:df:ae:d6:b6:45:ad:f9:97:c7:
                    74:5f:0a:77:52:6c:46:06:4f:30:ae:f4:c9:af:ac:
                    e4:24:b9:30:56:bc:bf:0f:50:92:08:92:e1:ed:95:
                    04:54:e4:f9:3d:35:13:34:19:46:00:3c:1e:e0:67:
                    dd:5e:0a:e9:c1:3e:f2:84:a1:8e:3f:28:61:25:80:
                    9c:87:a8:e6:df:9a:24:d2:c5:98:79:57:ef:f0:24:
                    73:ff:b6:96:ac:df:09:1c:6e:2f:bc:85:69:b6:97:
                    46:f8:03:a7:49:8e:38:05:d4:f3:83:f4:9a:36:fd:
                    88:0e:cb:82:b0:af:7e:9c:d7:2c:75:1b:96:d8:22:
                    0c:b8:86:74:db:20:4b:c8:10:2e:8f:6d:a0:a5:33:
                    2e:ed:20:9c:30:6e:8f:91:d1:59:ad:ea:cf:92:4d:
                    c1:bd:2e:aa:b2:cd:31:9d:c2:a3:c4:ba:2f:03:e8:
                    d7:78:ae:75:38:f7:e8:a9:f3:f1:44:cb:ff:a6:07:
                    26:d7
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:127.0.0.1
    Signature Algorithm: sha256WithRSAEncryption
         08:7d:42:76:9f:ca:f6:2f:bc:54:df:b6:ac:e4:0a:7e:4c:3d:
         4a:1d:35:28:30:9d:1a:d5:9a:d5:79:c6:99:2a:98:f2:80:ab:
         7e:7d:cc:c7:12:2e:fd:9a:f7:94:de:91:12:2d:10:50:63:d2:
         a9:1c:9b:83:a1:c1:4e:89:e3:a6:57:26:6a:1f:72:a1:86:ae:
         b4:15:cc:db:e8:c4:29:28:d6:c0:ff:c8:4d:bb:0f:ed:57:72:
         4e:48:b9:e8:3f:1d:09:41:28:f8:6c:60:7d:fb:53:fd:76:9e:
         a7:5f:58:4b:5d:9b:a8:2a:65:41:d2:ac:1c:3c:f4:db:3f:61:
         3b:9a:1b:bd:0a:a6:f3:ca:98:09:ed:45:a3:11:97:3a:1a:5b:
         69:02:e6:bb:fa:1c:b1:bd:aa:ed:5b:91:d2:ab:03:1b:3c:d4:
         c5:71:81:6b:cd:52:fe:21:62:e9:16:d9:1e:74:b6:9d:4d:e2:
         b4:bf:72:d0:1a:c9:41:81:71:a3:2e:7f:30:1c:46:55:12:38:
         3d:36:3e:3a:56:b3:48:65:b2:04:ea:ef:91:2c:94:ca:87:c7:
         d2:40:50:de:c6:f5:dc:8c:b4:fa:72:52:be:a5:4c:fa:05:39:
         75:80:d4:56:54:b1:a6:d9:90:64:0e:c0:c3:41:8e:21:0f:91:
         3b:cb:39:1d

当我尝试连接到我的主题时,我在 Java 中收到以下错误:

[2021-09-27 11:50:26,486] INFO  com.comp.mqtt.ClientManager - Connecting to Network(protocol=ssl, hostname=127.0.0.1, port=8883, topics=[/myTopic/#, /yourTopic/#])
[2021-09-27 11:50:26,506] ERROR com.comp.mqtt.ClientManager - Something went wrong trying to connect to Network(protocol=ssl, hostname=127.0.0.1, port=8883, topics=[/myTopic/#, /yourTopic/#])
MqttException (0) - javax.net.ssl.SSLHandshakeException: No subject alternative names present
    at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
    at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:738)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javax.net.ssl.SSLHandshakeException: No subject alternative names present
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:349)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:287)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1356)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1231)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1174)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1418)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1324)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:411)
    at org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:159)
    at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:724)
    ... 1 more
Caused by: java.security.cert.CertificateException: No subject alternative names present
    at java.base/sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142)
    at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:101)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:415)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1340)
    ... 14 more

这是我在经纪人那里收到的错误:

Sep 27 12:30:26 my-pc mosquitto[2498]: 1632738626: OpenSSL Error[0]: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown
Sep 27 12:30:26 my-pc mosquitto[2498]: 1632738626: Socket error on client <unknown>, disconnecting.

我在/etc/mosquitto/ca_certificates中有我的 ca 证书

server.crt server.key证书位于/etc/mosquitto/certs

以下作品用于创建 CA + 服务器证书

$ openssl genrsa -out ca.key 2048
$ openssl req -new -x509 -days 365 -key ca.key -subj "/C=GB/ST=Gloucestershire/O=localhost CA/CN=locahost Root CA" -out ca.pem
$ openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=GB/ST=Gloucestershire/O=Localhost CA/CN=localhost" -out server.csr
$ openssl x509 -req -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:::1") -days 365 -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server.pem

您可以在此处查看 SAN 条目:

$ openssl x509 -noout -text -in server.pem 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            7c:06:89:ba:1d:00:04:db:11:1b:e9:6c:44:a4:c3:58:49:0c:12:a1
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, ST = Gloucestershire, L = Dursley, O = Localhost CA, CN = Localhost Root CA
        Validity
            Not Before: Sep 27 14:40:32 2021 GMT
            Not After : Sep 27 14:40:32 2022 GMT
        Subject: C = GB, ST = Gloucestershire, L = Dursley, O = Localhost CA, CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:bf:d0:7a:ae:0a:d6:c4:eb:56:9c:8a:1a:d1:c8:
                    a2:91:a6:e4:9b:dc:d6:a8:98:fb:27:66:0b:14:24:
                    f9:af:a9:ed:b3:38:ab:e3:1d:3c:b6:22:c3:8b:92:
                    04:8d:61:b3:d1:19:ba:5c:2d:1c:53:c7:12:87:25:
                    2b:a5:24:0e:0f:b0:04:6b:c7:54:bf:c9:2d:49:bb:
                    54:fa:58:71:10:15:e0:98:0e:30:ba:52:c8:f7:a5:
                    93:a9:88:8d:7c:32:d7:d5:f5:23:de:a6:77:2c:2d:
                    41:51:ec:18:0e:66:b0:51:35:dd:f4:2d:d0:97:e7:
                    de:6f:43:0c:4a:48:0c:c8:44:ab:8f:6f:46:a9:1c:
                    9d:07:c7:1a:9a:b2:ae:e5:e8:0c:76:62:75:90:79:
                    3b:b9:0d:74:34:3a:9f:a6:09:57:b9:37:d5:bf:83:
                    1b:07:6f:2e:25:ae:59:bb:21:86:c1:20:01:5f:36:
                    4e:cf:d2:a5:65:02:12:8a:cd:1a:a2:d0:2f:f5:c2:
                    b1:ee:1f:1c:e0:d1:09:77:4d:d1:b5:86:55:84:31:
                    c1:6d:c2:d3:84:20:f0:65:d9:77:f1:89:76:aa:cd:
                    f3:cc:6a:60:54:8f:21:ae:cf:5d:d5:1a:8a:59:91:
                    df:4e:f5:94:c8:54:23:e6:92:e6:fb:ee:44:ca:fb:
                    59:93
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
    Signature Algorithm: sha256WithRSAEncryption
         91:7c:7f:2f:0b:22:d0:c2:1c:a3:12:5f:16:ac:c9:85:09:74:
         de:62:77:db:d8:e3:64:f8:4a:e7:b8:e7:26:d5:66:b6:d7:52:
         d3:d3:5b:a6:9a:ad:41:e5:9e:0a:00:9f:e8:19:e8:52:b2:b6:
         a4:35:93:d4:23:f0:0c:73:ff:51:ab:25:d7:b9:30:4b:ed:bc:
         ea:c6:d9:c9:b9:95:e6:8c:e3:01:9a:e3:3f:1d:cb:59:2c:49:
         73:c4:98:b6:52:a0:1c:b8:7e:89:c9:c6:b6:85:14:24:bc:82:
         8f:4b:58:a8:99:aa:c8:d3:c7:50:a0:7c:ac:df:8a:c7:7e:80:
         9c:64:be:39:10:67:89:83:8f:c0:d3:c0:39:09:6a:00:f2:10:
         ad:36:de:31:d8:89:f4:d7:b1:65:88:2d:b6:2e:72:30:14:e1:
         e9:43:e1:51:4b:de:3e:2f:67:5e:1f:09:6f:20:35:7d:27:37:
         a5:82:9a:07:ba:52:13:ef:10:10:5f:58:06:aa:d1:ec:c3:1f:
         73:50:1e:da:2c:30:a2:26:f6:83:7b:ad:27:6d:87:f4:c9:85:
         53:76:69:a5:7a:6f:95:4d:df:9b:22:aa:9d:9c:41:74:1c:88:
         0a:01:2e:63:e2:07:73:6f:2d:e6:bc:f7:c4:66:99:ac:8b:5c:
         48:cc:2f:56

然后与以下示例一起使用:

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.io.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;

public class MqttPublishSample {

  public static void main(String[] args) {
    String topic        = "MQTT Examples";
    String content      = "Message from MqttPublishSample";
    int qos             = 2;
    String broker       = "ssl://127.0.0.1:8883";
    String clientId     = "JavaSample";
    MemoryPersistence persistence = new MemoryPersistence();

    try {
      MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
      MqttConnectOptions connOpts = new MqttConnectOptions();
      connOpts.setCleanSession(true);
      try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null,null);
        var file = new FileInputStream("./ca.pem");
        trustStore.setCertificateEntry("Custom CA", CertificateFactory.getInstance("X509")
          .generateCertificate(file));

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        TrustManager[] trustManagers = tmf.getTrustManagers();

        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustManagers, null);
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        connOpts.setSocketFactory(sslSocketFactory);
      } catch (Exception e){
        System.out.println(e.getMessage());
      }

      System.out.println("Connecting to broker: "+broker);
      sampleClient.connect(connOpts);
      System.out.println("Connected");
      System.out.println("Publishing message: "+content);
      MqttMessage message = new MqttMessage(content.getBytes());
      message.setQos(qos);
      sampleClient.publish(topic, message);
      System.out.println("Message published");
      sampleClient.disconnect();
      System.out.println("Disconnected");
      System.exit(0);
    } catch(MqttException me) {
      System.out.println("reason "+me.getReasonCode());
      System.out.println("msg "+me.getMessage());
      System.out.println("loc "+me.getLocalizedMessage());
      System.out.println("cause "+me.getCause());
      System.out.println("excep "+me);
      me.printStackTrace();
    }
  }
}

mosquitto 使用以下配置文件运行:

allow_anonymous true
listener 8883 127.0.0.1
cafile ca.pem
certfile server.pem
keyfile server.key

listener 8883 ::1
cafile ca.pem
certfile server.pem
keyfile server.key

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM