From 84b36f837222efbd3160bd41a9437058e1c5f2ff Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Mon, 22 May 2023 08:34:20 +0200 Subject: chore(saml2): optimize metadata signature-verification filter Select trusted X509 certificates based on KeyInfo from XML-Signature, if possible --- .../SimpleMetadataSignatureVerificationFilter.java | 79 +++++++++++++++++++--- 1 file changed, 68 insertions(+), 11 deletions(-) (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java') diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java index 5a97924f..f4b008af 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/validation/metadata/SimpleMetadataSignatureVerificationFilter.java @@ -25,17 +25,24 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata; import java.security.KeyStore; import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.xml.security.keys.KeyInfo; +import org.apache.xml.security.keys.keyresolver.KeyResolverException; import org.opensaml.saml.common.SignableSAMLObject; import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.signature.Signature; +import org.opensaml.xmlsec.signature.impl.SignatureImpl; import org.opensaml.xmlsec.signature.support.SignatureException; import org.opensaml.xmlsec.signature.support.SignatureValidator; @@ -124,28 +131,78 @@ public class SimpleMetadataSignatureVerificationFilter extends AbstractMetadataS } // perform cryptographic signature verification - boolean isTrusted = false; - for (final BasicX509Credential cred : getTrustedCertificates()) { - log.trace("Validating signature with credential: {} ... ", - cred.getEntityCertificate().getSubjectDN()); + if (!performCryptographicCheck(signedElement.getSignature())) { + log.info("PVP2 metadata: " + metadataUrl + " are NOT trusted!"); + throw new SamlMetadataSignatureException(metadataUrl, ERROR_MSG_SIGNOTVALID); + + } + } + + private boolean performCryptographicCheck(Signature signature) throws EaafConfigurationException { + + // extract trusted signer certificate from signature + BasicX509Credential x509FromSig = extractTrustedX509FromSignature(signature); + if (x509FromSig != null) { try { - SignatureValidator.validate(signedElement.getSignature(), cred); - isTrusted = true; + SignatureValidator.validate(signature, x509FromSig); + return true; } catch (final SignatureException e) { log.debug("Failed to verfiy Signature with cert: {} Reason: {}", - cred.getEntityCertificate().getSubjectDN(), e.getMessage()); + x509FromSig.getEntityCertificate().getSubjectDN(), e.getMessage()); + + } + } else { + for (final BasicX509Credential cred : getTrustedCertificates()) { + log.trace("Validating signature with credential: {} ... ", + cred.getEntityCertificate().getSubjectDN()); + try { + SignatureValidator.validate(signature, cred); + return true; + + } catch (final SignatureException e) { + log.debug("Failed to verfiy Signature with cert: {} Reason: {}", + cred.getEntityCertificate().getSubjectDN(), e.getMessage()); + + } } } - if (!isTrusted) { - log.info("PVP2 metadata: " + metadataUrl + " are NOT trusted!"); - throw new SamlMetadataSignatureException(metadataUrl, ERROR_MSG_SIGNOTVALID); + return false; + + } + + private BasicX509Credential extractTrustedX509FromSignature(Signature signature) { + try { + KeyInfo keyInfo = ((SignatureImpl) signature).getXMLSignature().getKeyInfo(); + + byte[] encSigCert = keyInfo.getX509Certificate() != null + ? keyInfo.getX509Certificate().getEncoded() + : ArrayUtils.EMPTY_BYTE_ARRAY; + + return getTrustedCertificates().stream() + .filter(el -> { + try { + return MessageDigest.isEqual(el.getEntityCertificate().getEncoded(), encSigCert); + + } catch (CertificateEncodingException e) { + log.warn("Can not match certificates.", e); + return false; + + } + }) + .findFirst() + .orElse(null); + + } catch (KeyResolverException | EaafConfigurationException | CertificateEncodingException e) { + log.info("Can not extract X509 certificate from XML signature. Reason: {}", e.getMessage()); } + return null; + } - + private List getTrustedCertificates() throws EaafConfigurationException { try { final List certs = -- cgit v1.2.3