From 0d52fe861a46f8ba595bdd34b106c98096c4304b Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Thu, 18 Jun 2020 14:39:29 +0200 Subject: add symmetric-key functionality into EaafKeyStoreFactory that supports passphrase based symmetric keys and keys from HSM-Facade --- .../core/impl/credential/EaafKeyStoreFactory.java | 123 +++++++++++- .../core/impl/credential/EaafKeyStoreUtils.java | 5 +- .../impl/credential/SymmetricKeyConfiguration.java | 221 +++++++++++++++++++++ .../SecurePendingRequestIdGenerationStrategy.java | 57 ++++-- .../messages/eaaf_utils_message.properties | 2 + .../test/credentials/EaafKeyStoreFactoryTest.java | 162 +++++++++++++++ .../credentials/SymmetricKeyConfigurationTest.java | 162 +++++++++++++++ 7 files changed, 705 insertions(+), 27 deletions(-) create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java index 9db38670..711a3517 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java @@ -2,6 +2,7 @@ package at.gv.egiz.eaaf.core.impl.credential; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.security.Key; @@ -12,13 +13,19 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.Security; +import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.PostConstruct; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -26,10 +33,12 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.utils.FileUtils; import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; @@ -53,6 +62,8 @@ public class EaafKeyStoreFactory { public static final String ERRORCODE_06 = "internal.keystore.06"; public static final String ERRORCODE_07 = "internal.keystore.07"; public static final String ERRORCODE_10 = "internal.keystore.10"; + + public static final String ERRORCODE_KEY_00 = "internal.key.00"; private static final String HSM_FACADE_PROVIDER_CLASS = "at.asitplus.hsmfacade.provider.HsmFacadeProvider"; private static final String HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS @@ -71,6 +82,43 @@ public class EaafKeyStoreFactory { private boolean isHsmFacadeInitialized = false; + /** + * Get a new symmetric key based on a {@link SymmetricKeyConfiguration} object. + * + * @param config Symmetric key configuration + * @return {@link Pair} of a new {@link SecretKey} instance and an optional {@link Provider}. + * The {@link SecretKey} is {@link Nonnull}. If the {@link Provider} is not null + * this {@link SecretKey} requires a specific {@link Provider} for {@link Key} operations. + * @throws EaafException In case of a KeyStore initialization error + */ + @Nonnull + public Pair buildNewSymmetricKey(SymmetricKeyConfiguration config) throws EaafException { + log.trace("Starting symmetric-key generation based on configuration object ... "); + if (SymmetricKeyType.PASSPHRASE.equals(config.getKeyType())) { + return generatePassPhraseBasedSymmetricKey(config); + + } else if (SymmetricKeyType.HSMFACADE.equals(config.getKeyType())) { + if (isHsmFacadeInitialized) { + return getSymmetricKeyFromHsmFacade(config); + + } else { + log.error("HSMFacade can NOT be used for symmetric Key: {} because {} is not initialized", + config.getFriendlyName()); + throw new EaafConfigurationException(ERRORCODE_00, + new Object[] { config.getFriendlyName() }); + + } + + } else { + log.warn("Symmetric KeyType: {} is unrecognized", config.getKeyType()); + throw new EaafConfigurationException(ERRORCODE_01, + new Object[] { config.getFriendlyName() }); + + } + + + } + /** * Get a new KeyStore based on a KeyStore configuration-object. * @@ -241,24 +289,31 @@ public class EaafKeyStoreFactory { @Nonnull private Pair getKeyStoreFromHsmFacade(KeyStoreConfiguration config) throws EaafFactoryException, EaafConfigurationException { - final String keyStoreName = checkConfigurationParameter(config.getKeyStoreName(), - ERRORCODE_06, config.getFriendlyName(), "KeyStoreName missing for HSM Facade"); + return getKeyStoreFromHsmFacade(config.getKeyStoreName(), config.getFriendlyName()); + + } + + @Nonnull + private Pair getKeyStoreFromHsmFacade(String keyStoreName, String friendlyName) + throws EaafFactoryException, EaafConfigurationException { + final String validatedKeyStoreName = checkConfigurationParameter(keyStoreName, + ERRORCODE_06, friendlyName, "KeyStoreName missing for HSM Facade"); try { final KeyStore keyStore = KeyStore.getInstance(HSM_FACADE_KEYSTORE_TYPE, HSM_FACADE_PROVIDER); - keyStore.load(getHsmFacadeKeyStoreParameter(keyStoreName)); + keyStore.load(getHsmFacadeKeyStoreParameter(validatedKeyStoreName)); return Pair.newInstance(keyStore, keyStore.getProvider()); } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException | NoSuchProviderException | EaafException e) { log.error("Can not initialize KeyStore: {} with reason: {}", - config.getFriendlyName(), e.getMessage()); + friendlyName, e.getMessage()); throw new EaafFactoryException(ERRORCODE_06, - new Object[] { config.getFriendlyName(), e.getMessage() }, e); + new Object[] {friendlyName, e.getMessage() }, e); } } - + private KeyStore.LoadStoreParameter getHsmFacadeKeyStoreParameter(String keyStoreName) throws EaafException { try { Class clazz = Class.forName(HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS); @@ -274,6 +329,62 @@ public class EaafKeyStoreFactory { } + @Nonnull + private Pair generatePassPhraseBasedSymmetricKey(SymmetricKeyConfiguration config) + throws EaafConfigurationException { + checkConfigurationParameter(config.getSoftKeyPassphrase(), + ERRORCODE_KEY_00, config.getFriendlyName(), "passphrase missing"); + checkConfigurationParameter(config.getSoftKeySalt(), + ERRORCODE_KEY_00, config.getFriendlyName(), "salt missing"); + + try { + final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); + final KeySpec spec = new PBEKeySpec( + config.getSoftKeyPassphrase().toCharArray(), + config.getSoftKeySalt().getBytes("UTF-8"), + 10000, 128); + return Pair.newInstance(keyFactory.generateSecret(spec), null); + + } catch (NoSuchAlgorithmException | InvalidKeySpecException | UnsupportedEncodingException e) { + log.error("Passphrase based symmetric-key generation FAILED", e); + throw new EaafConfigurationException(ERRORCODE_KEY_00, + new Object[] { config.getFriendlyName(), e.getMessage() }, + e); + + } + } + + @Nonnull + private Pair getSymmetricKeyFromHsmFacade(SymmetricKeyConfiguration config) + throws EaafFactoryException, EaafConfigurationException, EaafKeyAccessException { + Pair keyStore = getKeyStoreFromHsmFacade( + config.getKeyStoreName(), config.getFriendlyName()); + + checkConfigurationParameter(config.getKeyAlias(), + ERRORCODE_KEY_00, config.getFriendlyName(), "keyAlias missing"); + + try { + SecretKey secretKey = (SecretKey) keyStore.getFirst().getKey(config.getKeyAlias(), null); + if (secretKey == null) { + throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09, + config.getFriendlyName(), config.getKeyAlias(), "No SecretKey with Alias "); + + } + + return Pair.newInstance(secretKey, keyStore.getSecond()); + + } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { + throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09, e, + config.getFriendlyName(), config.getKeyAlias(), e.getMessage()); + + } catch (ClassCastException e) { + throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09, + config.getFriendlyName(), config.getKeyAlias(), "Wrong SecretKey type "); + + } + + } + private X509Certificate getHsmFacadeTrustSslCertificate() throws EaafConfigurationException { try { final String certFilePath = getConfigurationParameter(CONFIG_PROP_HSM_FACADE_SSLTRUST); diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java index b4b44724..12541222 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java @@ -24,13 +24,13 @@ import lombok.extern.slf4j.Slf4j; public class EaafKeyStoreUtils { private static final String ERROR_MSG_REASON = "Maybe 'Alias' is not valid"; private static final String ERROR_MSG_1 = "Can NOT access key: {} in KeyStore: {}. Reason: {}"; - private static final String ERROR_MSG_2 = "Key: {} will be NOT available"; + private static final String ERROR_MSG_2 = "Key: {} will be NOT available"; /** * Read all certificates from a {@link KeyStore}. * * @param keyStore KeyStore with certificates - * @return {@link List} of {@link X509Certificate}, but never null + * @return Unmodifiable {@link List} of {@link X509Certificate}, but never null * @throws KeyStoreException In case of an error during KeyStore operations */ @Nonnull @@ -45,6 +45,7 @@ public class EaafKeyStoreUtils { final Certificate cert = keyStore.getCertificate(el); if (cert != null && cert instanceof X509Certificate) { result.add((X509Certificate) cert); + } else { log.info("Can not process entry: {}. Reason: {}", el, cert != null ? cert.getType() : "cert is null"); } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java new file mode 100644 index 00000000..45b51975 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java @@ -0,0 +1,221 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +public class SymmetricKeyConfiguration { + + public static final String PROP_CONFIG_KEY_TYPE = + "key.type"; + + public static final String PROP_CONFIG_HSMFACADE_NAME = + "keystore.name"; + public static final String PROP_CONFIG_HSM_KEY_ALIAS = + "key.alias"; + + public static final String PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE = + "key.passphrase"; + public static final String PROP_CONFIG_SOFTWARE_KEY_SALT = + "key.salt"; + + /** + * FriendlyName for this KeyStore. Mainly used for logging. + */ + private String friendlyName; + + /** + * General type of the KeyStore that should be generated. + */ + private SymmetricKeyType keyType; + + /** + * Name of the KeyStore in HSM Facade. + */ + private String keyStoreName; + + /** + * Alias of the Key in HSM Facade keystore. + */ + private String keyAlias; + + /** + * Software key passphrase. + */ + private String softKeyPassphrase; + + /** + * Software key salt. + */ + private String softKeySalt; + + /** + * Build a {@link SymmetricKeyConfiguration} from a configuration map.
+ *

+ * The configuration parameters defined in this class are used to load the + * configuration. + *

+ * + * @param config Configuration + * @param friendlyName FriendlyName for this KeyStore + * @return Configuration object for {@link EaafKeyStoreFactory} + * @throws EaafConfigurationException In case of a configuration error. + */ + public static SymmetricKeyConfiguration buildFromConfigurationMap(Map config, + String friendlyName) throws EaafConfigurationException { + + final SymmetricKeyConfiguration internalConfig = new SymmetricKeyConfiguration(); + internalConfig.setFriendlyName(friendlyName); + + final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString( + getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE)); + if (internalKeyStoreType != null) { + internalConfig.setKeyType(internalKeyStoreType); + + } else { + log.error("Symmetric Key-configuration: {} sets an unknown Keytype: {}", + friendlyName, getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE)); + throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01, + new Object[] { friendlyName }); + + } + + if (internalKeyStoreType.equals(SymmetricKeyType.HSMFACADE)) { + log.trace("Set-up HSM-Facade Symmentric-Key ... "); + internalConfig.setKeyStoreName(getConfigurationParameter(config, PROP_CONFIG_HSMFACADE_NAME)); + internalConfig.setKeyAlias(getConfigurationParameter(config, PROP_CONFIG_HSM_KEY_ALIAS)); + + } else { + log.trace("Set-up software passphrase based symmetric key ... "); + internalConfig.setSoftKeyPassphrase(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE)); + internalConfig.setSoftKeySalt(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_SALT)); + + } + + return internalConfig; + } + + /** + * Set the Type of the symmetric key based on String identifier. + * + * @param keyType String based KeyStore type + * @throws EaafConfigurationException In case of an unknown KeyStore type + */ + public void setKeyType(@Nonnull String keyType) throws EaafConfigurationException { + final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString(keyType); + if (internalKeyStoreType != null) { + setKeyType(internalKeyStoreType); + + } else { + log.error("KeyStore: {} sets an unknown KeyStore type: {}", + friendlyName, keyType); + throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01, + new Object[] { friendlyName }); + + } + + } + + /** + * Set the Type of the symmetric Key based on String identifier. + * + * @param type of tke symmetric key + */ + public void setKeyType(@Nonnull SymmetricKeyType type) { + this.keyType = type; + + } + + /** + * Validate the internal state of this configuration object. + * + * @throws EaafConfigurationException In case of a configuration error + */ + public void validate() throws EaafConfigurationException { + if (SymmetricKeyType.HSMFACADE.equals(keyType)) { + log.trace("Validate HSM-Facade symmetric key ... "); + checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07, + friendlyName, "Missing 'KeyStoreName' for HSM-Facade"); + checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07, + friendlyName, "Missing 'KeyAlias' for HSM-Facade"); + + } else { + log.trace("Validate passphrase based symmetric key ... "); + checkConfigurationValue(softKeyPassphrase, EaafKeyStoreFactory.ERRORCODE_07, + friendlyName, "Missing 'passphrase' for symmetric-key generation"); + checkConfigurationValue(softKeySalt, EaafKeyStoreFactory.ERRORCODE_07, + friendlyName, "Missing 'salt' for symmetric-key generation"); + + } + } + + public enum SymmetricKeyType { + PASSPHRASE("passphrase"), HSMFACADE("hsmfacade"); + + private final String keyType; + + SymmetricKeyType(final String keyStoreType) { + this.keyType = keyStoreType; + } + + /** + * Get Type of this Key. + * + * @return + */ + public String getKeyType() { + return this.keyType; + } + + /** + * Get KeyType from String representation. + * + * @param s Config parameter + * @return + */ + public static SymmetricKeyType fromString(final String s) { + try { + return SymmetricKeyType.valueOf(s.toUpperCase()); + + } catch (IllegalArgumentException | NullPointerException e) { + return null; + } + } + + @Override + public String toString() { + return getKeyType(); + + } + } + + @Nonnull + private static String getConfigurationParameter(@Nonnull Map config, + @Nonnull String configParamKey) + throws EaafConfigurationException { + final String configValue = config.get(configParamKey); + checkConfigurationValue(configValue, EaafKeyStoreFactory.ERRORCODE_04, configParamKey); + return configValue; + + } + + private static void checkConfigurationValue(String configValue, String errorCode, String... params) + throws EaafConfigurationException { + if (StringUtils.isEmpty(configValue)) { + throw new EaafConfigurationException(errorCode, + params); + + } + + } +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java index bc770a8c..ad6471d5 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java @@ -1,19 +1,14 @@ package at.gv.egiz.eaaf.core.impl.utils; import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; import java.util.Arrays; import java.util.Base64; import javax.annotation.PostConstruct; import javax.crypto.Mac; import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; @@ -32,6 +27,9 @@ import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException; import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; /** * PendingRequestId generation strategy based on signed tokens that facilitates @@ -45,11 +43,22 @@ public class SecurePendingRequestIdGenerationStrategy private static final Logger log = LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class); - @Autowired(required = true) - IConfiguration baseConfig; + @Autowired(required = true) IConfiguration baseConfig; + @Autowired EaafKeyStoreFactory keyStoreFactory; + private static final String FRIENDLYNAME = "pendingRequestId key"; + + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE = + "core.pendingrequestid.digist.type"; public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET = "core.pendingrequestid.digist.secret"; + + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE = + "core.pendingrequestid.digist.keystore.name"; + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS = + "core.pendingrequestid.digist.key.alias"; + + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM = "core.pendingrequestid.digist.algorithm"; public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME = @@ -67,7 +76,7 @@ public class SecurePendingRequestIdGenerationStrategy private final int maxPendingReqIdSize = 1024; private String digistAlgorithm = null; private SecretKey key = null; - private final byte[] salt = "notRequiredInThisScenario".getBytes(Charset.defaultCharset()); + private final String salt = "notRequiredInThisScenario"; @Override public String generateExternalPendingRequestId() throws EaafException { @@ -183,13 +192,6 @@ public class SecurePendingRequestIdGenerationStrategy private void initialize() throws EaafConfigurationException { log.debug("Initializing " + this.getClass().getName() + " ... "); - final String pendingReqIdDigistSecret = - baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET); - if (StringUtils.isEmpty(pendingReqIdDigistSecret)) { - throw new EaafConfigurationException("config.08", - new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET }); - } - digistAlgorithm = baseConfig.getBasicConfiguration( CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM); @@ -197,12 +199,29 @@ public class SecurePendingRequestIdGenerationStrategy Integer.parseInt(baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME, DEFAULT_PENDINGREQUESTID_MAX_LIFETIME)); + + SymmetricKeyConfiguration secretKeyConfig = new SymmetricKeyConfiguration(); + secretKeyConfig.setFriendlyName(FRIENDLYNAME); + secretKeyConfig.setKeyType( + baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE, + SymmetricKeyType.PASSPHRASE.name())); + + secretKeyConfig.setSoftKeyPassphrase( + baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET)); + secretKeyConfig.setSoftKeySalt(salt); + + secretKeyConfig.setKeyStoreName( + baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE)); + secretKeyConfig.setKeyAlias( + baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS)); + + //validate symmetric-key configuration + secretKeyConfig.validate(); + try { - final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); - final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128); - key = keyFactory.generateSecret(spec); + key = keyStoreFactory.buildNewSymmetricKey(secretKeyConfig).getFirst(); - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + } catch (EaafException e) { log.error("Can NOT initialize TokenService with configuration object", e); throw new EaafConfigurationException("config.09", new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, "Can NOT generate HMAC key" }, diff --git a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties index e0c86b03..572a3f5a 100644 --- a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties +++ b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties @@ -13,6 +13,8 @@ internal.keystore.08=Can not access Key: {1} in KeyStore: {0} internal.keystore.09=Can not access Key: {1} in KeyStore: {0} Reason: {2} internal.keystore.10=HSM-Facade NOT INITIALIZED. Find HSM-Facade class: {0} put that looks WRONG. +internal.key.00=Can not generate passphrase based symmetric-key: {0} Reason: {1} + internal.httpclient.00=HttpClient:{0} uses http Basic-Auth, but 'Username' is NOT set internal.httpclient.01=HttpClient:{0} uses X509 client-auth, but 'KeyStoreConfig' is NOT set internal.httpclient.02=HttpClient:{0} uses KeyStore:{1}, but 'keyPassword' is NOT set diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java index cefb1e7e..fc945fdd 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java @@ -7,6 +7,8 @@ import java.security.Provider; import java.security.cert.X509Certificate; import java.util.List; +import javax.crypto.SecretKey; + import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; import org.junit.Before; @@ -33,6 +35,8 @@ import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; import io.grpc.StatusRuntimeException; @@ -372,6 +376,67 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext + public void symmetricSoftwareKeyWithOutConfig() { + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); + try { + keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.fail("Wrong config not detected"); + + } catch (final EaafException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); + Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + + } + } + + @Test + @DirtiesContext + public void symmetricSoftwareKeyWithOutSalt() { + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); + keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10)); + try { + keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.fail("Wrong config not detected"); + + } catch (final EaafException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); + Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + + } + } + + @Test + @DirtiesContext + public void symmetricSoftwareKeyValid() throws EaafException { + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); + keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10)); + keyConfig.setSoftKeySalt(RandomStringUtils.randomAlphanumeric(10)); + + Pair key = keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.assertNotNull("Key container is null", key); + Assert.assertNotNull("Key is null", key.getFirst()); + Assert.assertNull("Provider is not null", key.getSecond()); + + } + + @Test + @DirtiesContext public void hsmFacadeOnlyHostConfig() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -386,6 +451,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingPort() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -405,6 +471,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingUsername() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -423,6 +490,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingPassword() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -442,6 +510,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingTrustedCertificate() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -463,6 +532,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingTrustedCertificateFile() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -486,6 +556,7 @@ public class EaafKeyStoreFactoryTest { } @Test + @DirtiesContext public void hsmFacadeMissingWrongTrustedCertificate() { mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, RandomStringUtils.randomNumeric(10)); @@ -577,6 +648,97 @@ public class EaafKeyStoreFactoryTest { } } + @Test + @DirtiesContext + public void symmetricHsmFacadeKeyWithOutConfig() { + configureHsmFacade(); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + try { + keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.fail("Wrong config not detected"); + + } catch (final EaafException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); + Assert.assertEquals("wrong errorCode", "internal.keystore.06", e.getErrorId()); + + } + } + + @Test + @DirtiesContext + public void symmetricHsmFacadeKeyWithOutKeyAlias() { + configureHsmFacade(); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + keyConfig.setKeyStoreName("authhandler"); + try { + keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.fail("Wrong config not detected"); + + } catch (final EaafException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); + Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + + } + } + + @Test + @DirtiesContext + public void symmetricHsmFacadeKeyWrongKeyAlias() { + configureHsmFacade(); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + keyConfig.setKeyStoreName("authhandler"); + keyConfig.setKeyAlias("notExist"); + + try { + keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.fail("Wrong config not detected"); + + } catch (final EaafException e) { + org.springframework.util.Assert.isInstanceOf(EaafKeyAccessException.class, e, "Wong ExceptionType"); + Assert.assertEquals("wrong errorCode", "internal.keystore.09", e.getErrorId()); + + } + } + + @Test + @DirtiesContext + public void symmetricHsmFacadeKeyValid() throws EaafException { + configureHsmFacade(); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + keyConfig.setKeyStoreName("authhandler"); + keyConfig.setKeyAlias("aes-key-1"); + + Pair key = keyStoreFactory.buildNewSymmetricKey(keyConfig); + Assert.assertNotNull("Key container is null", key); + Assert.assertNotNull("Key is null", key.getFirst()); + Assert.assertNotNull("Provider is null", key.getFirst()); + + } + @Test @DirtiesContext public void hsmFacadeKeyStoreSuccessASitTestFacade() throws EaafException, KeyStoreException { diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java new file mode 100644 index 00000000..eb4eb212 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java @@ -0,0 +1,162 @@ +package at.gv.egiz.eaaf.core.test.credentials; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; + +@RunWith(BlockJUnit4ClassRunner.class) +public class SymmetricKeyConfigurationTest { + + private Map config; + + @Before + public void testSetup() { + config = new HashMap<>(); + + } + + @Test + public void emptyConfigMap() { + try { + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void emptyKeyType() { + try { + config.put("key.type", ""); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void unknownKeyType() { + try { + config.put("key.type", "test"); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.01", e.getErrorId()); + } + } + + @Test + public void hsmFacadeKeyTypeMissingName() { + try { + config.put("key.type", "hsmfacade"); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void hsmFacadeKeyTypeMissingAlias() { + try { + final String keyStoreName = RandomStringUtils.randomAlphabetic(5); + config.put("key.type", "hsmfacade"); + config.put("keystore.name", keyStoreName); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void hsmFacadeKeyTypeSucces() throws EaafConfigurationException { + final String keyStoreName = RandomStringUtils.randomAlphabetic(5); + final String keyAlias = RandomStringUtils.randomAlphabetic(5); + config.put("key.type", "hsmfacade"); + config.put("keystore.name", keyStoreName); + config.put("key.alias", keyAlias); + + final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config, + "jUnitTest"); + + Assert.assertNotNull("KeyStore config object", keyStoreConfig); + Assert.assertEquals("Wrong Type", SymmetricKeyType.HSMFACADE, keyStoreConfig.getKeyType()); + Assert.assertEquals("Wrong KeyStoreName", keyStoreName, keyStoreConfig.getKeyStoreName()); + Assert.assertEquals("Wrong KeyStoreName", keyAlias, keyStoreConfig.getKeyAlias()); + + + keyStoreConfig.validate(); + + } + + @Test + public void passphraseKeyTypeMissingPassphrase() { + try { + config.put("key.type", "passphrase"); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void passphraseKeyTypeMissingSalt() { + try { + final String passphrase = RandomStringUtils.randomAlphabetic(5); + config.put("key.type", "passphrase"); + config.put("key.passphrase", passphrase); + + SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); + Assert.fail("Wrong config not detected"); + + } catch (final EaafConfigurationException e) { + Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); + } + } + + @Test + public void passphraseKeyTypeSucces() throws EaafConfigurationException { + final String passphrase = RandomStringUtils.randomAlphabetic(5); + final String salt = RandomStringUtils.randomAlphabetic(5); + config.put("key.type", "passphrase"); + config.put("key.passphrase", passphrase); + config.put("key.salt", salt); + + final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config, + "jUnitTest"); + + Assert.assertNotNull("KeyStore config object", keyStoreConfig); + Assert.assertEquals("Wrong Type", SymmetricKeyType.PASSPHRASE, keyStoreConfig.getKeyType()); + Assert.assertEquals("Wrong KeyStoreName", passphrase, keyStoreConfig.getSoftKeyPassphrase()); + Assert.assertEquals("Wrong KeyStoreName", salt, keyStoreConfig.getSoftKeySalt()); + + keyStoreConfig.validate(); + + } +} + -- cgit v1.2.3