Trong trường hợp của tôi, tôi đã có một tệp pem chứa hai chứng chỉ và khóa riêng được mã hóa để sử dụng trong xác thực SSL lẫn nhau. Vì vậy, tập tin pem của tôi trông như thế này:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C8BF220FC76AA5F9
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
Đây là những gì tôi đã làm:
Chia tệp thành ba tệp riêng biệt, sao cho mỗi tệp chỉ chứa một mục nhập, bắt đầu bằng "--- BEGIN .." và kết thúc bằng dòng "--- END ..". Giả sử bây giờ chúng ta có ba tệp: cert1.pem cert2.pem và pkey.pem
Chuyển đổi pkey.pem sang định dạng DER bằng openssl và cú pháp sau:
openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER
Lưu ý rằng nếu khóa riêng được mã hóa, bạn cần cung cấp mật khẩu (lấy từ nhà cung cấp tệp pem gốc) để chuyển đổi sang định dạng DER, openssl sẽ yêu cầu bạn nhập mật khẩu như sau: "nhập mật khẩu cho pkey .pem: "Nếu chuyển đổi thành công, bạn sẽ nhận được một tệp mới có tên là" pkey.der "
Tạo một kho lưu trữ khóa java mới và nhập khóa riêng và chứng chỉ:
String keypass = "password"; // this is a new password, you need to come up with to protect your java key store file
String defaultalias = "importkey";
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
// this section does not make much sense to me,
// but I will leave it intact as this is how it was in the original example I found on internet:
ks.load( null, keypass.toCharArray());
ks.store( new FileOutputStream ( "mykeystore" ), keypass.toCharArray());
ks.load( new FileInputStream ( "mykeystore" ), keypass.toCharArray());
// end of section..
// read the key file from disk and create a PrivateKey
FileInputStream fis = new FileInputStream("pkey.der");
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
byte[] key = new byte[bais.available()];
KeyFactory kf = KeyFactory.getInstance("RSA");
bais.read(key, 0, bais.available());
bais.close();
PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
PrivateKey ff = kf.generatePrivate (keysp);
// read the certificates from the files and load them into the key store:
Collection col_crt1 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert1.pem"));
Collection col_crt2 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert2.pem"));
Certificate crt1 = (Certificate) col_crt1.iterator().next();
Certificate crt2 = (Certificate) col_crt2.iterator().next();
Certificate[] chain = new Certificate[] { crt1, crt2 };
String alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName();
String alias2 = ((X509Certificate) crt2).getSubjectX500Principal().getName();
ks.setCertificateEntry(alias1, crt1);
ks.setCertificateEntry(alias2, crt2);
// store the private key
ks.setKeyEntry(defaultalias, ff, keypass.toCharArray(), chain );
// save the key store to a file
ks.store(new FileOutputStream ( "mykeystore" ),keypass.toCharArray());
(tùy chọn) Xác minh nội dung của kho lưu trữ khóa mới của bạn:
keytool -list -keystore mykeystore -storepass password
Loại kho khóa: JKS Nhà cung cấp khóa: SUN
Kho khóa của bạn chứa 3 mục
cn = ..., ou = ..., o = .., ngày 2 tháng 9 năm 2014, TrustedCertEntry, Chứng nhận dấu vân tay (SHA1): 2C: B8: ...
importkey, ngày 2 tháng 9 năm 2014, PrivateKeyEntry, Dấu vân tay (SHA1): 9C: B0: ...
cn = ..., o = ...., ngày 2 tháng 9 năm 2014, TrustedCertEntry, Chứng chỉ vân tay (SHA1): 83:63: ...
(tùy chọn) Kiểm tra chứng chỉ và khóa riêng từ kho lưu trữ khóa mới của bạn với máy chủ SSL của bạn: (Bạn có thể muốn bật gỡ lỗi dưới dạng tùy chọn VM: -Djavax.net.debug = all)
char[] passw = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
ks.load(new FileInputStream ( "mykeystore" ), passw );
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passw);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sclx = SSLContext.getInstance("TLS");
sclx.init( kmf.getKeyManagers(), tm, null);
SSLSocketFactory factory = sclx.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.1.111", 443 );
socket.startHandshake();
//if no exceptions are thrown in the startHandshake method, then everything is fine..
Cuối cùng đăng ký chứng chỉ của bạn với HttpsURLCconnectection nếu có kế hoạch sử dụng nó:
char[] passw = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS", "SUN");
ks.load(new FileInputStream ( "mykeystore" ), passw );
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passw);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sclx = SSLContext.getInstance("TLS");
sclx.init( kmf.getKeyManagers(), tm, null);
HostnameVerifier hv = new HostnameVerifier()
{
public boolean verify(String urlHostName, SSLSession session)
{
if (!urlHostName.equalsIgnoreCase(session.getPeerHost()))
{
System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
}
return true;
}
};
HttpsURLConnection.setDefaultSSLSocketFactory( sclx.getSocketFactory() );
HttpsURLConnection.setDefaultHostnameVerifier(hv);