From cbfadcc7681c9f362c1e7e2c3eab43980c1236ef Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 12 Feb 2020 19:01:59 +0100 Subject: add first untested version of EaafKeyStoreFactory that supports Software-Keystore and HSM-Facade --- eaaf_core_utils/pom.xml | 5 + .../core/impl/credential/EaafKeyStoreFactory.java | 216 +++++++++++++++++++++ .../impl/credential/KeyStoreConfiguration.java | 59 ++++++ 3 files changed, 280 insertions(+) create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java (limited to 'eaaf_core_utils') diff --git a/eaaf_core_utils/pom.xml b/eaaf_core_utils/pom.xml index 84ab46f5..6392fb76 100644 --- a/eaaf_core_utils/pom.xml +++ b/eaaf_core_utils/pom.xml @@ -41,6 +41,11 @@ eaaf_core_api + + at.asitplus.hsmfacade + provider + + org.springframework spring-webmvc 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 new file mode 100644 index 00000000..af184050 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java @@ -0,0 +1,216 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; + +import at.asitplus.hsmfacade.provider.HsmFacadeProvider; +import at.asitplus.hsmfacade.provider.RemoteKeyStoreLoadParameter; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +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.utils.FileUtils; +import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EaafKeyStoreFactory { + + public static final String CONFIG_PROP_HSM_FACADE_HOST = "security.hsmfacade.host"; + public static final String CONFIG_PROP_HSM_FACADE_PORT = "security.hsmfacade.port"; + public static final String CONFIG_PROP_HSM_FACADE_SSLTRUST = "security.hsmfacade.trustedsslcert"; + public static final String CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME = "security.hsmfacade.username"; + public static final String CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD = "security.hsmfacade.password"; + public static final String CONFIG_PROP_HSM_FACADE_HSM_NAME = "security.hsmfacade.hsmname"; + + public static final String ERRORCODE_00 = "internal.keystore.00"; + public static final String ERRORCODE_01 = "internal.keystore.01"; + public static final String ERRORCODE_02 = "internal.keystore.02"; + public static final String ERRORCODE_03 = "internal.keystore.03"; + public static final String ERRORCODE_04 = "internal.keystore.04"; + public static final String ERRORCODE_05 = "internal.keystore.05"; + public static final String ERRORCODE_06 = "internal.keystore.06"; + + @Autowired private IConfiguration basicConfig; + @Autowired private ResourceLoader resourceLoader; + + private boolean isHsmFacadeInitialized = false; + + + + public KeyStore buildNewKeyStore(KeyStoreConfiguration config) throws EaafException { + log.trace("Starting KeyStore generation based on configuration object ... "); + if (KeyStoreType.SOFTWARE.equals(config.getKeyStoreType())) { + return getKeyStoreFromFileSystem(config); + + } else if (KeyStoreType.HSMFACADE.equals(config.getKeyStoreType())) { + if (isHsmFacadeInitialized) { + getKeyStoreFromHsmFacade(config); + + } else { + log.error("HSMFacade can NOT be used for KeyStore: {} because {} is not initialized", + config.getFriendlyName()); + throw new EaafConfigurationException(ERRORCODE_00, + new Object[]{config.getFriendlyName()}); + + } + + } else if (KeyStoreType.PKCS11.equals(config.getKeyStoreType())) { + log.warn("KeyStoreType: {} is NOT supported", config.getKeyStoreType()); + throw new EaafConfigurationException(ERRORCODE_02, + new Object[]{config.getFriendlyName(), config.getKeyStoreType()}); + + } else { + log.warn("KeyStoreType: {} is unrecognized", config.getKeyStoreType()); + throw new EaafConfigurationException(ERRORCODE_01, + new Object[]{config.getFriendlyName()}); + + } + return null; + } + + @PostConstruct + private void initialize() throws EaafException { + + final String hsmFacadeHost = basicConfig.getBasicConfiguration(CONFIG_PROP_HSM_FACADE_HOST); + if (StringUtils.isNotEmpty(hsmFacadeHost)) { + log.debug("Find host for HSMFacade. Starting crypto provider initialization ... "); + try { + final int port = Integer.valueOf( + getConfigurationParameter(CONFIG_PROP_HSM_FACADE_PORT)); + final String clientUsername = + getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME); + final String clientPassword = + getConfigurationParameter(CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD); + final String hsmName = + getConfigurationParameter(CONFIG_PROP_HSM_FACADE_HSM_NAME); + + final HsmFacadeProvider provider = HsmFacadeProvider.Companion.getInstance(); + provider.init(getHsmFacadeTrustSslCertificate(), clientUsername, clientPassword, hsmFacadeHost, port, hsmName); + Security.addProvider(provider); + isHsmFacadeInitialized = true; + log.info("HSM Facade is initialized. {} can provide KeyStores based on remote HSM", + EaafKeyStoreFactory.class.getSimpleName()); + + } catch (final EaafException e) { + throw e; + + } catch (final Exception e) { + log.error("HSM Facade initialization FAILED with an generic error.", e); + throw new EaafConfigurationException(ERRORCODE_03, new Object[] {e.getMessage()}, e); + } + + } else { + log.info("HSM Facade is not configurated. {} can only provide software keystores", + EaafKeyStoreFactory.class.getSimpleName()); + + } + + } + + private KeyStore getKeyStoreFromFileSystem(KeyStoreConfiguration config) throws EaafConfigurationException { + try { + final String keyStorePath = config.getKeyStoreFilePath(); + final String keyStorePassword = config.getKeyStorePassword(); + + //TODO: check config + + final String absKeyStorePath = FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig.getConfigurationRootDirectory()); + final Resource ressource = resourceLoader.getResource(absKeyStorePath); + if (!ressource.exists()) { + throw new EaafConfigurationException(ERRORCODE_05, + new Object[] {CONFIG_PROP_HSM_FACADE_SSLTRUST, + "File not found at: " + absKeyStorePath}); + + } + + return KeyStoreUtils.loadKeyStore(ressource.getInputStream(), keyStorePassword); + + } catch (KeyStoreException | IOException e) { + log.error("Software KeyStore initialization FAILED with an generic error.", e); + throw new EaafConfigurationException(ERRORCODE_03, new Object[] {e.getMessage()}, e); + + } + } + + private KeyStore getKeyStoreFromHsmFacade(KeyStoreConfiguration config) throws EaafFactoryException, EaafConfigurationException { + final String keyStoreName = config.getKeyStoreName(); + if (StringUtils.isEmpty(keyStoreName)) { + throw new EaafConfigurationException(ERRORCODE_06, + new Object[] {config.getFriendlyName(), "No KeyStore name"}); + + } + + try { + final KeyStore keyStore = KeyStore.getInstance("RemoteKeyStore", "HsmFacade"); + keyStore.load(new RemoteKeyStoreLoadParameter(keyStoreName)); + return keyStore; + + } catch (NoSuchAlgorithmException | CertificateException | IOException | + KeyStoreException | NoSuchProviderException e) { + log.error("Can not initialize KeyStore: {} with reason: {}", + config.getFriendlyName(), e.getMessage()); + throw new EaafFactoryException(ERRORCODE_06, + new Object[] {config.getFriendlyName(), e.getMessage()}, e); + + } + } + + private X509Certificate getHsmFacadeTrustSslCertificate() throws EaafConfigurationException { + try { + final String certFilePath = getConfigurationParameter(CONFIG_PROP_HSM_FACADE_SSLTRUST); + + final String absolutCertFilePath = FileUtils.makeAbsoluteUrl( + certFilePath, basicConfig.getConfigurationRootDirectory()); + final Resource certFile = resourceLoader.getResource(absolutCertFilePath); + + if (!certFile.exists()) { + throw new EaafConfigurationException(ERRORCODE_05, + new Object[] {CONFIG_PROP_HSM_FACADE_SSLTRUST, + "File not found at: " + absolutCertFilePath }); + + } + + return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certFile.getInputStream()); + + } catch (final EaafConfigurationException e) { + throw e; + + } catch (CertificateException | IOException e) { + log.error("Can not load trusted server-certificate for HSM-Facade. Reason: {}", e.getMessage()); + throw new EaafConfigurationException(ERRORCODE_05, + new Object[] {CONFIG_PROP_HSM_FACADE_SSLTRUST, e.getMessage()}, e); + + } + } + + @Nonnull + private String getConfigurationParameter(@Nonnull String configParamKey) + throws EaafConfigurationException{ + final String configValue = basicConfig.getBasicConfiguration(configParamKey); + if (StringUtils.isEmpty(configValue)) { + throw new EaafConfigurationException(ERRORCODE_04, new Object[] {configParamKey}); + + } + + return configValue; + } + +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java new file mode 100644 index 00000000..c8489ac0 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java @@ -0,0 +1,59 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import lombok.Getter; + +@Getter +public class KeyStoreConfiguration { + + private String friendlyName; + + private KeyStoreType keyStoreType; + + private String keyStoreName; + + private String keyStoreFilePath; + + private String keyStorePassword; + + + public enum KeyStoreType { + SOFTWARE("software"), HSMFACADE("hsmfacade"), PKCS11("pkcs11"); + + private final String keyStoreType; + + KeyStoreType(final String keyStoreType) { + this.keyStoreType = keyStoreType; + } + + /** + * Get Type of this KeyStore. + * + * @return + */ + public String getKeyStoreType() { + return this.keyStoreType; + } + + /** + * Get KeyStore type from String representation. + * + * @param s Config parameter + * @return + */ + public static KeyStoreType fromString(final String s) { + try { + return KeyStoreType.valueOf(s.toUpperCase()); + + } catch (IllegalArgumentException | NullPointerException e) { + return null; + } + } + + @Override + public String toString() { + return getKeyStoreType(); + + } + + } +} -- cgit v1.2.3