简体   繁体   中英

Imported Private key issue in Java and HTTPS

Java's keytool does not provide a facility to create a new keystore from a private key, or import a private key to an existing jks store. I have a service host that requires they generate the private key and give it to us, the client, to call their service.

The private key and cert is downloaded from them in firefox, exported on a windows machine into p12 formatted file. I used openssl to convert that pkcs12 to a PEM file. I then manually split that file into a cert.der and privateKey.der files respectively. I then wrote a java program to import this pair into our existing keystore (use bouncy castle). I verify the keystore is created and contains my key/cert with keytool after I run the program and it looks good.

The program code and error message I get when I run it is below. I also noticed the fingerprint signature from when I keytool -printcert is different than what firefox shows in its View Certificate menu, is that a red flag?

Any help on things to look out for here and/or thoughts are greatly appreciated.

private static InputStream fullStream(String fname) throws IOException {
        File f = new File(fname);
        if (f == null || f.exists() == false) {
            System.out.println("File " + fname + " does not exist");
            System.exit(1);
        }
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        byte[] bytes = new byte[dis.available()];
        dis.readFully(bytes);
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        return bais;
    }


    public static void main(String args[]) {
        try {
            if (args.length < 6) {
                System.out
                        .println("\nImportPrivateKeyTool Usage: \njava ImportPrivateKeyTool parameters:\n"
                                + "\n<keystoreFileName> - JKS format\n"
                                + "\n<keystorePassword>\n"
                                + "\n<keyFileName> - PKCS12 format \n"
                                + "\n<keyPwd>\n"
                                + "\n<keyAlias>\n");
                System.out
                        .println("\n\nRequires jsse for PKCS12 keystore support \n"
                                + " - source storetype can be JKS or PKCS12\n"
                                + " - destination storetype must be JKS type (PKCS12 write not supported)\n");
                System.exit(1);
            }

            String keystoreFileName = args[0];
            String keystorePassword = args[1];
            String keyFileName = args[2];
            String keyPwd = args[3];
            String keyAlias = args[4];
            String certFileName = args[5];

            System.setProperty("javax.net.ssl.keyStore", keystoreFileName);// ie
                                                                            // "C:/Dev/security/keystores/.deluxeKeyStore.jks"
            System.setProperty("javax.net.ssl.keyStorePassword",
                    keystorePassword);

            Security.addProvider(new BouncyCastleProvider());

            // initializing keystore , clear it first by passing null??
            KeyStore ks = KeyStore.getInstance("JKS");// second param SUN?
                                                        // "SUN", //TODO allow
                                                        // passing of PKCS12 or
                                                        // JKS?

            File f = new File(keystoreFileName);
            if (f == null || f.exists() == false) {
                //create new
                ks.load(null, keystorePassword.toCharArray());//initialize
                ks.store(new FileOutputStream(keystoreFileName),keystorePassword.toCharArray());
                System.out.println("Keystore file " + keystoreFileName + " did not exist so created new key store.");
            }

            ks.load(fullStream(keystoreFileName),keystorePassword.toCharArray());
            System.out.println("Using keystore-file : " + keystoreFileName);



            KeyFactory kf = KeyFactory.getInstance("RSA");

            BufferedReader br = new BufferedReader(new FileReader(keyFileName));
            PEMReader privateKeyPEMReader = new PEMReader(br);
            KeyPair kp = (KeyPair) privateKeyPEMReader.readObject();
            PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); 
            PrivateKey ff = kf.generatePrivate(keysp);//keysp
            System.out.println("Successfully loaded into memory private key: "+ keyFileName);

            // loading CertificateChain
            CertificateFactory cf = CertificateFactory.getInstance("X.509");of
            BufferedReader br2 = new BufferedReader(new FileReader(certFileName));// cert?
            //InputStream certstream = fullStream(certFileName);
            PEMReader certPEMReader = new PEMReader(br2);
            Certificate cert = (Certificate)certPEMReader.readObject(); //TODO support chain array of certs..
            Certificate[] certs = new Certificate[1];
            certs[0] = cert;


            // storing keystore
            ks.setKeyEntry(keyAlias, ff, keyPwd.toCharArray(), certs);
            System.out
                    .println("Key and certificate successfully imported as alias:"
                            + keyAlias);
            ks.store(new FileOutputStream(keystoreFileName),
                    keystorePassword.toCharArray()); // TODO use key pass
                                                        // instead? doubt it
            System.out.println("Successfully saved updated key store.");







ClientKeyExchange, RSA PreMasterSecret, TLSv1
main, WRITE: TLSv1 Handshake, length = 876
SESSION KEYGEN:
PreMaster Secret:
<removed>....
CONNECTION KEYGEN:
Client Nonce:
<remove>.....
Server Nonce:
<remove>
Master Secret:
<removed>
Client MAC write Secret:
<removed>
Server MAC write Secret:
<removed>
Client write key:
<removed>
Server write key:
<removed>
... no IV used for this cipher
*** CertificateVerify
main, WRITE: TLSv1 Handshake, length = 262
main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data:  { 20, 221, 183, 152, 78, 193, 208, 28, 198, 116, 172, 58 }
***
main, WRITE: TLSv1 Handshake, length = 32
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, decrypt_error
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
    at com.oflows.seam.test.deluxechecks.DeluxeChecksOrderProTest.main(DeluxeChecksOrderProTest.java:84)

I'm not sure I understand what the end-goal is...

  • If you want to use a cert + private key that is already in a PKCS#12 file, no need to convert it: use the PKCS12 keystore type in Java. You're not showing the client code you're using, but one of the ways to use it would be to set javax.net.ssl.keyStoreType to PKCS12 .

  • keytool , as provided by Sun/Oracle since Java 6, can import pairs of cert+private key from a keystore (including PKCS#12) into another one, for example:

     keytool -importkeystore -srckeystore thekeystore.p12 \\ -srcstoretype PKCS12 \\ -destkeystore thekeystore.jks \\ -deststoretype JKS 

You shouldn't need BouncyCastle for these options (nor exporting via OpenSSL).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM