summaryrefslogtreecommitdiff
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
parente23226c47807be597bbbae3891dbb94069d56836 (diff)
downloadEAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.tar.gz
EAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.tar.bz2
EAAF-Components-c4e1a45e7958cab402d83f6f4ae208df1bb2ab58.zip
add common-code for KeyStore and Credential handling
-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
-rw-r--r--eaaf_core_utils/src/main/resources/messages/eaaf_utils_message.properties4
-rw-r--r--eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EaafKeyStoreFactoryTest.java81
-rw-r--r--eaaf_core_utils/src/test/resources/data/junit.jksbin0 -> 3980 bytes
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java40
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java271
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java11
10 files changed, 460 insertions, 158 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}
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 805000cb..c47805e8 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
@@ -1,6 +1,10 @@
package at.gv.egiz.eaaf.core.test.credentials;
+import java.security.Key;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.X509Certificate;
+import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Assert;
@@ -20,12 +24,15 @@ import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
+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.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.data.Pair;
import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap;
import io.grpc.StatusRuntimeException;
@@ -34,6 +41,8 @@ import io.grpc.StatusRuntimeException;
@DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public class EaafKeyStoreFactoryTest {
+ private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS =
+ "src/test/resources/data/junit.jks";
private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS =
"src/test/resources/data/junit_without_trustcerts.jks";
private static final String PATH_TO_SOFTWARE_KEYSTORE_PKCS12 =
@@ -254,11 +263,79 @@ public class EaafKeyStoreFactoryTest {
keyStoreConfig.setSoftKeyStoreFilePath(PATH_TO_SOFTWARE_KEYSTORE_JKS);
keyStoreConfig.setSoftKeyStorePassword(SOFTWARE_KEYSTORE_PASSWORD);
+ keyStoreConfig.validate();
final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig);
Assert.assertNotNull("KeyStore is null", keyStore);
}
+
+ @Test
+ @DirtiesContext
+ public void softwareKeyStoreAccessOperations() throws EaafException, KeyStoreException {
+ final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class);
+ Assert.assertFalse("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized());
+
+ final KeyStoreConfiguration keyStoreConfig = new KeyStoreConfiguration();
+ keyStoreConfig.setKeyStoreType(KeyStoreType.JKS);
+ keyStoreConfig.setSoftKeyStoreFilePath(PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS);
+ keyStoreConfig.setSoftKeyStorePassword(SOFTWARE_KEYSTORE_PASSWORD);
+
+ keyStoreConfig.validate();
+
+ final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig);
+ Assert.assertNotNull("KeyStore is null", keyStore);
+
+ //read trusted certs
+ List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(keyStore);
+ Assert.assertNotNull("Trusted certs", trustedCerts);
+ Assert.assertEquals("Trusted certs size", 2, trustedCerts.size());
+
+ //read priv. key
+ Pair<Key, X509Certificate[]> privCred1 = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "meta", "password".toCharArray(), true, "jUnit test");
+ Assert.assertNotNull("Credential 1", privCred1);
+ Assert.assertNotNull("Credential 1 priv. key", privCred1.getFirst());
+ Assert.assertNotNull("Credential 1 certificate", privCred1.getSecond());
+
+ //read priv. key
+ Pair<Key, X509Certificate[]> privCred2 = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "sig", "password".toCharArray(), true, "jUnit test");
+ Assert.assertNotNull("Credential 2", privCred2);
+ Assert.assertNotNull("Credential 2 priv. key", privCred2.getFirst());
+ Assert.assertNotNull("Credential 2 certificate", privCred2.getSecond());
+
+
+ //read priv. key
+ Pair<Key, X509Certificate[]> privCred3 = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "notexist", "password".toCharArray(), false, "jUnit test");
+ Assert.assertNull("Credential 3", privCred3);
+
+ //read priv. key
+ Pair<Key, X509Certificate[]> privCred4 = EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "meta", "wrong".toCharArray(), false, "jUnit test");
+ Assert.assertNull("Credential 3", privCred4);
+
+ try {
+ EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "meta", "wrong".toCharArray(), true, "jUnit test");
+ Assert.fail("Wrong password not detected");
+
+ } catch (EaafKeyAccessException e) {
+ Assert.assertEquals("wrong errorcode", "internal.keystore.09", e.getErrorId());
+ }
+
+ try {
+ EaafKeyStoreUtils.getPrivateKeyAndCertificates(
+ keyStore, "wrong", "password".toCharArray(), true, "jUnit test");
+ Assert.fail("Wrong alias not detected");
+
+ } catch (EaafKeyAccessException e) {
+ Assert.assertEquals("wrong errorcode", "internal.keystore.09", e.getErrorId());
+ }
+
+
+ }
@Test
@DirtiesContext
@@ -271,6 +348,8 @@ public class EaafKeyStoreFactoryTest {
keyStoreConfig.setSoftKeyStoreFilePath(PATH_TO_SOFTWARE_KEYSTORE_PKCS12);
keyStoreConfig.setSoftKeyStorePassword(SOFTWARE_KEYSTORE_PASSWORD);
+ keyStoreConfig.validate();
+
final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig);
Assert.assertNotNull("KeyStore is null", keyStore);
@@ -524,6 +603,8 @@ public class EaafKeyStoreFactoryTest {
keyStoreConfig.setKeyStoreType(KeyStoreType.HSMFACADE);
keyStoreConfig.setKeyStoreName("testkeyStore");
+ keyStoreConfig.validate();
+
try {
final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig);
Assert.assertNotNull("KeyStore is null", keyStore);
diff --git a/eaaf_core_utils/src/test/resources/data/junit.jks b/eaaf_core_utils/src/test/resources/data/junit.jks
new file mode 100644
index 00000000..59e6ad13
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/junit.jks
Binary files differ
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
index f607f8cb..11fd41fb 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java
@@ -7,17 +7,37 @@ public class Constants {
public static final String CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID = CONFIG_PROP_PREFIX
+ ".vda.authblock.transformation.id";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH = CONFIG_PROP_PREFIX + ".security.keystore.path";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD = CONFIG_PROP_PREFIX
- + ".security.keystore.password";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS = CONFIG_PROP_PREFIX + ".security.sign.alias";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = CONFIG_PROP_PREFIX
- + ".security.sign.password";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = CONFIG_PROP_PREFIX
- + ".security.encryption.alias";
- public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = CONFIG_PROP_PREFIX
- + ".security.encryption.password";
+
+ //KeyStore configuration
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_TYPE =
+ CONFIG_PROP_PREFIX + ".security.keystore.type";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_NAME =
+ CONFIG_PROP_PREFIX + ".security.keystore.name";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH =
+ CONFIG_PROP_PREFIX + ".security.keystore.path";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD =
+ CONFIG_PROP_PREFIX + ".security.keystore.password";
+
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS =
+ CONFIG_PROP_PREFIX + ".security.sign.alias";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD =
+ CONFIG_PROP_PREFIX + ".security.sign.password";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS =
+ CONFIG_PROP_PREFIX + ".security.encryption.alias";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD =
+ CONFIG_PROP_PREFIX + ".security.encryption.password";
+ //TrustStore configuration
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE =
+ CONFIG_PROP_PREFIX + ".security.truststore.type";
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_NAME =
+ CONFIG_PROP_PREFIX + ".security.truststore.name";
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PATH =
+ CONFIG_PROP_PREFIX + ".security.truststore.path";
+ public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD =
+ CONFIG_PROP_PREFIX + ".security.truststore.password";
+
+
public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT = "default";
public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = CONFIG_PROP_VDA_ENDPOINT_QUALeID
+ CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT;
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
index 0d2c1815..259c21bf 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java
@@ -1,17 +1,12 @@
package at.gv.egiz.eaaf.modules.auth.sl20.utils;
import java.io.IOException;
-import java.net.MalformedURLException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
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;
@@ -38,9 +33,13 @@ import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonNode;
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.impl.utils.FileUtils;
-import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
+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.data.Pair;
import at.gv.egiz.eaaf.core.impl.utils.X509Utils;
import at.gv.egiz.eaaf.modules.auth.sl20.Constants;
import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult;
@@ -53,88 +52,60 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException;
public class JsonSecurityUtils implements IJoseTools {
private static final Logger log = LoggerFactory.getLogger(JsonSecurityUtils.class);
- @Autowired(required = true)
- IConfiguration authConfig;
- private Key signPrivKey = null;
- private X509Certificate[] signCertChain = null;
-
- private Key encPrivKey = null;
- private X509Certificate[] encCertChain = null;
-
- private List<X509Certificate> trustedCerts = new ArrayList<>();
-
+ private static final String FRIENDLYNAME_KEYSTORE = "SL2.0 KeyStore";
+ private static final String FRIENDLYNAME_TRUSTSTORE = "SL2.0 TrustStore";
+
+ @Autowired(required = true) IConfiguration authConfig;
+ @Autowired(required = true) EaafKeyStoreFactory keystoreFactory;
+
+ private KeyStore keyStore;
+ private KeyStore trustStore;
+
private static JsonMapper mapper = new JsonMapper();
@PostConstruct
- protected void initalize() {
+ protected void initalize() throws SL20Exception {
log.info("Initialize SL2.0 authentication security constrains ... ");
try {
- if (getKeyStoreFilePath() != null) {
- final KeyStore keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), getKeyStorePassword());
-
- // load signing key
- signPrivKey = keyStore.getKey(getSigningKeyAlias(), getSigningKeyPassword().toCharArray());
- final Certificate[] certChainSigning = keyStore.getCertificateChain(getSigningKeyAlias());
- signCertChain = new X509Certificate[certChainSigning.length];
- for (int i = 0; i < certChainSigning.length; i++) {
- if (certChainSigning[i] instanceof X509Certificate) {
- signCertChain[i] = (X509Certificate) certChainSigning[i];
- } else {
- log.warn("NO X509 certificate for signing: " + certChainSigning[i].getType());
- }
-
- }
-
- // load encryption key
- try {
- encPrivKey = keyStore.getKey(getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray());
- if (encPrivKey != null) {
- final Certificate[] certChainEncryption = keyStore.getCertificateChain(getEncryptionKeyAlias());
- encCertChain = new X509Certificate[certChainEncryption.length];
- for (int i = 0; i < certChainEncryption.length; i++) {
- if (certChainEncryption[i] instanceof X509Certificate) {
- encCertChain[i] = (X509Certificate) certChainEncryption[i];
- } else {
- log.warn("NO X509 certificate for encryption: " + certChainEncryption[i].getType());
- }
- }
- } else {
- log.info("No encryption key for SL2.0 found. End-to-End encryption is not used.");
- }
-
- } catch (final Exception e) {
- log.warn("No encryption key for SL2.0 found. End-to-End encryption is not used. Reason: " + e.getMessage(),
- e);
-
- }
-
- // load trusted certificates
- trustedCerts = readCertsFromKeyStore(keyStore);
-
- // some short validation
- if (signPrivKey == null || !(signPrivKey instanceof PrivateKey)) {
- log.info("Can NOT open privateKey for SL2.0 signing. KeyStore=" + getKeyStoreFilePath());
- throw new SL20Exception("sl20.03", new Object[] { "Can NOT open private key for signing" });
-
- }
-
- if (signCertChain == null || signCertChain.length == 0) {
- log.info("NO certificate for SL2.0 signing. KeyStore=" + getKeyStoreFilePath());
- throw new SL20Exception("sl20.03", new Object[] { "NO certificate for SL2.0 signing" });
-
- }
-
- log.info("SL2.0 authentication security constrains initialized.");
-
+ //load KeyStore
+ KeyStoreConfiguration keyStoreConfig = buildKeyStoreConfiguration();
+ keyStore = keystoreFactory.buildNewKeyStore(keyStoreConfig);
+
+ //load TrustStore
+ KeyStoreConfiguration trustStoreConfig = buildTrustStoreConfiguration();
+ trustStore = keystoreFactory.buildNewKeyStore(trustStoreConfig);
+
+ //validate KeyStore entries
+ EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, getSigningKeyAlias(),
+ getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE);
+ Pair<Key, X509Certificate[]> encCredentials =
+ EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, getEncryptionKeyAlias(),
+ getEncryptionKeyPassword(), false, FRIENDLYNAME_TRUSTSTORE);
+ if (encCredentials == null) {
+ log.info("No encryption key for SL2.0 found. End-to-End encryption is not used.");
+
+ }
+
+ //validate TrustStore
+ List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore);
+ if (trustedCerts.isEmpty()) {
+ log.info("No certificates in TrustStore: {}. Signature validation will FAIL!",
+ FRIENDLYNAME_TRUSTSTORE);
+
} else {
- log.info("NO SL2.0 authentication security configuration. Initialization was skipped");
+ log.info("Find #{} certificates in TrustStore: {}",
+ trustedCerts.size(), FRIENDLYNAME_TRUSTSTORE);
+
}
+
+ log.info("SL2.0 authentication security constrains initialized.");
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {
- log.error("SL2.0 security constrains initialization FAILED.", e);
+ log.error("SL2.0 security constrains initialization FAILED.");
+ throw new SL20Exception("sl20.11", new Object[] {e.getMessage()}, e);
}
@@ -153,15 +124,18 @@ public class JsonSecurityUtils implements IJoseTools {
// set signing information
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
- jws.setKey(signPrivKey);
+ Pair<Key, X509Certificate[]> signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore,
+ getSigningKeyAlias(), getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE);
+
+ jws.setKey(signingCred.getFirst());
// TODO:
- jws.setCertificateChainHeaderValue(signCertChain);
- jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]);
+ jws.setCertificateChainHeaderValue(signingCred.getSecond());
+ jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]);
return jws.getCompactSerialization();
- } catch (final JoseException e) {
+ } catch (final JoseException | EaafKeyAccessException e) {
log.warn("Can NOT sign SL2.0 command.", e);
throw new SlCommandoBuildException("Can NOT sign SL2.0 command.", e);
@@ -172,7 +146,7 @@ public class JsonSecurityUtils implements IJoseTools {
@Override
public VerificationResult validateSignature(final String serializedContent, final KeyStore trustStore,
final AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException {
- final List<X509Certificate> trustedCertificates = readCertsFromKeyStore(trustStore);
+ final List<X509Certificate> trustedCertificates = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore);
return validateSignature(serializedContent, trustedCertificates, algconstraints);
}
@@ -244,7 +218,8 @@ public class JsonSecurityUtils implements IJoseTools {
SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING
.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()]));
- final VerificationResult result = validateSignature(serializedContent, trustedCerts, algConstraints);
+ final VerificationResult result =
+ validateSignature(serializedContent, EaafKeyStoreUtils.readCertsFromKeyStore(trustStore), algConstraints);
if (!result.isValidSigned()) {
log.info("JWS signature invalide. Stopping authentication process ...");
@@ -256,7 +231,7 @@ public class JsonSecurityUtils implements IJoseTools {
log.debug("SL2.0 commando signature validation sucessfull");
return result;
- } catch (JoseException | JsonParseException e) {
+ } catch (JoseException | JsonParseException | KeyStoreException e) {
log.warn("SL2.0 commando signature validation FAILED", e);
throw new SL20SecurityException(new Object[] { e.getMessage() }, e);
@@ -284,6 +259,9 @@ public class JsonSecurityUtils implements IJoseTools {
// set payload
receiverJwe.setCompactSerialization(compactSerialization);
+ Pair<Key, X509Certificate[]> encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore,
+ getEncryptionKeyAlias(), getEncryptionKeyPassword(), true, FRIENDLYNAME_KEYSTORE);
+
// validate key from header against key from config
final List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue();
final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue();
@@ -292,7 +270,7 @@ public class JsonSecurityUtils implements IJoseTools {
log.trace("Sorting received X509 certificates ... ");
final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
- if (!sortedX5cCerts.get(0).equals(encCertChain[0])) {
+ if (!sortedX5cCerts.get(0).equals(encryptionCred.getSecond()[0])) {
log.info("Certificate from JOSE header does NOT match encryption certificate");
try {
@@ -307,7 +285,7 @@ public class JsonSecurityUtils implements IJoseTools {
} else if (StringUtils.isNotEmpty(x5t256)) {
log.debug("Found x5t256 fingerprint in JOSE header .... ");
- final String certFingerPrint = X509Util.x5tS256(encCertChain[0]);
+ final String certFingerPrint = X509Util.x5tS256(encryptionCred.getSecond()[0]);
if (!certFingerPrint.equals(x5t256)) {
log.info("X5t256 from JOSE header does NOT match encryption certificate");
log.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint);
@@ -324,12 +302,12 @@ public class JsonSecurityUtils implements IJoseTools {
}
// set key
- receiverJwe.setKey(encPrivKey);
+ receiverJwe.setKey(encryptionCred.getFirst());
// decrypt payload
return mapper.getMapper().readTree(receiverJwe.getPlaintextString());
- } catch (final JoseException e) {
+ } catch (final JoseException | EaafKeyAccessException e) {
log.warn("SL2.0 result decryption FAILED", e);
throw new SL20SecurityException(new Object[] { e.getMessage() }, e);
@@ -340,37 +318,74 @@ public class JsonSecurityUtils implements IJoseTools {
} catch (final IOException e) {
log.warn("Decrypted SL2.0 result can not be parsed.", e);
throw new SlCommandoParserException("Decrypted SL2.0 result can not be parsed", e);
+
}
-
}
@Override
public X509Certificate getEncryptionCertificate() {
- // TODO: maybe update after SL2.0 update on encryption certificate parts
- if (encCertChain != null && encCertChain.length > 0) {
- return encCertChain[0];
- } else {
- return null;
+ Pair<Key, X509Certificate[]> encryptionCred;
+ try {
+ encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore,
+ getEncryptionKeyAlias(), getEncryptionKeyPassword(), false, FRIENDLYNAME_KEYSTORE);
+ if (encryptionCred != null && encryptionCred.getSecond().length > 0) {
+ return encryptionCred.getSecond()[0];
+
+ }
+
+ } catch (EaafKeyAccessException e) {
+ log.trace("Exception is skipped because Encryption is not mandatory on this level", e);
+
}
+
+ return null;
+
}
- private String getKeyStoreFilePath() throws EaafConfigurationException, MalformedURLException {
- return FileUtils.makeAbsoluteUrl(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH),
- authConfig.getConfigurationRootDirectory());
+ private KeyStoreConfiguration buildKeyStoreConfiguration() throws EaafConfigurationException {
+ KeyStoreConfiguration config = new KeyStoreConfiguration();
+ config.setFriendlyName(FRIENDLYNAME_KEYSTORE);
+
+ config.setKeyStoreType(authConfig.getBasicConfiguration(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_TYPE),
+ KeyStoreType.JKS.getKeyStoreType()));
+ config.setKeyStoreName(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_NAME));
+ config.setSoftKeyStoreFilePath(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH));
+ config.setSoftKeyStorePassword(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD));
+
+ //validate configuration state
+ config.validate();
+
+ return config;
+
}
-
- private String getKeyStorePassword() {
- String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD);
- if (value != null) {
- value = value.trim();
- }
-
- return value;
-
+
+ private KeyStoreConfiguration buildTrustStoreConfiguration() throws EaafConfigurationException {
+ KeyStoreConfiguration config = new KeyStoreConfiguration();
+ config.setFriendlyName(FRIENDLYNAME_TRUSTSTORE);
+
+ config.setKeyStoreType(authConfig.getBasicConfiguration(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE),
+ KeyStoreType.JKS.getKeyStoreType()));
+ config.setKeyStoreName(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_NAME));
+ config.setSoftKeyStoreFilePath(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PATH));
+ config.setSoftKeyStorePassword(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD));
+
+ //validate configuration state
+ config.validate();
+
+ return config;
}
+
private String getSigningKeyAlias() {
- String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS).trim();
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS);
if (value != null) {
value = value.trim();
}
@@ -378,18 +393,17 @@ public class JsonSecurityUtils implements IJoseTools {
return value;
}
- private String getSigningKeyPassword() {
- String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD).trim();
+ private char[] getSigningKeyPassword() {
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD);
if (value != null) {
- value = value.trim();
+ return value.trim().toCharArray();
}
- return value;
+ return null;
}
private String getEncryptionKeyAlias() {
- String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS)
- .trim();
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS);
if (value != null) {
value = value.trim();
}
@@ -397,36 +411,13 @@ public class JsonSecurityUtils implements IJoseTools {
return value;
}
- private String getEncryptionKeyPassword() {
- String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD)
- .trim();
+ private char[] getEncryptionKeyPassword() {
+ String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD);
if (value != null) {
- value = value.trim();
- }
-
- return value;
- }
-
- @Nonnull
- private 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 value.trim().toCharArray();
}
- return Collections.unmodifiableList(result);
+ return null;
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java
index 6477d8ff..cd77228c 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java
@@ -73,7 +73,13 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi
* @return keyStore friendlyName
*/
public final String getFriendlyName() {
- return getBasicKeyStoreConfig().getFriendlyName();
+ try {
+ return getBasicKeyStoreConfig().getFriendlyName();
+
+ } catch (EaafConfigurationException e) {
+ return "No KeyStoreName";
+
+ }
}
@@ -81,9 +87,10 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi
* Get the basic KeyStore configuration object for this SAML2 credential.
*
* @return KeyStore configuration object
+ * @throws EaafConfigurationException In case of a configuration error
*/
@Nonnull
- public abstract KeyStoreConfiguration getBasicKeyStoreConfig();
+ public abstract KeyStoreConfiguration getBasicKeyStoreConfig() throws EaafConfigurationException;
/**
* Get alias of key for metadata signing.