-
-
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(); | |
| } | |
| } |
@mluis , et. al. - Does this connect to AWS IOT core using X.509 cert authentication to port 8883?
I have only a slight difference in sample project below because it seems that bouncycastle is being deprecated, but since private key and cert is properly parsed into a data structure and successful connection to mosquitto.org:8883 proves it works.
yes it worked at the time for aws iot
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.
I checked in other MQTT client like MQTTBox and MQTTX the connection is successful by using only client certificate and client key.