From be7b4a37fb0844e9f1b9ed91742af3d204f68f22 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 26 Aug 2020 16:21:39 +0200 Subject: refactor JWS and JWE implementation in SL2.0 module to reuse JWS and JWE specific implementation in other classes --- .../modules/auth/sl20/utils/JsonSecurityUtils.java | 203 +++++++-------------- 1 file changed, 61 insertions(+), 142 deletions(-) (limited to 'eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java') 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 dae11370..10cfeafa 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 @@ -7,24 +7,38 @@ import java.security.KeyStoreException; import java.security.Provider; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.PostConstruct; +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.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; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.JoseUtils.JwsResult; + import org.apache.commons.lang3.StringUtils; import org.jose4j.jca.ProviderContext; import org.jose4j.jwa.AlgorithmConstraints; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwe.JsonWebEncryption; import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.jwx.JsonWebStructure; +import org.jose4j.jwx.HeaderParameterNames; import org.jose4j.keys.X509Util; -import org.jose4j.keys.resolvers.X509VerificationKeyResolver; import org.jose4j.lang.JoseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,22 +50,6 @@ import org.springframework.util.Base64Utils; 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.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; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20SecurityException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoBuildException; -import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; - @Service public class JsonSecurityUtils implements IJoseTools { private static final Logger log = LoggerFactory.getLogger(JsonSecurityUtils.class); @@ -127,41 +125,16 @@ public class JsonSecurityUtils implements IJoseTools { @Override public String createSignature(final String payLoad, boolean addFullCertChain) throws SlCommandoBuildException { try { - final JsonWebSignature jws = new JsonWebSignature(); - - // set payload - jws.setPayload(payLoad); - - // set basic header - jws.setContentTypeHeaderValue(SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND); - - // set signing information - final Pair signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates( - keyStore.getFirst(), getSigningKeyAlias(), getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE); - jws.setKey(signingCred.getFirst()); - jws.setAlgorithmHeaderValue(getKeyOperationAlgorithmFromCredential(jws.getKey(), - AlgorithmIdentifiers.RSA_USING_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256)); - - // set special provider if required - if (keyStore.getSecond() != null) { - log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName()); - final ProviderContext providerCtx = new ProviderContext(); - providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( - keyStore.getSecond().getName()); - jws.setProviderContext(providerCtx); - - } - - if (addFullCertChain) { - jws.setCertificateChainHeaderValue(signingCred.getSecond()); - - } - - jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]); - - return jws.getCompactSerialization(); + return JoseUtils.createSignature(keyStore, getSigningKeyAlias(), getSigningKeyPassword(), + payLoad, addFullCertChain, + Collections.singletonMap( + HeaderParameterNames.CONTENT_TYPE, + SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND), + getRsaSigningAlgorithm(), + getEccSigningAlgorithm(), + FRIENDLYNAME_KEYSTORE); - } catch (final JoseException | EaafKeyAccessException e) { + } catch (final JoseException | EaafException e) { log.warn("Can NOT sign SL2.0 command.", e); throw new SlCommandoBuildException("Can NOT sign SL2.0 command.", e); @@ -182,61 +155,12 @@ public class JsonSecurityUtils implements IJoseTools { public VerificationResult validateSignature(@Nonnull final String serializedContent, @Nonnull final List trustedCerts, @Nonnull final AlgorithmConstraints constraints) throws JoseException, IOException { - final JsonWebSignature jws = new JsonWebSignature(); - // set payload - jws.setCompactSerialization(serializedContent); - - // set security constrains - jws.setAlgorithmConstraints(constraints); - - // load signinc certs - Key selectedKey = null; - final List x5cCerts = jws.getCertificateChainHeaderValue(); - final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue(); - if (x5cCerts != null) { - log.debug("Found x509 certificate in JOSE header ... "); - log.trace("Sorting received X509 certificates ... "); - final List sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); - - if (trustedCerts.contains(sortedX5cCerts.get(0))) { - selectedKey = sortedX5cCerts.get(0).getPublicKey(); - - } else { - log.info("Can NOT find JOSE certificate in truststore."); - try { - log.debug("Cert: " + Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded())); - - } catch (final CertificateEncodingException e) { - e.printStackTrace(); - - } - - } - - } else if (StringUtils.isNotEmpty(x5t256)) { - log.debug("Found x5t256 fingerprint in JOSE header .... "); - final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver( - trustedCerts); - selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.emptyList()); - - } else { - throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint"); - - } - - if (selectedKey == null) { - throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED"); - - } - - // set verification key - jws.setKey(selectedKey); - // load payLoad + final JwsResult result = JoseUtils.validateSignature(serializedContent, trustedCerts, constraints); return new VerificationResult( - mapper.getMapper().readTree(jws.getHeaders().getFullHeaderAsJsonString()), - mapper.getMapper().readTree(jws.getPayload()), - x5cCerts, jws.verifySignature()); + mapper.getMapper().readTree(result.getFullJoseHeader().getFullHeaderAsJsonString()), + mapper.getMapper().readTree(result.getPayLoad()), + result.getX5cCerts(), result.isValid()); } @@ -244,7 +168,7 @@ public class JsonSecurityUtils implements IJoseTools { @Nonnull public VerificationResult validateSignature(@Nonnull final String serializedContent) throws SL20Exception { try { - final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST, + final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.PERMIT, SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])); @@ -254,7 +178,7 @@ public class JsonSecurityUtils implements IJoseTools { if (!result.isValidSigned()) { log.info("JWS signature invalide. Stopping authentication process ..."); - log.debug("Received JWS msg: " + serializedContent); + log.debug("Received JWS msg: {}", serializedContent); throw new SL20SecurityException("JWS signature invalide."); } @@ -281,11 +205,11 @@ public class JsonSecurityUtils implements IJoseTools { // set security constrains receiverJwe.setAlgorithmConstraints( - new AlgorithmConstraints(ConstraintType.WHITELIST, + new AlgorithmConstraints(ConstraintType.PERMIT, SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.size()]))); receiverJwe.setContentEncryptionAlgorithmConstraints( - new AlgorithmConstraints(ConstraintType.WHITELIST, SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION + new AlgorithmConstraints(ConstraintType.PERMIT, SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.size()]))); // set payload @@ -304,7 +228,7 @@ public class JsonSecurityUtils implements IJoseTools { receiverJwe.setProviderContext(providerCtx); } - + // validate key from header against key from config final List x5cCerts = receiverJwe.getCertificateChainHeaderValue(); final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue(); @@ -331,7 +255,7 @@ public class JsonSecurityUtils implements IJoseTools { 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); + log.debug("X5t256 from JOSE header: {} Encrytption cert: {}", x5t256, certFingerPrint); throw new SL20Exception("sl20.05", new Object[] { "X5t256 from JOSE header does NOT match encryption certificate" }); @@ -346,7 +270,7 @@ public class JsonSecurityUtils implements IJoseTools { // set key receiverJwe.setKey(encryptionCred.getFirst()); - + // decrypt payload return mapper.getMapper().readTree(receiverJwe.getPlaintextString()); @@ -424,33 +348,6 @@ public class JsonSecurityUtils implements IJoseTools { return config; } - /** - * Select signature algorithm for a given credential. - * - * @param key {@link X509Credential} that will be used for key operations - * @param rsaSigAlgorithm RSA based algorithm that should be used in - * case of RSA credential - * @param ecSigAlgorithm EC based algorithm that should be used in case - * of RSA credential - * @return either the RSA based algorithm or the EC based algorithm - * @throws SlCommandoBuildException In case of an unsupported credential - */ - private static String getKeyOperationAlgorithmFromCredential(Key key, - String rsaSigAlgorithm, String ecSigAlgorithm) throws SlCommandoBuildException { - if (key instanceof RSAPrivateKey) { - return rsaSigAlgorithm; - - } else if (key instanceof ECPrivateKey) { - return ecSigAlgorithm; - - } else { - log.warn("Could NOT evaluate the Private-Key type from do select algorithm"); - throw new SlCommandoBuildException("Could NOT evaluate the Private-Key type from do select algorithm"); - - } - - } - private String getSigningKeyAlias() { String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS); if (value != null) { @@ -490,4 +387,26 @@ public class JsonSecurityUtils implements IJoseTools { return null; } + private String getRsaSigningAlgorithm() { + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_SIG_ALG_RSA, + AlgorithmIdentifiers.RSA_PSS_USING_SHA256); + if (value != null) { + value = value.trim(); + } + + return value; + + } + + private String getEccSigningAlgorithm() { + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_SIG_ALG_ECC, + AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256); + if (value != null) { + value = value.trim(); + } + + return value; + + } + } -- cgit v1.2.3