diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-06-18 14:39:29 +0200 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-06-18 14:39:29 +0200 | 
| commit | 0d52fe861a46f8ba595bdd34b106c98096c4304b (patch) | |
| tree | 566f30e8c6bfebddfa90b7062ec952b1bd945916 /eaaf_core_utils | |
| parent | f39a0a004bbe6b6b126218993767b897efa06745 (diff) | |
| download | EAAF-Components-0d52fe861a46f8ba595bdd34b106c98096c4304b.tar.gz EAAF-Components-0d52fe861a46f8ba595bdd34b106c98096c4304b.tar.bz2 EAAF-Components-0d52fe861a46f8ba595bdd34b106c98096c4304b.zip | |
add symmetric-key functionality into EaafKeyStoreFactory that supports passphrase based symmetric keys and keys from HSM-Facade
Diffstat (limited to 'eaaf_core_utils')
7 files changed, 705 insertions, 27 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 index 9db38670..711a3517 100644 --- 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 @@ -2,6 +2,7 @@ package at.gv.egiz.eaaf.core.impl.credential;  import java.io.IOException;  import java.io.InputStream; +import java.io.UnsupportedEncodingException;  import java.lang.reflect.Constructor;  import java.lang.reflect.Method;  import java.security.Key; @@ -12,13 +13,19 @@ import java.security.NoSuchAlgorithmException;  import java.security.NoSuchProviderException;  import java.security.Provider;  import java.security.Security; +import java.security.UnrecoverableKeyException;  import java.security.cert.CertificateException;  import java.security.cert.CertificateFactory;  import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec;  import javax.annotation.Nonnull;  import javax.annotation.Nullable;  import javax.annotation.PostConstruct; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec;  import org.apache.commons.lang3.StringUtils;  import org.springframework.beans.factory.annotation.Autowired; @@ -26,10 +33,12 @@ import org.springframework.core.io.Resource;  import org.springframework.core.io.ResourceLoader;  import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException;  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.credential.SymmetricKeyConfiguration.SymmetricKeyType;  import at.gv.egiz.eaaf.core.impl.data.Pair;  import at.gv.egiz.eaaf.core.impl.utils.FileUtils;  import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; @@ -53,6 +62,8 @@ public class EaafKeyStoreFactory {    public static final String ERRORCODE_06 = "internal.keystore.06";    public static final String ERRORCODE_07 = "internal.keystore.07";    public static final String ERRORCODE_10 = "internal.keystore.10"; +   +  public static final String ERRORCODE_KEY_00 = "internal.key.00";    private static final String HSM_FACADE_PROVIDER_CLASS = "at.asitplus.hsmfacade.provider.HsmFacadeProvider";    private static final String HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS  @@ -72,6 +83,43 @@ public class EaafKeyStoreFactory {    private boolean isHsmFacadeInitialized = false;    /** +   * Get a new symmetric key based on a {@link SymmetricKeyConfiguration} object. +   * +   * @param config Symmetric key configuration +   * @return {@link Pair} of a new {@link SecretKey} instance and an optional {@link Provider}. +   *     The {@link SecretKey} is {@link Nonnull}. If the {@link Provider} is not <code>null</code> +   *     this {@link SecretKey} requires a specific {@link Provider} for {@link Key} operations. +   * @throws EaafException In case of a KeyStore initialization error +   */ +  @Nonnull +  public Pair<SecretKey, Provider> buildNewSymmetricKey(SymmetricKeyConfiguration config) throws EaafException { +    log.trace("Starting symmetric-key generation based on configuration object ... ");     +    if (SymmetricKeyType.PASSPHRASE.equals(config.getKeyType())) { +      return generatePassPhraseBasedSymmetricKey(config); +       +    } else if (SymmetricKeyType.HSMFACADE.equals(config.getKeyType())) { +      if (isHsmFacadeInitialized) { +        return getSymmetricKeyFromHsmFacade(config); + +      } else { +        log.error("HSMFacade can NOT be used for symmetric Key: {} because {} is not initialized", +            config.getFriendlyName()); +        throw new EaafConfigurationException(ERRORCODE_00, +            new Object[] { config.getFriendlyName() }); + +      } +       +    } else { +      log.warn("Symmetric KeyType: {} is unrecognized", config.getKeyType()); +      throw new EaafConfigurationException(ERRORCODE_01, +          new Object[] { config.getFriendlyName() }); + +    } +     +     +  } +   +  /**     * Get a new KeyStore based on a KeyStore configuration-object.     *     * @param config KeyStore configuration @@ -241,24 +289,31 @@ public class EaafKeyStoreFactory {    @Nonnull    private Pair<KeyStore, Provider> getKeyStoreFromHsmFacade(KeyStoreConfiguration config)        throws EaafFactoryException, EaafConfigurationException { -    final String keyStoreName = checkConfigurationParameter(config.getKeyStoreName(), -        ERRORCODE_06, config.getFriendlyName(), "KeyStoreName missing for HSM Facade"); +    return getKeyStoreFromHsmFacade(config.getKeyStoreName(), config.getFriendlyName()); +    +  } + +  @Nonnull +  private Pair<KeyStore, Provider> getKeyStoreFromHsmFacade(String keyStoreName, String friendlyName) +      throws EaafFactoryException, EaafConfigurationException { +    final String validatedKeyStoreName = checkConfigurationParameter(keyStoreName, +        ERRORCODE_06, friendlyName, "KeyStoreName missing for HSM Facade");          try {        final KeyStore keyStore = KeyStore.getInstance(HSM_FACADE_KEYSTORE_TYPE, HSM_FACADE_PROVIDER); -      keyStore.load(getHsmFacadeKeyStoreParameter(keyStoreName)); +      keyStore.load(getHsmFacadeKeyStoreParameter(validatedKeyStoreName));        return Pair.newInstance(keyStore, keyStore.getProvider());      } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException          | NoSuchProviderException | EaafException e) {        log.error("Can not initialize KeyStore: {} with reason: {}", -          config.getFriendlyName(), e.getMessage()); +          friendlyName, e.getMessage());        throw new EaafFactoryException(ERRORCODE_06, -          new Object[] { config.getFriendlyName(), e.getMessage() }, e); +          new Object[] {friendlyName, e.getMessage() }, e);      }    } - +      private KeyStore.LoadStoreParameter getHsmFacadeKeyStoreParameter(String keyStoreName) throws EaafException {      try {        Class<?> clazz = Class.forName(HSM_FACADE_KEYSTORELOADPARAMETERS_CLASS); @@ -274,6 +329,62 @@ public class EaafKeyStoreFactory {    } +  @Nonnull +  private Pair<SecretKey, Provider> generatePassPhraseBasedSymmetricKey(SymmetricKeyConfiguration config)  +      throws EaafConfigurationException { +    checkConfigurationParameter(config.getSoftKeyPassphrase(), +        ERRORCODE_KEY_00, config.getFriendlyName(), "passphrase missing"); +    checkConfigurationParameter(config.getSoftKeySalt(), +        ERRORCODE_KEY_00, config.getFriendlyName(), "salt missing"); +     +    try { +      final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); +      final KeySpec spec = new PBEKeySpec( +          config.getSoftKeyPassphrase().toCharArray(),  +          config.getSoftKeySalt().getBytes("UTF-8"),  +          10000, 128); +      return Pair.newInstance(keyFactory.generateSecret(spec), null); + +    } catch (NoSuchAlgorithmException | InvalidKeySpecException | UnsupportedEncodingException e) { +      log.error("Passphrase based symmetric-key generation FAILED", e); +      throw new EaafConfigurationException(ERRORCODE_KEY_00, +          new Object[] { config.getFriendlyName(), e.getMessage() }, +          e); + +    } +  } +   +  @Nonnull +  private Pair<SecretKey, Provider> getSymmetricKeyFromHsmFacade(SymmetricKeyConfiguration config)  +      throws EaafFactoryException, EaafConfigurationException, EaafKeyAccessException { +    Pair<KeyStore, Provider> keyStore = getKeyStoreFromHsmFacade( +        config.getKeyStoreName(), config.getFriendlyName()); +     +    checkConfigurationParameter(config.getKeyAlias(), +        ERRORCODE_KEY_00, config.getFriendlyName(), "keyAlias missing"); +     +    try { +      SecretKey secretKey = (SecretKey) keyStore.getFirst().getKey(config.getKeyAlias(), null); +      if (secretKey == null) { +        throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09,  +            config.getFriendlyName(), config.getKeyAlias(), "No SecretKey with Alias "); +         +      }        +       +      return Pair.newInstance(secretKey, keyStore.getSecond()); +       +    } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { +      throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09, e,  +          config.getFriendlyName(), config.getKeyAlias(), e.getMessage()); +       +    } catch (ClassCastException e) { +      throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09,  +          config.getFriendlyName(), config.getKeyAlias(), "Wrong SecretKey type "); +       +    } +             +  } +      private X509Certificate getHsmFacadeTrustSslCertificate() throws EaafConfigurationException {      try {        final String certFilePath = getConfigurationParameter(CONFIG_PROP_HSM_FACADE_SSLTRUST); diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java index b4b44724..12541222 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java @@ -24,13 +24,13 @@ import lombok.extern.slf4j.Slf4j;  public class EaafKeyStoreUtils {    private static final String ERROR_MSG_REASON = "Maybe 'Alias' is not valid";    private static final String ERROR_MSG_1 = "Can NOT access key: {} in KeyStore: {}. Reason: {}"; -  private static final String ERROR_MSG_2 = "Key: {} will be NOT available"; +  private static final String ERROR_MSG_2 = "Key: {} will be NOT available";      /**     * Read all certificates from a {@link KeyStore}.     *      * @param keyStore KeyStore with certificates -   * @return {@link List} of {@link X509Certificate}, but never null +   * @return Unmodifiable {@link List} of {@link X509Certificate}, but never null     * @throws KeyStoreException In case of an error during KeyStore operations     */    @Nonnull @@ -45,6 +45,7 @@ public class EaafKeyStoreUtils {          final Certificate cert = keyStore.getCertificate(el);          if (cert != null && cert instanceof X509Certificate) {            result.add((X509Certificate) cert); +                      } else {            log.info("Can not process entry: {}. Reason: {}", el, cert != null ? cert.getType() : "cert is null");          } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java new file mode 100644 index 00000000..45b51975 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/SymmetricKeyConfiguration.java @@ -0,0 +1,221 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +public class SymmetricKeyConfiguration { + +  public static final String PROP_CONFIG_KEY_TYPE = +      "key.type"; + +  public static final String PROP_CONFIG_HSMFACADE_NAME = +      "keystore.name"; +  public static final String PROP_CONFIG_HSM_KEY_ALIAS = +      "key.alias"; +   +  public static final String PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE = +      "key.passphrase"; +  public static final String PROP_CONFIG_SOFTWARE_KEY_SALT = +      "key.salt"; +   +  /** +   * FriendlyName for this KeyStore. Mainly used for logging. +   */ +  private String friendlyName; + +  /** +   * General type of the KeyStore that should be generated. +   */ +  private SymmetricKeyType keyType; + +  /** +   * Name of the KeyStore in HSM Facade. +   */ +  private String keyStoreName; + +  /** +   * Alias of the Key in HSM Facade keystore. +   */ +  private String keyAlias; +   +  /** +   * Software key passphrase. +   */ +  private String softKeyPassphrase; + +  /** +   * Software key salt. +   */ +  private String softKeySalt; + +  /** +   * Build a {@link SymmetricKeyConfiguration} from a configuration map. <br> +   * <p> +   * The configuration parameters defined in this class are used to load the +   * configuration. +   * </p> +   * +   * @param config       Configuration +   * @param friendlyName FriendlyName for this KeyStore +   * @return Configuration object for {@link EaafKeyStoreFactory} +   * @throws EaafConfigurationException In case of a configuration error. +   */ +  public static SymmetricKeyConfiguration buildFromConfigurationMap(Map<String, String> config, +      String friendlyName) throws EaafConfigurationException { + +    final SymmetricKeyConfiguration internalConfig = new SymmetricKeyConfiguration(); +    internalConfig.setFriendlyName(friendlyName); + +    final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString( +        getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE)); +    if (internalKeyStoreType != null) { +      internalConfig.setKeyType(internalKeyStoreType); + +    } else { +      log.error("Symmetric Key-configuration: {} sets an unknown Keytype: {}", +          friendlyName, getConfigurationParameter(config, PROP_CONFIG_KEY_TYPE)); +      throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01, +          new Object[] { friendlyName }); + +    } + +    if (internalKeyStoreType.equals(SymmetricKeyType.HSMFACADE)) { +      log.trace("Set-up HSM-Facade Symmentric-Key ... "); +      internalConfig.setKeyStoreName(getConfigurationParameter(config, PROP_CONFIG_HSMFACADE_NAME)); +      internalConfig.setKeyAlias(getConfigurationParameter(config, PROP_CONFIG_HSM_KEY_ALIAS)); +       +    } else { +      log.trace("Set-up software passphrase based symmetric key ... "); +      internalConfig.setSoftKeyPassphrase(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_PASSPHRASE)); +      internalConfig.setSoftKeySalt(getConfigurationParameter(config, PROP_CONFIG_SOFTWARE_KEY_SALT)); + +    }  + +    return internalConfig; +  } + +  /** +   * Set the Type of the symmetric key based on String identifier. +   * +   * @param keyType String based KeyStore type +   * @throws EaafConfigurationException In case of an unknown KeyStore type +   */ +  public void setKeyType(@Nonnull String keyType) throws EaafConfigurationException { +    final SymmetricKeyType internalKeyStoreType = SymmetricKeyType.fromString(keyType); +    if (internalKeyStoreType != null) { +      setKeyType(internalKeyStoreType); + +    } else { +      log.error("KeyStore: {} sets an unknown KeyStore type: {}", +          friendlyName, keyType); +      throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_01, +          new Object[] { friendlyName }); + +    } + +  } + +  /** +   * Set the Type of the symmetric Key based on String identifier. +   * +   * @param type of tke symmetric key +   */ +  public void setKeyType(@Nonnull SymmetricKeyType type) { +    this.keyType = type; + +  } + +  /** +   * Validate the internal state of this configuration object. +   * +   * @throws EaafConfigurationException In case of a configuration error +   */ +  public void validate() throws EaafConfigurationException { +    if (SymmetricKeyType.HSMFACADE.equals(keyType)) { +      log.trace("Validate HSM-Facade symmetric key ... "); +      checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'KeyStoreName' for HSM-Facade"); +      checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'KeyAlias' for HSM-Facade"); +       +    } else { +      log.trace("Validate passphrase based symmetric key ... "); +      checkConfigurationValue(softKeyPassphrase, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'passphrase' for symmetric-key generation"); +      checkConfigurationValue(softKeySalt, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'salt' for symmetric-key generation"); + +    }  +  } + +  public enum SymmetricKeyType { +    PASSPHRASE("passphrase"), HSMFACADE("hsmfacade"); + +    private final String keyType; + +    SymmetricKeyType(final String keyStoreType) { +      this.keyType = keyStoreType; +    } + +    /** +     * Get Type of this Key. +     * +     * @return +     */ +    public String getKeyType() { +      return this.keyType; +    } + +    /** +     * Get KeyType from String representation. +     * +     * @param s Config parameter +     * @return +     */ +    public static SymmetricKeyType fromString(final String s) { +      try { +        return SymmetricKeyType.valueOf(s.toUpperCase()); + +      } catch (IllegalArgumentException | NullPointerException e) { +        return null; +      } +    } + +    @Override +    public String toString() { +      return getKeyType(); + +    } +  } + +  @Nonnull +  private static String getConfigurationParameter(@Nonnull Map<String, String> config, +      @Nonnull String configParamKey) +      throws EaafConfigurationException { +    final String configValue = config.get(configParamKey); +    checkConfigurationValue(configValue, EaafKeyStoreFactory.ERRORCODE_04, configParamKey); +    return configValue; + +  } + +  private static void checkConfigurationValue(String configValue, String errorCode, String... params) +      throws EaafConfigurationException { +    if (StringUtils.isEmpty(configValue)) { +      throw new EaafConfigurationException(errorCode, +         params); + +    } + +  } +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java index bc770a8c..ad6471d5 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java @@ -1,19 +1,14 @@  package at.gv.egiz.eaaf.core.impl.utils;  import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset;  import java.security.InvalidKeyException;  import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec;  import java.util.Arrays;  import java.util.Base64;  import javax.annotation.PostConstruct;  import javax.crypto.Mac;  import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec;  import org.apache.commons.lang3.StringUtils;  import org.joda.time.DateTime; @@ -32,6 +27,9 @@ import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;  import at.gv.egiz.eaaf.core.exceptions.EaafException;  import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException;  import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;  /**   * PendingRequestId generation strategy based on signed tokens that facilitates @@ -45,11 +43,22 @@ public class SecurePendingRequestIdGenerationStrategy    private static final Logger log =        LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class); -  @Autowired(required = true) -  IConfiguration baseConfig; +  @Autowired(required = true) IConfiguration baseConfig; +  @Autowired EaafKeyStoreFactory keyStoreFactory; +  private static final String FRIENDLYNAME = "pendingRequestId key"; + +  public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE = +      "core.pendingrequestid.digist.type";    public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET =        "core.pendingrequestid.digist.secret"; + +  public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE = +      "core.pendingrequestid.digist.keystore.name"; +  public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS = +      "core.pendingrequestid.digist.key.alias"; +   +      public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM =        "core.pendingrequestid.digist.algorithm";    public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME = @@ -67,7 +76,7 @@ public class SecurePendingRequestIdGenerationStrategy    private final int maxPendingReqIdSize = 1024;    private String digistAlgorithm = null;    private SecretKey key = null; -  private final byte[] salt = "notRequiredInThisScenario".getBytes(Charset.defaultCharset()); +  private final String salt = "notRequiredInThisScenario";    @Override    public String generateExternalPendingRequestId() throws EaafException { @@ -183,13 +192,6 @@ public class SecurePendingRequestIdGenerationStrategy    private void initialize() throws EaafConfigurationException {      log.debug("Initializing " + this.getClass().getName() + " ... "); -    final String pendingReqIdDigistSecret = -        baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET); -    if (StringUtils.isEmpty(pendingReqIdDigistSecret)) { -      throw new EaafConfigurationException("config.08", -          new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET }); -    } -      digistAlgorithm = baseConfig.getBasicConfiguration(          CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM); @@ -197,12 +199,29 @@ public class SecurePendingRequestIdGenerationStrategy          Integer.parseInt(baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME,              DEFAULT_PENDINGREQUESTID_MAX_LIFETIME)); + +    SymmetricKeyConfiguration secretKeyConfig = new SymmetricKeyConfiguration(); +    secretKeyConfig.setFriendlyName(FRIENDLYNAME); +    secretKeyConfig.setKeyType( +        baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_TYPE,  +            SymmetricKeyType.PASSPHRASE.name())); +     +    secretKeyConfig.setSoftKeyPassphrase( +        baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET)); +    secretKeyConfig.setSoftKeySalt(salt); +     +    secretKeyConfig.setKeyStoreName( +        baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_KEYSTORE)); +    secretKeyConfig.setKeyAlias( +        baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_HSM_ALIAS)); + +    //validate symmetric-key configuration +    secretKeyConfig.validate(); +          try { -      final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); -      final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128); -      key = keyFactory.generateSecret(spec); +      key = keyStoreFactory.buildNewSymmetricKey(secretKeyConfig).getFirst(); -    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { +    } catch (EaafException e) {        log.error("Can NOT initialize TokenService with configuration object", e);        throw new EaafConfigurationException("config.09",            new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, "Can NOT generate HMAC key" }, diff --git a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties index e0c86b03..572a3f5a 100644 --- a/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties +++ b/eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties @@ -13,6 +13,8 @@ internal.keystore.08=Can not access Key: {1} in KeyStore: {0}  internal.keystore.09=Can not access Key: {1} in KeyStore: {0} Reason: {2}  internal.keystore.10=HSM-Facade NOT INITIALIZED. Find HSM-Facade class: {0} put that looks WRONG. +internal.key.00=Can not generate passphrase based symmetric-key: {0} Reason: {1} +  internal.httpclient.00=HttpClient:{0} uses http Basic-Auth, but 'Username' is NOT set  internal.httpclient.01=HttpClient:{0} uses X509 client-auth, but 'KeyStoreConfig' is NOT set  internal.httpclient.02=HttpClient:{0} uses KeyStore:{1}, but 'keyPassword' is NOT set diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java index cefb1e7e..fc945fdd 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java @@ -7,6 +7,8 @@ import java.security.Provider;  import java.security.cert.X509Certificate;  import java.util.List; +import javax.crypto.SecretKey; +  import org.apache.commons.lang3.RandomStringUtils;  import org.junit.Assert;  import org.junit.Before; @@ -33,6 +35,8 @@ import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;  import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils;  import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;  import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType;  import at.gv.egiz.eaaf.core.impl.data.Pair;  import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;  import io.grpc.StatusRuntimeException; @@ -372,6 +376,67 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext +  public void symmetricSoftwareKeyWithOutConfig() { +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); +    try { +      keyStoreFactory.buildNewSymmetricKey(keyConfig); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafException e) { +      org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); +      Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + +    }     +  } +   +  @Test +  @DirtiesContext +  public void symmetricSoftwareKeyWithOutSalt() { +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); +    keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10)); +    try { +      keyStoreFactory.buildNewSymmetricKey(keyConfig); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafException e) { +      org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); +      Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + +    }     +  } +   +  @Test +  @DirtiesContext +  public void symmetricSoftwareKeyValid() throws EaafException { +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.PASSPHRASE); +    keyConfig.setSoftKeyPassphrase(RandomStringUtils.randomAlphanumeric(10)); +    keyConfig.setSoftKeySalt(RandomStringUtils.randomAlphanumeric(10)); + +    Pair<SecretKey, Provider> key = keyStoreFactory.buildNewSymmetricKey(keyConfig); +    Assert.assertNotNull("Key container is null", key); +    Assert.assertNotNull("Key is null", key.getFirst()); +    Assert.assertNull("Provider is not null", key.getSecond()); +     +  } +   +  @Test +  @DirtiesContext    public void hsmFacadeOnlyHostConfig() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -386,6 +451,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingPort() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -405,6 +471,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingUsername() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -423,6 +490,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingPassword() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -442,6 +510,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingTrustedCertificate() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -463,6 +532,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingTrustedCertificateFile() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -486,6 +556,7 @@ public class EaafKeyStoreFactoryTest {    }    @Test +  @DirtiesContext    public void hsmFacadeMissingWrongTrustedCertificate() {      mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST,          RandomStringUtils.randomNumeric(10)); @@ -579,6 +650,97 @@ public class EaafKeyStoreFactoryTest {    @Test    @DirtiesContext +  public void symmetricHsmFacadeKeyWithOutConfig() { +    configureHsmFacade(); +     +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); +    try { +      keyStoreFactory.buildNewSymmetricKey(keyConfig); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafException e) { +      org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); +      Assert.assertEquals("wrong errorCode", "internal.keystore.06", e.getErrorId()); + +    }     +  } +   +  @Test +  @DirtiesContext +  public void symmetricHsmFacadeKeyWithOutKeyAlias() { +    configureHsmFacade(); +     +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); +    keyConfig.setKeyStoreName("authhandler"); +    try { +      keyStoreFactory.buildNewSymmetricKey(keyConfig); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafException e) { +      org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e, "Wong ExceptionType"); +      Assert.assertEquals("wrong errorCode", "internal.key.00", e.getErrorId()); + +    }     +  } +   +  @Test +  @DirtiesContext +  public void symmetricHsmFacadeKeyWrongKeyAlias() { +    configureHsmFacade(); +     +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); +    keyConfig.setKeyStoreName("authhandler"); +    keyConfig.setKeyAlias("notExist"); +     +    try { +      keyStoreFactory.buildNewSymmetricKey(keyConfig); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafException e) { +      org.springframework.util.Assert.isInstanceOf(EaafKeyAccessException.class, e, "Wong ExceptionType"); +      Assert.assertEquals("wrong errorCode", "internal.keystore.09", e.getErrorId()); + +    }     +  } +   +  @Test +  @DirtiesContext +  public void symmetricHsmFacadeKeyValid() throws EaafException { +    configureHsmFacade(); +     +    final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); +    Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + +    SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); +    keyConfig.setFriendlyName("jUnit test"); +    keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); +    keyConfig.setKeyStoreName("authhandler"); +    keyConfig.setKeyAlias("aes-key-1"); + +    Pair<SecretKey, Provider> key = keyStoreFactory.buildNewSymmetricKey(keyConfig); +    Assert.assertNotNull("Key container is null", key); +    Assert.assertNotNull("Key is null", key.getFirst()); +    Assert.assertNotNull("Provider is null", key.getFirst()); +     +  } +   +  @Test +  @DirtiesContext    public void hsmFacadeKeyStoreSuccessASitTestFacade() throws EaafException, KeyStoreException {      configureHsmFacade(); diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java new file mode 100644 index 00000000..eb4eb212 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/SymmetricKeyConfigurationTest.java @@ -0,0 +1,162 @@ +package at.gv.egiz.eaaf.core.test.credentials; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; + +@RunWith(BlockJUnit4ClassRunner.class) +public class SymmetricKeyConfigurationTest { + +  private Map<String, String> config; + +  @Before +  public void testSetup() { +    config = new HashMap<>(); + +  } + +  @Test +  public void emptyConfigMap() { +    try { +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } +   +  @Test +  public void emptyKeyType() { +    try { +      config.put("key.type", ""); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } + +  @Test +  public void unknownKeyType() { +    try { +      config.put("key.type", "test"); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.01", e.getErrorId()); +    } +  } +   +  @Test +  public void hsmFacadeKeyTypeMissingName() { +    try { +      config.put("key.type", "hsmfacade"); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } + +  @Test +  public void hsmFacadeKeyTypeMissingAlias() { +    try { +      final String keyStoreName = RandomStringUtils.randomAlphabetic(5); +      config.put("key.type", "hsmfacade"); +      config.put("keystore.name", keyStoreName); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } +   +  @Test +  public void hsmFacadeKeyTypeSucces() throws EaafConfigurationException { +    final String keyStoreName = RandomStringUtils.randomAlphabetic(5); +    final String keyAlias = RandomStringUtils.randomAlphabetic(5); +    config.put("key.type", "hsmfacade"); +    config.put("keystore.name", keyStoreName); +    config.put("key.alias", keyAlias); +     +    final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config, +        "jUnitTest"); + +    Assert.assertNotNull("KeyStore config object", keyStoreConfig); +    Assert.assertEquals("Wrong Type", SymmetricKeyType.HSMFACADE, keyStoreConfig.getKeyType()); +    Assert.assertEquals("Wrong KeyStoreName", keyStoreName, keyStoreConfig.getKeyStoreName()); +    Assert.assertEquals("Wrong KeyStoreName", keyAlias, keyStoreConfig.getKeyAlias()); +     +     +    keyStoreConfig.validate(); +     +  } +   +  @Test +  public void passphraseKeyTypeMissingPassphrase() { +    try { +      config.put("key.type", "passphrase"); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } + +  @Test +  public void passphraseKeyTypeMissingSalt() { +    try { +      final String passphrase = RandomStringUtils.randomAlphabetic(5); +      config.put("key.type", "passphrase"); +      config.put("key.passphrase", passphrase); + +      SymmetricKeyConfiguration.buildFromConfigurationMap(config, "jUnitTest"); +      Assert.fail("Wrong config not detected"); + +    } catch (final EaafConfigurationException e) { +      Assert.assertEquals("wrong errorCode", "internal.keystore.04", e.getErrorId()); +    } +  } +   +  @Test +  public void passphraseKeyTypeSucces() throws EaafConfigurationException { +    final String passphrase = RandomStringUtils.randomAlphabetic(5); +    final String salt = RandomStringUtils.randomAlphabetic(5); +    config.put("key.type", "passphrase"); +    config.put("key.passphrase", passphrase); +    config.put("key.salt", salt); +     +    final SymmetricKeyConfiguration keyStoreConfig = SymmetricKeyConfiguration.buildFromConfigurationMap(config, +        "jUnitTest"); + +    Assert.assertNotNull("KeyStore config object", keyStoreConfig); +    Assert.assertEquals("Wrong Type", SymmetricKeyType.PASSPHRASE, keyStoreConfig.getKeyType()); +    Assert.assertEquals("Wrong KeyStoreName", passphrase, keyStoreConfig.getSoftKeyPassphrase()); +    Assert.assertEquals("Wrong KeyStoreName", salt, keyStoreConfig.getSoftKeySalt()); +     +    keyStoreConfig.validate(); +     +  } +} + | 
