我正在研究MQTT协议。我配置了它的服务器并使用1883端口上的mosquitto库在java中进行了通信。 现在我想让这个通信安全。我知道端口8883是为其基于tls的安全通信而保留的。 它需要X.509认证。 我为此找到了以下教程。
但我的问题是
1.我们可以用java代码生成这些证书吗?
2.我们可以一次使用多个证书。根据上面的教程,我们可以在服务器的mosquitto.conf文件中一次只指定一组证书。然后我们需要重新启动服务器。我不想这样做。)
3.我们可以让运行的服务器了解这些新生成的证书。除了在服务器的conf文件中指定外,还有其他方法吗?
答案 0 :(得分:1)
好的,我想你很想知道证书认证的工作原理。
它有2个部分(证明经纪人是它所说的那个,然后证明客户连接的是谁)
首先,经纪人将拥有1个证书,可以向全世界标识。您将Mosquitto配置为在启动时使用此证书,并且永远不需要更改它。该证书将由CA签署。
传感器(客户端)将拥有CA证书的副本,当他们连接到经纪人时将使用这些证书的副本,以确保它是声称的人。
其次,如果您想使用客户端证书来识别单独的传感器,那么他们每个人都需要一个证书。通常,这将由与经纪人证书相同的CA签署,以便经纪人可以验证客户是否是他们声称的人。可以将Mosquitto设置为使用证书(use_identity_as_username true
)中的CN作为连接客户端的用户名,然后您可以使用mosquitto_auth_plugin跟踪证书中的CN并应用ACL控制谁可以使用什么主题。
至于在java中创建证书,我建议你看看这个question
发布新证书时无需重启Mosquitto。
答案 1 :(得分:0)
//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);
}
}