使用自签名证书通过 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;
}
这是我使用以下命令时证书的输出:
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
我想在 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;
}
这是我使用以下命令时证书的输出:
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
并且 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