I need to add a digital signature to the SOAP request which has an attachment. I have tried several methods using xmlsec-3.0.2.jar and javax.xml.crypto library. But none of them worked as expected.
Below is the SOAP request with the attachment which needs to be digitally signed.
------=_Part_2_687190320.1680851267564
Content-Type: text/xml; charset="UTF-8"
Content-Id: <soappart>
Content-Transfer-Encoding: binary
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://www.w3.org/2001/XMLSchema-instance" ns0:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ file:packages/WmebXML/config/init/schemas/msg_1_0/envelope.xsd http://www.ebxml.org/namespaces/messageHeader file:packages/WmebXML/config/init/schemas/msg_1_0/messageHeaderv0_99.xsd">
<SOAP-ENV:Header>
<eb:MessageHeader eb:version="1.0" soapenv:mustUnderstand="1">
<eb:From>
<eb:PartyId eb:type="urn:xxxxx.net">xxxxxxxx</eb:PartyId>
</eb:From>
<eb:To>
<eb:PartyId eb:type="urn:frchub.net">xxxxxxxxx</eb:PartyId>
</eb:To>
</eb:MessageHeader>
<eb:TraceHeaderList SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next" eb:version="1.0" soapenv:mustUnderstand="1">
</eb:TraceHeaderList>
<eb:Via SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next" SOAP-ENV:mustUnderstand="1" eb:ackRequested="Signed" eb:version="1.0"/>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<eb:Manifest eb:version="1.0">
<eb:Reference eb:id="YYY" xlink:href="cid:attachmentID" xlink:type="simple">
<eb:Schema eb:location="urn:xxxx.xsd" eb:version="xx"/>
</eb:Reference>
</eb:Manifest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
------=_Part_2_687190320.1680851267564
Content-Type: text/xml
Content-ID: <attachmentID>
Content-Transfer-Encoding: binary
<?xml version="1.0" encoding="utf-8"?>
<aaa:aBC xsi:schemaLocation="urn:xxxxxxx.xsd" xmlns:aBC="urn:xxx:r40" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header>
<From>XXXX</From>
<To>XXXX</To>
</Header>
<Transactions>
.....
</Transactions>
</aaa:aBC>
------=_Part_2_687190320.1680851267564--
Signature should be like below.
<ds:Signature Id="XXXXXXX"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<ds:XPath>not(ancestor-or-self::eb:TraceHeaderList or ancestor-or-self::eb:Via)</ds:XPath>
</ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>ssssssssssssss</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="cid:attachmentID">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>yyyyyyyyyyyyyyyyyyyyy</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>dfdgrtr</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>ghrtjjyty</ds:Modulus>
<ds:Exponent>Aaaa</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
<ds:X509Data>
<ds:X509SubjectName>cn=dgrgree,o=hhnn,l=Melbourne,st=Victoria,c=AU</ds:X509SubjectName>
<ds:X509Certificate>fdghfhtyrrrrt</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</SOAP-ENV:Header>
Below is my code.
public void addSignature(Resource keyStoreFile, String keyStorePassword, String keyStoreAlias, SOAPMessage soapMessage) throws Exception {
//create basic structure of signature
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
File attachedFile = new File("file path to attachment");
Element element = null;
Document doc = dBuilder.parse(new InputSource(new StringReader(printSOAPResponse(soapMessage))));
Init.init();
org.apache.xml.security.signature.XMLSignature sig =
new org.apache.xml.security.signature.XMLSignature(doc, null, SignatureMethod.RSA_SHA1);
element = doc.getDocumentElement();
element.normalize();
element.getElementsByTagName("SOAP-ENV:Header").item(0).appendChild(sig.getElement());
Transforms transforms = new Transforms(doc);
transforms.addTransform(CanonicalizationMethod.ENVELOPED);
String xpathExpr = "not(ancestor-or-self::eb:TraceHeaderList or ancestor-or-self::eb:Via)";
XPathContainer xpathContainer = new XPathContainer(doc);
xpathContainer.setXPath(xpathExpr);
// Add the XPath transform to the Transforms object
transforms.addTransform(Transforms.TRANSFORM_XPATH, xpathContainer.getElement());
transforms.addTransform(CanonicalizationMethod.INCLUSIVE);
ResolverLocalFilesystem fileResolver = new ResolverLocalFilesystem();
ResourceResolver.register(fileResolver, false);
//Sign the content of SOAP Envelope
sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
//Adding the attachment to be signed
sig.addDocument(attachedFile.toURI().toURL().toString(), null, Constants.ALGO_ID_DIGEST_SHA1);
// Load the KeyStore and get the signing key and certificate.
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(keyStoreFile.getInputStream(), keyStorePassword.toCharArray());
KeyStore.PrivateKeyEntry keyEntry =
(KeyStore.PrivateKeyEntry) keyStore.getEntry(keyStoreAlias, new KeyStore.PasswordProtection(keyStorePassword.toCharArray()));
X509Certificate x509Certificate = (X509Certificate) keyEntry.getCertificate();
sig.setId("WmEbXML-Signature-54cl6h00gi08isbf003ient2");
sig.addKeyInfo(x509Certificate.getPublicKey());
sig.addKeyInfo(x509Certificate);
sig.sign(keyEntry.getPrivateKey());
DOMImplementationLS domImplementationLS = (DOMImplementationLS) doc.getImplementation();
LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
LSOutput lsOutput = domImplementationLS.createLSOutput();
lsOutput.setEncoding("UTF-8");
Writer stringWriter = new StringWriter();
lsOutput.setCharacterStream(stringWriter);
lsSerializer.write(doc, lsOutput);
String content = stringWriter.toString();}
Using xmlsec-3.0.2.jar, add the digital signature, but the <ds:X509SubjectName> tag is not in there and the value of URI attribute in Reference tag is “Path to the attachment file" instead of “cid:attachmentID”.
Please suggest a solution to solve this.