【问题标题】:Convert SSL .pem to .p12 with or without OpenSSL使用或不使用 OpenSSL 将 SSL .pem 转换为 .p12
【发布时间】: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 文件吗?

【问题讨论】:

    标签: java openssl pem pkcs#12


    【解决方案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();
        }
        
        }
        

        【讨论】:

        • 这是我能找到的将 LetsEncrypt privkey.pemchain.pem 转换为 Java 密钥库的最接近的示例。我永远感激你决定在 2015 年注册发布这个代码 sn-p。我必须做的唯一修改是 LetsEncrypt 没有公钥条目,所以我只是重构了没有它的链。
        【解决方案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

        【讨论】:

          猜你喜欢
          • 2011-07-22
          • 2015-03-07
          • 2023-03-20
          • 2014-11-26
          • 2023-03-04
          • 2014-09-01
          • 2020-10-30
          • 2013-02-15
          • 2016-04-07
          相关资源
          最近更新 更多