Импорт PEM в хранилище ключей Java
Я пытаюсь подключиться к серверу SSL, который требует от меня аутентификации. Для того, чтобы использовать SSL через Apache MINA мне нужен подходящий файл JKS. Однако мне дали только один.Файл PEM.
Как я могу создать файл JKS из файла PEM?
8 ответов:
во-первых, конвертировать сертификат в формате DER :
openssl x509 -outform der -in certificate.pem -out certificate.der
и после, импортировать его в хранилище ключей :
keytool -import -alias your-alias -keystore cacerts -file certificate.der
Если вы хотите импортировать сертификат только в формате PEM в хранилище ключей, keytool выполнит эту работу:
keytool -import -alias *alias* -keystore cacerts -file *cert.pem*
Я разработал http://code.google.com/p/java-keyutil/ который импортирует сертификаты PEM прямо в хранилище ключей Java. Его основной целью является импорт пакетов сертификатов операционной системы PEM из нескольких частей, таких как ca-bundle.ЭЛТ. Они часто включают заголовки, которые keytool не может обрабатывать
</self promotion>
в моем случае у меня был файл pem, который содержал два сертификата и зашифрованный закрытый ключ для использования во взаимной аутентификации SSL. Так что мой PEM файл выглядел так:
-----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-----
вот что я сделал
разделить файл на три отдельных файла, так что каждый из них содержит только одну запись, начиная с
---BEGIN..
и заканчивая---END..
строки. Предположим, что теперь у нас есть три файла:cert1.pem
,cert2.pem
иpkey.pem
.преобразование
pkey.pem
в DER форматирование с использованием openssl и следующего синтаксиса:openssl pkcs8-topk8-nocrypt-in pkey.PEM-inform PEM-out pkey.der-outform DER
обратите внимание, что если закрытый ключ зашифрован, вам необходимо предоставить пароль( получить его от поставщика исходного файла pem ) для преобразования в формат DER,
openssl
попросит вас ввести пароль следующим образом: "введите пароль дляpkey.pem
: ".если преобразование успешно, вы получите новый файл называется
pkey.der
.создайте новое хранилище ключей java и импортируйте закрытый ключ и сертификаты:
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());
(необязательно) проверьте содержимое вашего нового хранилища ключей:
$ keytool -list -keystore mykeystore -storepass password
тип хранилища ключей: JKS Поставщик хранилища ключей: SUN
ваше хранилище ключей содержит 3 записи:
cn=..., ou=...,о.=., 2 сентября 2014, trustedCertEntry, Отпечаток пальца сертификата (SHA1): 2C:B8: ...
importkey, 2 сентября 2014, PrivateKeyEntry, Отпечаток пальца сертификата (SHA1): 9C: B0:...
cn=...,о.=..., 2 сентября 2014, trustedCertEntry, Отпечаток пальца сертификата (SHA1): 83: 63:...
(необязательно) Проверьте сертификаты и закрытый ключ из нового хранилища ключей на сервере SSL: ( Вы можете включить отладку как вариант ВМ: -Djavax.чистая.отладки=все )
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..
наконец зарегистрируйте свои сертификаты с помощью HttpsURLConnection, если планируете использовать его:
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);
Я всегда забываю, как это сделать, потому что это то, что я просто делаю время от времени, это одно из возможных решений, и оно просто работает:
- перейдите в свой любимый браузер и загрузите основной сертификат с защищенного веб-сайта.
выполнить две следующие строки кода:
$ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der $ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der
при выполнении в среде Java SE добавьте следующие параметры:
$ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar
или добавить после кода java:
System.setProperty("javax.net.ssl.trustStore", "GlobalSignRootCA.jks"); System.setProperty("javax.net.ssl.trustStorePassword","trustStorePassword");
другой вариант для шага 2-это просто использовать . Ниже приведен пример с цепочкой сертификатов:
$ keytool -import -file org.eu.crt -alias orgcrt -keystore globalsignrs.jks $ keytool -import -file GlobalSignOrganizationValidationCA-SHA256-G2.crt -alias globalsignorgvalca -keystore globalsignrs.jks $ keytool -import -file GlobalSignRootCA.crt -alias globalsignrootca -keystore globalsignrs.jks
Если вам нужен простой способ загрузки файлов PEM в Java без необходимости иметь дело с внешними инструментами (opensll, keytool), вот мой код, который я использую в производстве:
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.List; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.xml.bind.DatatypeConverter; public class PEMImporter { public static SSLServerSocketFactory createSSLFactory(File privateKeyPem, File certificatePem, String password) throws Exception { final SSLContext context = SSLContext.getInstance("TLS"); final KeyStore keystore = createKeyStore(privateKeyPem, certificatePem, password); final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(keystore, password.toCharArray()); final KeyManager[] km = kmf.getKeyManagers(); context.init(km, null, null); return context.getServerSocketFactory(); } /** * Create a KeyStore from standard PEM files * * @param privateKeyPem the private key PEM file * @param certificatePem the certificate(s) PEM file * @param the password to set to protect the private key */ public static KeyStore createKeyStore(File privateKeyPem, File certificatePem, final String password) throws Exception, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { final X509Certificate[] cert = createCertificates(certificatePem); final KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(null); // Import private key final PrivateKey key = createPrivateKey(privateKeyPem); keystore.setKeyEntry(privateKeyPem.getName(), key, password.toCharArray(), cert); return keystore; } private static PrivateKey createPrivateKey(File privateKeyPem) throws Exception { final BufferedReader r = new BufferedReader(new FileReader(privateKeyPem)); String s = r.readLine(); if (s == null || !s.contains("BEGIN PRIVATE KEY")) { r.close(); throw new IllegalArgumentException("No PRIVATE KEY found"); } final StringBuilder b = new StringBuilder(); s = ""; while (s != null) { if (s.contains("END PRIVATE KEY")) { break; } b.append(s); s = r.readLine(); } r.close(); final String hexString = b.toString(); final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString); return generatePrivateKeyFromDER(bytes); } private static X509Certificate[] createCertificates(File certificatePem) throws Exception { final List<X509Certificate> result = new ArrayList<X509Certificate>(); final BufferedReader r = new BufferedReader(new FileReader(certificatePem)); String s = r.readLine(); if (s == null || !s.contains("BEGIN CERTIFICATE")) { r.close(); throw new IllegalArgumentException("No CERTIFICATE found"); } StringBuilder b = new StringBuilder(); while (s != null) { if (s.contains("END CERTIFICATE")) { String hexString = b.toString(); final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString); X509Certificate cert = generateCertificateFromDER(bytes); result.add(cert); b = new StringBuilder(); } else { if (!s.startsWith("----")) { b.append(s); } } s = r.readLine(); } r.close(); return result.toArray(new X509Certificate[result.size()]); } private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); final KeyFactory factory = KeyFactory.getInstance("RSA"); return (RSAPrivateKey) factory.generatePrivate(spec); } private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException { final CertificateFactory factory = CertificateFactory.getInstance("X.509"); return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes)); } }
получать удовольствие.
существует также инструмент GUI, который позволяет создавать визуальные JKS и импортировать сертификаты.
http://portecle.sourceforge.net/
Portecle-это удобное графическое приложение для создания, управления и изучения хранилищ ключей, ключей, сертификатов, запросов сертификатов, списков отзыва сертификатов и многое другое.
Я получил его из интернета. Он работает довольно хорошо для файлов pem, которые содержат несколько записей.
#!/bin/bash pemToJks() { # number of certs in the PEM file pemCerts= certPass= newCert=$(basename "$pemCerts") newCert="${newCert%%.*}" newCert="${newCert}"".JKS" ##echo $newCert $pemCerts $certPass CERTS=$(grep 'END CERTIFICATE' $pemCerts| wc -l) echo $CERTS # For every cert in the PEM file, extract it and import into the JKS keystore # awk command: step 1, if line is in the desired cert, print the line # step 2, increment counter when last line of cert is found for N in $(seq 0 $(($CERTS - 1))); do ALIAS="${pemCerts%.*}-$N" cat $pemCerts | awk "n==$N { print }; /END CERTIFICATE/ { n++ }" | $KEYTOOLCMD -noprompt -import -trustcacerts \ -alias $ALIAS -keystore $newCert -storepass $certPass done } pemToJks <pem to import> <pass for new jks>