diff options
Diffstat (limited to 'eaaf_core_utils/src/main')
5 files changed, 209 insertions, 6 deletions
| diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyAccessException.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyAccessException.java new file mode 100644 index 00000000..f9abd6d9 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyAccessException.java @@ -0,0 +1,22 @@ +package at.gv.egiz.eaaf.core.exception; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +public class EaafKeyAccessException extends EaafException { + +  private static final long serialVersionUID = -2641273589744430903L; + +  public static final String ERROR_CODE_08 = "internal.keystore.08"; +  public static final String ERROR_CODE_09 = "internal.keystore.09"; +   +  public EaafKeyAccessException(String errorCode, String... params) { +    super(errorCode, new Object[] {params}); +     +  } +   +  public EaafKeyAccessException(String errorCode, Throwable e, String... params) { +    super(errorCode, new Object[] {params}, e); +     +  } + +} 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 f13013f5..5e6ca34b 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 @@ -48,6 +48,7 @@ public class EaafKeyStoreFactory {    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"; 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 new file mode 100644 index 00000000..b4b44724 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java @@ -0,0 +1,147 @@ +package at.gv.egiz.eaaf.core.impl.credential; + +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import lombok.extern.slf4j.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"; +   +  /** +   * Read all certificates from a {@link KeyStore}. +   *  +   * @param keyStore KeyStore with certificates +   * @return {@link List} of {@link X509Certificate}, but never null +   * @throws KeyStoreException In case of an error during KeyStore operations +   */ +  @Nonnull +  public static List<X509Certificate> readCertsFromKeyStore(@Nonnull final KeyStore keyStore) throws KeyStoreException { +    final List<X509Certificate> result = new ArrayList<>(); + +    final Enumeration<String> aliases = keyStore.aliases(); +    while (aliases.hasMoreElements()) { +      final String el = aliases.nextElement(); +      log.trace("Process TrustStoreEntry: " + el); +      if (keyStore.isCertificateEntry(el)) { +        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"); +        } + +      } +    } + +    return Collections.unmodifiableList(result); +  } +   +  /** +   * Get a specific private Key and the corresponding certificate from a {@link KeyStore}. +   *  +   * @param keyStore KeyStore with certificates +   * @param keyAlias Alias of the entry +   * @param keyPassword Password to access the Key +   * @param isRequired if true, the method throw an {@link EaafKeyAccessException}  +   *     if the key is not available or invalid +   * @param friendlyName Name of the KeyStore for logging purposes +   * @return A {@link Pair} of {@link Key} and {@link X509Certificate} for this alias,  +   *     or maybe null if isRequired was <code>false</code> +   * @throws EaafKeyAccessException In case of an error during KeyStore operations +   */ +  @Nullable +  public static Pair<Key, X509Certificate[]> getPrivateKeyAndCertificates(@Nonnull KeyStore keyStore, +      @Nonnull String keyAlias, @Nullable char[] keyPassword, boolean isRequired, @Nonnull String friendlyName)  +          throws EaafKeyAccessException { +    try { +      Key privKey = keyStore.getKey(keyAlias, keyPassword);   +      if (privKey != null) { +        final Certificate[] certChainSigning = keyStore.getCertificateChain(keyAlias); +        X509Certificate[] certChain = new X509Certificate[certChainSigning.length]; +       +        for (int i = 0; i < certChainSigning.length; i++) { +          if (certChainSigning[i] instanceof X509Certificate) { +            certChain[i] = (X509Certificate) certChainSigning[i]; +          } else { +            log.warn("NO X509 certificate for signing: " + certChainSigning[i].getType()); +          } + +        } +         +        Pair<Key, X509Certificate[]> keyResult = Pair.newInstance(privKey, certChain); +        validateKeyResult(keyResult, friendlyName, keyAlias); +        return keyResult; +         +      } else { +        if (isRequired) { +          log.warn(ERROR_MSG_1,  +              keyAlias, friendlyName, ERROR_MSG_REASON); +          throw new EaafKeyAccessException(EaafKeyAccessException.ERROR_CODE_09,  +              friendlyName, keyAlias, ERROR_MSG_REASON); +           +        } else { +          log.info(ERROR_MSG_1,  +              keyAlias, friendlyName, ERROR_MSG_REASON); +          log.info(ERROR_MSG_2, keyAlias); +           +        } +      } +       +    } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException  e) { +      if (isRequired) { +        log.warn(ERROR_MSG_1,  +            keyAlias, friendlyName, e.getMessage()); +        throw new EaafKeyAccessException( +            EaafKeyAccessException.ERROR_CODE_09, e, friendlyName, keyAlias, e.getMessage()); +         +      } else { +        log.info(ERROR_MSG_1,  +            keyAlias, friendlyName, e.getMessage()); +        log.info(ERROR_MSG_2, keyAlias); +         +      } +    } +     +    return null; +     +  } +   +  private static void validateKeyResult(Pair<Key, X509Certificate[]> keyResult,  +      String friendlyName, String keyAlias) throws EaafKeyAccessException { +    // some short validation +    if (!(keyResult.getFirst() instanceof PrivateKey)) { +      log.info("PrivateKey: {} in KeyStore: {} is of wrong type", keyAlias, friendlyName); +      throw new EaafKeyAccessException( +          EaafKeyAccessException.ERROR_CODE_09,  +          friendlyName, keyAlias, "Wrong PrivateKey type "); + +    } + +    if (keyResult.getSecond() == null || keyResult.getSecond().length == 0) { +      log.info("NO certificate for Key: {} in KeyStore: {}", keyAlias, friendlyName); +      throw new EaafKeyAccessException( +          EaafKeyAccessException.ERROR_CODE_09,  +          friendlyName, keyAlias, "NO certificate for PrivateKey"); + +    } +  } +} 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 index 400b724f..6dbbba3e 100644 --- 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 @@ -137,6 +137,31 @@ public class KeyStoreConfiguration {    } +  /** +   * Validate the internal state of this configuration object. +   *  +   * @throws EaafConfigurationException In case of a configuration error +   */ +  public void validate() throws EaafConfigurationException { +    if (KeyStoreType.HSMFACADE.equals(keyStoreType)) { +      log.trace("Validate HSM-Facade KeyStore ... "); +      checkConfigurationValue(keyStoreName, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'KeyName' for HSM-Facade"); +      +    } else if (KeyStoreType.PKCS12.equals(keyStoreType) +        || KeyStoreType.JKS.equals(keyStoreType)) { +      log.trace("Validate software KeyStore ... "); +      checkConfigurationValue(softKeyStoreFilePath, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'KeyPath' for software keystore"); +      checkConfigurationValue(softKeyStorePassword, EaafKeyStoreFactory.ERRORCODE_07, +          friendlyName, "Missing 'KeyPassword' for software keystore"); +       +    } else { +      log.info("Validation of type: {} not supported yet", keyStoreType); +       +    } +  } +      public enum KeyStoreType {      PKCS12("pkcs12"), JKS("jks"), HSMFACADE("hsmfacade"), PKCS11("pkcs11"); @@ -182,12 +207,18 @@ public class KeyStoreConfiguration {        @Nonnull String configParamKey)        throws EaafConfigurationException {      final String configValue = config.get(configParamKey); -    if (StringUtils.isEmpty(configValue)) { -      throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_04, new Object[] { 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,  +          new Object[] { params}); +       +    } +     +  }  } 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 970b8e5a..2d9a863a 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 @@ -5,6 +5,8 @@ internal.keystore.03=HSM-Facade initialization failed with a generic error: {0}  internal.keystore.04=HSM-Facade has a wrong configuration. Missing property: {0}  internal.keystore.05=HSM-Facade has a wrong configuration. Property: {0} Reason:{1}    internal.keystore.06=KeyStore: {0} initialization failed. Reason: {1} - +internal.keystore.07=Validation of KeyStore: {0} failed. Reason: {1} +internal.keystore.08=Can not access Key: {1} in KeyStore: {0} +internal.keystore.09=Can not access Key: {1} in KeyStore: {0} Reason: {2} | 
