How to import an existing X.509 certificate and private key in Java keystore to use in SSL?

前端 未结 15 1049
说谎
说谎 2020-11-22 08:05

I have this in an ActiveMQ config:


        

        
15条回答
  •  轮回少年
    2020-11-22 08:17

    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 pass phraze for pkey.pem: " If conversion is successful, you will get a new file called "pkey.der"

    Create a new java key store 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);
    

提交回复
热议问题