Импорт PEM в хранилище ключей Java

Я пытаюсь подключиться к серверу SSL, который требует от меня аутентификации. Чтобы использовать SSL поверх Apache MINA, мне нужен подходящий файл JKS. Однако мне был предоставлен только файл .PEM.

Как я могу создать файл JKS из файла PEM?

Сначала конвертируйте свой сертификат в формат 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.crt. Они часто include заголовки, которые keytool не может обрабатывать

  

В моем случае у меня был файл 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 , у нас теперь есть три файла: 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 Поставщик Keystore: SUN

Ваше хранилище ключей содержит 3 записи:

  • cn = …, ou = …, o = .., Sep 2, 2014, trustedCertEntry, Отпечаток сертификата (SHA1): 2C: B8: …

  • importkey, Sep 2, 2014, PrivateKeyEntry, отпечаток сертификата (SHA1): 9C: B0: …

  • cn = …, o = …., 2 сентября 2014, trustedCertEntry, отпечаток сертификата (SHA1): 83:63: …

(необязательно) Проверьте свои сертификаты и закрытый ключ из вашего нового хранилища ключей против вашего сервера SSL: (Возможно, вы захотите включить отладку в качестве опции 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.. 

Наконец, зарегистрируйте свои сертификаты с помощью 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); 

Я всегда забываю, как это сделать, потому что это то, что я делаю время от времени, это одно возможное решение, и оно просто работает:

  1. Перейдите в свой любимый браузер и загрузите основной сертификат с защищенного сайта.
  2. Выполните две следующие строки кода:

     $ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der $ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der 
  3. При выполнении в среде Java SE добавьте следующие параметры:

     $ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar 
  4. Или добавьте в java-код следующее:

     System.setProperty("javax.net.ssl.trustStore", "GlobalSignRootCA.jks"); System.setProperty("javax.net.ssl.trustStorePassword","trustStorePassword"); 

Другой вариант для шага 2 – просто использовать команду keytool . Ниже приведен пример с цепочкой сертификатов:

 $ 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 result = new ArrayList(); 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=$1 certPass=$2 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   
  • Java: функция переопределения для отключения проверки сертификата SSL
  • Как заблокировать определенный HTTPS-трафик?
  • Thunderbird: Ошибка: imap.server.com: сервер не поддерживает RFC 5746, см. CVE-2009-3555
  • Отключить SSLv3 в основных браузерах
  • Настройка Apache для обслуживания нескольких поддоменов через HTTP + HTTPS
  • Недопустимый самоподписанный SSL-сертификат - «Тема альтернативного имени отсутствует»
  • Могут ли клиенты telnet или netcat связываться через SSL?
  • Доверяйте всем сертификатам, используя HttpClient over HTTPS
  • Не удалось добавить сертификат SSL при привязке к порту
  • Как установить доверенный сертификат CA на Android-устройство?
  • Как заставить java-сервер принимать только tls 1.2 и отклонять tls 1.0 и tls 1.1 соединения
  • Давайте будем гением компьютера.