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 ++++++++++++++++++++- 1 file changed, 117 insertions(+), 6 deletions(-) (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.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); -- cgit v1.2.3