【问题标题】:Programmatically Import CA trust cert into existing keystore file without using keytool以编程方式将 CA 信任证书导入现有的密钥库文件,而不使用 keytool
【发布时间】:2013-09-24 04:56:44
【问题描述】:

我想创建一个 JAVA 程序,将 .cer CA 导入现有的密钥库文件。 这样最终用户可以更方便地插入 CA 证书(无需在命令中使用 CMD 和 key)。

JAVA 代码可以做到这一点吗?

我尝试了一些方法,但仍然无法将证书导入 java

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream certstream = fullStream (certfile);
Certificate certs = cf.generateCertificates(certstream);

错误是不兼容的类型,还有其他建议吗?

非常感谢

【问题讨论】:

    标签: java keytool


    【解决方案1】:

    以下代码将 CA 证书文件 yourcert.cer 插入到您的密钥库中,而不使用 keytool

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.security.Key;
    import java.security.KeyStore;
    import java.security.cert.Certificate;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.DataInputStream;
    import java.io.ByteArrayInputStream;
    import java.security.spec.*;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.util.Collection;
    
    public class ImportCA {
    
        public static void main(String[] argv) throws Exception {
            String certfile = "yourcert.cer"; /*your cert path*/
            FileInputStream is = new FileInputStream("yourKeyStore.keystore");
    
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            keystore.load(is, "yourKeyStorePass".toCharArray());
    
            String alias = "youralias";
            char[] password = "yourKeyStorePass".toCharArray();
    
            //////
    
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream certstream = fullStream (certfile);
            Certificate certs =  cf.generateCertificate(certstream);
    
            ///
            File keystoreFile = new File("yourKeyStorePass.keystore");
            // Load the keystore contents
            FileInputStream in = new FileInputStream(keystoreFile);
            keystore.load(in, password);
            in.close();
    
            // Add the certificate
            keystore.setCertificateEntry(alias, certs);
    
            // Save the new keystore contents
            FileOutputStream out = new FileOutputStream(keystoreFile);
            keystore.store(out, password);
            out.close();
        }
    
        private static InputStream fullStream ( String fname ) throws IOException {
            FileInputStream fis = new FileInputStream(fname);
            DataInputStream dis = new DataInputStream(fis);
            byte[] bytes = new byte[dis.available()];
            dis.readFully(bytes);
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            return bais;
        }
    }
    

    【讨论】:

    • 什么是“你的别名”?我可以为此提供任何价值吗?
    • @turbanoff 这是任意的,但每个证书应该是唯一的。
    • 别名部分将是证书的 UID 关联。如果密钥库将证书存储在 Web 浏览器中,则别名将是从中检索证书的主机名。如果您可以找到证书与其拥有实体之间的唯一关联,则最好不要随意保留此值,通常您想知道是否修改了声明身份的公钥以使信任无效 - 如果 stackoverflow 的公钥.com 更改(而不是学习),然后引起怀疑,并且通常在与受信任的证书颁发机构进行检查之后。
    • 为什么要加载两次密钥库?
    • 没有密码怎么办?我有这个 - keytool -import -file /path/to/proxycert.crt -storepass changeit -keystore $JAVA_HOME/jre/lib/security/cacerts -alias proxycert
    【解决方案2】:

    从链接下载证书并存储到特定路径中。然后在运行时使用下面的代码将该文件加载到 trustStore 中。我希望这个示例对您有所帮助..

    KeyStore keyStore = KeyStore.getInstance("JKS");
    String fileName = "D:\\certs_path\\cacerts"; // cerrtification file path
    System.setProperty("javax.net.ssl.trustStore", fileName);
    

    【讨论】:

    • 这个例子不需要信任库密码,这很重要!
    • Yablargo 我认为,存储证书时需要密码。要设置信任库,您不需要密码。事实上,如果您在没有密码的信任库中写入,这是一个问题。
    • keyStore var 的用途是什么?
    【解决方案3】:

    对不起,这个答案没有带来任何新的东西,但是接受的答案中的代码太糟糕了,我只需要发布它。这只是一个完善的版本,仅此而已。因此,请考虑从此处复制/粘贴,但支持接受的答案而不是这个答案。

        public static void addX509CertificateToTrustStore(String certPath, String certAlias, String storePath, String storePassword, String storeType)
                throws FileNotFoundException, KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
    
            char[] storePasswordCharArr = Objects.requireNonNull(storePassword, "").toCharArray();
    
            KeyStore keystore;
            try (FileInputStream storeInputStream = new FileInputStream(storePath);
                    FileInputStream certInputStream = new FileInputStream(certPath)) {
                keystore = KeyStore.getInstance(storeType);
                keystore.load(storeInputStream, storePasswordCharArr);
    
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                Certificate certificate = certificateFactory.generateCertificate(certInputStream);
    
                keystore.setCertificateEntry(certAlias, certificate);
            } finally {
            }
    
            try (FileOutputStream storeOutputStream = new FileOutputStream(storePath)) {
                keystore.store(storeOutputStream, storePasswordCharArr);
            } finally {
            }
        }
    

    【讨论】:

    • 我想知道为什么 Java Keystore API 没有提供就地 store() 重用来自 load(x, y) 的相同路径和密码的方法重载,例如keyStore.store().
    猜你喜欢
    • 2012-01-14
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-17
    • 2019-05-12
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    相关资源
    最近更新 更多