Skip to content

Commit

Permalink
Merge pull request #313 from luisgoncalves/support-sig-alg-parameters
Browse files Browse the repository at this point in the history
Add support for signature algorithm parameters
  • Loading branch information
luisgoncalves authored Oct 25, 2024
2 parents 252d3f4 + eedfaaf commit 5b00fb0
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 76 deletions.
29 changes: 23 additions & 6 deletions src/main/java/xades4j/production/SignatureAlgorithms.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import xades4j.algorithms.CanonicalXMLWithoutComments;
import xades4j.algorithms.GenericAlgorithm;

import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -40,7 +41,7 @@
*/
public final class SignatureAlgorithms
{
private final Map<String, Algorithm> keyAlgToSignatureAlg = new HashMap<>();
private final Map<String, SignatureMethodAlgorithm> keyAlgToSignatureAlg = new HashMap<>();
private Algorithm canonicalizationAlgorithmForSignature = new CanonicalXMLWithoutComments();
private Algorithm canonicalizationAlgorithmForTimeStampProperties = new CanonicalXMLWithoutComments();
private String digestAlgorithmForDataObjectReferences = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256;
Expand All @@ -49,9 +50,9 @@ public final class SignatureAlgorithms

public SignatureAlgorithms()
{
keyAlgToSignatureAlg.put("DSA", new GenericAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_DSA));
keyAlgToSignatureAlg.put("RSA", new GenericAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256));
keyAlgToSignatureAlg.put("EC", new GenericAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256));
keyAlgToSignatureAlg.put("DSA", new SignatureMethodAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_DSA));
keyAlgToSignatureAlg.put("RSA", new SignatureMethodAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256));
keyAlgToSignatureAlg.put("EC", new SignatureMethodAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256));
}

/**
Expand All @@ -63,11 +64,27 @@ public SignatureAlgorithms()
*/
public SignatureAlgorithms withSignatureAlgorithm(String keyAlgorithmName, String signatureAlgorithm)
{
keyAlgToSignatureAlg.put(keyAlgorithmName, new GenericAlgorithm(signatureAlgorithm));
keyAlgToSignatureAlg.put(keyAlgorithmName, new SignatureMethodAlgorithm(signatureAlgorithm));
return this;
}

Algorithm getSignatureAlgorithm(String keyAlgorithmName) throws UnsupportedAlgorithmException
/**
* Set the signature algorithm and parameters to be used when the signing key has the given key algorithm.
*
* @param keyAlgorithmName the key's algorithm name as defined in JCA standard algorithm names
* @param signatureAlgorithm the signature algorithm
* @param parameters the signature algorithm parameters
* @return the current instance
*/
public SignatureAlgorithms withSignatureAlgorithm(String keyAlgorithmName,
String signatureAlgorithm,
AlgorithmParameterSpec parameters)
{
keyAlgToSignatureAlg.put(keyAlgorithmName, new SignatureMethodAlgorithm(signatureAlgorithm, parameters));
return this;
}

SignatureMethodAlgorithm getSignatureAlgorithm(String keyAlgorithmName) throws UnsupportedAlgorithmException
{
var algorithm = keyAlgToSignatureAlg.get(keyAlgorithmName);

Expand Down
45 changes: 45 additions & 0 deletions src/main/java/xades4j/production/SignatureMethodAlgorithm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* XAdES4j - A Java library for generation and verification of XAdES signatures.
* Copyright (C) 2024 Luis Goncalves.
*
* XAdES4j is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or any later version.
*
* XAdES4j is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with XAdES4j. If not, see <http://www.gnu.org/licenses/>.
*/

package xades4j.production;

import xades4j.algorithms.Algorithm;

import javax.annotation.Nullable;
import java.security.spec.AlgorithmParameterSpec;

final class SignatureMethodAlgorithm extends Algorithm
{
private final AlgorithmParameterSpec parameters;

SignatureMethodAlgorithm(String uri, @Nullable AlgorithmParameterSpec parameters)
{
super(uri);
this.parameters = parameters;
}

SignatureMethodAlgorithm(String uri)
{
this(uri, null);
}

@Nullable
AlgorithmParameterSpec getParameters()
{
return parameters;
}
}
42 changes: 20 additions & 22 deletions src/main/java/xades4j/production/SignerBES.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.ElementProxy;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
Expand Down Expand Up @@ -316,41 +315,40 @@ private String getDigestAlgUri()

private XMLSignature createSignature(Document signatureDocument, String baseUri, String signingKeyAlgorithm) throws XAdES4jXMLSigException, UnsupportedAlgorithmException
{
Algorithm signatureAlg = this.signatureAlgorithms.getSignatureAlgorithm(signingKeyAlgorithm);
Element signatureAlgElem = createElementForAlgorithm(signatureAlg, Constants._TAG_SIGNATUREMETHOD, signatureDocument);

SignatureMethodAlgorithm signatureAlg = this.signatureAlgorithms.getSignatureAlgorithm(signingKeyAlgorithm);
Algorithm canonAlg = this.signatureAlgorithms.getCanonicalizationAlgorithmForSignature();
if (null == canonAlg)
{
throw new NullPointerException("Canonicalization algorithm not provided");
}
Element canonAlgElem = createElementForAlgorithm(canonAlg, Constants._TAG_CANONICALIZATIONMETHOD, signatureDocument);

XMLSignature signature;
try
{
return new XMLSignature(signatureDocument, baseUri, signatureAlgElem, canonAlgElem);
signature = new XMLSignature(
signatureDocument,
baseUri,
signatureAlg.getUri(),
0,
canonAlg.getUri(),
null,
signatureAlg.getParameters());
}
catch (XMLSecurityException ex)
{
// Following the code, doesn't seem to be thrown at all.
throw new XAdES4jXMLSigException(ex.getMessage(), ex);
}
}

private Element createElementForAlgorithm(Algorithm algorithm, String elementName, Document signatureDocument) throws UnsupportedAlgorithmException
{
Element algorithmElem = XMLUtils.createElementInSignatureSpace(signatureDocument, elementName);
algorithmElem.setAttributeNS(null, Constants._ATT_ALGORITHM, algorithm.getUri());

List<Node> algorithmParams = this.algorithmsParametersMarshaller.marshalParameters(algorithm, signatureDocument);
if (algorithmParams != null)
List<Node> canonAlgParams = this.algorithmsParametersMarshaller.marshalParameters(canonAlg, signatureDocument);
if (canonAlgParams != null)
{
for (Node p : algorithmParams)
Element canonAlgElement = DOMHelper.getChildElementsByTagNameNS(
signature.getSignedInfo().getElement(),
Constants.SignatureSpecNS, Constants._TAG_CANONICALIZATIONMETHOD
).get(0);
for (Node p : canonAlgParams)
{
algorithmElem.appendChild(p);
canonAlgElement.appendChild(p);
}
}
return algorithmElem;

return signature;
}

private static void digestManifests(Iterable<Manifest> manifests) throws XAdES4jXMLSigException
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/xades4j/utils/DOMHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@
*/
package xades4j.utils;

import java.util.ArrayList;
import java.util.Collection;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.HelperNodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.util.ArrayList;
import java.util.List;

/**
* Utility methods for DOM nodes.
* @author Luís
Expand Down Expand Up @@ -163,10 +164,10 @@ public static Element getFirstDescendant(
* @param localName element name
* @return
*/
public static Collection<Element> getChildElementsByTagNameNS(Element e, String namespaceURI, String localName)
public static List<Element> getChildElementsByTagNameNS(Element e, String namespaceURI, String localName)
{
Node node = e.getFirstChild();
Collection<Element> elements = new ArrayList<>();
List<Element> elements = new ArrayList<>();

while (node != null)
{
Expand Down
6 changes: 5 additions & 1 deletion src/test/java/xades4j/production/OtherSignerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void testSignatureAlgorithms() throws Exception
XadesSigner signer = new XadesCSigningProfile(keyingProviderNist, vdp)
.withSignatureAlgorithms(new SignatureAlgorithms()
.withSignatureAlgorithm("RSA", ALGO_ID_SIGNATURE_RSA_SHA512)
.withCanonicalizationAlgorithmForTimeStampProperties(new ExclusiveCanonicalXMLWithoutComments())
.withCanonicalizationAlgorithmForTimeStampProperties(new ExclusiveCanonicalXMLWithoutComments("x", "y"))
.withDigestAlgorithmForReferenceProperties(ALGO_ID_DIGEST_SHA512))
.with(DEFAULT_TEST_TSA)
.newSigner();
Expand All @@ -157,6 +157,8 @@ void testSignatureAlgorithms() throws Exception

var tsC14n = (Attr) xpath.evaluate("//xades:UnsignedSignatureProperties/xades:SignatureTimeStamp/ds:CanonicalizationMethod/@Algorithm", doc, XPathConstants.NODE);
assertEquals(ALGO_ID_C14N_EXCL_OMIT_COMMENTS, tsC14n.getValue());
var tsC14nParam = (Attr) xpath.evaluate("//xades:UnsignedSignatureProperties/xades:SignatureTimeStamp/ds:CanonicalizationMethod/exc-c14n:InclusiveNamespaces/@PrefixList", doc, XPathConstants.NODE);
assertEquals("x y", tsC14nParam.getValue());

var certReferenceDigest = (Attr) xpath.evaluate("//xades:UnsignedSignatureProperties/xades:CompleteCertificateRefs/xades:CertRefs/xades:Cert/xades:CertDigest/ds:DigestMethod/@Algorithm", doc, XPathConstants.NODE);
assertEquals(ALGO_ID_DIGEST_SHA512, certReferenceDigest.getValue());
Expand All @@ -175,6 +177,8 @@ public String getNamespaceURI(String prefix)
return QualifyingProperty.XADES_XMLNS;
case "xades141":
return QualifyingProperty.XADESV141_XMLNS;
case "exc-c14n":
return "http://www.w3.org/2001/10/xml-exc-c14n#";
}
return null;
}
Expand Down
18 changes: 18 additions & 0 deletions src/test/java/xades4j/production/SignerBESTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package xades4j.production;

import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.resolver.implementations.ResolverDirectHTTP;
import org.apache.xml.security.utils.resolver.implementations.ResolverLocalFilesystem;
import org.junit.jupiter.api.Test;
Expand All @@ -36,6 +37,8 @@
import xades4j.properties.SigningCertificateProperty;

import java.io.File;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand Down Expand Up @@ -92,6 +95,21 @@ void testSignBESWithEllipticCurveKey() throws Exception
outputDocument(doc, "document.signed.bes.ec.xml");
}

@Test
void testSignBESWithRsaPss() throws Exception
{
Document doc = getTestDocument();
Element elemToSign = doc.getDocumentElement();

XadesSigner signer = new XadesBesSigningProfile(keyingProviderMy)
.withSignatureAlgorithms(new SignatureAlgorithms()
.withSignatureAlgorithm("RSA", XMLSignature.ALGO_ID_SIGNATURE_RSA_PSS, new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 64, 1)))
.newSigner();
new Enveloped(signer).sign(elemToSign);

outputDocument(doc, "document.signed.bes.rsa_pss.xml");
}

@Test
void testSignBESExternalRes() throws Exception
{
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/xades4j/verification/XadesVerifierImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,13 @@ void testVerifyBESCounterSigCounterSig() throws Exception
assertEquals(XAdESForm.BES, result.getSignatureForm());
}

@Test
void testVerifyBesSigAlgParams() throws Exception
{
var result = verifySignature("document.signed.bes.rsa_pss.xml");
assertEquals(XAdESForm.BES, result.getSignatureForm());
}

@Test
void testVerifyBESEnrichT() throws Exception
{
Expand Down
77 changes: 77 additions & 0 deletions src/test/xml/document.signed.bes.rsa_pss.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?><collection Id="root">
<album>
<title>Questions, unanswered</title>
<artist>Steve and the flubberblubs</artist>
<year>1989</year>
<t:tracks xmlns:t="http://test.xades4j/tracks">
<t:song length="4:05" tracknumber="1">
<t:title>What do you know?</t:title>
<t:artist>Steve and the flubberblubs</t:artist>
<t:lastplayed>2006-10-17-08:31</t:lastplayed>
</t:song>
<t:song length="3:45" tracknumber="2">
<t:title>Who do you know?</t:title>
<t:artist>Steve and the flubberblubs</t:artist>
<t:lastplayed>2006-10-17-08:35</t:lastplayed>
</t:song>
<t:song length="5:14" tracknumber="3">
<t:title>When do you know?</t:title>
<t:artist>Steve and the flubberblubs</t:artist>
<t:lastplayed>2006-10-17-08:39</t:lastplayed>
</t:song>
<t:song length="4:19" tracknumber="4">
<t:title>Do you know?</t:title>
<t:artist>Steve and the flubberblubs</t:artist>
<t:lastplayed>2006-10-17-08:44</t:lastplayed>
</t:song>
</t:tracks>
</album>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="signature-51bb5edf-039c-4c35-ab4b-4304e73a93ee">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#rsa-pss">
<pss:RSAPSSParams xmlns:pss="http://www.w3.org/2007/05/xmldsig-more#">
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<pss:SaltLength>64</pss:SaltLength>
<pss:TrailerField>1</pss:TrailerField>
</pss:RSAPSSParams>
</ds:SignatureMethod>
<ds:Reference URI="#root">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>rD/g8soqKz8EiPUBhEWfcQacS0ta4ULHX3dKMEH6ZoQ=</ds:DigestValue>
</ds:Reference>
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#signedproperties-211e1eb4-e409-4169-a083-06e2201a6e3f">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>GddpcMqEMdYowP4GlEdTiqQcp9Mym1Mz3o9CFSyCet8=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
UKoTfgDL22+mv7q9NmrtFyP55WBj8WNWTM+CXDrPk9aDxps5xS/wHv1X9k1bZK9O2nw4UAqBz42f&#13;
3h3o1or/JrDdI3w5gsY3+rFdzmUq2z0CC5I1yGkCsl9wepxJjFC9R+ODTd1rxzO0rFS+cCM8sOgr&#13;
7olgkXW4K+fViZ0KarY=
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU&#13;
MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw&#13;
NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL&#13;
MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN&#13;
ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm&#13;
AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF&#13;
Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA&#13;
/56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD&#13;
EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG&#13;
yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR&#13;
Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
<ds:Object><xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Target="#signature-51bb5edf-039c-4c35-ab4b-4304e73a93ee"><xades:SignedProperties Id="signedproperties-211e1eb4-e409-4169-a083-06e2201a6e3f"><xades:SignedSignatureProperties><xades:SigningTime>2024-10-18T23:17:54.123+01:00</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>4btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>cn=Itermediate,ou=CC,o=ISEL,c=PT</ds:X509IssuerName><ds:X509SerialNumber>-119284162484605703133798696662099777223</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>cn=TestCA,ou=CC,o=ISEL,c=PT</ds:X509IssuerName><ds:X509SerialNumber>-46248926895392336918291885380930606289</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>cn=TestCA,ou=CC,o=ISEL,c=PT</ds:X509IssuerName><ds:X509SerialNumber>-99704378678639105802976522062798066869</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object>
</ds:Signature></collection>
Loading

0 comments on commit 5b00fb0

Please sign in to comment.