MQTT is a lightweight and flexible IoT message exchange and data transfer protocol, dedicated to achieving a balance of flexibility and hardware/network resources for IoT developers. To ensure communication security, TLS/SSL is usually used for communication encryption.
This article mainly introduces how to perform TLS/SSL one-way authentication and two-way authentication through Android and MQTT.
Prepare
This article uses Eclipse Paho Android Service and BouncyCastle
, add dependencies
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.59'
}
The following is the core code part of Android connection TLS/SSL
MqttConnectOptions options = new MqttConnectOptions();
SSLSocketFactory sslSocketFactory = ...
options.setSocketFactory(sslSocketFactory);
The key point is how to obtain SSLSocketFactory
it. The one-way authentication and the two-way authentication are described below.
One-way authentication
One-way authentication means that the server authenticates the client. The following is the core code
public static SSLSocketFactory getSingleSocketFactory(InputStream caCrtFileInputStream) throws Exception {
Security.addProvider(new BouncyCastleProvider());
X509Certificate caCert = null;
BufferedInputStream bis = new BufferedInputStream(caCrtFileInputStream);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
}
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("cert-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
We ca.crt
put res/raw
under , then call
try {
InputStream caCrtFileI = context.getResources().openRawResource(R.raw.ca);
options.setSocketFactory(getSingleSocketFactory(caCrtFile));
} catch (Exception e) {
e.printStackTrace();
}
Two-way authentication
Two-way authentication refers to mutual authentication between the server and the client. The following is the key code
public static SSLSocketFactory getSocketFactory(InputStream caCrtFile, InputStream crtFile, InputStream keyFile,
String password) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
X509Certificate caCert = null;
BufferedInputStream bis = new BufferedInputStream(caCrtFile);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
}
// load client certificate
bis = new BufferedInputStream(crtFile);
X509Certificate cert = null;
while (bis.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(bis);
}
// load client private cert
PEMParser pemParser = new PEMParser(new InputStreamReader(keyFile));
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair key = converter.getKeyPair((PEMKeyPair) object);
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("cert-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("certificate", cert);
ks.setKeyEntry("private-cert", key.getPrivate(), password.toCharArray(),
new java.security.cert.Certificate[]{cert});
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
We need to prepare the server certificate, put the client certificate and secret key res/raw
under , and then call, note that the password is set to an empty string
try {
InputStream caCrtFile = context.getResources().openRawResource(R.raw.ca);
InputStream crtFile = context.getResources().openRawResource(R.raw.cert);
InputStream keyFile = context.getResources().openRawResource(R.raw.key);
options.setSocketFactory(getSocketFactory(caCrtFile, crtFile, keyFile, ""));
} catch (Exception e) {
e.printStackTrace();
}
The above is how to perform TLS/SSL one-way authentication and two-way authentication with MQTT on Android.
Copyright statement: This article is original by EMQ , please indicate the source when reprinting.
Original link: https://www.emqx.io/cn/blog/android-mqtt-ssl-tls-authentication