可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I get external .pem
files that need to be converted to .p12
files - I add a username and password in the process. (I need to do this to utilize a third party API.)
Using openssl
, the command is...
openssl pkcs12 -export -in xxxx.pem -inkey xxxx.pem -out xxx.p12 -passout pas:newpassword -name "newname"
I can run this from a terminal session and it works perfectly.
However, I will need to do this often and have written a Java class that handles this and more (my application is mostly .jsp
with Tomcat and Apache). When I try run the same command from Java using Runtime.exec
, I get the dreaded "unable to write 'random state'" error ( Using OpenSSL what does "unable to write 'random state'" mean? ).
I assume that the difference is that, when I run from Java, the user is not "root".
So, is there a better way to convert from pem to .p12 using a Java library rather than executing a command line program (i.e. openssl)?
Otherwise, I guess I need to do some configuration on my server. I can not find any .md
file anywhere on the server. The only openssl.cnf
file is in a weird directory (/etc/pki/tls
). Do I need to create a new openssl.cnf
file somewhere else?
回答1:
This should do what you want to do (using the BouncyCastle PEMReader as suggested above) -- take a PEM-encoded private key + certificate, and output a PKCS#12 file. Uses the same password for the PKCS12 that was used to protect the private key.
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:
In Java, use Bouncycastle but be warned, learning curve is steep and documentation scarce. I strongly recommend you look at the examples which are available as part of the source distribution
Start with the PemReader.
回答3:
Based on @MugglesMerriweather 's answer, an updated version to v1.51 is the following:
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(); }
回答4:
Based on the answers i created a java 7 class, which handles everything for creating a valid SSLContext. Also it creates the necessary chain. TODO: Trustmanager if necessary.
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(); } }