使用或不使用 OpenSSL 将 SSL .pem 转换为 .p12
Posted
技术标签:
【中文标题】使用或不使用 OpenSSL 将 SSL .pem 转换为 .p12【英文标题】:Convert SSL .pem to .p12 with or without OpenSSL 【发布时间】:2012-03-31 10:56:30 【问题描述】:我得到需要转换为 .p12
文件的外部 .pem
文件 - 我在此过程中添加了用户名和密码。 (我需要这样做才能利用第三方 API。)
使用openssl
,命令是……
openssl pkcs12 -export -in xxxx.pem -inkey xxxx.pem -out xxx.p12 -passout pas:newpassword -name "newname"
我可以从终端会话中运行它,它运行良好。
但是,我需要经常这样做,并编写了一个 Java 类来处理这个以及更多问题(我的应用程序主要是 .jsp
与 Tomcat 和 Apache)。当我尝试使用Runtime.exec
从Java 运行相同的命令时,我得到了可怕的“无法写入'随机状态'”错误(Using OpenSSL what does "unable to write 'random state'" mean?)。
我假设不同之处在于,当我从 Java 运行时,用户不是“root”。
那么,有没有更好的方法来使用 Java 库将 pem 转换为 .p12,而不是执行命令行程序(即 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();
【讨论】:
SC
代表 SpongyCastle 提供者。【参考方案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();
【讨论】:
这是我能找到的将 LetsEncryptprivkey.pem
和 chain.pem
转换为 Java 密钥库的最接近的示例。我永远感激你决定在 2015 年注册发布这个代码 sn-p。我必须做的唯一修改是 LetsEncrypt 没有公钥条目,所以我只是重构了没有它的链。 【参考方案5】:
此解决方案是对@sascha-arthur 的改编,以适应:
处理edge-case where PrivateKey format is not as expected。 优雅处理公钥不可用的场景 修复了一些小的冗余和格式代码:
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
【讨论】:
以上是关于使用或不使用 OpenSSL 将 SSL .pem 转换为 .p12的主要内容,如果未能解决你的问题,请参考以下文章
OpenSSL使用2(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12概念说明)(转)