Reputation: 257
i am working on MQTT protocol. i configured its server and performed the communication in java using its mosquitto library on port 1883. now i want to make this communication secure.What i know is port 8883 is reserved for its tls based secure communication. It requires X.509 certiicates. I found the following tutorial for this purpose.
But my question are
1.how can we generate these certificates in java code?
2.how can we use multiple certificates at a time.As according to above tutorial we can specify only one set of ceritificates at a time in mosquitto.conf file of server.And then we need to restart the server.(that i dont want to do.)
3.how can we let a running server know about these newly generated certificates. Is there anyother way to do this except to specify in conf file of server?
Upvotes: 2
Views: 6459
Reputation: 59628
OK, I think you've miss understood how Certificate authentication works.
There are 2 parts to it (Proving the broker is who it says it is and then proving who the client connecting is)
Firstly the broker will have 1 certificate that identifies it to the world. You configure Mosquitto to use this certificate at startup and never need to change it (less it expires). This certificate will be signed by a CA.
The sensors (clients) will have a copy of the CA cert which they will use when they connect to the broker to ensure it is who it claims to be.
Secondly if you want to use client certificates to identify the separate sensors then they will each need a certificate as well. Normally this will be signed by the same CA as the Broker certificate so the broker can verify the clients are who they claim to be. Mosquitto can be set up to use the CN from the certificates (use_identity_as_username true
) as the username for the connecting clients and then you can use the mosquitto_auth_plugin to keep track of the CN's in the certificates and apply ACLs to control who can use what topics.
As for creating certificates in java I suggest you look at this question
There is no need to restart Mosquitto when you issue a new cert.
Upvotes: 4
Reputation: 1
//add bcpkix-jdk15on-161, bcprov-jdk15on-1.52 and eclips pago-mqtt3.1
//lib in build path
import java.io.*;
import java.nio.file.*;
import java.security.*;
import java.security.cert.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.net.ssl.*;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.*;
import org.bouncycastle.openssl.*;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
public class SslUtil
{
@SuppressWarnings("deprecation")
//It will return SSLSocketFactory
public static SSLSocketFactory getSocketFactory (final String
caCrtFile, final String crtFile, final String keyFile,
final String password) throws Exception
{
try{
Security.addProvider(new BouncyCastleProvider());
X509Certificate caCert =
(X509Certificate)SslUtil.getCertificate(caCrtFile);
X509Certificate cert =
(X509Certificate)SslUtil.getCertificate(crtFile);
FileReader fileReader = new FileReader(keyFile);
PEMParser parser = new PEMParser(fileReader);
PEMKeyPair kp = (PEMKeyPair) parser.readObject();
PrivateKeyInfo info = kp.getPrivateKeyInfo();
PrivateKey rdKey = new JcaPEMKeyConverter().setProvider("BC")
.getPrivateKey(info);
// 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(TrustManagerFactory.getDefaultAlgorithm());
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", rdKey, 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");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
//Get MqttClient for Subscripe Pulish
public static void mqttClient(String caCrtFile,String clientCrtFilePath,String clientKeyFilePath,String password){
try{
String serverUrl = "ssl://serverip:8883";
MqttClient client = new MqttClient(serverUrl, "consumerId" , null);
//this MyCallback class extends mqtt there we have to override some function //like message arriver etc
client.setCallback(new MyCallback());
MqttConnectOptions options = new MqttConnectOptions();
options.setConnectionTimeout(60);
options.setKeepAliveInterval(60);
options.setSocketFactory(SslUtil.getSocketFactory(caCrtFile, clientCrtFilePath, clientKeyFilePath, password));
client.connect(options);
client.subscribe("topic", 0);
}catch (Exception e) {
System.out.println("#Exception :"+e.getMessage());
}
}
//start execution
public static void main(String[] args) throws Exception {
String caCrtFile = "path Certification Authority";
String clientCrtFilePath ="path for client crt file";
String clientKeyFilePath ="path of client key";
String password = "password while generating files";
mqttClient(caCrtFile,clientCrtFilePath,clientKeyFilePath,password);
// getCertificate(caCrtFile);
}
//return certificate
public static java.security.cert.X509Certificate getCertificate(String pemfile) throws Exception
{
java.security.cert.X509Certificate cert = null;
try {
FileReader fRd = new FileReader(pemfile);
final PemReader certReader = new PemReader(fRd);
final PemObject certAsPemObject = certReader.readPemObject();
if (!certAsPemObject.getType().equalsIgnoreCase("CERTIFICATE")) {
throw new Exception("Certificate file does not contain a certificate but a " + certAsPemObject.getType());
}
final byte[] x509Data = certAsPemObject.getContent();
final CertificateFactory fact = CertificateFactory.getInstance("X509");
cert = (X509Certificate) fact.generateCertificate(new ByteArrayInputStream(x509Data));
if (!(cert instanceof X509Certificate)) {
throw new Exception("Certificate file does not contain an X509 certificate");
}
} catch (FileNotFoundException e) {
throw new IOException("Can't find file " + pemfile);
}catch (Exception e) {
System.out.println("#Exceotion :"+e.getMessage());
}
return cert;
}
//retuen keyPair Object form client key
public KeyPair decodeKeys(byte[] privKeyBits,byte[] pubKeyBits)
throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privKey=keyFactory.generatePrivate(new
PKCS8EncodedKeySpec(privKeyBits));
PublicKey pubKey=keyFactory.generatePublic(new
X509EncodedKeySpec(pubKeyBits));
return new KeyPair(pubKey,privKey);
}
}
Upvotes: 0