我是靠谱客的博主 魁梧乌冬面,最近开发中收集的这篇文章主要介绍mqtt java ssl_MQTT研究之EMQ:【SSL证书链验证】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

package com.taikang.iot.re.security;

import org.apache.log4j.Logger;

import org.bouncycastle.asn1.pkcs.RSAPrivateKey;

import org.bouncycastle.util.io.pem.PemObject;

import org.bouncycastle.util.io.pem.PemReader;

import javax.net.ssl.*;

import java.io.*;

import java.security.*;

import java.security.cert.Certificate;

import java.security.cert.CertificateFactory;

import java.security.cert.X509Certificate;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.RSAPrivateKeySpec;/**

* @Author: chengsh05

* @Date: 2019/3/1 17:51*/

public classSSLUtil {private static Logger logger = Logger.getLogger(OpensslHelper.class);/**

* 利用开源的工具类解析openssl私钥,openssl私钥文件格式为pem,需要去除页眉页脚后才能被java读取

*

* @param file

* @return*/

public staticPrivateKey getPrivateKey(File file) {if (file == null) {return null;

}

PrivateKey privKey= null;

PemReader pemReader= null;try{

pemReader= new PemReader(newFileReader(file));

PemObject pemObject=pemReader.readPemObject();byte[] pemContent =pemObject.getContent();//支持从PKCS#1或PKCS#8 格式的私钥文件中提取私钥

if (pemObject.getType().endsWith("RSA PRIVATE KEY")) {/** 取得私钥 for PKCS#1

* openssl genrsa 默认生成的私钥就是PKCS1的编码*/RSAPrivateKey asn1PrivKey=RSAPrivateKey.getInstance(pemContent);

RSAPrivateKeySpec rsaPrivKeySpec= newRSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());

KeyFactory keyFactory= KeyFactory.getInstance("rsa");

privKey=keyFactory.generatePrivate(rsaPrivKeySpec);

}else if (pemObject.getType().endsWith("PRIVATE KEY")) {/** 通过openssl pkcs8 -topk8转换为pkcs8,例如(-nocrypt不做额外加密操作):

* openssl pkcs8 -topk8 -in pri.key -out pri8.key -nocrypt

*

* 取得私钥 for PKCS#8*/PKCS8EncodedKeySpec privKeySpec= newPKCS8EncodedKeySpec(pemContent);

KeyFactory kf= KeyFactory.getInstance("rsa");

privKey=kf.generatePrivate(privKeySpec);

}

}catch(FileNotFoundException e) {

logger.error("read private key fail,the reason is the file not exist");

e.printStackTrace();

}catch(IOException e) {

logger.error("read private key fail,the reason is :"+e.getMessage());

e.printStackTrace();

}catch(NoSuchAlgorithmException e) {

logger.error("read private key fail,the reason is :"+e.getMessage());

e.printStackTrace();

}catch(InvalidKeySpecException e) {

logger.error("read private key fail,the reason is :"+e.getMessage());

e.printStackTrace();

}finally{try{if (pemReader != null) {

pemReader.close();

}

}catch(IOException e) {

logger.error(e.getMessage());

}

}returnprivKey;

}/**

* 获取SSLContext,基于CA, Certificate, key及密码进行SSL上下文的创建

*

* @param caPath

* @param crtPath

* @param keyPath

* @param password

* @return

* @throws Exception*/

private staticSSLContext getSSLContext(String caPath, String crtPath, String keyPath, String password) throws Exception {/** CA证书是用来认证服务端的,这里的CA就是一个公认的认证证书

* TrustManagerFactory 管理的是授信的CA证书,所以KeyStore里面存放的不需要私钥信息,通常也不可能有*/CertificateFactory cAf= CertificateFactory.getInstance("X.509");

FileInputStream caIn= newFileInputStream(caPath);

X509Certificate ca=(X509Certificate) cAf.generateCertificate(caIn);

KeyStore caKs= KeyStore.getInstance("JKS");

caKs.load(null, password.toCharArray());

caKs.setCertificateEntry("ca1", ca); //可以通过设置alias不同,配置多个ca实例,即配置多个可信的root CA。

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");

tmf.init(caKs);

caIn.close();//这个客户端证书,是用来发送给服务端的,准备做双向验证用的。

CertificateFactory cf = CertificateFactory.getInstance("X.509");

FileInputStream crtIn= newFileInputStream(crtPath);

X509Certificate caCert=(X509Certificate) cf.generateCertificate(crtIn);

crtIn.close();//客户端私钥,是用来处理双向SSL验证中服务端用客户端证书加密的数据的解密(解析签名)工具

KeyStore ks = KeyStore.getInstance("JKS");

ks.load(null, password.toCharArray());

ks.setCertificateEntry("certificate3", caCert);

String sslPath= "E:\HOWTO\emqtt-ssl\self1\";

FileInputStream crtIn1= new FileInputStream(sslPath + "chainca1.crt");

FileInputStream crtIn2= new FileInputStream(sslPath + "chainca2.crt");

X509Certificate caCert1=(X509Certificate) cf.generateCertificate(crtIn1);

X509Certificate caCert2=(X509Certificate) cf.generateCertificate(crtIn2);

crtIn1.close();

crtIn2.close();

ks.setCertificateEntry("certificate1", caCert1);

ks.setCertificateEntry("certificate2", caCert2);

PrivateKey privateKey= getPrivateKey(newFile(keyPath));/** 注意:下面这行代码中非常重要的一点是:

* setKeyEntry这个函数的第二个参数 password,他不是指私钥的加密密码,只是KeyStore对这个私钥进行管理设置的密码

*

* setKeyEntry中最后一个参数,chain的顺序是证书链中越靠近当前privateKey节点的证书,越靠近数字下标0的位置。即chain[0]是privateKey对应的证书,

* chain[1]是签发chain[0]的证书,以此类推,有chain[i+1]签发chain[i]的关系。*/ks.setKeyEntry("private-key", privateKey, password.toCharArray(), newCertificate[]{caCert, caCert2, caCert1});/** KeyManagerFactory必须是证书和私钥配对使用,即KeyStore里面装载客户端证书以及对应的私钥,双向SSL验证需要。*/KeyManagerFactory kmf= KeyManagerFactory.getInstance("PKIX");

kmf.init(ks, password.toCharArray());/** 最后创建SSL套接字工厂 SSLSocketFactory

* 注意:这里,SSLContext不支持TLSv2创建*/SSLContext context= SSLContext.getInstance("TLSv1");

KeyManager[] kms=kmf.getKeyManagers();

TrustManager[] tms=tmf.getTrustManagers();

context.init(kms, tms,newSecureRandom());returncontext;

}/**

* 基于给定的CA文件,客户端证书文件以及客户端私钥文件,进行SSL上下文环境的构建, 此处创建的SSLSocketFactory是支持双向SSL验证的。

*

* NOTE: 证书及秘钥文件,都是通过openssl创建获取的。

*

* @param caPath CA证书文件

* @param crtPath 客户证书文件

* @param keyPath 客户私钥文件

* @param password KeyStore存储私钥配置的安全密码,类似数据库存了数据,想访问,需要密码一样。

* @return

* @throws Exception*/

public staticSSLSocketFactory getSSLSocketFactory(String caPath, String crtPath, String keyPath, String password) throws Exception {

SSLContext ctx=getSSLContext(caPath, crtPath, keyPath, password);

SSLSocketFactory factory=ctx.getSocketFactory();returnfactory;

}

}

最后

以上就是魁梧乌冬面为你收集整理的mqtt java ssl_MQTT研究之EMQ:【SSL证书链验证】的全部内容,希望文章能够帮你解决mqtt java ssl_MQTT研究之EMQ:【SSL证书链验证】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部