From c4e1a45e7958cab402d83f6f4ae208df1bb2ab58 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 14 Feb 2020 15:22:13 +0100 Subject: add common-code for KeyStore and Credential handling --- .../gv/egiz/eaaf/modules/auth/sl20/Constants.java | 40 ++- .../modules/auth/sl20/utils/JsonSecurityUtils.java | 271 ++++++++++----------- 2 files changed, 161 insertions(+), 150 deletions(-) (limited to 'eaaf_modules/eaaf_module_auth_sl20') 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 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 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 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 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 trustedCertificates = readCertsFromKeyStore(trustStore); + final List 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 encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, + getEncryptionKeyAlias(), getEncryptionKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + // validate key from header against key from config final List 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 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 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 readCertsFromKeyStore(@Nonnull final KeyStore keyStore) throws KeyStoreException { - final List result = new ArrayList<>(); - - final Enumeration 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; } } -- cgit v1.2.3