使用Java和HTTPS导入私钥问题

时间:2011-12-05 21:49:46

标签: java authentication ssl client

Java的keytool不提供从私钥创建新密钥库的工具,也不提供将私钥导入现有jks存储的工具。我有一个服务主机,要求他们生成私钥并将其提供给我们(客户端)来调用他们的服务。

私钥和证书是从firefox下载的,在windows机器上导出为p12格式的文件。我使用openssl将pkcs12转换为PEM文件。然后我分别手动将该文件拆分为cert.der和privateKey.der文件。然后我编写了一个java程序将该对导入我们现有的密钥库(使用充气城堡)。我在运行程序后验证密钥库是否已创建并包含我的key / cert和keytool,它看起来不错。

我运行时得到的程序代码和错误消息如下。我还注意到,当我的keytool -printcert与firefox在其View Certificate菜单中显示的不同时,指纹签名是否是一个红旗?

非常感谢任何有关此处和/或想法的事情的帮助。

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)

1 个答案:

答案 0 :(得分:0)

我不确定我明白最终目标是什么......

  • 如果要使用已存在于PKCS#12文件中的cert +私钥,则无需转换它:在Java中使用PKCS12密钥库类型。您没有显示您正在使用的客户端代码,但使用它的方法之一是将javax.net.ssl.keyStoreType设置为PKCS12

  • 自Java 6以来由Sun / Oracle提供的
  • keytool可以将密钥库(包括PKCS#12)中的一对cert +私钥导入到另一个密钥库中,例如:

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

您不应该为这些选项使用BouncyCastle(也不需要通过OpenSSL导出)。