Как экспортировать сертификат и закрытый ключ в один файл, используя код Java? - PullRequest
0 голосов
/ 24 мая 2019

Мое требование - объединить сертификат и закрытый ключ, а затем, используя PEMwriter, мне нужно экспортировать файл.

Я использовал bouncycastle для генерации закрытого ключа и csr.Затем я отправил CSR в CA и получил сертификат.Следующий код предназначен для генерации пары ключей

KeyPair idPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
PublicKey publicKey = idPair.getPublic();
PrivateKey privkey = idPair.getPrivate();

Следующий код предназначен для получения сертификата и его экспорта в файл .cer.

CertStore store = response.getCertStore();
            Collection<? extends Certificate> certs = store
                    .getCertificates(null);
            Certificate[] chain = new Certificate[certs.size()];

            int i = 0;
            for (Certificate certificate : certs) {
                chain[i++] = certificate;
            }

            FileOutputStream os = new FileOutputStream("cert.cer");
            os.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
            os.write(Base64.encodeBase64(chain[0].getEncoded(), true));
            os.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));
            os.close();

Теперь моя цель - открытьэкспортированный файл, мне нужно будет ввести пароль для установки / просмотра сертификата.Я действительно запутался в этой части.Ранее я добавил пароль в хранилище ключей, как показано ниже:

KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        keyStore.load(null, null);

        keyStore.setKeyEntry("mykey", (Key) keyPair.getPrivate(), "Password1!".toCharArray(), certz);

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        keyStore.store(bout, "Password1!".toCharArray()); // this is the password to open the .p12

        byte[] keystore = bout.toByteArray();
        bout.close();

Но теперь мне нужно защитить сертификат паролем.Это вообще возможно?Если так, каково будет расширение файла?И, пожалуйста, ведите меня в части кодирования (PemWriter).Спасибо

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

Следующий код предназначен для получения сертификата и его экспорта в файл .cer.

        CertStore store = response.getCertStore();
        Collection<? extends Certificate> certs = store
                .getCertificates(null);
        Certificate[] chain = new Certificate[certs.size()];
        int i = 0;
        for (Certificate certificate : certs) {
            chain[i++] = certificate;
        }

В сторону: вам не нужен этот цикл для преобразования Collection вмассив, всего один вызов .toArray (new T[optionally_correct_size]) сделает это.С другой стороны, поскольку вы используете только первый элемент, вам вообще не нужен массив, просто Collection<T>.iterator().next().

Более существенно и, с другой стороны, для многих - но определенно не всех - операций, выполняемых с помощью privatekey, также требуется полная цепочка сертификатов, а не только сертификат конечного / конечного объекта, для правильной работы.Например, некоторые подписывающие лица могут вычислить подпись без цепочки, но в некоторых случаях или обстоятельствах эта подпись не может быть проверена и, следовательно, будет отклонена тем, кто ее получит.Поскольку вы не знаете, как, для чего и для чего будут использоваться ваши экспортированные файлы, невозможно дать какие-либо советы по этому вопросу.И если необходима полная цепочка , это также зависит от того, можете ли вы просто использовать последовательность отдельных / отдельных сертификатов PEM или вам нужно что-то еще.

Я не знаю, какой Base64 кодер вы используете;эта подпись не совпадает с подписью BouncyCastle.Я надеюсь, что это создает правильные разрывы строк.Формат PEM - это НЕ просто BEGIN-строка, base64, END-строка;это BEGIN-строка, base64 с разрывами строки , END-line. Некоторое программное обеспечение будет работать, иногда , даже без разрывов строки, но некоторые программы, иногда, не будут работать.См. RFC 7468 с 2 около конца .

Теперь моя цель - когда я открываю экспортированный файл, мне нужно ввести пароль для установки / просмотра сертификата.... Но теперь мне нужно защитить сертификат паролем.Это вообще возможно?

Необходимо различать приватный ключ и сертификат (ы).Хотя они связаны между собой важным способом, это разные вещи, и приватный ключ разработан как закрытый / секретный, а сертификат - публичный.В частности, сертификат формата PEM не зашифрован, поэтому любой может его просмотреть и использовать для операций с открытыми ключами (шифровать или проверять), а также делать с ними все, что ему нравится.

Но для выполнения операций с закрытыми ключами (расшифровка)или подписать) вам нужен приватный ключ - обычно связанный с сертификатом или цепочкой, как указано выше - и приватный ключ может быть зашифрован паролем (как минимум) в двух разных способов в обычных форматах PEM, таким образом, требуется пароль, чтобы «открыть» его.В 1990-х годах OpenSSL де-факто определили схему шифрования PEM, которую можно использовать для нескольких 'унаследованных' или 'традиционных' форматов закрытых ключей, которые различны для каждого алгоритма и указаны в типе PEM встрока BEGIN, таким образом -----BEGIN RSA PRIVATE KEY-----, -----BEGIN DSA PRIVATE KEY-----, -----BEGIN EC PRIVATE KEY----- и т. д. Позже PKCS8 определила общий формат закрытого ключа для всех используемых алгоритмовмногими другими программами, включая Java crypto (JCA), включая зашифрованный вариант, обозначенный -----BEGIN ENCRYPTED PRIVATE KEY----- (обратите внимание, нет имени алгоритма).Версия PKCS8 (только) была официально опубликована RFC7468 sec 11 .(Существуют также другие и совсем другие PEM-подобные форматы для приватных ключей, используемые OpenSSH, PuTTY и PGP, но ни один из них не использует сертификаты типа X.509. Хотя GnuPG теперь реализует и PGP и S / MIME, и использует X.509 / PKIX * ​​1052 * для S / MIME . Существует множество существующих Q для SO и некоторые для security.SX или crypto.SX, если вы заинтересованы в них. * bcpkix реализует OpenSSL-наследствоформы и формы PKCS8.(Только Java без BouncyCastle реализует PKCS8 в незашифрованном виде .)

Точно так же «устаревшие» хранилища ключей Java (JKS и JCEKS) шифруют паролем приватный ключ (ключи), но не сертификат (ы).Стандарт PKCS12 на самом деле очень гибок (и сложен), но , как обычно реализуется (включая пример вашего хранилища ключей BC), использует надежное шифрование пароля для частного ключа (ключей) и очень слабое легко взламываемое шифрование пароля длясертификат (ы);Я никогда не был уверен, почему, потому что это менее удобно без предоставления каких-либо преимуществ для безопасности.

Если так, каким будет расширение файла?

Это в основном зависит от вас или от того, кому (если кто-нибудь) нужны эти файлы.Ни один стандарт не требует расширения файла, чтобы соответствовать содержимому файла или наоборот, хотя люди обычно делают это, потому что это намного удобнее.Официально .cer должен быть DER сертификатом, а RFC7468 sec 5.3 рекомендует , используя .crt для сертификата PEM.Если вы записываете ключ в отдельный файл, кажется, что довольно часто используется .key или .pem, но я не знаю ни одного стандарта (и, конечно, регистрации IANA), определяющего это.(RFC5958 регистрирует .p8 для того, что на самом деле DER PKCS8 незашифровано, а RFC8351 регистрирует DER PKCS8 в зашифрованном виде без указания любого расширения .) Если вы записываете ключ и сертификаты в тот же файл, который поддерживает формат PEM, но не все программы, я даже не видел обычной практики, кроме .pem.

Итак, чтобы окончательно перейти к вашему вопросу :-) Учитывая, что у вас есть поставщик BC в списке поставщиков (и путь к классам), bcpkix в пути к классам и объект PrivateKey в kv:

import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
import org.bouncycastle.util.io.pem.PemWriter;

        // for the OpenSSL legacy form
        JcaPEMWriter x = new JcaPEMWriter (new OutputStreamWriter(System.out)); // or whatever 
        x.writeObject(kv, new JcePEMEncryptorBuilder("DES-EDE3-CBC").build("password".toCharArray()) );
        // can substitute AES-{128,192,256}-CBC if desired, for more see source
        x.close(); // or flush to keep underlying writer/stream

        // for the PKCS8 form
        PemWriter y = new PemWriter (new OutputStreamWriter(System.out)); // or whatever 
        y.writeObject(new JcaPKCS8Generator (kv, new JceOpenSSLPKCS8EncryptorBuilder(
                PKCS8Generator.DES3_CBC).setPasssword("password".toCharArray()).build() ) );
        // or AES_{128,192,256}_CBC, others will use PBES1 which is deprecated
        y.close(); // or flush to keep underlying writer/stream
1 голос
/ 27 мая 2019

Как упоминалось выше для обычного использования, вам не нужно защищать сертификаты паролями. Но если вы хотите хранить некоторые сертификаты в надежном месте, вы можете сделать это в защищенном паролем файле хранилища ключей (только код java.security, PemWriter не требуется).

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(null, null);

            Certificate cert = getX509Cert(); // load certificate
            ks.setCertificateEntry("myCertAlias", cert);

            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(PATH + "newKeyStore.p12");
                char[] password = PASSWORD_.toCharArray();
                ks.store(fos, password);
            } finally {
                if (fos != null) {
                    fos.close();
                }
            }
...