【问题标题】:Need to add certificate from txt file in runtime需要在运行时从txt文件添加证书
【发布时间】:2023-11-27 03:51:01
【问题描述】:

客户端已提供 2 个 '.txt' 格式的证书,我需要在运行时添加这些证书,同时调用 SOAP 服务。无法添加“.txt”格式文件,因为我越来越喜欢“无效格式”。证书在 txt 文件的顶部和底部有“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----”标题,所以它是 PEM 类型文件(我假设)。任何帮助/建议都将不胜感激。

遇到异常 ::

Exception in thread "main" java.io.IOException: Invalid keystore format

使用下面的代码..

public KeyManagerFactory getKeyManagerFactory() throws UnrecoverableKeyException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
    InputStream inputStream = null;
    KeyStore ts = null;
    KeyManagerFactory keyManagerFactory = null;
    try {
        ts = KeyStore.getInstance("JKS");
        inputStream = this.getClass().getClassLoader().getResourceAsStream("publicCert.txt");
        ts.load(inputStream, null);
        keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(ts, null);
    } catch (Exception e) {
        throw e;
    } finally {
        try {
            inputStream.close();
        } catch (Exception e) {
            throw e;
        }
    }
    return keyManagerFactory;
}

得到答案后,使用下面的代码,它正在工作

        rootInterIS = new FileInputStream("rootIntermediaryCertificate.txt");
        domainIS = new FileInputStream("domainCertificate.txt");

        keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(null);

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        X509Certificate rootInterCert = (X509Certificate) certFactory.generateCertificate(rootInterIS);
        X509Certificate domainCert = (X509Certificate) certFactory.generateCertificate(domainIS);
        keystore.setCertificateEntry("domainCertificate", domainCert);
        keystore.setCertificateEntry("rootInterCe", rootInterrtificateCert);

        trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keystore);

【问题讨论】:

    标签: java ssl-certificate keystore pem jks


    【解决方案1】:

    PEM 格式由一行 ----BEGIN x----- 组成一个或多个单词 x,一行或多行 base64 包含内部结构匹配 x 的数据,以及匹配的 END 行。虽然有人可以创建一个包含正确 BEGIN/END 行但 base64 错误的伪造文件,除非他们正在积极尝试给您带来麻烦,您描述的文件看起来很可能是 PEM 证书。 p>

    证书(PEM 格式)不是密钥库,尤其不是 JKS。 Java 支持几种不同的密钥库格式,其中没有一种是 PEM,也没有一种仅限于证书。仅使用KeyStore.getInstance(type) 读取您没有的密钥库;使用 CertificateFactory.getInstance("X.509") 读取证书文件(实际上是 PEM 或二进制,也就是 DER,但目前您只关心前者)。

    在 SSL/TLS 中,KeyManager 仅用于验证(证明)您自己的身份的证书使用您没有的私钥。将没有私钥的证书放在KeyManager 中将完全没用且无效。如果有人只给了你一个证书而不是私钥来连接到他们的系统,那应该是一个证书来验证他们的系统,而不是你的系统;询问供应商或查看文件以确认这一点。给定 Java,您可以使用 keytool -printcert -file $file 查看证书的详细信息。

    您需要将该证书放在TrustManager 中。请注意KeyManagerTrustManager 都使用KeyStore 对象,但以不同的方式用于不同的目的。因此,您创建了一个内存中的空 KeyStore(先执行 .getInstance(type),然后执行 .load(null)),添加上面的证书作为“可信”证书,并将其传递给TrustManagerFactory,然后在您的SSLContext 等中使用生成的TrustManager

    【讨论】:

    • 实际上我从客户端得到了 2 个文件,1 个(域)有单个“BEGIN”和“END”标签,另一个有 2 个相同的块(根证书和中间证书,按名称我可以告诉).. 所以我必须在 TrustManagerFactory 中加载这两个文件并在 KeyManagerFactory 中加载 null ...
    • @Balaji211:对于 正确配置 服务器,您只需要 TrustManager 中的根证书(标准要求服务器发送其他所有内容),但我不知道您无法识别的特定服务器。您可以进行实验,也可以将所有证书放入;最坏的情况是,如果他们的服务器遭到入侵,您的代码仍将连接并信任攻击者/犯罪分子。如果您没有用于客户端身份验证的证书和密钥,则不需要 any KeyManager 只需将第一个参数的 null 传递给 SSLContext.init
    • 在信任管理器工厂中添加了域和(根 + 中介)证书