Проблема с закрытым ключом в Java и HTTPS - PullRequest
0 голосов
/ 06 декабря 2011

Java keytool не предоставляет средства для создания нового хранилища ключей из закрытого ключа или импорта закрытого ключа в существующее хранилище jks. У меня есть сервисный хост, который требует, чтобы они сгенерировали закрытый ключ и дали его нам, клиенту, для вызова их сервиса.

Закрытый ключ и сертификат загружаются с них в Firefox и экспортируются на компьютере с Windows в файл формата p12. Я использовал openssl для преобразования этого pkcs12 в файл PEM. Затем я вручную разделяю этот файл на файлы cert.der и privateKey.der соответственно. Затем я написал Java-программу для импорта этой пары в наше существующее хранилище ключей (используйте надувной замок). Я проверяю, что хранилище ключей создано и содержит мой ключ / сертификат с помощью 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 голосов
/ 06 декабря 2011

Я не уверен, что понимаю, какова конечная цель ...

  • Если вы хотите использовать сертификат + закрытый ключ, который уже находится в файле PKCS # 12, нет необходимости его преобразовывать: используйте тип хранилища ключей PKCS12 в Java. Вы не показываете код клиента, который вы используете, но одним из способов его использования было бы установить javax.net.ssl.keyStoreType на PKCS12.

  • keytool, предоставляемый Sun / Oracle начиная с Java 6, может импортировать пары сертификатов + закрытый ключ из хранилища ключей (включая PKCS # 12) в другое, например:

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

Вам не нужен BouncyCastle для этих опций (или экспорта через OpenSSL).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...