diff options
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java')
-rw-r--r-- | eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java | 257 |
1 files changed, 257 insertions, 0 deletions
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..5e6ca34b --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java @@ -0,0 +1,257 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import java.io.IOException; +import java.io.InputStream; +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.Nullable; +import javax.annotation.PostConstruct; + +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 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 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"; + public static final String ERRORCODE_07 = "internal.keystore.07"; + + private static final String HSM_FACADE_PROVIDER = "HsmFacade"; + private static final String HSM_FACADE_KEYSTORE_TYPE = "RemoteKeyStore"; + + @Autowired + private IConfiguration basicConfig; + @Autowired + private ResourceLoader resourceLoader; + + private boolean isHsmFacadeInitialized = false; + + /** + * Get a new KeyStore based on a KeyStore configuration-object. + * + * @param config KeyStore configuration + * @return new KeyStore instance + * @throws EaafException In case of a KeyStore initialization error + */ + public KeyStore buildNewKeyStore(KeyStoreConfiguration config) throws EaafException { + log.trace("Starting KeyStore generation based on configuration object ... "); + if (KeyStoreType.PKCS12.equals(config.getKeyStoreType()) + || KeyStoreType.JKS.equals(config.getKeyStoreType())) { + return getKeyStoreFromFileSystem(config); + + } else if (KeyStoreType.HSMFACADE.equals(config.getKeyStoreType())) { + if (isHsmFacadeInitialized) { + return 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() }); + + } + } + + /** + * Get the initialization state of the HSM Facade module. + * + * @return true if HSM Facade is available, otherwise false + */ + public boolean isHsmFacadeInitialized() { + return isHsmFacadeInitialized; + + } + + @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.parseUnsignedInt( + 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, + EaafFactoryException { + try { + final String keyStorePath = checkConfigurationParameter(config.getSoftKeyStoreFilePath(), + ERRORCODE_06, config.getFriendlyName(), "Software-KeyStore missing filepath to KeyStore"); + + final String keyStorePassword = checkConfigurationParameter(config.getSoftKeyStorePassword(), + ERRORCODE_06, config.getFriendlyName(), "Software-KeyStore missing Password for KeyStore"); + + 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 }); + + } + + final InputStream is = ressource.getInputStream(); + final KeyStore keyStore = KeyStoreUtils.loadKeyStore(is, keyStorePassword); + is.close(); + if (keyStore == null) { + throw new EaafFactoryException(ERRORCODE_06, + new Object[] { config.getFriendlyName(), "KeyStore not valid or password wrong" }); + + } + + return keyStore; + + } 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 = checkConfigurationParameter(config.getKeyStoreName(), + ERRORCODE_06, config.getFriendlyName(), "KeyStoreName missing for HSM Facade"); + + try { + final KeyStore keyStore = KeyStore.getInstance(HSM_FACADE_KEYSTORE_TYPE, HSM_FACADE_PROVIDER); + 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 { + return checkConfigurationParameter( + basicConfig.getBasicConfiguration(configParamKey), ERRORCODE_04, configParamKey); + + } + + @Nonnull + private String checkConfigurationParameter(@Nullable String configParam, @Nonnull String errorCode, + @Nonnull String... errorParams) + throws EaafConfigurationException { + if (StringUtils.isEmpty(configParam)) { + throw new EaafConfigurationException(errorCode, new Object[] { errorParams }); + + } + return configParam; + + } + +} |