Import PEM into Java Key Store

匿名 (未验证) 提交于 2019-12-03 02:11:02

问题:

I am trying to connect to an SSL server which requires me to authenticate myself. In order to use SSL over Apache MINA I need a suitable JKS file. However, I have only been given a .PEM file.

How would I go about creating a JKS file from a PEM file?

回答1:

First, convert your certificate in a DER format :

openssl x509 -outform der -in certificate.pem -out certificate.der

And after, import it in the keystore :

keytool -import -alias your-alias -keystore cacerts -file certificate.der


回答2:

If you only want to import a certificate in PEM format into a keystore, keytool will do the job:

keytool -import -alias *alias* -keystore cacerts -file *cert.pem*


回答3:

I've developed http://code.google.com/p/java-keyutil/ which imports PEM certificates straight into a Java keystore. Its primary purpose is to import a multi-part PEM Operating System certificate bundles such as ca-bundle.crt. These often includes headers which keytool cannot handle

</self promotion>


回答4:

In my case I had a pem file which contained two certificates and an encrypted private key to be used in mutual SSL authentication. So my pem file looked like this:

-----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-----

Here is what I did

Split the file into three separate files, so that each one contains just one entry, starting with ---BEGIN.. and ending with ---END.. lines. Lets assume we now have three files: cert1.pem, cert2.pem, and pkey.pem.

Convert pkey.pem into DER format using openssl and the following syntax:

openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER

Note, that if the private key is encrypted you need to supply a password( obtain it from the supplier of the original pem file ) to convert to DER format, openssl will ask you for the password like this: "enter a passphrase for pkey.pem: ".

If conversion is successful, you will get a new file called pkey.der.

Create a new java keystore and import the private key and the certificates:

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());

(optional) Verify the content of your new key store:

$ keytool -list -keystore mykeystore -storepass password

Keystore type: JKS Keystore provider: SUN

Your keystore contains 3 entries:

  • cn=...,ou=...,o=.., Sep 2, 2014, trustedCertEntry, Certificate fingerprint (SHA1): 2C:B8: ...

  • importkey, Sep 2, 2014, PrivateKeyEntry, Certificate fingerprint (SHA1): 9C:B0: ...

  • cn=...,o=...., Sep 2, 2014, trustedCertEntry, Certificate fingerprint (SHA1): 83:63: ...

(optional) Test your certificates and private key from your new key store against your SSL server: ( You may want to enable debugging as an VM option: -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..

Finally register your certificates with HttpsURLConnection if plan to use it:

        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);


回答5:

I'm always forgetting how to do this because it's something that I just do once in a while, this is one possible solution, and it just works:

  1. Go to your favourite browser and download the main certificate from the secured website.
  2. Execute the two following lines of code:

    $ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der $ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der
  3. If executing in Java SE environment add the following options:

    $ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar
  4. Or add the following to the java code:

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

The other option for step 2 is to just using the keytool command. Bellow is an example with a chain of certificates:

$ 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


回答6:

If you need an easy way to load PEM files in Java without having to deal with external tools (opensll, keytool), here is my code I use in production :

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));     }  }

Have fun.



转载请标明出处:Import PEM into Java Key Store
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!