1.构建Retrofit

1
2
3
4
5
6
7
Retrofit retrofit = builder.baseurl(baseUrl)
.sslSocketFactory(SSLHelper.getSSLCertifcation(path,
StateConfig.getInstance().getCertServerPath(),
StateConfig.getInstance().getPassword()), new
HttpsUtil.UnSafeTrustManager())
.hostnameVerifier(new HttpsUtil.UnSafeHostnameVerifier())
.build();

在构建Retrofit实例的时候,传入sslSocketFactory和trustManager

2.PKCS#12格式证书(.jks)构建sslSocketFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public static SSLSocketFactory getSSLCertifcation(String certPath, String certServerPath, String password) {
SSLSocketFactory sslSocketFactory = null;
try {
//计算证书密码
password = Utils.SHA1Algorithm(password);
// 服务器端需要验证的客户端证书,其实就是客户端的keystore
KeyStore keyStore = KeyStore.getInstance(Constants.CLIENT_KEYSTORE_TYPE);
// 客户端信任的服务器端证书
KeyStore trustStore = KeyStore.getInstance(Constants.SERVER_KEYSTORE_TYPE);

InputStream ksIn = null;
InputStream tsIn = null;
try {
//读取证书
ksIn = new FileInputStream(new File(certPath));
tsIn = new FileInputStream(new File(certServerPath));
//ksIn = context.getAssets().open("Data_Secret_CA.pfx");
//tsIn = context.getAssets().open("certCA.bks");

//加载证书
keyStore.load(ksIn, password.toCharArray());
trustStore.load(tsIn, Constants.TRUSTSTORE_BKS_PASSWORD.toCharArray());
} catch (Exception e) {
LogUtils.e(TAG, "please ensure the path of certs contain the certificates !");
} finally {
if (ksIn != null) {
ksIn.close();
}
if (tsIn != null) {
tsIn.close();
}
}

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(Constants.CERTIFICATE_STANDARD);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(Constants.CERTIFICATE_STANDARD);
trustManagerFactory.init(trustStore);
keyManagerFactory.init(keyStore, password.toCharArray());

//初始化SSLContext
SSLContext sslContext = SSLContext.getInstance(Constants.PROTOCOL_TYPE);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());

sslSocketFactory = sslContext.getSocketFactory();
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | UnrecoverableKeyException |
KeyManagementException | DigestException e) {
e.printStackTrace();
}
return sslSocketFactory;
}

3.PKCS#8格式证书构建sslSocketFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
public class GACPemTlsDemo {
private static String VEHICLE_CRT_PATH = "D:\\gac_xinghe\\vehicleCA.crt";
private static String VEHICLE_KEY_PATH = "D:\\gac_xinghe\\vehicleCA.key";
private static String VEHICLE_KEY_PWD = "53A070BD720A2D9ED38EDA72C3EBE854A2AEE92B";
private static String ROOT_CRT_PATH = "D:\\gac_xinghe\\rootCA.crt";

private static String API_URL = "https://xx.xx.com";


public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException, InvalidKeyException, InvalidKeySpecException {
System.setProperty("javax.net.debug", "ssl");//输出SSL通讯信息
/* 读取证书证书 */
String vehicleCrt = readVehicleStr(VEHICLE_CRT_PATH);
Map<String, String> rootMap = readRootCA(ROOT_CRT_PATH);
String root1 = rootMap.get("root1");
String root2 = rootMap.get("root2");

/*构造客户端证书的KeyStore*/
char[] pwd = "123456".toCharArray(); //构造keyStore对象,需要设定的密码,该密码可以任意设置

Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(new BouncyCastleProvider());

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

//构造客户端证书的KeyStore对象
KeyStore clientCertKeyStore = KeyStore.getInstance("BKS", bcProvider);
clientCertKeyStore.load(null, pwd);
//读取车端证书,公钥
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decodeBase64(vehicleCrt));
X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(bais);

//定义车端证书alias
String keyAlias = "vehicleCA";

KeyPair keyPair = getKey(VEHICLE_KEY_PWD, VEHICLE_KEY_PATH);

Certificate[] certificates = new Certificate[]{x509Certificate};
clientCertKeyStore.setKeyEntry(keyAlias, keyPair.getPrivate(), pwd, certificates);

//构造可信服务端证书的KeyStore对象
KeyStore trustKeyStore = KeyStore.getInstance("BKS", bcProvider);
trustKeyStore.load(null, pwd);
//读取根证书
ByteArrayInputStream trust1Bais = new ByteArrayInputStream(Base64.decodeBase64(root1));
X509Certificate trust1X509Certificate = (X509Certificate) certificateFactory.generateCertificate(trust1Bais);
trustKeyStore.setCertificateEntry("root1", trust1X509Certificate);

ByteArrayInputStream trust2Bais = new ByteArrayInputStream(Base64.decodeBase64(root2));
X509Certificate trust2X509Certificate = (X509Certificate) certificateFactory.generateCertificate(trust2Bais);
trustKeyStore.setCertificateEntry("root2", trust2X509Certificate);

SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(trustKeyStore, new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}})
.loadKeyMaterial(clientCertKeyStore, pwd)
.build();

SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"},// 协议
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());

CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();

List<NameValuePair> parameters = new ArrayList<NameValuePair>();

HttpPost httpPost = new HttpPost(API_URL);
httpPost.setEntity(new UrlEncodedFormEntity(parameters,Charset.forName("UTF-8")));

httpPost.setHeader("Content-AppKey", "");
httpPost.setHeader("Content-Signature","" );
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpPost);

int status = response.getStatusLine().getStatusCode();
System.out.println("通讯返回状态码:"+status);

HttpEntity entity = response.getEntity();

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

copy(entity.getContent(),outputStream);

String respStr = new String(outputStream.toByteArray(), "UTF-8");

System.out.println("返回结果:"+respStr);
}

public static long copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024 * 4];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
public static KeyPair getKey(String keyPWD,String keyFile) {
Security.addProvider(new BouncyCastleProvider());
try {
File privateKeyFile = new File(keyFile); // private key file in PEM format
PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile));
Object object = pemParser.readObject();
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(keyPWD.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
if (object instanceof PEMEncryptedKeyPair) {
return converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
} else {
return converter.getKeyPair((PEMKeyPair) object);
}

} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String readVehicleStr(String filePath) {
String pemStr = "";
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
String lineStr = null;
while((lineStr=bufferedReader.readLine())!=null){
if(lineStr.length()== 0 || lineStr.indexOf(": ")>=0 || lineStr.indexOf("-----BEGIN")>=0 || lineStr.indexOf("-----END")>=0 ) {
continue;
}
pemStr+= lineStr.replace("\t", "");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return pemStr;
}

public static Map<String, String> readRootCA(String filePath) {
Map<String, String> retMap = new HashMap<String, String>();
String root1Str = "";
String root2Str = "";
int bolCount = 0;
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
String lineStr = null;
while((lineStr=bufferedReader.readLine())!=null){
if(lineStr.length()== 0 ) {
continue;
}
if(lineStr.indexOf("-----BEGIN")>=0) {
bolCount ++ ;
continue;
}
if(lineStr.indexOf("-----END")>=0 ) {
continue;
}

if(bolCount<=1) {
root1Str+= lineStr.replace("\t", "");
}else {
root2Str+= lineStr.replace("\t", "");
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

retMap.put("root1", root1Str);
retMap.put("root2", root2Str);

return retMap;
}
}

依赖库:bcprov-jdk15on-1.57.jar和bcpkix-jdk15on-1.57.jar

4.使用openssl读取加密私钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//此demo提供一种openssl获取私钥文件的方式
//如果使用EVP_PKEY格式私钥,可以调用EVP_PKEY_set1_RSA接口实现

int pass_cb(char* buf,int size,int rwflag,void* u)
{
if(!u || strlen((char*)u) <=0)
return 0;

const char* pwd = (char*)u;

LOG_I("pass_cb ,%s",pwd);

char pass[44] = {0};
int plen = 44;

//调用szitrus_certPass 计算得到pass和plen

size_t len = plen;

memcpy(buf, pass, len);
return len;
err:

return ret;
}


//读取私钥文件,pass_cb为回调接口,计算口令
int readRSAPrivateKey(RSA** rsa,const char* path,const char* pwd)
{
if(!path )
return ERROR_PARAM;

FILE* fp = NULL;
int ret = 0;

fp= fopen(path,"r");
if(!fp){
ret = 1;
goto err;
}

if(!*rsa){
*rsa = RSA_new();
if(!*rsa){
ret = 1;
goto err;
}
}

*rsa = PEM_read_RSAPrivateKey(fp,NULL,pass_cb,pwd);
if(!*rsa){
ret = 1;
}

fclose(fp);

return 0;
err:
if(fp){
fclose(fp);
}

if(*rsa){
RSA_free(*rsa);
}

return 0;
}

查看私钥key是不是PKCS#1, PKCS#1格式的证书没有ASN.1格式

ASN.1 JavaScript decoder (lapo.it)

参考代码:

1.TLS_Okhttp融合