SSL/TLS 认证需要服务端提供 KeyStore.jks、TrustStore.jks
实现方式 | 优缺点 |
---|---|
服务端提供 CA、Client CRT、Client Key 文件 | 缺点:服务端提供原始签名,不安全 不建议采用 |
服务端提供 KeyStore.jks、TrustStore.jks、Password | 优点:安全 |
1、通过 CA、Client CRT、Client Key,客户端自己创建 KeyStore、TrustStore,再创建 SSLSocketFactory
/**
* 创建 SSLSocketFactory 工厂
*
* @param caCrtFile 服务端 CA 证书
* @param crtFile 客户端 CRT 文件
* @param keyFile 客户端 Key 文件
* @param password SSL 密码,随机
* @return {@link SSLSocketFactory}
* @throws Exception 异常
*/
public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile, final String password) throws Exception {
InputStream caInputStream = null;
InputStream crtInputStream = null;
InputStream keyInputStream = null;
try {
Security.addProvider(new BouncyCastleProvider());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// load CA certificate
caInputStream = new ClassPathResource(caCrtFile).getInputStream();
X509Certificate caCert = null;
while (caInputStream.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(caInputStream);
}
// load client certificate
crtInputStream = new ClassPathResource(crtFile).getInputStream();
X509Certificate cert = null;
while (crtInputStream.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(crtInputStream);
}
// load client private key
keyInputStream = new ClassPathResource(keyFile).getInputStream();
PEMParser pemParser = new PEMParser(new InputStreamReader(keyInputStream));
Object object = pemParser.readObject();
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair key;
if (object instanceof PEMEncryptedKeyPair) {
System.out.println("Encrypted key - we will use provided password");
key = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
} else {
System.out.println("Unencrypted key - no password needed");
key = converter.getKeyPair((PEMKeyPair) object);
}
pemParser.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("X509");
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.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
finally {
if (null != caInputStream) {
caInputStream.close();
}
if (null != crtInputStream) {
crtInputStream.close();
}
if (null != keyInputStream) {
keyInputStream.close();
}
}
}
2、服务端提供 KeyStore.jks、TrustStore.jks,创建 SSLSocketFactory
/**
* 创建 SSLSocketFactory 工厂
*
* @param keyStoreJks 客户端 KeyStore
* @param trustStoreJks 客户端 信任库 trust store
* @param password 密码
* @return {@link SSLSocketFactory}
* @throws Exception 异常
*/
public static SSLSocketFactory getSocketFactory(final String keyStoreJks, final String trustStoreJks, final String password) throws Exception {
InputStream keyStoreJksInputStream = null;
InputStream trustStoreJksInputStream = null;
try {
ClassPathResource classPathResource = new ClassPathResource(keyStoreJks);
keyStoreJksInputStream = classPathResource.getInputStream();
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(keyStoreJksInputStream, password.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
classPathResource = new ClassPathResource(trustStoreJks);
trustStoreJksInputStream = classPathResource.getInputStream();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(trustStoreJksInputStream, password.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
trustManagerFactory.init(trustStore);
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
return context.getSocketFactory();
}
finally {
try {
if (null != keyStoreJksInputStream) {
keyStoreJksInputStream.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
try {
if (null != trustStoreJksInputStream) {
trustStoreJksInputStream.close();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}