Skip to content

Commit

Permalink
Merge pull request #312 from luisgoncalves/verify-signing-cert-keyinf…
Browse files Browse the repository at this point in the history
…o-only

Support verification of signature protecting the signing certificate in KeyInfo only
  • Loading branch information
luisgoncalves authored Oct 19, 2024
2 parents c3a492a + 62205d0 commit ec13ce8
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 120 deletions.
8 changes: 4 additions & 4 deletions src/main/java/xades4j/production/Enveloped.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public Enveloped(XadesSigner signer)
* reference is used.
*
* @param elementToSign the element that will be signed and will be the signature's parent
*
* @throws XAdES4jException see {@link XadesSigner#sign(xades4j.production.SignedDataObjects, org.w3c.dom.Node)}
* @return the signature result
* @throws XAdES4jException see {@link XadesSigner#sign(xades4j.production.SignedDataObjects, org.w3c.dom.Node)}
* @throws IllegalArgumentException if {@code elementToSign} doesn't have an Id and isn't the document root
*/
public void sign(Element elementToSign) throws XAdES4jException
public XadesSignatureResult sign(Element elementToSign) throws XAdES4jException
{
String refUri;
if (elementToSign.hasAttribute("Id"))
Expand All @@ -65,6 +65,6 @@ public void sign(Element elementToSign) throws XAdES4jException
}

DataObjectDesc dataObjRef = new DataObjectReference(refUri).withTransform(new EnvelopedSignatureTransform());
signer.sign(new SignedDataObjects(dataObjRef), elementToSign);
return signer.sign(new SignedDataObjects(dataObjRef), elementToSign);
}
}
30 changes: 10 additions & 20 deletions src/main/java/xades4j/verification/CounterSignatureVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@

import jakarta.inject.Inject;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.signature.Reference;
import org.apache.xml.security.signature.SignedInfo;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import xades4j.XAdES4jException;
import xades4j.properties.CounterSignatureProperty;
import xades4j.properties.QualifyingProperty;
import xades4j.properties.data.GenericDOMData;
import xades4j.utils.CanonicalizerUtils;
import xades4j.utils.DOMHelper;

import static xades4j.verification.SignatureUtils.signatureReferencesElement;

/**
* XAdES section G.2.2.7
*
* @author Luís
*/
class CounterSignatureVerifier implements QualifyingPropertyVerifier<GenericDOMData>
Expand All @@ -56,7 +56,8 @@ public QualifyingProperty verify(
{
Element sigElem = DOMHelper.getFirstChildElement(propData.getPropertyElement());
res = verifier.verify(sigElem, null);
} catch (XAdES4jException ex)
}
catch (XAdES4jException ex)
{
throw new CounterSignatureXadesVerificationException(ex);
}
Expand All @@ -69,25 +70,14 @@ public QualifyingProperty verify(

try
{
SignedInfo si = res.getXmlSignature().getSignedInfo();
for (int i = 0; i < si.getLength(); i++)
if (signatureReferencesElement(res.getXmlSignature(), (Element) targetSigValueElem))
{
Reference r = si.item(i);
if (r.getContentsAfterTransformation().getSubNode() == targetSigValueElem)
{
// The signature references the SignatureValue element.
return new CounterSignatureProperty(res);
}
else if (r.getContentsBeforeTransformation().getSubNode() == targetSigValueElem && CanonicalizerUtils.allTransformsAreC14N(r))
{
// The signature references the SignatureValue element with
// C14N transforms only.
// TODO: same return value as before
return new CounterSignatureProperty(res);
}
return new CounterSignatureProperty(res);
}

throw new CounterSignatureSigValueRefException();
} catch (XMLSecurityException e)
}
catch (XMLSecurityException e)
{
// Shouldn't happen because the signature was already verified.
throw new CounterSignatureVerificationException(e);
Expand Down
70 changes: 33 additions & 37 deletions src/main/java/xades4j/verification/KeyInfoProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
*/
package xades4j.verification;

import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.keys.content.X509Data;
Expand All @@ -29,8 +24,14 @@
import xades4j.providers.CertificateValidationException;
import xades4j.providers.X500NameStyleProvider;

import javax.annotation.Nullable;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
*
* @author Luís
*/
class KeyInfoProcessor
Expand All @@ -42,39 +43,36 @@ private KeyInfoProcessor()

static class KeyInfoRes
{
final X509CertSelector certSelector;
final List<X509Certificate> keyInfoCerts;
final X509CertSelector signingCertSelector;
final boolean signingCertSelectorFromKeyInfo;
final List<X509Certificate> certs;
@Nullable
final XMLX509IssuerSerial issuerSerial;

KeyInfoRes(
X509CertSelector certSelector,
List<X509Certificate> keyInfoCerts,
XMLX509IssuerSerial issuerSerial)
private KeyInfoRes(
X509CertSelector signingCertSelector,
boolean signingCertSelectorFromKeyInfo,
List<X509Certificate> certs,
@Nullable XMLX509IssuerSerial issuerSerial)
{
this.keyInfoCerts = keyInfoCerts;
this.certSelector = certSelector;
this.signingCertSelector = signingCertSelector;
this.signingCertSelectorFromKeyInfo = signingCertSelectorFromKeyInfo;
this.certs = certs;
this.issuerSerial = issuerSerial;
}

KeyInfoRes(X509CertSelector certSelector)
{
this.certSelector = certSelector;
this.keyInfoCerts = Collections.emptyList();
this.issuerSerial = null;
}
}

static KeyInfoRes process(
KeyInfo keyInfo, CertRef signingCertRef, X500NameStyleProvider x500NameStyleProvider) throws CertificateValidationException
KeyInfo keyInfo, @Nullable CertRef signingCertRef, X500NameStyleProvider x500NameStyleProvider) throws CertificateValidationException
{
if (null == keyInfo || !keyInfo.containsX509Data())
{
return tryUseSigningCertificateReference(signingCertRef, x500NameStyleProvider);
}

List<X509Certificate> keyInfoCerts = new ArrayList<>(1);
XMLX509IssuerSerial issuerSerial = null;
X509CertSelector certSelector = new X509CertSelector();
X509CertSelector signingCertSelector = new X509CertSelector();

// XML-DSIG 4.4.4: "Any X509IssuerSerial, X509SKI, and X509SubjectName elements
// that appear MUST refer to the certificate or certificates containing the
Expand All @@ -100,13 +98,13 @@ static KeyInfoRes process(
if (x509Data.containsIssuerSerial())
{
issuerSerial = x509Data.itemIssuerSerial(0);
certSelector.setIssuer(x500NameStyleProvider.fromString(issuerSerial.getIssuerName()));
certSelector.setSerialNumber(issuerSerial.getSerialNumber());
signingCertSelector.setIssuer(x500NameStyleProvider.fromString(issuerSerial.getIssuerName()));
signingCertSelector.setSerialNumber(issuerSerial.getSerialNumber());
hasSelectionCriteria = true;
}
else if (x509Data.containsSubjectName())
{
certSelector.setSubject(x500NameStyleProvider.fromString(x509Data.itemSubjectName(0).getSubjectName()));
signingCertSelector.setSubject(x500NameStyleProvider.fromString(x509Data.itemSubjectName(0).getSubjectName()));
hasSelectionCriteria = true;
}
}
Expand All @@ -121,22 +119,20 @@ else if (x509Data.containsSubjectName())
}
}

if (!hasSelectionCriteria)
if (!hasSelectionCriteria && !keyInfoCerts.isEmpty())
{
if (keyInfoCerts.isEmpty())
{
return tryUseSigningCertificateReference(signingCertRef, x500NameStyleProvider);
}

certSelector.setCertificate(keyInfoCerts.get(0));
signingCertSelector.setCertificate(keyInfoCerts.get(0));
hasSelectionCriteria = true;
}
}
catch (XMLSecurityException ex)
{
throw new InvalidKeyInfoDataException("Cannot process X509Data", ex);
}

return new KeyInfoRes(certSelector, keyInfoCerts, issuerSerial);
return hasSelectionCriteria
? new KeyInfoRes(signingCertSelector, true, keyInfoCerts, issuerSerial)
: tryUseSigningCertificateReference(signingCertRef, x500NameStyleProvider);
}

private static KeyInfoRes tryUseSigningCertificateReference(CertRef signingCertRef, X500NameStyleProvider x500NameStyleProvider) throws CertificateValidationException
Expand All @@ -149,7 +145,7 @@ private static KeyInfoRes tryUseSigningCertificateReference(CertRef signingCertR
X509CertSelector certSelector = new X509CertSelector();
certSelector.setIssuer(x500NameStyleProvider.fromString(signingCertRef.getIssuerDN()));
certSelector.setSerialNumber(signingCertRef.getSerialNumber());
return new KeyInfoRes(certSelector);

return new KeyInfoRes(certSelector, false, Collections.emptyList(), null);
}
}
32 changes: 26 additions & 6 deletions src/main/java/xades4j/verification/SignatureUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,28 @@
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.ElementProxy;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import xades4j.XAdES4jXMLSigException;
import xades4j.algorithms.GenericAlgorithm;
import xades4j.properties.QualifyingProperty;
import xades4j.utils.DOMHelper;

import static xades4j.utils.CanonicalizerUtils.allTransformsAreC14N;

/**
*
* @author Luís
*/
class SignatureUtils
{

private SignatureUtils()
{
}
/**/

static class ReferencesRes
{

/**
* In signature order.
*/
Expand Down Expand Up @@ -98,10 +98,9 @@ static ReferencesRes processReferences(
}

if (null == signedPropsRef)
// !!!
// Still may be a XAdES signature, if the signing certificate is
// protected. For now, that scenario is not supported.
{
// TODO Still may be a XAdES signature, if the signing certificate is
// protected. For now, that scenario is not supported.
throw new QualifyingPropertiesIncorporationException("SignedProperties reference not found");
}

Expand Down Expand Up @@ -258,4 +257,25 @@ private static Element getReferencedSignedPropsElem(Reference signedPropsRef) th
// The referenced signed properties element must be the child of qualifying properties.
return (Element) sPropsNode;
}

static boolean signatureReferencesElement(XMLSignature signature, ElementProxy elementProxy) throws XMLSecurityException
{
return signatureReferencesElement(signature, elementProxy.getElement());
}

static boolean signatureReferencesElement(XMLSignature signature, Element element) throws XMLSecurityException
{
SignedInfo si = signature.getSignedInfo();
for (int i = 0; i < si.getLength(); i++)
{
Reference r = si.item(i);
if (r.getContentsAfterTransformation().getSubNode() == element ||
r.getContentsBeforeTransformation().getSubNode() == element && allTransformsAreC14N(r))
{
return true;
}
}

return false;
}
}
Loading

0 comments on commit ec13ce8

Please sign in to comment.