diff options
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> | 
