Следующий код предназначен для получения сертификата и его экспорта в файл .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