diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultClient.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultClient.java index 4c24037edb8a1..7ea0c267afd05 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultClient.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultClient.java @@ -8,20 +8,26 @@ import com.azure.security.keyvault.jca.model.CertificatePolicy; import com.azure.security.keyvault.jca.model.KeyProperties; import com.azure.security.keyvault.jca.model.SecretBundle; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.Key; +import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Base64; import java.util.HashMap; @@ -249,16 +255,25 @@ Key getKey(String alias, char[] password) { if (body != null) { JsonConverter converter = JsonConverterFactory.createJsonConverter(); SecretBundle secretBundle = (SecretBundle) converter.fromJson(body, SecretBundle.class); - try { - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - keyStore.load( - new ByteArrayInputStream(Base64.getDecoder().decode(secretBundle.getValue())), - "".toCharArray() - ); - alias = keyStore.aliases().nextElement(); - key = keyStore.getKey(alias, "".toCharArray()); - } catch (IOException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException ex) { - LOGGER.log(WARNING, "Unable to decode key", ex); + if (secretBundle.getContentType().equals("application/x-pkcs12")) { + try { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load( + new ByteArrayInputStream(Base64.getDecoder().decode(secretBundle.getValue())), + "".toCharArray() + ); + alias = keyStore.aliases().nextElement(); + key = keyStore.getKey(alias, "".toCharArray()); + } catch (IOException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException ex) { + LOGGER.log(WARNING, "Unable to decode key", ex); + } + } + if (secretBundle.getContentType().equals("application/x-pem-file")) { + try { + key = createPrivateKeyFromPem(secretBundle.getValue()); + } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | IllegalArgumentException ex) { + LOGGER.log(WARNING, "Unable to decode key", ex); + } } } } @@ -271,4 +286,37 @@ Key getKey(String alias, char[] password) { LOGGER.exiting("KeyVaultClient", "getKey", key); return key; } + + /** + * Get the private key from the PEM string. + * + * @param pemString the PEM file in string format. + * @return the private key + * @throws IOException when an I/O error occurs. + * @throws NoSuchAlgorithmException when algorithm is unavailable. + * @throws InvalidKeySpecException when the private key cannot be generated. + */ + private PrivateKey createPrivateKeyFromPem(String pemString) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + + StringBuilder builder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new StringReader(pemString))) { + String line = reader.readLine(); + if (line == null || !line.contains("BEGIN PRIVATE KEY")) { + throw new IllegalArgumentException("No PRIVATE KEY found"); + } + line = ""; + while (line != null) { + if (line.contains("END PRIVATE KEY")) { + break; + } + builder.append(line); + line = reader.readLine(); + } + } + byte[] bytes = Base64.getDecoder().decode(builder.toString()); + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes); + KeyFactory factory = KeyFactory.getInstance("RSA"); + return factory.generatePrivate(spec); + } } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java index 5fc5d1ff27750..3b1557f0538f4 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java @@ -179,6 +179,9 @@ public Key engineGetKey(String alias, char[] password) { key = keyVaultClient.getKey(alias, password); if (key != null) { certificateKeys.put(alias, key); + if (aliases == null) { + aliases = keyVaultClient.getAliases(); + } if (!aliases.contains(alias)) { aliases.add(alias); } diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/SecretBundle.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/SecretBundle.java index 7e77605c7d082..b955d7c968f17 100644 --- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/SecretBundle.java +++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/model/SecretBundle.java @@ -14,12 +14,26 @@ public class SecretBundle implements Serializable { * Stores the serial version UID. */ private static final long serialVersionUID = 1L; + + /** + * Stores the content type. + */ + private String contentType; /** * Stores the value. */ private String value; + /** + * Get the content type. + * + * @return the content type. + */ + public String getContentType() { + return contentType; + } + /** * Get the value. * @@ -28,6 +42,15 @@ public class SecretBundle implements Serializable { public String getValue() { return value; } + + /** + * Set the content type. + * + * @param contentType the content type. + */ + public void setContentType(String contentType) { + this.contentType = contentType; + } /** * Set the value.