Centos 安装EMQX,使用自带的SSL,并用java验证
centos7安装EMQX
使用EMQ官网,选择系统环境和安装方式,进行下载安装
emqx broker
使用指南中依赖包安装、特定版本安装、启动方式等命令。
EMQ X的SSL
/emqx/etc/certs里面存储自带的服务器证书和客户端证书
注意:client-key-pkcs8.pem是另外生成,为了java连接用的,不在certs里面。
1.证书转换,将 client-key.pem 转换成 pkcs8 格式的证书:
// An highlighted block
openssl pkcs8 -topk8 -inform PEM -in client-key.pem -outform PEM -nocrypt -out client-key-pkcs8.pem
2.修改emqx.conf配置
/emqx/etc/emqx.conf里面主要是取消双向验证的注释即可
## A server only does x509-path validation in mode verify_peer,
## as it then sends a certificate request to the client (this
## message is not sent if the verify option is verify_none).
## You can then also want to specify option fail_if_no_peer_cert.
## More information at: http://erlang.org/doc/man/ssl.html
##
## Value: verify_peer | verify_none
listener.ssl.external.verify = verify_peer
## Used together with {verify, verify_peer} by an SSL server. If set to true,
## the server fails if the client does not have a certificate to send, that is,
## sends an empty certificate.
##
## Value: true | false
listener.ssl.external.fail_if_no_peer_cert = true
3.emqtt重启
使用zip安装的解压文件,进入/emqx/bin/emqx start
4.mqtt.fx客户端测试
注意protocil选择TLSv1.2
CA File 选择cacert.pem
Client Certificate File 选择client-cert.pem
Client Key File 选择client-key.pem
测试连接成功。
5.java模拟SSL连接(一)
注意,java代码验证的key文件,因为是key的pem格式不识别,需要转换成 pkcs8 格式的证书。需要使用第二部生成的文件client-key-pkcs8.pem。
并且自带的证书无password,所以用“”即可。
// An highlighted block
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class EmqSSL {
public static void main(String[] args) {
EmqSSL ss = new EmqSSL();
ss.connect();
}
private static void connect() {
String topic = "MQTT Examples";
String content = "Message from MqttPublishSample";
int qos = 2;
String broker = "ssl://IP地址:8883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
SSLSocketFactory factory = null;
try {
factory = getSSLSocktet("E:\\test\\emqx\\etc\\certs\\cacert.pem",
"E:\\test\\emqx\\etc\\certs\\client-cert.pem",
"E:\\test\\emqx\\etc\\certs\\client-key-pkcs8.pem", "");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connOpts.setSocketFactory(factory);
System.out.println("Connecting to broker: " + broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: " + content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
}
private static SSLSocketFactory getSSLSocktet(String caPath, String crtPath, String keyPath, String password)
throws Exception {
// CA certificate is used to authenticate server
CertificateFactory cAf = CertificateFactory.getInstance("X.509");
FileInputStream caIn = new FileInputStream(caPath);
X509Certificate ca = (X509Certificate) cAf.generateCertificate(caIn);
KeyStore caKs = KeyStore.getInstance("JKS");
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", ca);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(caKs);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream crtIn = new FileInputStream(crtPath);
X509Certificate caCert = (X509Certificate) cf.generateCertificate(crtIn);
crtIn.close();
// 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", caCert);
ks.setKeyEntry("private-key", getPrivateKey(keyPath), password.toCharArray(),
new java.security.cert.Certificate[] { caCert });
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
return context.getSocketFactory();
}
public static PrivateKey getPrivateKey(String path) throws Exception {
org.apache.commons.codec.binary.Base64 base64 = new Base64();
byte[] buffer = base64.decode(getPem(path));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
private static String getPem(String path) throws Exception {
FileInputStream fin = new FileInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(fin));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
fin.close();
return sb.toString();
}
}
6.java验证方式(二)
其中的crt文件,也是pem格式的。
package testMqttSSL;
import javax.net.ssl.SSLSocketFactory;
import java.security.Security;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class SslUtil {
public static void main(String[] args) throws MqttException {
String topic = "MQTT Examples";
String content = "Message from MqttPublishSample";
int qos = 2;
String broker = "ssl://192.168.20.197:8883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setCleanSession(true);
//如果匿名登录连接,这2行注释掉
mqttConnectOptions.setUserName("easthouse");
mqttConnectOptions.setPassword("liberty".toCharArray());
//mqtt 建立连接时赋值 双向
try {
//经测试用crt证书
mqttConnectOptions.setSocketFactory(SslUtil.getSocketFactory("D:\\emqttd-windows10-v2.3.3\\emqttd\\etc\\certs\\ca.crt",
"D:\\emqttd-windows10-v2.3.3\\emqttd\\etc\\certs\\client.crt",
"D:\\emqttd-windows10-v2.3.3\\emqttd\\etc\\certs\\client.key", ""));
//单向
// mqttConnectOptions.setSocketFactory(SslUtil.getSocketFactorySingle(rootCrtPath));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Connecting to broker: " + broker);
sampleClient.connect(mqttConnectOptions);
System.out.println("Connected");
System.out.println("Publishing message: " + content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
}
public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile,
final String keyFile,
final String password) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
PEMReader reader = new PEMReader(
new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
X509Certificate caCert = (X509Certificate) reader.readObject();
reader.close();
// load client certificate
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
X509Certificate cert = (X509Certificate) reader.readObject();
reader.close();
// load client private key
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))));
KeyPair key = (KeyPair) reader.readObject();
reader.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(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", 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();
}
/* public static SSLSocketFactory getSocketFactorySingle(final String caCrtFile) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
PEMReader reader = new PEMReader(
new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
X509Certificate caCert = (X509Certificate) reader.readObject();
reader.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(TrustManagerFactory.getDefaultAlgorithm());
// tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate us
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());// "JKS"
ks.load(null, null);
ks.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());// "PKIX"
tmf.init(ks);
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, tmf.getTrustManagers(), new SecureRandom());
// ----------------------------------------------------------------
// CertificateFactory cAf = CertificateFactory.getInstance("X.509");
// FileInputStream caIn = new FileInputStream(caPath);
// X509Certificate ca = (X509Certificate) cAf.generateCertificate(caIn);
// KeyStore caKs = KeyStore.getInstance("JKS");
// caKs.load(null, null);
// caKs.setCertificateEntry("ca-certificate", ca);
// TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
// tmf.init(caKs);
//
//
// SSLContext context = SSLContext.getInstance("TLSv1");
// context.init(null, tmf.getTrustManagers(), new SecureRandom());
//
// return context.getSocketFactory();
return context.getSocketFactory();
}*/
}
Connecting to broker: ssl://服务IP:8883
Connected
Publishing message: Message from MqttPublishSample
Message published
Disconnected