summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv/egiz
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-14 15:22:13 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-14 15:22:13 +0100
commitc4e1a45e7958cab402d83f6f4ae208df1bb2ab58 (patch)
tree73d8118a00bc4eaf5e5a9b0981d3c660843f5a38 /eaaf_core_utils/src/main/java/at/gv/egiz
parente23226c47807be597bbbae3891dbb94069d56836 (diff)
downloadEAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.tar.gz
EAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.tar.bz2
EAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.zip
add common-code for KeyStore and Credential handling
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/exception/EaafKeyAccessException.java22
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreFactory.java1
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/EaafKeyStoreUtils.java147
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/KeyStoreConfiguration.java41
4 files changed, 206 insertions, 5 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});
+
+ }
+
+ }
}