当前位置: 首页 > 知识库问答 >
问题:

如何从PEM证书和密钥构建SSLSocketFactory而不转换到Keystore?

赫连彬炳
2023-03-14
  1. client.crt(客户端证书)
  2. client.key(客户端私钥)
  3. CA.crt(CA证书)

解决该任务的一种方法是生成Java密钥库:

  1. 使用openssl将客户端证书和密钥转换为PKCS12密钥存储
  2. 使用keytool将CA证书导入存储区
InputStream stream = new ByteArrayInputStream(pksData);         
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(stream, password);

KeyManagerFactory kmf = KeyManagerFactory.getInstance(
    KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();

TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(keyStore);
TrustManager[] trustManagers = tmfactory.getTrustManagers();

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
sslSocketFactory = sslContext.getSocketFactory();

问题是:是否有一种方法可以避免密钥存储库文件创建,并以某种方式从PublicKey和Certificate实例(例如,可以使用BouncyCastle的PemReader从PEM文件获得)开始构建SSLSocketFactory?

共有1个答案

艾正浩
2023-03-14

结果表明,仍然需要构建密钥存储实例,但可以在内存中完成(从PEM文件作为输入开始),而不需要使用KeyTool构建中间密钥存储文件。

要构建内存中的密钥存储库,可以使用如下代码:

private static final String TEMPORARY_KEY_PASSWORD = "changeit";

private KeyStore getKeyStore() throws ConfigurationException {
    try {
        Certificate clientCertificate = loadCertificate(certificatePem);
        PrivateKey privateKey = loadPrivateKey(privateKeyPem);
        Certificate caCertificate = loadCertificate(caPem);

        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca-cert", caCertificate);
        keyStore.setCertificateEntry("client-cert", clientCertificate);
        keyStore.setKeyEntry("client-key", privateKey, TEMPORARY_KEY_PASSWORD.toCharArray(), new Certificate[]{clientCertificate});
        return keyStore;
    } catch (GeneralSecurityException | IOException e) {
        throw new ConfigurationException("Cannot build keystore", e);
    }
}

private Certificate loadCertificate(String certificatePem) throws IOException, GeneralSecurityException {
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
    final byte[] content = readPemContent(certificatePem);
    return certificateFactory.generateCertificate(new ByteArrayInputStream(content));
}

private PrivateKey loadPrivateKey(String privateKeyPem) throws IOException, GeneralSecurityException {
    return pemLoadPrivateKeyPkcs1OrPkcs8Encoded(privateKeyPem);
}

private byte[] readPemContent(String pem) throws IOException {
    final byte[] content;
    try (PemReader pemReader = new PemReader(new StringReader(pem))) {
        final PemObject pemObject = pemReader.readPemObject();
        content = pemObject.getContent();
    }
    return content;
}

private static PrivateKey pemLoadPrivateKeyPkcs1OrPkcs8Encoded(
        String privateKeyPem) throws GeneralSecurityException, IOException {
    // PKCS#8 format
    final String PEM_PRIVATE_START = "-----BEGIN PRIVATE KEY-----";
    final String PEM_PRIVATE_END = "-----END PRIVATE KEY-----";

    // PKCS#1 format
    final String PEM_RSA_PRIVATE_START = "-----BEGIN RSA PRIVATE KEY-----";
    final String PEM_RSA_PRIVATE_END = "-----END RSA PRIVATE KEY-----";

    if (privateKeyPem.contains(PEM_PRIVATE_START)) { // PKCS#8 format
        privateKeyPem = privateKeyPem.replace(PEM_PRIVATE_START, "").replace(PEM_PRIVATE_END, "");
        privateKeyPem = privateKeyPem.replaceAll("\\s", "");

        byte[] pkcs8EncodedKey = Base64.getDecoder().decode(privateKeyPem);

        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));

    } else if (privateKeyPem.contains(PEM_RSA_PRIVATE_START)) {  // PKCS#1 format

        privateKeyPem = privateKeyPem.replace(PEM_RSA_PRIVATE_START, "").replace(PEM_RSA_PRIVATE_END, "");
        privateKeyPem = privateKeyPem.replaceAll("\\s", "");

        DerInputStream derReader = new DerInputStream(Base64.getDecoder().decode(privateKeyPem));

        DerValue[] seq = derReader.getSequence(0);

        if (seq.length < 9) {
            throw new GeneralSecurityException("Could not parse a PKCS1 private key.");
        }

        // skip version seq[0];
        BigInteger modulus = seq[1].getBigInteger();
        BigInteger publicExp = seq[2].getBigInteger();
        BigInteger privateExp = seq[3].getBigInteger();
        BigInteger prime1 = seq[4].getBigInteger();
        BigInteger prime2 = seq[5].getBigInteger();
        BigInteger exp1 = seq[6].getBigInteger();
        BigInteger exp2 = seq[7].getBigInteger();
        BigInteger crtCoef = seq[8].getBigInteger();

        RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2,
                exp1, exp2, crtCoef);

        KeyFactory factory = KeyFactory.getInstance("RSA");

        return factory.generatePrivate(keySpec);
    }

    throw new GeneralSecurityException("Not supported format of a private key");
}

其思想来源于以编程方式从PEM获取密钥存储库

 类似资料:
  • 我正在尝试对现有API启用Azure密钥库证书。我们已经在Azure Key Vault帐户中拥有秘密和Azure Key Vault证书。下面是配置证书的代码: 在我的本地计算机上,我正确地导入了证书,其中包括下载pfx格式。

  • 过去,我一直在通过导出带有密码的PFX证书来制作安全的TcpListener,但我想知道是否可以跳过这一步。 我没有使用商业SSL证书,并且有一个根CA,用于颁发服务器证书。在C#中托管TcpListener时,这些服务器证书需要额外的步骤(我想是因为没有使用CSR)。。。但是如果我有私钥和OpenSSL生成/使用的证书呢。 这很好,但是我必须发出openssl命令,从证书和私钥生成pfx文件,然

  • 我是新来配置Jetty服务器的SSL。我按照digcert的步骤创建了私钥文件、证书请求CSR文件。 我向CA发送了证书请求,并拿回了我签名的CSR。但是CA给我发了一个有两个证书的捆绑包,一个是我的证书,由CA签名,第二个是CA证书。(1star_xyx_abc_comcrt文件,2.CRT文件)。现在我面临着从这些文件创建密钥库的麻烦。 当我按照Oracle文档的步骤4、5和6使用keytoo

  • 我有一个集成,在其中验证另一个服务创建的JSON。它们提供了一个公共endpoint来获取要验证的公共证书。 但我正在为此设置一个测试,并希望与Nimbus创建相同的JWT,以使用我自己的私钥对其进行签名。所以我这样做(这是一个嵌套的加密JWT):https://connect2id.com/products/nimbus-jose-jwt/examples/signed-and-encrypte

  • 我试图签署一个Android应用程序,但显然原始的keystore文件是不可用的。我所得到的只有以下几点: 私钥md5 0123456789abcdef0123456789abcdef<--虚构值,但 证书md5 fedcba9876543210fedcba9876543210<-原始为32个十六进制数字 已签署的生产Android应用程序 是否有任何方法可以从这些资产中重新创建一个keystor

  • 如何为密钥对创建X509证书?(我的类已经有了密钥对,我需要创建一个证书来保存我的公钥,然后将其存储在密钥库中)。 我期望有一个X509证书构造函数能够接收我的公钥,然后通过keystore.set条目(pvtkey,cert)存储它,但我没有发现任何有用的关联新证书和我的密钥对... 任何想法? 编辑:我也试图通过证书链为空,但它不起作用,它看起来像一个错误报告http://bugs.sun.c