1 openssl安装
opensll emq安装包及客户端下载路径
https://download.csdn.net/download/h4241778/12647477
用于证书生产
$ tar zxf openssl openssl-1.0.1.tar.gz
$ cd openssl-1.0.1
$ ./config --prefix=/usr/local
我记得执行到这就可以了,openssl version 可查看版本
$ make
$ make clean
$ sudo make install
2 emq安装
emqx-ubuntu16.04-v4.1.1_amd64.deb 安装
sudo dpkg -i emqx-ubuntu16.04-v4.1.1_amd64.deb
自动安装在 /etc/emqx 目录下;修改emqx.conf需要知道
客户端连接端口默认:18083 admin public
ssl默认端口为8883,具体可以查看emqx.conf
3 ssl创建证书
3.1准备工作
在opt目录下创建ssl目录用来临时存储生成的证书文件
mkdir /opt/ssl
cd /opt/ssl/
生成证书索引库数据库文件
touch demoCA/newcerts/index.txt
touch demoCA/index.txt
touch demoCA/serial
指定第一个颁发证书的序列号
echo 01 > demoCA/serial
3.2 证书生成
3.2.1 CA证书生成
openssl req -x509 -new -days 3650 -keyout ca.key -out rootCA.crt -nodes
openssl req -x509 -new -days 3650 -keyout ca.key -out rootCA.crt -nodes
参数:
Country Name (2 letter code) [XX]:国家【中国---CN】
State or Province Name (full name) []:省份
Locality Name (eg, city) [Default City]:城市
Organization Name (eg, company) [Default Company Ltd]:组织名称
Organizational Unit Name (eg, section) []:组织单元名称
Common Name (eg, your name or your server's hostname) []:服务器IP
Email Address []: 邮箱地址
3.2.2 为server端生成证书
1生成私钥
openssl genrsa -out server.key 2048
2生成证书请求csr文件
openssl req -new -key server.key -out server.csr
参数填写与前面类似
A challenge password []: 密码
An optional company name []:公司名称
3生成证书
openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650
3.2.3 为Client端生成证书
1生成私钥
openssl genrsa -out client.key 2048
2生成证书请求:
openssl req -new -key client.key -out client.csr
参数与服务端证书生成类似,不过这里我用到ip是客户端ip
3生成证书
openssl ca -in client.csr -out client.crt -cert rootCA.crt -keyfile ca.key
4 ssl双向验证和单向验证ssl配置
修改 emqx.conf文件
4.1单向认证
## SSL Options
listener.ssl.external.handshake_timeout = 15
listener.ssl.external.keyfile = etc/certs/server-key.pem
listener.ssl.external.certfile = etc/certs/server-cert.pem
## 开启双向认证
## listener.ssl.external.cacertfile = etc/certs/rootca-cert.pem
## listener.ssl.external.verify = verify_peer
## listener.ssl.external.fail_if_no_peer_cert = true
4.2 双向认证
## SSL Options
listener.ssl.external.handshake_timeout = 15
listener.ssl.external.keyfile = etc/certs/server-key.pem
listener.ssl.external.certfile = etc/certs/server-cert.pem
## 开启双向认证
listener.ssl.external.cacertfile = etc/certs/cacert.pem
listener.ssl.external.verify = verify_peer
listener.ssl.external.fail_if_no_peer_cert = true
5 代码实现
1 pom 依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.47</version>
</dependency>
2 建立连接时赋值进行如下处理:
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
//mqtt 建立连接时赋值 双向
mqttConnectOptions.setSocketFactory(SslUtil.getSocketFactory(rootCrtPath,
clientCrtPath, clientKeyPath, clientPassword));
//单向
mqttConnectOptions.setSocketFactory(SslUtil.getSocketFactorySingle(rootCrtPath));
3 加载证书工具类实现
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 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 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)))),
new PasswordFinder() {
@Override
public char[] getPassword() {
return password.toCharArray();
}
}
);
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.1");
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.1");
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();
}
}