diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-02-12 19:01:59 +0100 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-02-12 19:01:59 +0100 |
commit | cbfadcc7681c9f362c1e7e2c3eab43980c1236ef (patch) | |
tree | 6ca517c539a88574bd195c298ca1b47339a8fadf | |
parent | e02aa41578ec3e08dd96fde9ef0342b69a051ba6 (diff) | |
download | EAAF-Components-cbfadcc7681c9f362c1e7e2c3eab43980c1236ef.tar.gz EAAF-Components-cbfadcc7681c9f362c1e7e2c3eab43980c1236ef.tar.bz2 EAAF-Components-cbfadcc7681c9f362c1e7e2c3eab43980c1236ef.zip |
add first untested version of EaafKeyStoreFactory that supports Software-Keystore and HSM-Facade
6 files changed, 305 insertions, 6 deletions
diff --git a/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/EaafFactoryException.java b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/EaafFactoryException.java new file mode 100644 index 00000000..f556a781 --- /dev/null +++ b/eaaf_core_api/src/main/java/at/gv/egiz/eaaf/core/exceptions/EaafFactoryException.java @@ -0,0 +1,18 @@ +package at.gv.egiz.eaaf.core.exceptions; + +public class EaafFactoryException extends EaafException { + + private static final long serialVersionUID = 4710605711787308220L; + + /** + * In case that a factory can not build an object. + * + * @param errorId ErrorCode + * @param params Message parameters + * @param e Exception + */ + public EaafFactoryException(String errorId, Object[] params, Throwable e) { + super(errorId, params, e); + } + +} 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 @@ -42,6 +42,11 @@ </dependency> <dependency> + <groupId>at.asitplus.hsmfacade</groupId> + <artifactId>provider</artifactId> + </dependency> + + <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> 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(); + + } + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/pom.xml b/eaaf_modules/eaaf_module_pvp2_core/pom.xml index 14bf50d5..318fa500 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/pom.xml @@ -14,7 +14,6 @@ <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <hsm-facade-provider.version>0.1.1-SNAPSHOT</hsm-facade-provider.version> </properties> <dependencies> @@ -24,11 +23,6 @@ <version>${egiz.eaaf.version}</version> </dependency> <dependency> - <groupId>at.asitplus.hsmfacade</groupId> - <artifactId>provider</artifactId> - <version>${hsm-facade-provider.version}</version> - </dependency> - <dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml-core</artifactId> </dependency> @@ -43,6 +43,7 @@ <iaik.prod.iaik_xades.version>2.13_moa</iaik.prod.iaik_xades.version> <iaik.prod.iaik_xsect.version>2.13_moa</iaik.prod.iaik_xsect.version> + <hsm-facade-provider.version>0.1.1-SNAPSHOT</hsm-facade-provider.version> <!-- Other third-party libs --> <org.springframework.version>5.1.5.RELEASE</org.springframework.version> @@ -315,6 +316,12 @@ </dependency> <dependency> + <groupId>at.asitplus.hsmfacade</groupId> + <artifactId>provider</artifactId> + <version>${hsm-facade-provider.version}</version> + </dependency> + + <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>${javax.annotation-api}</version> |