Overload createKeyStore to allow password parameter to be set
- Overload the CertificateBundle.createKeyStore() to allow a String password parameter to be set - Overload the static KeystoreUtil.createKeyStore() to allow a String password parameter to be set - Added javadoc and unit tests - Code formatting, best practices and cosmetic changes Fixes gh-708 Original pull request: gh-711
This commit is contained in:
committed by
Mark Paluch
parent
dd9c3cfab8
commit
e7fa983fa4
@@ -44,6 +44,7 @@ import org.springframework.vault.VaultException;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Alex Bremora
|
||||
* @author Bogdan Cardos
|
||||
* @see #getPrivateKeySpec()
|
||||
* @see #getX509Certificate()
|
||||
* @see #getIssuingCaCertificate()
|
||||
@@ -147,13 +148,13 @@ public class CertificateBundle extends Certificate {
|
||||
*/
|
||||
public String getRequiredPrivateKeyType() {
|
||||
|
||||
String privateKeyType = getPrivateKeyType();
|
||||
String requiredPrivateKeyType = getPrivateKeyType();
|
||||
|
||||
if (privateKeyType == null) {
|
||||
if (requiredPrivateKeyType == null) {
|
||||
throw new IllegalStateException("Private key type is not set");
|
||||
}
|
||||
|
||||
return privateKeyType;
|
||||
return requiredPrivateKeyType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,6 +182,30 @@ public class CertificateBundle extends Certificate {
|
||||
return createKeyStore(keyAlias, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param password the password to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public KeyStore createKeyStore(String keyAlias, String password) {
|
||||
return createKeyStore(keyAlias, false, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param password the password to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public KeyStore createKeyStore(String keyAlias, char[] password) {
|
||||
return createKeyStore(keyAlias, false, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain.
|
||||
@@ -191,8 +216,38 @@ public class CertificateBundle extends Certificate {
|
||||
* @since 2.3.3
|
||||
*/
|
||||
public KeyStore createKeyStore(String keyAlias, boolean includeCaChain) {
|
||||
return createKeyStore(keyAlias, includeCaChain, new char[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param includeCaChain whether to include the certificate authority chain instead of
|
||||
* just the issuer certificate.
|
||||
* @param password the password to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public KeyStore createKeyStore(String keyAlias, boolean includeCaChain, String password) {
|
||||
Assert.hasText(password, "Password must not be empty");
|
||||
return createKeyStore(keyAlias, includeCaChain, password.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param includeCaChain whether to include the certificate authority chain instead of
|
||||
* just the issuer certificate.
|
||||
* @param password the password to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public KeyStore createKeyStore(String keyAlias, boolean includeCaChain, char[] password) {
|
||||
|
||||
Assert.hasText(keyAlias, "Key alias must not be empty");
|
||||
Assert.notNull(password, "Password must not be null");
|
||||
|
||||
try {
|
||||
|
||||
@@ -206,7 +261,7 @@ public class CertificateBundle extends Certificate {
|
||||
certificates.add(getX509IssuerCertificate());
|
||||
}
|
||||
|
||||
return KeystoreUtil.createKeyStore(keyAlias, getPrivateKeySpec(),
|
||||
return KeystoreUtil.createKeyStore(keyAlias, getPrivateKeySpec(), password,
|
||||
certificates.toArray(new X509Certificate[0]));
|
||||
}
|
||||
catch (GeneralSecurityException | IOException e) {
|
||||
@@ -223,7 +278,7 @@ public class CertificateBundle extends Certificate {
|
||||
|
||||
List<X509Certificate> certificates = new ArrayList<>();
|
||||
|
||||
for (String data : caChain) {
|
||||
for (String data : this.caChain) {
|
||||
try {
|
||||
certificates.addAll(getCertificates(data));
|
||||
}
|
||||
|
||||
@@ -32,11 +32,14 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Keystore utility to create a {@link KeyStore} containing a {@link CertificateBundle}
|
||||
* with the certificate chain and its private key.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Cardos
|
||||
*/
|
||||
class KeystoreUtil {
|
||||
|
||||
@@ -73,14 +76,62 @@ class KeystoreUtil {
|
||||
/**
|
||||
* Create a {@link KeyStore} containing the {@link KeySpec} and {@link X509Certificate
|
||||
* certificates} using the given {@code keyAlias}.
|
||||
* @param keyAlias
|
||||
* @param certificates
|
||||
* @return
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param privateKeySpec the private key to use.
|
||||
* @param certificates the certificate chain to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @throws GeneralSecurityException if exception occur when creating the instance of
|
||||
* the {@link KeyStore}
|
||||
* @throws IOException if there is an I/O or format problem with the keystore data, if
|
||||
* a password is required but not given, or if the given password was incorrect. If
|
||||
* the error is due to a wrong password, the {@link Throwable#getCause cause} of the
|
||||
* {@code IOException} should be an {@code UnrecoverableKeyException}
|
||||
*/
|
||||
static KeyStore createKeyStore(String keyAlias, KeySpec privateKeySpec, X509Certificate... certificates)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return createKeyStore(keyAlias, privateKeySpec, new char[0], certificates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} containing the {@link KeySpec} and {@link X509Certificate
|
||||
* certificates} using the given {@code keyAlias} and {@code keyPassword}.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param privateKeySpec the private key to use.
|
||||
* @param keyPassword the password to use.
|
||||
* @param certificates the certificate chain to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @throws GeneralSecurityException if exception occur when creating the instance of
|
||||
* the {@link KeyStore}
|
||||
* @throws IOException if there is an I/O or format problem with the keystore data, if
|
||||
* a password is required but not given, or if the given password was incorrect. If
|
||||
* the error is due to a wrong password, the {@link Throwable#getCause cause} of the
|
||||
* {@code IOException} should be an {@code UnrecoverableKeyException}
|
||||
*/
|
||||
static KeyStore createKeyStore(String keyAlias, KeySpec privateKeySpec, String keyPassword,
|
||||
X509Certificate... certificates) throws GeneralSecurityException, IOException {
|
||||
Assert.hasText(keyPassword, "keyPassword must not be empty");
|
||||
return createKeyStore(keyAlias, privateKeySpec, keyPassword.toCharArray(), certificates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link KeyStore} containing the {@link KeySpec} and {@link X509Certificate
|
||||
* certificates} using the given {@code keyAlias} and {@code keyPassword}.
|
||||
* @param keyAlias the key alias to use.
|
||||
* @param privateKeySpec the private key to use.
|
||||
* @param keyPassword the password to use.
|
||||
* @param certificates the certificate chain to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
* @throws GeneralSecurityException if exception occur when creating the instance of
|
||||
* the {@link KeyStore}
|
||||
* @throws IOException if there is an I/O or format problem with the keystore data, if
|
||||
* a password is required but not given, or if the given password was incorrect. If
|
||||
* the error is due to a wrong password, the {@link Throwable#getCause cause} of the
|
||||
* {@code IOException} should be an {@code UnrecoverableKeyException}
|
||||
*/
|
||||
static KeyStore createKeyStore(String keyAlias, KeySpec privateKeySpec, char[] keyPassword,
|
||||
X509Certificate... certificates) throws GeneralSecurityException, IOException {
|
||||
|
||||
Assert.notNull(keyPassword, "keyPassword must not be null");
|
||||
|
||||
PrivateKey privateKey = (privateKeySpec instanceof RSAPrivateKeySpec
|
||||
|| privateKeySpec instanceof PKCS8EncodedKeySpec) ? RSA_KEY_FACTORY.generatePrivate(privateKeySpec)
|
||||
@@ -91,7 +142,7 @@ class KeystoreUtil {
|
||||
List<X509Certificate> certChain = new ArrayList<>();
|
||||
Collections.addAll(certChain, certificates);
|
||||
|
||||
keyStore.setKeyEntry(keyAlias, privateKey, new char[0],
|
||||
keyStore.setKeyEntry(keyAlias, privateKey, keyPassword,
|
||||
certChain.toArray(new java.security.cert.Certificate[certChain.size()]));
|
||||
|
||||
return keyStore;
|
||||
@@ -100,10 +151,14 @@ class KeystoreUtil {
|
||||
/**
|
||||
* Create a {@link KeyStore} containing the {@link X509Certificate certificates}
|
||||
* stored with as {@code cert_0, cert_1...cert_N}.
|
||||
* @param certificates
|
||||
* @return
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
* @param certificates the certificate chain to use.
|
||||
* @return the {@link KeyStore} containing the certificate chain.
|
||||
* @throws GeneralSecurityException if exception occur when creating the instance of
|
||||
* the {@link KeyStore}
|
||||
* @throws IOException if there is an I/O or format problem with the keystore data, if
|
||||
* a password is required but not given, or if the given password was incorrect. If
|
||||
* the error is due to a wrong password, the {@link Throwable#getCause cause} of the
|
||||
* {@code IOException} should be an {@code UnrecoverableKeyException}
|
||||
* @since 2.0
|
||||
*/
|
||||
static KeyStore createKeyStore(X509Certificate... certificates) throws GeneralSecurityException, IOException {
|
||||
@@ -133,8 +188,12 @@ class KeystoreUtil {
|
||||
/**
|
||||
* Create an empty {@link KeyStore}.
|
||||
* @return the {@link KeyStore}.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
* @throws GeneralSecurityException if exception occur when creating the instance of
|
||||
* the {@link KeyStore}
|
||||
* @throws IOException if there is an I/O or format problem with the keystore data, if
|
||||
* a password is required but not given, or if the given password was incorrect. If
|
||||
* the error is due to a wrong password, the {@link Throwable#getCause cause} of the
|
||||
* {@code IOException} should be an {@code UnrecoverableKeyException}
|
||||
*/
|
||||
private static KeyStore createKeyStore() throws GeneralSecurityException, IOException {
|
||||
|
||||
|
||||
@@ -276,14 +276,12 @@ public class PemObject {
|
||||
|
||||
enum PemObjectType {
|
||||
|
||||
CERTIFICATE_REQUEST("CERTIFICATE REQUEST"), NEW_CERTIFICATE_REQUEST("NEW CERTIFICATE REQUEST"), CERTIFICATE(
|
||||
"CERTIFICATE"), TRUSTED_CERTIFICATE("TRUSTED CERTIFICATE"), X509_CERTIFICATE(
|
||||
"X509 CERTIFICATE"), X509_CRL("X509 CRL"), PKCS7("PKCS7"), CMS("CMS"), ATTRIBUTE_CERTIFICATE(
|
||||
"ATTRIBUTE CERTIFICATE"), EC_PARAMETERS(
|
||||
"EC PARAMETERS"), PUBLIC_KEY("PUBLIC KEY"), RSA_PUBLIC_KEY(
|
||||
"RSA PUBLIC KEY"), RSA_PRIVATE_KEY("RSA PRIVATE KEY"), EC_PRIVATE_KEY(
|
||||
"EC PRIVATE KEY"), ENCRYPTED_PRIVATE_KEY(
|
||||
"ENCRYPTED PRIVATE KEY"), PRIVATE_KEY("PRIVATE KEY");
|
||||
CERTIFICATE_REQUEST("CERTIFICATE REQUEST"), NEW_CERTIFICATE_REQUEST("NEW CERTIFICATE REQUEST"),
|
||||
CERTIFICATE("CERTIFICATE"), TRUSTED_CERTIFICATE("TRUSTED CERTIFICATE"), X509_CERTIFICATE("X509 CERTIFICATE"),
|
||||
X509_CRL("X509 CRL"), PKCS7("PKCS7"), CMS("CMS"), ATTRIBUTE_CERTIFICATE("ATTRIBUTE CERTIFICATE"),
|
||||
EC_PARAMETERS("EC PARAMETERS"), PUBLIC_KEY("PUBLIC KEY"), RSA_PUBLIC_KEY("RSA PUBLIC KEY"),
|
||||
RSA_PRIVATE_KEY("RSA PRIVATE KEY"), EC_PRIVATE_KEY("EC PRIVATE KEY"),
|
||||
ENCRYPTED_PRIVATE_KEY("ENCRYPTED PRIVATE KEY"), PRIVATE_KEY("PRIVATE KEY");
|
||||
|
||||
// cache
|
||||
private static final PemObjectType[] constants = values();
|
||||
|
||||
@@ -109,7 +109,7 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
this.vaultOperations.write("pki/config/ca", pembundle);
|
||||
|
||||
Map<String, String> role = new HashMap<String, String>();
|
||||
Map<String, String> role = new HashMap<>();
|
||||
role.put("allowed_domains", "localhost,example.com");
|
||||
role.put("allow_subdomains", "true");
|
||||
role.put("allow_localhost", "true");
|
||||
@@ -150,8 +150,20 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
KeyStore keyStore = data.createKeyStore("vault");
|
||||
assertThat(keyStore.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPassword = data.createKeyStore("vault", "mypassword");
|
||||
assertThat(keyStoreWithPassword.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPasswordChar = data.createKeyStore("vault", new char[0]);
|
||||
assertThat(keyStoreWithPasswordChar.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithCaChain = data.createKeyStore("vault", true);
|
||||
assertThat(keyStoreWithCaChain.getCertificateChain("vault")).hasSize(3);
|
||||
|
||||
KeyStore keyStoreWithCaChainAndPassword = data.createKeyStore("vault", true, "mypassword");
|
||||
assertThat(keyStoreWithCaChainAndPassword.getCertificateChain("vault")).hasSize(3);
|
||||
|
||||
KeyStore keyStoreWithCaChainAndPasswordChar = data.createKeyStore("vault", true, new char[0]);
|
||||
assertThat(keyStoreWithCaChainAndPasswordChar.getCertificateChain("vault")).hasSize(3);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -175,8 +187,21 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
KeyStore keyStore = data.createKeyStore("vault");
|
||||
assertThat(keyStore.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPassword = data.createKeyStore("vault", "mypassword");
|
||||
assertThat(keyStoreWithPassword.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPasswordChar = data.createKeyStore("vault", new char[0]);
|
||||
assertThat(keyStoreWithPasswordChar.getCertificateChain("vault")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithCaChain = data.createKeyStore("vault", true);
|
||||
assertThat(keyStoreWithCaChain.getCertificateChain("vault")).hasSize(3);
|
||||
|
||||
KeyStore keyStoreWithCaChainAndPassword = data.createKeyStore("vault", true, "mypassword");
|
||||
assertThat(keyStoreWithCaChainAndPassword.getCertificateChain("vault")).hasSize(3);
|
||||
|
||||
KeyStore keyStoreWithCaChainAndPasswordChar = data.createKeyStore("vault", true, new char[0]);
|
||||
assertThat(keyStoreWithCaChainAndPasswordChar.getCertificateChain("vault")).hasSize(3);
|
||||
|
||||
}
|
||||
|
||||
static Stream<KeyFixture> keyTypeFixtures() {
|
||||
@@ -213,7 +238,7 @@ class VaultPkiTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s, %s, %s]", format, privateKeyFormat, keyType);
|
||||
return String.format("[%s, %s, %s]", this.format, this.privateKeyFormat, this.keyType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,10 +41,9 @@ class CertificateBundleUnitTests {
|
||||
|
||||
CertificateBundle certificateBundle;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
void before() {
|
||||
certificateBundle = loadCertificateBundle("certificate.json");
|
||||
this.certificateBundle = loadCertificateBundle("certificate.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,9 +102,16 @@ class CertificateBundleUnitTests {
|
||||
|
||||
CertificateBundle bundle = loadCertificateBundle("certificate.json");
|
||||
KeyStore keyStore = bundle.createKeyStore("mykey");
|
||||
|
||||
assertThat(keyStore.size()).isEqualTo(1);
|
||||
assertThat(keyStore.getCertificateChain("mykey")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPassword = bundle.createKeyStore("mykey", "mypassword");
|
||||
assertThat(keyStoreWithPassword.size()).isEqualTo(1);
|
||||
assertThat(keyStoreWithPassword.getCertificateChain("mykey")).hasSize(2);
|
||||
|
||||
KeyStore keyStoreWithPasswordChar = bundle.createKeyStore("mykey", new char[0]);
|
||||
assertThat(keyStoreWithPasswordChar.size()).isEqualTo(1);
|
||||
assertThat(keyStoreWithPasswordChar.getCertificateChain("mykey")).hasSize(2);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -116,8 +122,13 @@ class CertificateBundleUnitTests {
|
||||
|
||||
CertificateBundle bundle = loadCertificateBundle(path);
|
||||
KeyStore keyStore = bundle.createKeyStore("localhost");
|
||||
|
||||
assertThat(keyStore).isNotNull();
|
||||
|
||||
KeyStore keyStoreWithPassword = bundle.createKeyStore("localhost", "mypassword");
|
||||
assertThat(keyStoreWithPassword).isNotNull();
|
||||
|
||||
KeyStore keyStoreWithPasswordChar = bundle.createKeyStore("localhost", new char[0]);
|
||||
assertThat(keyStoreWithPasswordChar).isNotNull();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -126,11 +137,15 @@ class CertificateBundleUnitTests {
|
||||
|
||||
CertificateBundle bundle = loadCertificateBundle(path);
|
||||
KeyStore keyStore = bundle.createKeyStore("localhost");
|
||||
|
||||
assertThat(keyStore).isNotNull();
|
||||
|
||||
KeyStore keyStoreWithPassword = bundle.createKeyStore("localhost", "mypassword");
|
||||
assertThat(keyStoreWithPassword).isNotNull();
|
||||
|
||||
KeyStore keyStoreWithPasswordChar = bundle.createKeyStore("localhost", new char[0]);
|
||||
assertThat(keyStoreWithPasswordChar).isNotNull();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
CertificateBundle loadCertificateBundle(String path) {
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user