How to add digital signature to SOAP request which has an attachment in java

218 Views Asked by At

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.

0

There are 0 best solutions below