From cbfadcc7681c9f362c1e7e2c3eab43980c1236ef Mon Sep 17 00:00:00 2001
From: Thomas Lenz <thomas.lenz@egiz.gv.at>
Date: Wed, 12 Feb 2020 19:01:59 +0100
Subject: add first untested version of EaafKeyStoreFactory that supports
 Software-Keystore and HSM-Facade

---
 .../core/impl/credential/EaafKeyStoreFactory.java  | 216 +++++++++++++++++++++
 .../impl/credential/KeyStoreConfiguration.java     |  59 ++++++
 2 files changed, 275 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/src')

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