使用 Java SDK 从 Azure KeyVault 下载 .PFX 证书时遇到问题

问题描述 投票:0回答:2

使用 Java SDK 从 Azure KeyVault 下载 .PFX 证书时遇到问题。

下载后,在将证书上传到 Azure KeyVault 中的证书边栏选项卡之前,该证书无法像原始的十六进制编码 .PFX 文件一样打开。注意:我尝试了带密码的 PFX 文件和不带密码的 PFX 文件。

下载后,生成的 HEX 文件有 373 行和 14,919 个字符,且无法打开。上传之前,.pfx 十六进制文件有 374 行和 14,947 个字符。

有人知道我做错了什么吗?下载后,使用原始密码或空白密码,我收到此错误:

test.pfx is not a KeyStore of any of the following recognized types: JCE, JCEKS, PKCS#12, UBER or BCFKS
(我使用 Keystore Explorer 进行测试)

public static void main(String[] args) throws Exception {

    System.setProperty("AZURE_CLIENT_ID", "...");
    System.setProperty("AZURE_CLIENT_SECRET", "...");
    System.setProperty("AZURE_TENANT_ID", "..."");
    final DefaultAzureCredential azureCredential = new DefaultAzureCredentialBuilder()
            .build();
    CertificateClient certificateClient = new CertificateClientBuilder()
            .vaultUrl("https://djangofan-kv-test.vault.azure.net")
            .credential(azureCredential)
            .buildClient();

    String certificateName = "test";

    KeyVaultCertificateWithPolicy certificate = certificateClient.getCertificate(certificateName);
    CertificateKeyType keyType = certificate.getPolicy().getKeyType();
    System.out.println("\nKey type: " + keyType);

    String secretIdAndUrl = certificate.getKeyId();
    System.out.println("\nSecret ID: " + secretIdAndUrl);

    String secretValue = secretClient.getSecret(certificateName).getValue();
    System.out.println("\nSecret value:\n" + secretValue);

    Base64.Decoder decoder = Base64.getDecoder();
    byte[] decodedBytes = decoder.decode(secretValue);
    System.out.println("\nSecret value decoded:\n" + Arrays.toString(decodedBytes));

    String hexData = bytesToHex(decodedBytes);
    System.out.println("\nSecret value HEX dump:\n" + hexData);
    try (BufferedWriter writer = new BufferedWriter(new FileWriter("test.pfx", StandardCharsets.UTF_8))) {
        writer.write(hexData);
    }
    System.exit(0);
}

注意:从 KeyVault GUI 手动下载 .pfx 证书效果很好。

我也用SecretsClient尝试过这种方式:

SecretClient secretClient = new SecretClientBuilder()
        .vaultUrl("https://djangofan-kv-test.vault.azure.net")
        .credential(azureCredential)
        .buildClient();
String secretName = "secretnopass";
KeyVaultSecret secret = secretClient.getSecret(secretName);
String secretValue = secret.getValue();
System.out.println("\nSecret value:\n" + secretValue);
String hexData = bytesToHex(secretValue.getBytes(StandardCharsets.UTF_8));
System.out.println("\nSecret value HEX dump:\n" + hexData);

Maven 依赖项:

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-security-keyvault-certificates</artifactId>
  <version>4.3.0</version>
</dependency>
<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-security-keyvault-secrets</artifactId>
  <version>4.3.0</version>
</dependency>
<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-identity</artifactId>
  <version>1.3.5</version>
</dependency>

注意:我将尝试这种替代方法,但我不确定为什么直接下载到 keyVault 不起作用:https://youtu.be/26WGUCQ_LAI?t=618

azure-keyvault pfx azure-java-sdk certificate-store
2个回答
0
投票

PFX - 也称为 PKCS #12 - 是一种二进制编码。您不应该将

byte[]
编码为十六进制字符串以写入文件。即使原始证书导入是 PEM,您也不会进行任何解码 - 只需保存文件,该文件已标记为 Base64 编码数据。

请参阅我编写的 .NET SDK 实现。你在正确的道路上找到了秘密;不过,您应该使用附加到证书的秘密 ID:它是相同的 ID,这只是一个可能更改的实现细节。仅当内容类型为“application/x-pkcs12”时才进行 base64 解码。


0
投票

这是解决方案,尽管它并不理想,因为我的意思是我必须下载密钥库部分,然后在代码中重新组装它们以生成有效的密钥库。不幸的是,我找不到方法只将密钥库下载到我的函数中。也许这是因为该函数必须“在内存中执行操作”并且它没有文件存储。

为此,您需要将 3 个公共证书 + 1 个私钥上传到 KeyVault 实例的 Secrets 边栏选项卡中。

您可以通过引用传递方式将 KeyStore 对象传递到此方法中以重新构建密钥库:

private void addNonprodKeysToKeystore(KeyStore keyStore, String nonprodCertificateAlias, SecretClient secretClient) throws Exception {
    // get cert chain root cert
    KeyVaultSecret rootCertSecret = secretClient.getSecret(DIGICERT_ROOT_AZURE_PEM);
    String rootCertPEM = rootCertSecret.getValue();
    // get cert chain intermediate cert
    KeyVaultSecret intermediateCertSecret = secretClient.getSecret(DIGICERT_INTERMEDIATE_AZURE_PEM);
    String intermediateCertPEM = intermediateCertSecret.getValue();
    // get cert chain head cert
    KeyVaultSecret headCertSecret = secretClient.getSecret(HEAD_CERT_AZURE_PEM);
    String headCertPEM = headCertSecret.getValue();
    // build cert chain for keystore
    Certificate[] certificateChain = buildCertificateChain(headCertPEM, intermediateCertPEM, rootCertPEM);

    KeyVaultSecret privateKeySecret = secretClient.getSecret(PRIVATE_KEY_AZURE_PEM);
    String encodedPrivateKey = privateKeySecret.getValue();
    byte[] decodedPrivateKey = Base64.getDecoder().decode(encodedPrivateKey);
    String decodedPkString = new String(decodedPrivateKey, StandardCharsets.UTF_8);
    String strippedPkPEM = stripPEMHeadersFromPrivateKey(decodedPkString);
    byte[] decodedPkBody = Base64.getDecoder().decode(strippedPkPEM);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decodedPkBody);
    PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
    keyStore.setKeyEntry(nonprodCertificateAlias, privateKey, this.resolveKeystorePassword(), certificateChain);
}
© www.soinside.com 2019 - 2024. All rights reserved.