-
-
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.
https://github.com/srlohr/PublicPahoClient.git
if you get:
Received fatal alert: protocol_version
change the line to
SSLContext context = SSLContext.getInstance("TLSv1.3");
hi, i faced two issue Issue 1: Got exception in parsing private key excpetion java.lang.ClassCastException: org.bouncycastle.asn1.pkcs.PrivateKeyInfo cannot be cast to org.bouncycastle.openssl.PEMKeyPair.. then i modified code to parse private key
if (object instanceof PrivateKeyInfo) { final JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter(); Log.d(TAG,"Unencrypted key - no password needed"); //key = converter.getKeyPair((PEMKeyPair) object); PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) object; key = jcaPEMKeyConverter.getPrivateKey(privateKeyInfo); with the above code change exception solved. issue 2: i am getting error when i connect to mosquito mqtt broker in linux. mosquito error-1562115998: OpenSSL Error: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown 1562115998: OpenSSL Error: error:140940E5:SSL routines:ssl3_read_bytes:ssl handshake failure AndroidGetting Exception: MqttException (0) - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Using bouncy castle - bcprov-jdk15on:1.62,bcpkix-jdk15on:1.62 Help to fix this
KeyPair key;
if (object instanceof PEMEncryptedKeyPair pemEncryptedKeyPair) {
...
} else if (object instanceof PrivateKeyInfo pKey) {
var privateKey = converter.getPrivateKey(pKey);
key = new KeyPair(null, privateKey);
} else {
...
}
I had a similar problem and i fixed with the code above
Dear all,
If I have only cert.pem, privkey.pem. How can I connect to MQTT Broker.
I can conenct to MQTT Broker by using Python and React, but can not conenct to MQTT Broker by using Java/Kotlin.
Please help me. Thanks a lots
In my case I have only client certificate (crt) and client key (key) files, how can I connect to Azure Event Grid MQTT. With the above code I get error as follows:
javax.net.ssl.SSLException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
I checked in other MQTT client like MQTTBox and MQTTX the connection is successful by using only client certificate and client key.
@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.
Hi All
Using Maven dependencies
org.eclipse.paho org.eclipse.paho.client.mqttv3 1.2.2 org.bouncycastle bcpkix-jdk15on 1.64using JDK 12, SSLSocketFactory getSocketFactory(...) in TestMQTT.java class I am able to publish and subscribe using MQTT 3.x
However if include
org.eclipse.paho
org.eclipse.paho.mqttv5.client
1.2.5
I am getting an error of Unsupported protocol version. when I try to publish and subscribe using MQTT 5.x. Please exception below.
org.eclipse.paho.mqttv5.common.MqttException: Unsupported protocol version.
at org.eclipse.paho.mqttv5.client.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:32)
at org.eclipse.paho.mqttv5.client.internal.ClientState.notifyReceivedAck(ClientState.java:1074)
at org.eclipse.paho.mqttv5.client.internal.CommsReceiver.run(CommsReceiver.java:153)
at java.base/java.lang.Thread.run(Thread.java:835)
Can you please advise what I need to get MQTT 5.x. works with SSL certificate.
Thank you for your help