Преобразование SSL.pem в .p12 с OpenSSL или без него
Я получаю внешние .pem
файлы, которые необходимо преобразовать в файлы .p12
. Я добавляю имя пользователя и пароль в этот процесс. (Мне нужно сделать это, чтобы использовать сторонний API.)
Используя openssl
, команда...
openssl pkcs12 -export -in xxxx.pem -inkey xxxx.pem -out xxx.p12 -passout pas:newpassword -name "newname"
Я могу запустить это из сеанса терминала, и он отлично работает.
Однако мне нужно будет делать это часто и написали класс Java, который обрабатывает это и многое другое (мое приложение в основном .jsp
с Tomcat и Apache). Когда я пытаюсь запустить ту же команду из Java с помощью Runtime.exec
, я получаю страшное "неспособное записать ошибку" случайное состояние "(Использование OpenSSL, что "не удается записать" случайный состояние" означает?).
Я предполагаю, что разница в том, что при запуске с Java пользователь не является "root".
Итак, есть ли лучший способ конвертировать из pem в .p12 с использованием библиотеки Java, а не выполнять программу командной строки (то есть openssl)?
В противном случае, я думаю, мне нужно сделать некоторые настройки на моем сервере. Я не могу найти файл .md
в любом месте сервера. Единственный openssl.cnf
файл находится в странном каталоге (/etc/pki/tls
). Нужно ли мне создавать новый файл openssl.cnf
где-то еще?
Ответы
Ответ 1
Это должно делать то, что вы хотите сделать (используя BouncyCastle PEMReader, как было предложено выше) - взять закрытый ключ + PEM-код и вывести файл PKCS # 12. Использует тот же пароль для PKCS12, который использовался для защиты закрытого ключа.
public static byte[] pemToPKCS12(final String keyFile, final String cerFile, final String password) throws Exception {
// Get the private key
FileReader reader = new FileReader(keyFile);
PEMReader pem = new PEMReader(reader, new PasswordFinder() {
@Override public char[] getPassword() {
return password.toCharArray();
}
});
PrivateKey key = ((KeyPair)pem.readObject()).getPrivate();
pem.close();
reader.close();
// Get the certificate
reader = new FileReader(cerFile);
pem = new PEMReader(reader);
X509Certificate cert = (X509Certificate)pem.readObject();
pem.close();
reader.close();
// Put them into a PKCS12 keystore and write it to a byte[]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null);
ks.setKeyEntry("alias", (Key)key, password.toCharArray(), new java.security.cert.Certificate[]{cert});
ks.store(bos, password.toCharArray());
bos.close();
return bos.toByteArray();
}
Ответ 2
На основе ответа @MugglesMerriweather обновленная версия версии v1.51 выглядит следующим образом:
public static byte[] convertPEMToPKCS12(final String keyFile, final String cerFile,
final String password)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
{
// Get the private key
FileReader reader = new FileReader(keyFile);
PEMParser pem = new PEMParser(reader);
PEMKeyPair pemKeyPair = ((PEMKeyPair)pem.readObject());
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter().setProvider("SC");
KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);
PrivateKey key = keyPair.getPrivate();
pem.close();
reader.close();
// Get the certificate
reader = new FileReader(cerFile);
pem = new PEMParser(reader);
X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
java.security.cert.Certificate X509Certificate =
new JcaX509CertificateConverter().setProvider("SC")
.getCertificate(certHolder);
pem.close();
reader.close();
// Put them into a PKCS12 keystore and write it to a byte[]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null);
ks.setKeyEntry("alias", (Key) key, password.toCharArray(),
new java.security.cert.Certificate[]{X509Certificate});
ks.store(bos, password.toCharArray());
bos.close();
return bos.toByteArray();
}
Ответ 3
В Java используйте Bouncycastle, но будьте осторожны, кривая обучения крутая и документация скудна. Я настоятельно рекомендую вам ознакомиться с примерами, которые доступны как часть исходного дистрибутива.
Начните с PemReader.
Ответ 4
На основе ответов я создал класс java 7, который обрабатывает все для создания достоверного SSLContext. Также он создает необходимую цепочку. TODO: Trustmanager при необходимости.
public final class SSL_Context {
private static SSL_Context instance = new SSL_Context();
public static SSL_Context getInstance() {
return instance;
}
private SSLContext sslContext = null;
private SSL_Context() {
try {
sslContext = generateSSLContext();
}
catch (Exception e)
{
ErrorLogger.logException(e);
}
}
final private void dumpKeyStore(KeyStore keyStore)
{
try {
// List the aliases
Enumeration aliases = keyStore.aliases();
for (; aliases.hasMoreElements(); ) {
String alias = (String) aliases.nextElement();
// Does alias refer to a private key?
boolean a = keyStore.isKeyEntry(alias);
// Does alias refer to a trusted certificate?
boolean b = keyStore.isCertificateEntry(alias);
ErrorLogger.log(alias + " " + a + " " + b, 2);
}
} catch (Exception e) {
ErrorLogger.logException(e);
}
}
final private KeyStore convertPEMToPKCS12(final String keyAndPubFile, final String chainFile, final String password) {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PrivateKey key;
Certificate pubCert;
try (FileReader reader = new FileReader(keyAndPubFile);
PEMParser pem = new PEMParser(reader)) {
PEMKeyPair pemKeyPair = ((PEMKeyPair) pem.readObject());
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);
key = keyPair.getPrivate();
X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
pubCert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
}
// Get the certificates
try (FileReader reader = new FileReader(chainFile);
PEMParser pem = new PEMParser(reader)) {
//load all certs
LinkedList<Certificate> certsll = new LinkedList<>();
X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
do {
Certificate X509Certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
certsll.add(X509Certificate);
}
while ((certHolder = (X509CertificateHolder) pem.readObject()) != null);
Certificate[] chain = new Certificate[certsll.size()+1];
chain[0] = pubCert;
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null);
int i = 1;
for (Certificate cert : certsll) {
ks.setCertificateEntry("chain" + i, cert);
chain[i] = ks.getCertificate("chain" + i);
i++;
}
ks.setKeyEntry("cert", key, password.toCharArray(), chain);
return ks;
}
}
catch (Exception e)
{
ErrorLogger.logException(e);
}
return null;
}
final private SSLContext generateSSLContext()
{
String keyStorePassword = "";
try {
KeyStore keyStore = convertPEMToPKCS12("ssl/keyandcert.pem", "ssl/ca_bundle.crt", keyStorePassword);
SSLContext sslContext = SSLContext.getInstance("TLSv1");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return sslContext;
} catch (Exception e) {
ErrorLogger.logException(e);
}
return null;
}
final public SSLContext getContext() {
return sslContext;
}
final public static void main(String args[])
{
getInstance().getContext();
}
}
Ответ 5
Это решение является адаптацией @sascha-arthur для размещения:
Код:
String alias="myalias";
char[] password = "mypassword".toCharArray();
// Private Key
PEMParser pem = new PEMParser(new FileReader(keyFile));
Object parsedObject = pem.readObject();
PrivateKeyInfo privateKeyInfo = parsedObject instanceof PEMKeyPair ? ((PEMKeyPair)parsedObject).getPrivateKeyInfo() : (PrivateKeyInfo)parsedObject;
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey key = factory.generatePrivate(privateKeySpec);
List<X509Certificate> certs = new ArrayList<>();
X509CertificateHolder certHolder = (X509CertificateHolder)pem.readObject();
if(certHolder != null) {
certs.add(new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder));
}
// Certificate
pem = new PEMParser(new FileReader(certFile));
while((certHolder = (X509CertificateHolder)pem.readObject()) != null) {
certs.add(new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder));
}
// Keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null);
for (int i = 0; i < certs.size(); i++) {
ks.setCertificateEntry(alias + "_" + i, certs.get(i));
}
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null);
keyStore.setKeyEntry(alias, key, password, certs.toArray(new X509Certificate[certs.size()]));
Для работы с сертификатом LetsEncrypt вам необходимо использовать следующие файлы:
privkey.pem
fullchain.pem