summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2019-11-14 13:35:19 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2019-11-14 13:35:19 +0100
commitf6273721193b5a36e71d48e5388b24103468a175 (patch)
tree8ef37fe222ae2930265ccfc5fc6aa8851c14f29c
parentd0cecdd8df679ea2d40b5a38299d7cf2a72f01b0 (diff)
downloadEAAF-Components-f6273721193b5a36e71d48e5388b24103468a175.tar.gz
EAAF-Components-f6273721193b5a36e71d48e5388b24103468a175.tar.bz2
EAAF-Components-f6273721193b5a36e71d48e5388b24103468a175.zip
refactor JoseTools to support JWS signature verification by using one truststore
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java45
-rw-r--r--eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java162
2 files changed, 136 insertions, 71 deletions
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java
index 35e6de4f..b124ada7 100644
--- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java
+++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/IJOSETools.java
@@ -1,6 +1,15 @@
package at.gv.egiz.eaaf.modules.auth.sl20.utils;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.lang.JoseException;
import com.fasterxml.jackson.databind.JsonNode;
@@ -20,14 +29,44 @@ public interface IJOSETools {
public String createSignature(String payLoad) throws SLCommandoBuildException;
/**
- * Validates a JWS signature
+ * Validates a signed SL2.0 message
*
* @param serializedContent
* @return
* @throws SLCommandoParserException
* @throws SL20Exception
*/
- public VerificationResult validateSignature(String serializedContent) throws SL20Exception;
+ @Nonnull
+ public VerificationResult validateSignature(@Nonnull String serializedContent) throws SL20Exception;
+
+ /**
+ * Validate a JWS signature
+ *
+ * @param serializedContent JWS in serialized form
+ * @param trustedCerts trusted X509 certificates
+ * @param constraints signature verification constraints
+ * @return Signature-verification result
+ * @throws JoseException
+ * @throws IOException
+ */
+ @Nonnull
+ public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull List<X509Certificate> trustedCerts,
+ @Nonnull AlgorithmConstraints constraints) throws JoseException, IOException;
+
+ /**
+ * Validate a JWS signature
+ *
+ * @param serializedContent JWS in serialized form
+ * @param trustStore with trusted X509 certificates
+ * @param algconstraints signature verification constraints
+ * @return Signature-verification result
+ * @throws JoseException
+ * @throws IOException
+ * @throws KeyStoreException
+ */
+ @Nonnull
+ public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull KeyStore trustStore,
+ @Nonnull AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException;
/**
* Get the encryption certificate for SL2.0 End-to-End encryption
@@ -44,5 +83,5 @@ public interface IJOSETools {
* @throws SL20Exception
*/
public JsonNode decryptPayload(String compactSerialization) throws SL20Exception;
-
+
}
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 33873f43..c07c6081 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
@@ -4,6 +4,7 @@ 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;
@@ -13,6 +14,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
+import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
@@ -28,6 +30,7 @@ import org.jose4j.lang.JoseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
@@ -57,7 +60,7 @@ public class JsonSecurityUtils implements IJOSETools{
private Key encPrivKey = null;
private X509Certificate[] encCertChain = null;
- private final List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>();
+ private List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>();
private static JsonMapper mapper = new JsonMapper();
@@ -100,22 +103,10 @@ public class JsonSecurityUtils implements IJOSETools{
log.warn("No encryption key for SL2.0 found. End-to-End encryption is not used. Reason: " + e.getMessage(), e);
}
-
+
//load trusted certificates
- 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)
- trustedCerts.add((X509Certificate) cert);
- else
- log.info("Can not process entry: " + el + ". Reason: " + cert.toString());
-
- }
- }
-
+ trustedCerts = readCertsFromKeyStore(keyStore);
+
//some short validation
if (signPrivKey == null || !(signPrivKey instanceof PrivateKey)) {
log.info("Can NOT open privateKey for SL2.0 signing. KeyStore=" + getKeyStoreFilePath());
@@ -141,7 +132,6 @@ public class JsonSecurityUtils implements IJOSETools{
}
-
@Override
public String createSignature(String payLoad) throws SLCommandoBuildException {
try {
@@ -172,75 +162,90 @@ public class JsonSecurityUtils implements IJOSETools{
}
@Override
- public VerificationResult validateSignature(String serializedContent) throws SL20Exception {
- try {
- final JsonWebSignature jws = new JsonWebSignature();
- //set payload
- jws.setCompactSerialization(serializedContent);
-
- //set security constrains
- jws.setAlgorithmConstraints(new AlgorithmConstraints(ConstraintType.WHITELIST,
- SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])));
+ public VerificationResult validateSignature(String serializedContent, KeyStore trustStore,
+ AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException {
+ final List<X509Certificate> trustedCertificates = readCertsFromKeyStore(trustStore);
+ return validateSignature(serializedContent, trustedCertificates , algconstraints);
+
+ }
+
+ @Override
+ @NonNull
+ public VerificationResult validateSignature(@Nonnull String serializedContent, @Nonnull List<X509Certificate> trustedCerts, @Nonnull AlgorithmConstraints constraints) throws JoseException, IOException {
+ final JsonWebSignature jws = new JsonWebSignature();
+ //set payload
+ jws.setCompactSerialization(serializedContent);
- //load signinc certs
- Key selectedKey = null;
- final List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue();
- final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue();
- if (x5cCerts != null) {
- log.debug("Found x509 certificate in JOSE header ... ");
+ //set security constrains
+ jws.setAlgorithmConstraints(constraints);
+
+ //load signinc certs
+ Key selectedKey = null;
+ final List<X509Certificate> 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<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
-
- if (trustedCerts.contains(sortedX5cCerts.get(0))) {
- selectedKey = sortedX5cCerts.get(0).getPublicKey();
+ final List<X509Certificate> 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()));
- } else {
- log.info("Can NOT find JOSE certificate in truststore.");
- log.debug("JOSE certificate: " + sortedX5cCerts.get(0).toString());
- try {
- log.debug("Cert: " + Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded()));
- } catch (final CertificateEncodingException e) {
- e.printStackTrace();
- }
+ } 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.<JsonWebStructure>emptyList());
+ }
+
+ } else if (StringUtils.isNotEmpty(x5t256)) {
+ log.debug("Found x5t256 fingerprint in JOSE header .... ");
+ final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(trustedCerts);
+ selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList());
+
+ } else {
+ throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint");
+
+ }
- } else {
- log.info("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
- throw new SLCommandoParserException("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
+ if (selectedKey == null) {
+ throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED");
+
+ }
- }
-
- if (selectedKey == null) {
- log.info("Can NOT select verification key for JWS. Signature verification FAILED.");
- throw new SLCommandoParserException("Can NOT select verification key for JWS. Signature verification FAILED");
+ //set verification key
+ jws.setKey(selectedKey);
- }
+ //load payLoad
+ return new VerificationResult(mapper.getMapper().readTree(jws.getPayload()), null, jws.verifySignature()) ;
+
+
+ }
+
+ @Override
+ @Nonnull
+ public VerificationResult validateSignature(@Nonnull String serializedContent) throws SL20Exception {
+ try {
+ final AlgorithmConstraints algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST,
+ SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()]));
- //set verification key
- jws.setKey(selectedKey);
+ final VerificationResult result = validateSignature(serializedContent, trustedCerts, algConstraints);
- //validate signature
- final boolean valid = jws.verifySignature();
- if (!valid) {
+ if (!result.isValidSigned()) {
log.info("JWS signature invalide. Stopping authentication process ...");
log.debug("Received JWS msg: " + serializedContent);
throw new SL20SecurityException("JWS signature invalide.");
}
-
- //load payLoad
log.debug("SL2.0 commando signature validation sucessfull");
- final JsonNode sl20Req = mapper.getMapper().readTree(jws.getPayload());
-
- return new VerificationResult(sl20Req, null, valid) ;
-
+ return result;
+
} catch (JoseException | JsonParseException e) {
log.warn("SL2.0 commando signature validation FAILED", e);
throw new SL20SecurityException(new Object[]{e.getMessage()}, e);
@@ -391,4 +396,25 @@ public class JsonSecurityUtils implements IJOSETools{
return value;
}
+ @Nonnull
+ private List<X509Certificate> readCertsFromKeyStore(@Nonnull 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: " + el + ". Reason: " + cert.toString());
+
+ }
+ }
+
+ return Collections.unmodifiableList(result);
+ }
+
}