-
-
Save jimrok/d25cb45b840f5a4ad700 to your computer and use it in GitHub Desktop.
package test_mqtt; | |
import java.io.BufferedInputStream; | |
import java.io.FileInputStream; | |
import java.io.FileReader; | |
import java.security.KeyPair; | |
import java.security.KeyStore; | |
import java.security.Security; | |
import java.security.cert.CertificateFactory; | |
import java.security.cert.X509Certificate; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSocketFactory; | |
import javax.net.ssl.TrustManagerFactory; | |
import org.bouncycastle.jce.provider.BouncyCastleProvider; | |
import org.bouncycastle.openssl.PEMDecryptorProvider; | |
import org.bouncycastle.openssl.PEMEncryptedKeyPair; | |
import org.bouncycastle.openssl.PEMKeyPair; | |
import org.bouncycastle.openssl.PEMParser; | |
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; | |
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; | |
import org.eclipse.paho.client.mqttv3.MqttClient; | |
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; | |
import org.eclipse.paho.client.mqttv3.MqttException; | |
public class TestMQTT { | |
public static void main(String[] args) { | |
String serverUrl = "ssl://serverip:1883"; | |
String caFilePath = "/your_ssl/cacert.pem"; | |
String clientCrtFilePath = "/your_ssl/client.pem"; | |
String clientKeyFilePath = "/your_ssl/client.key"; | |
String mqttUserName = "guest"; | |
String mqttPassword = "123123"; | |
MqttClient client; | |
try { | |
client = new MqttClient(serverUrl, "2"); | |
MqttConnectOptions options = new MqttConnectOptions(); | |
options.setUserName(mqttUserName); | |
options.setPassword(mqttPassword.toCharArray()); | |
options.setConnectionTimeout(60); | |
options.setKeepAliveInterval(60); | |
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1); | |
SSLSocketFactory socketFactory = getSocketFactory(caFilePath, | |
clientCrtFilePath, clientKeyFilePath, ""); | |
options.setSocketFactory(socketFactory); | |
System.out.println("starting connect the server..."); | |
client.connect(options); | |
System.out.println("connected!"); | |
Thread.sleep(1000); | |
client.subscribe( | |
"/u/56ca327d17531d08e76bddd4a215e37f5fd6082f7442151c4d3f1d100a0ffd4e", | |
0); | |
client.disconnect(); | |
System.out.println("disconnected!"); | |
} catch (MqttException e) { | |
e.printStackTrace(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
private static SSLSocketFactory getSocketFactory(final String caCrtFile, | |
final String crtFile, final String keyFile, final String password) | |
throws Exception { | |
Security.addProvider(new BouncyCastleProvider()); | |
// load CA certificate | |
X509Certificate caCert = null; | |
FileInputStream fis = new FileInputStream(caCrtFile); | |
BufferedInputStream bis = new BufferedInputStream(fis); | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
while (bis.available() > 0) { | |
caCert = (X509Certificate) cf.generateCertificate(bis); | |
// System.out.println(caCert.toString()); | |
} | |
// load client certificate | |
bis = new BufferedInputStream(new FileInputStream(crtFile)); | |
X509Certificate cert = null; | |
while (bis.available() > 0) { | |
cert = (X509Certificate) cf.generateCertificate(bis); | |
// System.out.println(caCert.toString()); | |
} | |
// load client private key | |
PEMParser pemParser = new PEMParser(new FileReader(keyFile)); | |
Object object = pemParser.readObject(); | |
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder() | |
.build(password.toCharArray()); | |
JcaPEMKeyConverter converter = new JcaPEMKeyConverter() | |
.setProvider("BC"); | |
KeyPair key; | |
if (object instanceof PEMEncryptedKeyPair) { | |
System.out.println("Encrypted key - we will use provided password"); | |
key = converter.getKeyPair(((PEMEncryptedKeyPair) object) | |
.decryptKeyPair(decProv)); | |
} else { | |
System.out.println("Unencrypted key - no password needed"); | |
key = converter.getKeyPair((PEMKeyPair) object); | |
} | |
pemParser.close(); | |
// CA certificate is used to authenticate server | |
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType()); | |
caKs.load(null, null); | |
caKs.setCertificateEntry("ca-certificate", caCert); | |
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); | |
tmf.init(caKs); | |
// client key and certificates are sent to server so it can authenticate | |
// us | |
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); | |
ks.load(null, null); | |
ks.setCertificateEntry("certificate", cert); | |
ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), | |
new java.security.cert.Certificate[] { cert }); | |
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(); | |
} | |
} |
Hi All
I am getting the following error show below when running with JDK 12. Any idea, thank you for your help.
20:52:36.312 [main] INFO au.gov.nsw.rms.its.sdcs.mb.vernemq.TestMQTTSSL - starting connect the server... 20:52:36.454 [main] ERROR au.gov.nsw.rms.its.sdcs.mb.vernemq.TestMQTTSSL - Exception encounter with error MqttException org.eclipse.paho.client.mqttv3.MqttException: MqttException 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:835) 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:320) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:258) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:641) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:460) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:360) 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:177)
//禁止服务端检查
options.setHttpsHostnameVerificationEnabled(false);
Works like a charm for AWS IoT. I'm using OpenJDK 21, with paho mqtt v5. Only some small modifications to adapt to v5 API is needed.
yes it worked at the time for aws iot