简体   繁体   English

将证书和私钥加载到 Java KeyStore

[英]Load certificate and private key into Java KeyStore

I'm trying to fetch a certificate and its private key from Azure Key Vault then call a remote server and do client certificate authentication.我正在尝试从 Azure Key Vault 获取证书及其私钥,然后调用远程服务器并进行客户端证书身份验证。

The first part works well (fetching from Key Vault), however i'm completely stuck at importing the public and private material into KeyStore.第一部分运行良好(从 Key Vault 获取),但是我完全坚持将公共和私有材料导入 KeyStore。

I've tried我试过了

keyStore.load(publicKey, null);
keyStore.load(new ByteArrayInputStream(privateKey.getBytes()),
    "thePassphrase".toCharArray());

but this leads to但这导致

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)

Here's the full thing minus what i don't know how to implement -这是完整的东西减去我不知道如何实现的东西 -

DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();

SecretClient secretClient = new SecretClientBuilder()
    .vaultUrl("https://<myvault>.vault.azure.net")
    .credential(credential)
    .buildClient();

CertificateClient certClient = new CertificateClientBuilder()
    .vaultUrl("https://<myvault>.vault.azure.net")
    .credential(credential)
    .buildClient();

// Get the public part of the cert
KeyVaultCertificateWithPolicy certificate = certClient.getCertificate("Joes-Crab-Shack");
byte[] publicKey = certificate.getCer();

// Get the private key
KeyVaultSecret secret = secretClient.getSecret(
    certificate.getName(),
    certificate.getProperties().getVersion());
String privateKey = secret.getValue();

// ***************
// How do i get the cert and its private key into KeyStore?
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// I've also tried "JKS" but that leads to
//    java.io.IOException: Invalid keystore format
keyStore.load(...)
// ***************

// Do client certificate authentication
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, null).build();

CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
response = httpClient.execute(new HttpGet("https://remote.that.asks.for.client.cert/"));

InputStream inputStream = response.getEntity().getContent();

body = IOUtils.readInputStreamToString(inputStream, Charsets.UTF_8);

How do i get the certificate and its private key into KeyStore so i can then use it in my HTTP client?我如何将证书及其私钥放入 KeyStore,以便我可以在我的 HTTP 客户端中使用它?

It sounds to me that the import is a "one time job" and do not need to get solved programmatically.在我看来,导入是一项“一次性工作”,不需要以编程方式解决。 I recommend (same as @pedrofb) that you use the Keystore Explorer for this job - it worked perfectly in my testcase:我建议(与@pedrofb 相同)您使用 Keystore Explorer 来完成这项工作 - 它在我的测试用例中完美运行:

Here are my steps to do the import, all files are available in my GitHub-Repo ( https://github.com/java-crypto/Stackoverflow/tree/master/Load_certificate_and_private_key_into_Java_KeyStore ):这是我进行导入的步骤,所有文件都在我的 GitHub-Repo ( https://github.com/java-crypto/Stackoverflow/tree/master/Load_certificate_and_private_key_into_Java_KeyStore ) 中可用:

  1. create the private key + certificate file with open ssl:使用打开的 ssl 创建私钥 + 证书文件:

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

This will create the 2 files key.pem (encrypted private key) and cert.pem (certificate with public key).这将创建 2 个文件 key.pem(加密的私钥)和 cert.pem(带有公钥的证书)。 I used some sample data and the password for key.pem is 123456.我使用了一些示例数据,key.pem 的密码是 123456。

  1. download the Keystore Explorer from https://keystore-explorer.org/downloads.htmlhttps://keystore-explorer.org/downloads.html下载 Keystore Explorer

  2. run explorer and create a new KeyStore运行资源管理器并创建一个新的 KeyStore

创建新的密钥库

  1. select KeyStore type = PKCS12 select KeyStore 类型 = PKCS12

选择密钥存储类型

  1. Import KeyPair with "Tools" - "Import Key Pair"使用“工具”导入密钥对 - “导入密钥对”

导入密钥对

  1. Select Key Pair Type as PKCS #8 Select 密钥对类型为 PKCS #8

选择密钥对类型

  1. Set the password (123456) and choose the key- and cert-file and press "Import"设置密码(123456)并选择密钥和证书文件,然后按“导入”

设置密码

  1. Choose the alias for the key (default is the given email in the certificate选择密钥的别名(默认为证书中给定的 email

选择别名

  1. Set a Key Pair Entry password: kpe123456设置密钥对输入密码:kpe123456

设置密钥对进入密码

  1. Message: Key Pair Import successful消息:密钥对导入成功

消息密钥对导入成功

保存新的密钥库

  1. save your new keystore with "File" - "Save as"使用“文件”-“另存为”保存新的密钥库

保存新的密钥库

  1. Set a password for the Key Store: ks123456为密钥库设置密码:ks123456

设置密钥库的密码

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

  2. ready - your private and certificate are imported in the new created Key Store keystore.p12准备就绪 - 您的私有证书和证书已导入新创建的密钥库 keystore.p12

It is a bit late, but I want to place a resolution that I have practiced whilst retrieving a certificate from Azure Keyvault then putting it into the java Keystore.有点晚了,但我想提出一个我在从 Azure Keyvault 检索证书然后将其放入 java 密钥库时实践过的解决方案。

The dependencies that I utilized are the following.我使用的依赖项如下。

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

Then, the code block is below.然后,代码块如下。

        char[] emptyPass = {};
        
        // 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);

        // "certificateStream" should be closed
        // 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);

        // "keyStream" should be closed as well.

        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, pass)
                .build(),
            NoopHostnameVerifier.INSTANCE);

        CloseableHttpClient httpClient = HttpClients.custom()
                                                    .setSSLSocketFactory(socketFactory)
                                                    .build();

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

I hope someone looking for a solution around using Azure Keyvault certificates in java Keystores can benefit from it.我希望在 java 密钥库中使用 Azure Keyvault 证书寻找解决方案的人可以从中受益。

When searching via Google and "azure key vault get private key" I found a GitHub-issue that describes in detail how to retrieve a private key from Azure Key Vault:通过 Google 和“azure key vault get private key”搜索时,我发现了一个 GitHub 问题,详细描述了如何从 Azure Key Vault 检索私钥:

https://github.com/Azure/azure-sdk-for-js/issues/7647 https://github.com/Azure/azure-sdk-for-js/issues/7647

Scrolling down to answer https://github.com/Azure/azure-sdk-for-js/issues/7647#issuecomment-594935307 there is this statement from one of the Dev's:向下滚动以回答https://github.com/Azure/azure-sdk-for-js/issues/7647#issuecomment-594935307有来自开发人员之一的以下声明:

How to obtain the private key如何获取私钥

Knowing that the private key is stored in a KeyVault Secret, with the public certificate included, we can retrieve it by using the KeyVault-Secrets client, as follows:知道私钥存储在 KeyVault Secret 中,包括公共证书,我们可以使用 KeyVault-Secrets 客户端检索它,如下所示:

// Using the same credential object we used before,
// and the same keyVaultUrl,
// let's create a SecretClient
const secretClient = new SecretClient(keyVaultUrl, credential);

// Assuming you've already created a KeyVault certificate,
// and that certificateName contains the name of your certificate
const certificateSecret = await secretClient.getSecret(certificateName);

// Here we can find both the private key and the public certificate, in PKCS 12 format:
const PKCS12Certificate = certificateSecret.value!;

// You can write this into a file:
fs.writeFileSync("myCertificate.p12", PKCS12Certificate);

Note that, by default, the contentType of the certificates is PKCS 12 .请注意,默认情况下,证书的 contentType 是 PKCS 12 Though specifying the content type of your certificate will make it trivial to get it's secret key in PEM format, let's explore how to retrieve a PEM secret key from a PKCS 12 certificate first.尽管指定证书的内容类型会使获取 PEM 格式的密钥变得微不足道,但让我们首先探讨如何从 PKCS 12 证书中检索 PEM 密钥。

Using openssl, you can retrieve the public certificate in PEM format by using the following command:
openssl pkcs12 -in myCertificate.p12 -out myCertificate.crt.pem -clcerts -nokeys
You can also use openssl to retrieve the private key, as follows:
openssl pkcs12 -in myCertificate.p12 -out myCertificate.key.pem -nocerts -nodes

In short: You do not need to "rebuild" a PKCS12-keystore from separate "files" (private key-PEM and certificate-PEM) as you get the PKCS12/P12-keystore as shown in the example .简而言之:您不需要从单独的“文件”(私钥-PEM 和证书-PEM)“重建”PKCS12-keystore,因为您获得了示例中所示的 PKCS12/P12-keystore

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 KeyStore 和 TrustStore 加载失败 - 私钥必须附带证书链 - KeyStore and TrustStore load failed - Private key must be accompanied by certificate chain 将证书加载到KeyStore(JAVA) - Load certificate to KeyStore (JAVA) 从私钥和 CA 证书包创建 java 密钥库 - Create java keystore from private key and CA certificate bundle 如何将证书链和私钥导入Java密钥库 - How to import certificate chain and private key into java keystore 使用 java.security.KeyStore 将椭圆曲线证书和私钥导入 Java Keystore - Import elliptic curve Certificate and Private Key into Java Keystore using java.security.KeyStore 如何使用Java KeyStore在Windows存储中加载私钥 - how to load private key in windows store using Java KeyStore 私钥和密钥库中签名证书之间的链接 - link between private key and signed certificate in keystore 未找到证书链,但密钥库包含私钥 - Certificate chain not found, but keystore contains private key 将受信任的证书(加上私钥/链)从Java密钥库(jks)传输到Windows证书管理器 - Transfer trusted certificate (plus private key / chain) from Java keystore (jks) to Windows Certificate Manager 我怎么知道Java密钥库中哪个别名包含证书和私钥? - How do I know which alias contains the certificate and private key in a Java keystore?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM