我不知道答案是否完美。就我而言,我有服务器提供的 pem 格式的 X.509 证书和 RSA 密钥。进行 REST 调用时需要它们。我要做的是将证书和密钥加载到密钥库中,然后创建 SSLContext。然后将此 SSLContext 绑定到 HttpsURLConnection
public SSLContext getSSLContext() {
try {
//== Setting certificate format to X509 and converting bytes to certificate object
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
//== Reading the certificate provided by FDMS API using above format
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new FileInputStream(certsfolder + "server-certificate.pem"));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(new FileInputStream(certsfolder + "privkey.pem").readAllBytes());
KeyFactory kf = KeyFactory.getInstance("RSA");
//== Reading the private key of the client i.e. machine running this code
//== Private key also used in generating certificate by FMDS API
//== Converting key bytes to string for processing
String privateKeyPEM = new String(new FileInputStream(certsfolder + "privkey.pem").readAllBytes())
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PRIVATE KEY-----", "");
//== Decoding key string to base64
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
//== Turning decoded string to PrivateKey object
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
PrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
//== Load the certificate and private key into a keystore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, null); // Initialize an empty keystore
keystore.setCertificateEntry("zimra.co.zw", cert);
//== Important that it has a certificate chain
keystore.setKeyEntry("cottco-1-0000010605", key, "".toCharArray(), new X509Certificate[]{cert});
//== Create SSL context with the keystore
SSLContext sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(keystore, "".toCharArray()) // Use an empty password
.loadTrustMaterial(null, (chain, authType) -> true) // Trust all certificates
.build();
return sslContext;
} catch (KeyStoreException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (CertificateException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeySpecException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnrecoverableKeyException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyManagementException ex) {
Logger.getLogger(InvoiceLocalServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
上面创建了 SSLContext。然后绑定它:
//== Calling method to generate SSL Context for use in TLS Handshake
SSLContext sslContext = getSSLContext();
//== Adding SSL Context to HttpsURLConnection calls
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());