在项目中使用到了tlsv1.2来请求三方支付渠道,在拿到证书xxx.crt 和 密钥 xxx.key后,通过java代码配置keyStore和trustStore后一直报错,说加载证书失败,经查询发现java不能直接加载crt和key文件,需要转换成.p12或者.jks格式的文件
以下是转换方式:
.crt 转 .cer
openssl x509 -in xxx.crt -out xxx.cer -outform der
.cer 转 truststore
keytool -import -alias "merchant-support" -file xxx.cer -keystore xxx.truststore
.crt 转 .p12
openssl pkcs12 -export -in xxx.crt -inkey 20181030.key -out ms.p12 -name xxx
转换后如果直接用java加载keyStore和trustStore总是提示没有找到信任库,可以在项目发布的jdk中导入信任库,然后加载的时候不是用信任库,就会默认的使用jdk中的信任库。
如下,创建SSLContext
public static SSLContext getSSLContext(String password, String keyStorePath, String trustKeyStorePath)
throws Exception {
//KeyStore用于存放证书,创建对象时 指定交换数字证书的加密标准
File keyFile = new File(keyStorePath);
InputStream keyStoreStream = new FileInputStream(keyFile);
char[] pwdBArray = password.toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS12"); //KeyStore.getInstance(KeyStore.getDefaultType());
log.info("========KeyStore 加载========== keyStorePath :{},password:{}", keyStorePath, password);
keyStore.load(keyStoreStream, pwdBArray);
//KeyManager选择证书证明自己的身份
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, pwdBArray);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
/* //TrustManager决定是否信任对方的证书
// 取到证书的输入流
InputStream trustKeyStoreStream = new FileInputStream(trustKeyStorePath);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); //KeyStore.getInstance(KeyStore.getDefaultType());
log.info("========KeyStore 加载========== trustKeyStorePath :{},password:{}", trustKeyStorePath, password);
trustStore.load(trustKeyStoreStream, pwdBArray);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();*/
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(keyManagers, null, new java.security.SecureRandom());
keyStoreStream.close();
// trustKeyStoreStream.close();
return context;
}
使用SSLContext ,
String certFilePath = "/path/xxx.p12";
String certClientFilePath = "/path/xxx.truststore";
String certPassword = "xxx.p12 password";
CloseableHttpClient httpClient;
try {
SSLContext sslContext = CertificateManager.getSSLContext(certPassword, certFilePath, certClientFilePath);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.setSslcontext(sslContext)
.build();
} catch (Exception e) {
e.printStackTrace();
}
导入jdk证书
cd /usr/java/jre1.8.0_73/lib/security/
keytool -import -alias xxx -keystore cacerts -file /path/xxx.cer -trustcacerts
keytool -import -keystore cacerts -file /path/xxx.cer -trustcacerts
此时命令行会提示你输入cacerts证书库的密码,你敲入changeit就行了,这是java中cacerts证书库的默认密码
至此,https tlsv1.2通信已经可以通了