按照文档生成了自签名证书
在服务端控制台配置了证书,并且开启了客户端验证
使用mqttx工具配置客户端证书连接成功
按照列子 https://github.com/emqx/MQTT-Client-Examples/blob/master/mqtt-client-Java/src/main/java/io/emqx/mqtt/MqttTwoWayTlsSample.java 无法建立连接
服务端日志
2024-02-22T17:43:40.695000+08:00 [notice] TLS server: In state certify at ssl_handshake.erl:2109 generated SERVER ALERT: Fatal - Bad Certificate
2024-02-22T17:43:40.695000+08:00 [notice] supervisor: {esockd_connection_sup,<0.3009.0>}, errorContext: ssl_error, reason: {tls_alert,{bad_certificate,"TLS server: In state certify at ssl_handshake.erl:2109 generated SERVER ALERT: Fatal - Bad Certificate\n"}}, offender: [{pid,<0.3009.0>},{name,connection},{mfargs,{emqx_connection,start_link,[#{enable_authn => true,limiter => undefined,listener => {ssl,default},zone => default}]}}]
java客户端代码
SSLSocketFactory socketFactory = SSLUtils.getSocketFactory(sslCaFilePath, sslCrtFilePath, sslKeyFilePath, "");
//SSLSocketFactory socketFactory = getSSLSocketFactory(sslCrtFilePath, sslKeyFilePath, sslCaFilePath);
MemoryPersistence persistence = new MemoryPersistence();
MqttClient client = new MqttClient(broker, serverClientId + "-" + System.currentTimeMillis(), persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(username);
connOpts.setPassword(password.toCharArray());
connOpts.setCleanSession(true);
connOpts.setAutomaticReconnect(true);
connOpts.setKeepAliveInterval(10);
connOpts.setConnectionTimeout(60);
connOpts.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
connOpts.setSocketFactory(socketFactory);
client.connect(connOpts);
public static SSLSocketFactory getSocketFactory(final String caCrtFile,
final String crtFile, final String keyFile, final String password)
throws Exception {
Security.addProvider(new BouncyCastleProvider());
// Load CA certificates
KeyStore caKs = loadCAKeyStore(caCrtFile);
// Load client certificate chain and key
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
// Load the entire client certificate chain
Certificate[] chain;
try (FileInputStream fis = new FileInputStream(crtFile)) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certs = cf.generateCertificates(fis);
chain = certs.toArray(new Certificate[0]);
}
// Load client private key
try (PEMParser pemParser = new PEMParser(new FileReader(keyFile))) {
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
PrivateKey key = converter.getPrivateKey((PrivateKeyInfo) object);
ks.setKeyEntry("private-key", key, password.toCharArray(), chain);
}
// Set up key managers and trust managers
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(caKs);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
仔细检查过证书文件路径和在mqttx工具中配置的client.crt client.key root.crt路径是一样的,mqttx可以建立连接 但是 java客户端无法建立连接