Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support verification of signature protecting the signing certificate in KeyInfo only #312

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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