关于证书验证,网上许多文章可能会有很大区别,有些属于自签证书,这个没在实战中使用过,所以文章只说明一些特殊接口的证书问题。
文章只以我自己项目举例,不通用所有情况。
文章证书来源
由于我负责的接口,是需要先向第三方接口提供方提交证书,进行报备,然后使用提交的证书,进行证书认证,如果你的问题是自签证书,可能本文章的思路无法帮助到你,文章我会贴出部分源码
证书说明
由客户提供的证书(证书格式为PEM文件),同时提供了一个.key的私钥文件
PEM文件内容为
-----BEGIN CERTIFICATE-----
加密后的数据
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
加密后的数据
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
加密后的数据
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
加密后的数据
-----END CERTIFICATE-----
其实是四个证书组合成的一个证书,分别是Internal Root CA,apigateway,BlueCerts,OnDemand Issuing可能描述的不太准确,这个是我在第三方接口说明获取到的信息,可以不用纠结这个,因为证书生成跟你没关系
KEY文件内容为
----BEGIN RSA PRIVATE KEY-----
加密后的数据
-----END RSA PRIVATE KEY-----
网上许多参考文献,其实对这个说明很模棱两可,有些说需要格式转换,但是我在使用过程中,并没有进行格式转换
组合证书
到这一步,可能会难倒很多人,因为网上各种说法,真的很容易让人混乱,我大概整理了一下我的思路
关于证书
PEM文件:采用 PEM 编码格式的 X.509 证书的文件扩展名;
DER文件:采用 DER 编码格式的 X.509 证书的文件扩展名;
CRT文件:UNIX 系统,可能是 PEM 编码,也可能是 DER 编码,大多数情况下都是采用 PEM 编码;
CER文件:Windows 系统,可能是 PEM 编码,也可能是 DER 编码,大多数情况下都是采用 DER 编码
他们都是使用X.509的证书文件,只是编码格式有区别,这个需要搞清楚,不要搞混了,都是可以相互转换的,具体转换命令自行百度
key文件
key文件有很多种格式,key文件是私钥,可能是.key.pem或者其他,其实跟上面证书意思差不多,都是编码格式,这里客户提供给我们的文件是.key的后缀文件
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
证书 + key组合最终用于认证的文件
最终的文件为PKCS#12文件,他有两种后缀,一种为pfx和p12,两种区别不大
使用下列命令
将PEM证书文件和私钥转换为PKCS#12(.pfx .p12)
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt
-out文件,我理解为一个组合文件,证书 + 私钥,可以为.pfx文件,p12文件
-inkey文件,表示私钥,一般为带有key后缀或者,.key.pem等,如果没有带有key后缀,可以查看文件,参看上面
-in文件,表示证书,参考证书说明,可以是.crt .cer .pem .der
上面OpenSSL命令还有另一个版本,但是我实际应用中,没有用到(我没有深入了解原理,只是开发中使用到了)
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt
这里的-certfile文件 CACert.crt文件,其实我不太懂,他具体是用来干嘛的
执行上面的命令以后,会提示你输入密码,我设置了密码(这个不设密码我没有试过)
下面是我遇到的坑,仅供参考
我设置的密码很长,因为是密码是第三方提供的接口账号的密码,在Windows操作窗口使用OpenSSL执行转换命令后,生成的文件会有问题(具体问题未知,可能是我没有配置环境变量),不是无法生成,而是生成的文件有问题,所以我在公司服务器Linux上进行转换的文件
关于代码应用
先说代码的坑,之前网上各种找案例,最后发现,好像与自己的需求不太匹配。
/*
clientConfig是我定义的配置信息,包括需要访问的地址,搭配证书使用的参数等
*/
private HttpResponse merchantQARegisterSend(String param, String fileUrl, ClientConfig clientConfig) {
HttpResponse response = null;
try (FileInputStream inStream = new FileInputStream(fileUrl)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(inStream, clientConfig.getClientSecret().toCharArray());
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, clientConfig.getClientSecret().toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext, new String[]{"TLSv1", "TLSv1.2"}, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
org.apache.http.client.config.RequestConfig defaultRequestConfig = org.apache.http.client.config.RequestConfig.custom()
.setSocketTimeout(5000)
.setConnectTimeout(5000)
.setConnectionRequestTimeout(5000)
.setStaleConnectionCheckEnabled(true)
.build();
CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig)
.setSSLSocketFactory(sslsf)
.build();
HttpPost post = new HttpPost(clientConfig.getUrl());
org.apache.http.client.config.RequestConfig requestConfig = org.apache.http.client.config.RequestConfig.custom()
.setConnectTimeout(90 * 1000)
.setSocketTimeout(90 * 1000)
.build();
post.setConfig(requestConfig);
properties.put("KEY", clientConfig.getKey());
StringEntity entity = new StringEntity(param, "utf-8");
entity.setContentType("application/json");
post.setEntity(entity);
Properties properties = new Properties();
PropertiesConfigurationProvider configurationProvider = new PropertiesConfigurationProvider();
configurationProvider.setProperties(properties);
AuthProvider authProvider = HmacAuthBuilder.getBuilder()
.setConfiguration(configurationProvider)
.build();
//转换成map,写入请求的header中
Map<String, String> headers = authProvider.generateAuthHeaders(param, clientConfig.getUrl(), "POST");
for (Map.Entry<String, String> header : headers.entrySet()) {
post.setHeader(header.getKey(), header.getValue());
}
response = httpclient.execute(post);
} catch (Exception e) {
}
return response;
}