将证书和私钥加载到 Java KeyStore

evi*_*obu 5 java certificate keystore x509 azure-keyvault

我正在尝试从 Azure Key Vault 获取证书及其私钥,然后调用远程服务器并进行客户端证书身份验证。

第一部分运行良好(从 Key Vault 获取),但是我完全无法将公共和私有材料导入 KeyStore。

我试过了

keyStore.load(publicKey, null);
keyStore.load(new ByteArrayInputStream(privateKey.getBytes()),
    "thePassphrase".toCharArray());
Run Code Online (Sandbox Code Playgroud)

但这导致

java.io.IOException: DER input, Integer tag error
        at java.base/sun.security.util.DerInputStream.getInteger(DerInputStream.java:192)
        at java.base/sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1995)
        at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:222)
        at java.base/java.security.KeyStore.load(KeyStore.java:1479)
Run Code Online (Sandbox Code Playgroud)

这是全部内容减去我不知道如何实施的内容 -

keyStore.load(publicKey, null);
keyStore.load(new ByteArrayInputStream(privateKey.getBytes()),
    "thePassphrase".toCharArray());
Run Code Online (Sandbox Code Playgroud)

我如何将证书及其私钥放入 KeyStore 以便我可以在我的 HTTP 客户端中使用它?

nur*_*gin 6

虽然有点晚了,但我想提出一个我在从 Azure Keyvault 检索证书然后将其放入 java Keystore 时实践过的解决方案。

我使用的依赖项如下。

com.azure:azure-security-keyvault-certificates:jar:4.1.3
com.azure:azure-identity:jar:1.0.4
com.azure:azure-security-keyvault-secrets:jar:4.1.1
Run Code Online (Sandbox Code Playgroud)

然后,代码块如下。

public class RestTemplateProvider {

    @Value("${azure.keyvault.service.cert-alias}")
    private String alias;
    @Value("${azure.keyvault.tenant-id}")
    private String tenantId;
    @Value("${azure.keyvault.client-key}")
    private String clientSecret;
    @Value("${azure.keyvault.client-id}")
    private String clientId;
    @Value("${azure.keyvault.uri}")
    private String vaultUri;

    public RestTemplate provideRestTemplate() {
        char[] emptyPass = {};
        CloseIoStream closeableIoStream = CloseIoStream.newInstance();

        try {
            // Azure KeyVault Credentials
            ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                .tenantId(tenantId)
                .clientId(clientId)
                .clientSecret(clientSecret)
                .build();

            CertificateClient certificateClient = new CertificateClientBuilder()
                .vaultUrl(vaultUri)
                .credential(credential)
                .buildClient();

            SecretClient secretClient = new SecretClientBuilder()
                .vaultUrl(vaultUri)
                .credential(credential)
                .buildClient();
            // Azure KeyVault Credentials

            // Retrieving certificate
            KeyVaultCertificateWithPolicy certificateWithPolicy = certificateClient.getCertificate(alias);
            KeyVaultSecret secret = secretClient.getSecret(alias, certificateWithPolicy.getProperties().getVersion());

            byte[] rawCertificate = certificateWithPolicy.getCer();
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ByteArrayInputStream certificateStream = new ByteArrayInputStream(rawCertificate);
            Certificate certificate = cf.generateCertificate(certificateStream);

            close(certificateStream);
            // Retrieving certificate

            // Retrieving private key
            String base64PrivateKey = secret.getValue();
            byte[] rawPrivateKey = Base64.getDecoder().decode(base64PrivateKey);

            KeyStore rsaKeyGenerator = KeyStore.getInstance(KeyStore.getDefaultType());
            ByteArrayInputStream keyStream = new ByteArrayInputStream(rawPrivateKey);
            rsaKeyGenerator.load(keyStream, null);

            close(keyStream);

            Key rsaPrivateKey = rsaKeyGenerator.getKey(rsaKeyGenerator.aliases().nextElement(), emptyPass);
            // Retrieving private key

            // Importing certificate and private key into the KeyStore
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setKeyEntry(alias, rsaPrivateKey, emptyPass, new Certificate[] {certificate});
            // Importing certificate and private key into the KeyStore

            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
                new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustAllStrategy())
                    .loadKeyMaterial(keyStore, emptyPass)
                    .build(),
                NoopHostnameVerifier.INSTANCE);

            // It is just a sample, except for the sslsocketfactory please use the configuration which is right for you.
            CloseableHttpClient httpClient = HttpClients.custom()
                                                        .setSSLSocketFactory(socketFactory)
                                                        .setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS)
                                                        .setKeepAliveStrategy((httpResponse, httpContext) -> 10 * 1000)
                                                        .build();

            ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            RestTemplate restTemplate = new RestTemplate(requestFactory);

            return restTemplate;
        } catch (IOException | CertificateException
            | NoSuchAlgorithmException | UnrecoverableKeyException
            | KeyStoreException | KeyManagementException e) {
            log.error("Error!!!")
        }

        return null;
    }

    private void close(Closeable c) {
        if (c != null) {
            try {
                c.close();
            } catch (IOException e) {
                // log
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望寻找在 java Keystore 中使用 Azure Keyvault 证书的解决方案的人可以从中受益。


Mic*_*ehr 1

在我看来,导入是一项“一次性工作”,不需要以编程方式解决。我建议(与 @pedrofb 相同)您使用 Keystore Explorer 来完成这项工作 - 它在我的测试用例中完美运行:

以下是我进行导入的步骤,所有文件都可以在我的 GitHub-Repo 中找到(https://github.com/java-crypto/Stackoverflow/tree/master/Load_certificate_and_private_key_into_Java_KeyStore):

  1. 使用打开的 ssl 创建私钥+证书文件:

openssl req -x509 -days 365 -newkey rsa:2048 -keyout key.pem -out cert.pem

这将创建 2 个文件 key.pem(加密私钥)和 cert.pem(带有公钥的证书)。我使用了一些示例数据,key.pem 的密码是 123456。

  1. 从https://keystore-explorer.org/downloads.html下载密钥库资源管理器

  2. 运行资源管理器并创建一个新的 KeyStore

创建新的密钥库

  1. 选择密钥库类型 = PKCS12

选择密钥库类型

  1. 通过“工具”-“导入密钥对”导入密钥对

导入密钥对

  1. 选择密钥对类型作为 PKCS #8

选择密钥对类型

  1. 设置密码(123456)并选择密钥和证书文件,然后按“导入”

设置密码

  1. 选择密钥的别名(默认是证书中给定的电子邮件

选择别名

  1. 设置密钥对条目密码:kpe123456

设置密钥对输入密码

  1. 消息:密钥对导入成功

消息密钥对导入成功

保存您的新密钥库

  1. 使用“文件”-“另存为”保存新的密钥库

保存您的新密钥库

  1. 设置密钥库密码:ks123456

为密钥库设置密码

  1. 选择路径+文件名:keystore.p12

  2. 准备好 - 您的私有和证书将导入到新创建的密钥库 keystore.p12 中

  • 抱歉,我没有提到我不想放置静态 .pem 或 .pfx 或 .jks (已经可以使用,例如在 KeyStore 中加载 PFX 捆绑包),我只想获取 pub + 私钥材料通过安全机制(在本例中为托管标识)从 Azure Key Vault 获取。这也将使代码高度可移植(云/PaaS 平台/操作系统),并且不依赖于手动步骤,它还为我提供了托管证书续订,而无需再担心该证书。我非常欣赏你的文章。 (2认同)