[英]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 ) 中可用:
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。
download the Keystore Explorer from https://keystore-explorer.org/downloads.html从https://keystore-explorer.org/downloads.html下载 Keystore Explorer
run explorer and create a new KeyStore运行资源管理器并创建一个新的 KeyStore
choose path + filename: keystore.p12选择路径+文件名:keystore.p12
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.