Emilio De Castro Ruiz
Emilio De Castro Ruiz

Reputation: 21

Manually sign SOAP message Java

I have to sign a Soap message using java, but I can't use WSS4J, SAAJ, AXIS2 or CXF for classpath problems on my websphere server.

I have to sign the body message of the SOAP call.

I generate a XML with body inside body data correctly for the soap message and look like this:

<SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST>

Formated for best view:

<SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN">
<ns2:SERVICIO_CONSIGNACION_NOTARIAL>
    <ns2:REQUEST>
        <ns2:CABECERA>
            <ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION>
            <ns2:FECHA>2016-03-22</ns2:FECHA>
            <ns2:HORA>10:55:00</ns2:HORA>
            <ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION>
        </ns2:CABECERA>
        <ns2:MENSAJE>
            <ns2:TRANSFERENCIA>
                <ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO>
                <ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA>
                <ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION>
                <ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR>
                <ns2:NOTARIO>
                    <ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES>
                    <ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION>
                    <ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION>
                </ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE>
                <ns2:MONEDA>EUR</ns2:MONEDA>
                <ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE>
                <ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO>
            </ns2:TRANSFERENCIA>
            <ns2:TRANSFERENCIA>
                <ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO>
                <ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA>
                <ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION>
                <ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR>
                <ns2:NOTARIO>
                    <ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES>
                    <ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION>
                    <ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION>
                </ns2:NOTARIO>
                <ns2:IMPORTE>2.00</ns2:IMPORTE>
                <ns2:MONEDA>EUR</ns2:MONEDA>
                <ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE>
                <ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO>
            </ns2:TRANSFERENCIA>
        </ns2:MENSAJE>
    </ns2:REQUEST>
</ns2:SERVICIO_CONSIGNACION_NOTARIAL>

Then I do the Hash value to create the digest value using the previous XML with body start and end tag:

        // Change value if there is any problem on websphere
        // wsuId = "\"#MsgBody\"";
        wsuId = "\"#id-" + UUIDGenerator.getUUID() + "\"";
        // Create XML data for body SOAP
        String dataXMLSoap = generateBodySoap(doc);
        String startBodyHash = "<soapenv:Body xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" wsu:Id=" + wsuId+ ">";
        String endBodyHash  = "</soapenv:Body>";
        MessageDigest messageDigestFromBody= MessageDigest.getInstance("SHA-1");            
        String xmlHash = startBodyHash + dataXMLSoap + endBodyHash;
        byte[] hashSoapBody = messageDigestFromBody.digest(xmlHash.getBytes());
        String digestValueFromBody = new BASE64Encoder().encode(hashSoapBody);

Example of XML hash:

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" wsu:Id="#id-D1DD0227ECDC46640D147197713960845"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soapenv:Body>

With teh digest value generated I create a SignedInfo node:

String xmlDigestFromBody =
            "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" 
            + "<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"></ds:CanonicalizationMethod>" 
            + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></ds:SignatureMethod>" 
            + "<ds:Reference URI=" + wsuId + ">" 
            + "<ds:Transforms>" 
            + "<ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">" 
            + "</ds:Transform>" 
            + "</ds:Transforms>"
            + "<ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\">" 
            + "</ds:DigestMethod>"
            + "<ds:DigestValue>" 
            + digestValueFromBody 
            + "</ds:DigestValue>" 
            + "</ds:Reference>" 
            + "</ds:SignedInfo>";

The xml for signature looks like this:

<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod><ds:Reference URI="#id-D1DD0227ECDC46640D147197713960845"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod><ds:DigestValue>Dd7cqOPVujwavDwKWwWqI8NHfYw=</ds:DigestValue></ds:Reference></ds:SignedInfo>

With this XML and my X509 Certificate info I use this method to get the sign value:

byte[] signDigest = sign(privateKey, xmlDigestFromBody, algorithm);
String signValueDigest = new BASE64Encoder().encode(signDigest);

// privateKey-> private key from X509 Certificate
// data -> Data to get signed
// algorith -> algorith for sign, in this case with value -> SHA1withRSA
private static byte[] sign(PrivateKey privateKey, String data, String algorithm) throws GeneralSecurityException
{
    Signature signature = Signature.getInstance(algorithm);
    signature.initSign(privateKey);
    signature.update(data.getBytes());
    return signature.sign();
}

With all information generated I form the complete Soap message.

String signedSoap = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" 
            + "<soap:Header>"
            + "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" soap:mustUnderstand=\"1\">"
            + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">" 
            + xmlDigestCXFSoap 
            + "<ds:SignatureValue>" 
            + signValueDigest 
            + "</ds:SignatureValue>" 
            + "<ds:KeyInfo>" + "<wsse:SecurityTokenReference>"
            + "<wsse:KeyIdentifier EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" 
            + wsseKeyIdentifier
            + "</wsse:KeyIdentifier>" 
            + "</wsse:SecurityTokenReference>" 
            + "</ds:KeyInfo>" 
            + "</ds:Signature>" 
            + "</wsse:Security>" 
            + serviceDispatcher 
            + "</soap:Header>" 
            + "<soap:Body xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=" + wsuId+ ">"
            + dataXMLSoap 
            + "</soap:Body>"
            + "</soap:Envelope>";

Finally I get this Soap message:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#id-D1DD0227ECDC46640D147197713960845"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>Dd7cqOPVujwavDwKWwWqI8NHfYw=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>U4I0IFFDfpy32vTfpjLQkV10tGOG4XloOaPJPjymFIaV5tzxqd3bAiigghWgELA5WByZ/IqvCL08//BAq+G+ybYn0dwOS+JYZP5ftDow3ZCf5pQNp2DtSnLbLPjswAzcUvR1MfZHbkIhPWOd5fDIs+hPuRs0cq1owfrmXrik0uB48tq6X8bkrl68QMYOXtvi/MGmAIpyjUvXm91ex7YiHpvZG7Jfqn67sL1ca3mWt+14lHeidWZU7qVGCmL0OskIv4uzJO90BthUSlC2B2v+QBRfnL5mTZ+msSK6yI9jRhFazFNe/NG+obRLhns+1Fz/ETtcbdBs4WrLs78tZmcDnA==</ds:SignatureValue><ds:KeyInfo><wsse:SecurityTokenReference><wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">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</wsse:KeyIdentifier></wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature></wsse:Security><SERVICE_DISPATCHER xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><TIMESTAMP>2016-08-23T20:32:15.294+02:00</TIMESTAMP><TIPO_MSJ>1</TIPO_MSJ><EMISOR>TEST</EMISOR><RECEP>CGN</RECEP><SERVICIO>CN0001</SERVICIO></SERVICE_DISPATCHER></soap:Header><soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="#id-D1DD0227ECDC46640D147197713960845"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soap:Body></soap:Envelope>

When I use this soap message using SoapUI over my endpoint (https://test...) Always received this response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
  <soapenv:Fault>
     <faultcode>soapenv:Server.generalException</faultcode>
     <faultstring>WSDoAllReceiver: security processing failed; nested exception is: 
org.apache.ws.security.WSSecurityException: The signature verification failed</faultstring>
     <detail>
        <ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">hermes4</ns1:hostname>
     </detail>
  </soapenv:Fault>

I have a OK Soap message that I use to generate my Soap message on java a I don't find the structure difference over the XML that I generated. Correctly signed Soap:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#id-4A1E576857255EBB5114717876404904"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>K2IpilH1NxMSOTeA4yRZukLC2vk=</ds:DigestValue></ds:Reference></ds:SignedInfo>
<ds:SignatureValue>Yua1G4f8OV3M2xJDZZb3b6zr+9Bx4aufbIkzynYiZeHZhzPHwm4vumN7bmdcU0TC9mF7qpC7CkrcbvlIbnG0Wz/PPcJ7iQ0KLyMMqWhc2u56oMwZjJK4FPX6Pc8wFzSoPACP9c9bC0DDX0ZVBMxXkP2/yWVGIxHSL0oqTHK6vfGBRRYGw7mvzqGXtdKxnENE6akYJU8Xqf/QbP1Oh9sJwRBtbhrJfMWomyDn4FoftNQl2pwMf5PCNmsR7Ecc7iIzFpP141MGgYIecZzA0mxOeF4jqJg3Co/VM4etAFpIFT4GMDDj4JD8nKKfVdZ8+9qOCiZsP2MbSon9tPny2xxPDg==</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">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</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
<SERVICE_DISPATCHER xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN">
<TIMESTAMP>2017-08-21T15:53:58.308+02:00</TIMESTAMP>
<TIPO_MSJ>1</TIPO_MSJ>
<EMISOR>TEST</EMISOR>
<RECEP>CGN</RECEP>
<SERVICIO>CN0001</SERVICIO>
</SERVICE_DISPATCHER>
</soap:Header>
<soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-4A1E576857255EBB5114717876404904"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soap:Body>
</soap:Envelope>

Please can anybody help me telling me what Im doing wrong. Thanks everyone for your time reading my ask :)

A cordial greeting.

Upvotes: 1

Views: 11177

Answers (4)

Pratik Gaurav
Pratik Gaurav

Reputation: 907

I'm enhancing https://stackoverflow.com/a/63617195/5845739 Yash's Answer. Thank You for the excellent answer.

Also, I'm directly calling the SOAP Message, instead of using the File Call in the

callTheWebServiceFromFile()

Maven Dependencies

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>

        <dependency>
            <groupId>xalan</groupId>
            <artifactId>xalan</artifactId>
            <version>2.7.1</version>
        </dependency>
        <dependency>
            <groupId>xml-security</groupId>
            <artifactId>xmlsec</artifactId>
            <version>1.3.0</version>
        </dependency>

Java Complete Code


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Scanner;

import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.springframework.http.HttpHeaders;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
public class SOAP_Security_Signature {
    static final String 
    WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
    WSU_NS  = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
    DSIG_NS = "http://www.w3.org/2000/09/xmldsig#", // javax.xml.crypto.dsig.XMLSignature.XMLNS, Constants.SignatureSpecNS
    
    binarySecurityToken_Encoding = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary",
    binarySecurityToken_Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
    
    signatureMethodAlog_SHA1 = DSIG_NS + "rsa-sha1", // XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1
    digestMethodAlog_SHA1  = Constants.ALGO_ID_DIGEST_SHA1, // DSIG_NS + "sha1", // Constants.ALGO_ID_DIGEST_SHA1
    transformAlog = Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, //"http://www.w3.org/2001/10/xml-exc-c14n#";
    canonicalizerAlog = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; //"http://www.w3.org/2001/10/xml-exc-c14n#"; CanonicalizationMethod.EXCLUSIVE
    
    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }
    public static X509Certificate loadPublicKeyX509(InputStream cerFileStream) throws CertificateException, NoSuchProviderException {
        CertificateFactory  certificateFactory = CertificateFactory.getInstance("X.509", "BC");
        X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(cerFileStream);
        return x509Certificate;
    }
    public static PrivateKey loadPrivateKeyforSigning(InputStream cerFileStream, String password) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, NoSuchProviderException {
        KeyStore keyStore = KeyStore.getInstance("PKCS12"); //, "BC");
        keyStore.load(cerFileStream, password.toCharArray());
        
        Enumeration<String> keyStoreAliasEnum = keyStore.aliases();
        PrivateKey privateKey = null;
        String alias = null;
        if ( keyStoreAliasEnum.hasMoreElements() ) {
            alias = keyStoreAliasEnum.nextElement();
            if (password != null) {
                privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
            }
        }
        return privateKey;
    }
    static X509Certificate loadPublicKeyX509;
    static PrivateKey privateKey;
    static String  privateKeyFilePath = "pfxFileLocation/Ibtsam.pfx", publicKeyFilePath = "crtFileLocation/Ibtsam.crt",
                  inputFile= "sourceFileLocation/x.xml", outputFile = "destinationFileLocation/output.xml";
    public static void main(String[] args) throws Exception {
        
        InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
        privateKey = loadPrivateKeyforSigning(pkcs_FileStream, "password");//Password of PFX file
        System.out.println("privateKey : "+privateKey);
        
        InputStream cerFileStream = new FileInputStream(publicKeyFilePath);
        loadPublicKeyX509 = loadPublicKeyX509(cerFileStream);
        PublicKey publicKey = loadPublicKeyX509.getPublicKey();
        System.out.println("loadPublicKey : "+ publicKey);
        
        System.setProperty("javax.xml.soap.MessageFactory", "com.sun.xml.internal.messaging.saaj.soap.ver1_2.SOAPMessageFactory1_2Impl");
        System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.internal.bind.v2.ContextFactory");
        
        SOAPMessage soapMsg = WS_Security_signature(inputFile, false);
        outputSOAPMessageToFile(soapMsg);
        /*ByteArrayOutputStream out = new ByteArrayOutputStream();
        soapMsg.writeTo(out);
        String strMsg = new String(out.toByteArray());
        System.out.println("+++++++++++++++++++++++++++++++++++");
        System.out.println(strMsg);
        System.out.println("+++++++++++++++++++++++++++++++++++");*/
        new SOAP_Security_Signature().callTheWebServiceFromFile(soapMsg);
        //System.out.println("Signature Succesfull. Verify the Signature");
       // boolean soapXmlWSSEDigitalSignatureValid = isSOAPXmlWSSEDigitalSignatureValid(outputFile, publicKey);
       // System.out.println("isSOAPXmlDigitalSignatureValid :"+soapXmlWSSEDigitalSignatureValid);
    }
  
    
    public static void outputSOAPMessageToFile(SOAPMessage soapMessage) throws SOAPException, IOException {
        File outputFileNew = new File(outputFile);
        java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFileNew);
        soapMessage.writeTo(fos);
        fos.close();
    }
    
    public static String toStringDocument(Document doc) throws TransformerException {
        StringWriter sw = new StringWriter();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

        transformer.transform(new DOMSource(doc), new StreamResult(sw));
        return sw.toString();
    }
    public static String getFileString(String xmlFilePath) throws FileNotFoundException {
        File file = new File(xmlFilePath);
        //FileInputStream parseXMLStream = new FileInputStream(file.getAbsolutePath());
        
        Scanner scanner = new Scanner( file, "UTF-8" );
        String xmlContent = scanner.useDelimiter("\\A").next();
        scanner.close(); // Put this call in a finally block
        System.out.println("Str:"+xmlContent);
        return xmlContent;
    }
    public static Document getDocument(String xmlData, boolean isXMLData) throws Exception {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setNamespaceAware(true);
        dbFactory.setIgnoringComments(true);
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc;
        if (isXMLData) {
            InputSource ips = new org.xml.sax.InputSource(new StringReader(xmlData));
            doc = dBuilder.parse(ips);
        } else {
            doc = dBuilder.parse( new File(xmlData) );
        }
        return doc;
    }
 
    private void callTheWebServiceFromFile(SOAPMessage msg) throws IOException, SOAPException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
        msg.writeTo(out);
        
        // Set the soapPart Content with the stream source
        //soapPart.setContent(ss);
        SOAPPart soapPart = msg.getSOAPPart();
        
        // Create a webService connection
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();

        // Invoke the webService.
        String soapEndpointUrl = "https://mirsal2gwytest.dubaitrade.ae/customsb2g/oilfields";
        SOAPMessage resp = soapConnection.call(msg, soapEndpointUrl);

        // Reading result
        resp.writeTo(System.out);

        //fis.close();
        soapConnection.close();
    }

    
    public static SOAPMessage WS_Security_signature(String inputFile, boolean isDataXML) throws Exception {
        SOAPMessage soapMsg;
        Document docBody;
        if (isDataXML) {
            System.out.println("Sample DATA xml - Create SOAP Message");
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage soapMessage = messageFactory.createMessage();
            soapMsg = soapMessage;
            
            String xmlContent = getFileString(inputFile);
            docBody = getDocument(xmlContent.trim(), true);
            System.out.println("Data Document: "+docBody.getDocumentElement());
        } else {
            System.out.println("SOAP XML with Envelope");
            
            Document doc = getDocument(inputFile, false); // SOAP MSG removing comment elements
            String docStr = toStringDocument(doc); // https://stackoverflow.com/a/2567443/5081877
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(docStr.getBytes());
            
            MimeHeaders mimeHeaders = new MimeHeaders();
            mimeHeaders.removeHeader("Content-Type");
            mimeHeaders.addHeader(HttpHeaders.CONTENT_TYPE, "text/xml;charset=utf-8");
            mimeHeaders.addHeader("SOAPAction", "process");
            SOAPMessage message = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createMessage(mimeHeaders, byteArrayInputStream);
            soapMsg = message;
            
            docBody = soapMsg.getSOAPBody().extractContentAsDocument();
            System.out.println("SOAP DATA Document: "+docBody.getDocumentElement());
        }
        // A new SOAPMessage object contains: •SOAPPart object •SOAPEnvelope object •SOAPBody object •SOAPHeader object 
        SOAPPart soapPart = soapMsg.getSOAPPart();
        soapPart.setMimeHeader("Content-Type", "text/xml;charset=UTF-8");
        SOAPEnvelope soapEnv = soapPart.getEnvelope();
        SOAPHeader soapHeader = soapEnv.getHeader(); // soapMessage.getSOAPHeader();
        SOAPBody soapBody = soapEnv.getBody(); // soapMessage.getSOAPBody()
        
        soapBody.addDocument(docBody);
        soapBody.addAttribute(soapEnv.createName("Id", "wsu", WSU_NS), "Body");
        
        if (soapHeader == null) {
            soapHeader = soapEnv.addHeader();
            System.out.println("Provided SOAP XML does not contains any Header part. So creating it.");
        }
        // <wsse:Security> element adding to Header Part
        SOAPElement securityElement = soapHeader.addChildElement("Security", "wsse", WSSE_NS);
        securityElement.addNamespaceDeclaration("wsu", WSU_NS);

        String certEncodedID = "X509Token", timeStampID = "TS", signedBodyID = "Body";
        // (ii) Add Binary Security Token.
        // <wsse:BinarySecurityToken EncodingType="...#Base64Binary" ValueType="...#X509v3" wsu:Id="X509Token">The base64 encoded value of the ROS digital certificate.</wsse:BinarySecurityToken>
        SOAPElement binarySecurityToken = securityElement.addChildElement("BinarySecurityToken", "wsse");
        binarySecurityToken.setAttribute("ValueType", binarySecurityToken_Value);
        binarySecurityToken.setAttribute("EncodingType", binarySecurityToken_Encoding);
        binarySecurityToken.setAttribute("wsu:Id", certEncodedID);
            byte[] certByte = loadPublicKeyX509.getEncoded();
            String encodeToString = Base64.getEncoder().encodeToString(certByte);
        binarySecurityToken.addTextNode(encodeToString);
        
        //(iii) Add TimeStamp element - <wsu:Timestamp wsu:Id="TS">
        SOAPElement timestamp = securityElement.addChildElement("Timestamp", "wsu");
        timestamp.addAttribute(soapEnv.createName("Id", "wsu", WSU_NS), timeStampID);
            String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSX";
            DateTimeFormatter timeStampFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        timestamp.addChildElement("Created", "wsu").setValue(timeStampFormatter.format(ZonedDateTime.now().toInstant().atZone(ZoneId.of("UTC"))));
        timestamp.addChildElement("Expires", "wsu").setValue(timeStampFormatter.format(ZonedDateTime.now().plusSeconds(30).toInstant().atZone(ZoneId.of("UTC"))));

        // (iv) Add signature element
        // <wsse:Security> <ds:Signature> <ds:KeyInfo> <wsse:SecurityTokenReference>
        SOAPElement securityTokenReference = securityElement.addChildElement("SecurityTokenReference", "wsse");
        SOAPElement reference = securityTokenReference.addChildElement("Reference", "wsse");
        reference.setAttribute("URI", "#"+certEncodedID); // <wsse:BinarySecurityToken wsu:Id="X509Token"
        
        // <ds:SignedInfo>
        String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
        XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", (java.security.Provider) Class.forName(providerName).newInstance());

        //Digest method - <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
        javax.xml.crypto.dsig.DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(digestMethodAlog_SHA1, null);
        
        ArrayList<Transform> transformList = new ArrayList<Transform>();
        //Transform - <ds:Reference URI="#Body">
        Transform envTransform = xmlSignatureFactory.newTransform(transformAlog, (TransformParameterSpec) null);
        transformList.add(envTransform);
            //References <ds:Reference URI="#Body">
            ArrayList<Reference> refList = new ArrayList<Reference>();
                Reference refTS   = xmlSignatureFactory.newReference("#"+timeStampID,  digestMethod, transformList, null, null);
                Reference refBody = xmlSignatureFactory.newReference("#"+signedBodyID, digestMethod, transformList, null, null);
            refList.add(refBody);
            refList.add(refTS);

        javax.xml.crypto.dsig.CanonicalizationMethod cm = xmlSignatureFactory.newCanonicalizationMethod(canonicalizerAlog, (C14NMethodParameterSpec) null);

        javax.xml.crypto.dsig.SignatureMethod sm = xmlSignatureFactory.newSignatureMethod(signatureMethodAlog_SHA1, null);
        SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(cm, sm, refList);

        DOMSignContext signContext = new DOMSignContext(privateKey, securityElement);
        signContext.setDefaultNamespacePrefix("ds");
        signContext.putNamespacePrefix(DSIG_NS, "ds");
        signContext.putNamespacePrefix(WSU_NS, "wsu");

        signContext.setIdAttributeNS(soapBody, WSU_NS, "Id");
        signContext.setIdAttributeNS(timestamp, WSU_NS, "Id");

        KeyInfoFactory keyFactory = KeyInfoFactory.getInstance();
        DOMStructure domKeyInfo = new DOMStructure(securityTokenReference);
        javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo));
        javax.xml.crypto.dsig.XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
        signContext.setBaseURI("");

        signature.sign(signContext);
        return soapMsg;
    }
    
}

Upvotes: 0

Yash
Yash

Reputation: 9568

SOAP Enveloped signature: Signing XML Document with the qualified certificate.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<!-- <env:Header /> -->
    <env:Body>
       <product version="11.1.2.4.0"> <!-- Data XML -->
           <name>API Gateway</name>
           <company>Oracle</company>
           <description>SOA Security and Management</description>
       </product>
    </env:Body>
</env:Envelope>

By using the following function you can digitally Sign the XML using Certificate And Private Key Baeldung.cer, Baeldung.p12 (password = “password”)

public static Document getDigitalSignDoc(String sourceFile) throws Exception {

    Document doc = SOAP_Security_Signature.getDocument(sourceFile, false);
    String signatureID = "123", keyInfoID = "456", referenceID = "Id-0000011a101b167c-0000000000000012";
    //optional, but better
    Element signElementEnvelope = doc.getDocumentElement();
    //signElement.normalize();
    
    String nameSpace = "env"; //soap
    Node itemBody = signElementEnvelope.getElementsByTagName(nameSpace+":Body").item(0);
    Node itemHead = signElementEnvelope.getElementsByTagName(nameSpace+":Header").item(0);
    if (itemHead == null) {
        System.out.println("Provided SOAP XML does not contains any Header part. So creating it.");
        Element createElement = doc.createElement(nameSpace+":Header");
        signElementEnvelope.insertBefore(createElement, itemBody);
        
        itemHead = signElementEnvelope.getElementsByTagName(nameSpace+":Header").item(0);
    }
    ((Element)itemBody).setAttribute("Id", referenceID);
    
    
    String elementRefId = "#" + referenceID;
    
    Node firstChild = itemBody.getFirstChild();
    Document dataDoc = firstChild.getOwnerDocument(); // Total Entire XML
    System.out.println("Document: "+dataDoc.getDocumentElement());
    
    org.apache.xml.security.Init.init();
    org.apache.xml.security.signature.XMLSignature signature = new XMLSignature(dataDoc, elementRefId, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
    //XMLSignature signature = new XMLSignature(dataDoc, elementRefId, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
    itemHead.appendChild(signature.getElement());
    
    // Below code adds Sign element after Body tag: </soap:Body><ds:Signature> ... </ds:Signature></soap:Envelope>
    //signElement.appendChild(signature.getElement());
    
    Transforms transforms = new Transforms(signElementEnvelope.getOwnerDocument()); // doc | signElement.getOwnerDocument()
    // <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
    transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); // TRANSFORM_C14N_OMIT_COMMENTS
    //transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
    
    //Sign the content of SOAP Envelope
    signature.addDocument(elementRefId, transforms, Constants.ALGO_ID_DIGEST_SHA1);

    //Signing procedure
    signature.setId(signatureID);
    signature.addKeyInfo(loadPublicKeyX509);
    signature.addKeyInfo(loadPublicKeyX509.getPublicKey());
    
    KeyInfo keyInfo = signature.getKeyInfo();
    keyInfo.setId(keyInfoID);
    
    System.out.println("Start signing");
    signature.sign(privateKey);
    
    System.out.println("Finished signing : "+signature.getId());
    return doc;
}

Generated SOAP Signed XML file:

<env:Envelope
    xmlns:env="http://www.w3.org/2003/05/soap-envelope">
    <env:Header>
        <ds:Signature
            xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="123">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
                <ds:Reference URI="#Id-0000011a101b167c-0000000000000012">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                    <ds:DigestValue>Fk4qf2xFlZoM2jo9NA+6GkCwKfU=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>
VecBSDUFpBBcjLS1AK41NDwUvFl9mHktx2TqqcBtGQpNxMiJv/eRvApeKiHLp8iyVKqbcog4akxp
N6qBGEwOgThYlWdgVSPDct8l42+4XHLxUee5YcUVeW71r4mIuvoT0o9aLtNcjE7xzDeke3rzbOyz
7UORAqyuEe1rVk7QHNEZrW1nZRI9JadAuSboa1ZLI8BK0JqUZD/0UhswLXUtftYAA+2qeWQGRMAk
1RZsC4sfXqmp2oni/wihR+8HkEaiUfpTMq2Gcpnf3a59v67h4fxDtnYlAdN8LX53YHgB+0ONcIxO
vHt88hCLwKiaIeM4Wz7qzMMSmq9/dGBlqFU8Dw==
</ds:SignatureValue>
            <ds:KeyInfo Id="456">
                <ds:X509Data>
                    <ds:X509Certificate>
MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNVBAYTAk1BMRAw
DgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzAe
Fw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRaMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdN
b3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5
tGMhjozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oMAYm24xpL
j1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6IujrCZ2TtXGM0g/gP++28KT7
g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSjfs8cuhqVwRQaZpCOoHU/P8wpXKw80sSd
hz+SRueMPtVYqK0CiLL5/O0h0Y3le4IVwhgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMt
MCswCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEB
BQUAA4IBAQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1vpsw
b5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAPpHIqZsqo8lfcyAuh
8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhUCGPyIJXmvATMVvXMWCtfogAL+n42
vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJtXJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1P
D7OxoGiY7V544zeGqJam1qxUia7y5BL6uOa/4ShSV8pcJDYz
</ds:X509Certificate>
                </ds:X509Data>
                <ds:KeyValue>
                    <ds:RSAKeyValue>
                        <ds:Modulus>
zKLkaY543hBof8I/mBI7IdfzOdvlMMdZXzBz5lPuQ1TzO3m0YyGOjMrqFrHXnn/q06wENHStJgGE
v4Ob/64JVLuo6VEeF/pw0a3MYXWCc0kHZaMjygwBibbjGkuPVamEpTAqufedMw+dC6nk6g0AxiX3
1+UA2tFhWOPGstC8NkNSKjoi6OsJnZO1cYzSD+A/77bwpPuDUqVS6LfG0HS7ffDHtQ3wWLHcmaM5
o8cbDEanA/dUZKN+zxy6GpXBFBpmkI6gdT8/zClcrDzSxJ2HP5JG54w+1ViorQKIsvn87SHRjeV7
ghXCGCDcobWJMY5afrRQwWfURiZDXyTk2yZrpQ==
</ds:Modulus>
                        <ds:Exponent>AQAB</ds:Exponent>
                    </ds:RSAKeyValue>
                </ds:KeyValue>
            </ds:KeyInfo>
        </ds:Signature>
    </env:Header>
    <env:Body Id="Id-0000011a101b167c-0000000000000012">
        <product version="11.1.2.4.0">
            <name>API Gateway</name>
            <company>Oracle</company>
            <description>SOA Security and Management</description>
        </product>
    </env:Body>
</env:Envelope>

Verify the Signature of the XML with the puclic certificate

public static boolean isSOAPXmlDigitalSignatureValid(String signedXmlFilePath, PublicKey publicKey) throws Exception {
    String xmlContent = SOAP_Security_Signature.getFileString(signedXmlFilePath);
    
    Document doc = SOAP_Security_Signature.getDocument(xmlContent.trim(), true);
    System.out.println("Document: "+doc.getDocumentElement());
    
    // namespaceURI=http://www.w3.org/2000/09/xmldsig#", localName=Signature
    String localName = "Signature";
    String qualifiedName = "ds";
    doc.createElementNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, qualifiedName); 
    NodeList nl = doc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, localName); // "Signature"
    if (nl.getLength() == 0) {
        throw new Exception("No XML Digital Signature Found, document is discarded");
    }
    Node sigElement = nl.item(0);
    
    org.apache.xml.security.Init.init();
    org.apache.xml.security.signature.XMLSignature signature = new XMLSignature((Element) sigElement, "");
    return signature.checkSignatureValue(publicKey);
}

Full Example: Some of the functions used form this class SOAP_Security_Signature

//dependency: groupId:xml-security, artifactId:xmlsec, version:1.3.0
//dependency: groupId:xalan, artifactId:xalan, version:2.7.1
public class SOAP_XML_Signature {

    static PrivateKey privateKey;
    static X509Certificate loadPublicKeyX509;
    static String path = "C:/Yash/SOAP/", privateKeyFilePath = path+"Baeldung.p12", publicKeyFilePath = path+"Baeldung.cer",
                  inputFile= path+"Soap1.xml", outputFile = path+"output.xml";
    public static void main(String unused[]) throws Exception {
        
        InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
        privateKey = SOAP_Security_Signature.loadPrivateKeyforSigning(pkcs_FileStream, "password");
        System.out.println("privateKey : "+privateKey);
        
        InputStream cerFileStream = new FileInputStream(publicKeyFilePath);
        loadPublicKeyX509 = SOAP_Security_Signature.loadPublicKeyX509(cerFileStream);
        PublicKey publicKey = loadPublicKeyX509.getPublicKey();
        System.out.println("loadPublicKey : "+ publicKey);
        
        //SOAP envelope to be signed
        Document digitalSignDoc = getDigitalSignDoc(inputFile);

        File signatureFile = new File(outputFile);
        String BaseURI = signatureFile.toURI().toURL().toString();
        //write signature to file
        FileOutputStream f = new FileOutputStream(signatureFile);
        XMLUtils.outputDOMc14nWithComments(digitalSignDoc, f);
        f.close();
        System.out.println("Wrote signature to " + BaseURI);
        
        boolean soapXmlDigitalSignatureValid = isSOAPXmlDigitalSignatureValid(outputFile, publicKey);
        System.out.println("isSOAPXmlDigitalSignatureValid :"+soapXmlDigitalSignatureValid);
    }

}

Upvotes: 1

Emilio De Castro Ruiz
Emilio De Castro Ruiz

Reputation: 21

I answer to my question with my solution. @pedrofb tell a better way to fix my problem but I couldn't use on my WAS server.

I use a private method to canonicalized my XML to create the digest and later to create the signature:

private String canonicalize(String xml)
{
    try
    {
        String CHARSET = "UTF-8";
        Init.init();
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS);
        String canoninalizacion = new String(canon.canonicalize(xml.getBytes(CHARSET)), CHARSET);
        return canoninalizacion;
    }
    catch (Exception e)
    {
        e.printStackTrace();
        return xml;
    }
}

Then we transform the XML correctly to set the namespaces and prefix in the right place. For my needed I use:

private String createBodyXML(String dataXML)
{
    String docXML = canonicalize(dataXML);
    // Manual introduction of prefixes
    docXML = docXML.replaceAll("</", "</ns2:").replaceAll("<", "<ns2:").replaceAll("<ns2:/ns2:", "</ns2:");

    String startBodyHash = "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" Id=\"MsgBody\">";
    String endBodyHash = "</soap:Body>";
    String dataXMLSoap = "<SERVICE_DISPATCHER_REQUEST xmlns=\"http://inti.notariado.org/XML\">" 
        + "<ns2:SERVICIO_CONSIGNACION_NOTARIAL xmlns:ns2=\"http://ancert.notariado.org/XML/CSN\">" 
        + docXML 
        + "</ns2:SERVICIO_CONSIGNACION_NOTARIAL>" 
        + "</SERVICE_DISPATCHER_REQUEST>";

    String xmlHash = startBodyHash + dataXMLSoap + endBodyHash;
    // this xmlHash is the same body of the SOAP call
    return xmlHash;
}

We do at the time of the creation of the XML of body and XML of signedInfo. Is not the best way to make it:

String xmlDigest = "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" 
            + "<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">"
            + "<ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"soap\"></ec:InclusiveNamespaces>" 
            + "</ds:CanonicalizationMethod>" 
            + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></ds:SignatureMethod>"
            + "<ds:Reference URI=\"#MsgBody\">" 
            + "<ds:Transforms>" 
            + "<ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">" 
            + "<ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"\"></ec:InclusiveNamespaces>" 
            + "</ds:Transform>"
            + "</ds:Transforms>" 
            + "<ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></ds:DigestMethod>" 
            + "<ds:DigestValue>" 
            + digestValue 
            + "</ds:DigestValue>" 
            + "</ds:Reference>" 
            + "</ds:SignedInfo>";

I want to share how I call my web service with the SOAP message well signed, It is not in relation with this question , but maybe wil be usefull for someone:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
...
private String sendMessage(String xmlAEnviar) throws Exception
{
    try
    {
        // Metodo envio
        String POST = "POST";
        String urlEndpoint = "https://test.dominio.org/servicedispatcher/services/ServiceDispatcherSigned";
        final String httpsProxyHost = "180.100.14.70";
        final String httpsProxyPort = "8080";
        final String userProxy = "user";
        final String passProxy = "password";

        URL httpsURL = new URL(urlEndpoint);

        HttpsURLConnection httpsURLConnection = null;

        if (httpsProxyHost.length() > 0 && httpsProxyPort.length() > 0)
        {
            Proxy miProxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(httpsProxyHost, Integer.parseInt(httpsProxyPort)));
            httpsURLConnection = (HttpsURLConnection) httpsURL.openConnection(miProxy);
            if (userProxy.length() > 0 && passProxy.length() > 0)
            {
                String userPassword = userProxy + ":" + passProxy;
                sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
                String encodedLogin = encoder.encode(userPassword.getBytes());
                Authenticator.setDefault(new Authenticator()
                {
                    protected PasswordAuthentication getPasswordAuthentication()
                    {
                        return new PasswordAuthentication(userProxy, passProxy.toCharArray());
                    }
                });
                httpsURLConnection.setRequestProperty("Proxy-Authorization", (new StringBuilder("Basic ")).append(encodedLogin).toString());
            }
        }

        else
        {
            httpsURLConnection = (HttpsURLConnection) httpsURL.openConnection();
        }

        httpsURLConnection.setDoOutput(true);
        httpsURLConnection.setRequestMethod(POST);
        httpsURLConnection.setRequestProperty("Content-Type", "text/xml; charset=\"UTF-8\"");
        httpsURLConnection.setRequestProperty("SOAPAction", "");

        OutputStream outputStream = httpsURLConnection.getOutputStream();
        outputStream.write(xmlAEnviar.getBytes());
        outputStream.flush();

        InputStream httpsInputStream = httpsURLConnection.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader((httpsInputStream)));
        String lineanext = "";
        String outputnext = "";
        while ((lineanext = bufferedReader.readLine()) != null)
        {
            outputnext = outputnext.concat(lineanext);
        }
        httpsURLConnection.disconnect();

        return outputnext;
    }
    catch (NumberFormatException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (MalformedURLException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (ProtocolException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (IOException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
}

Thanks for everyone, especially to @pedrofb.

A cordial greeting.

Upvotes: 1

pedrofb
pedrofb

Reputation: 39241

You need to perform a compliant ws-security SOAP message which includes a XML DSig Signature

You are not building the message digest correctly and you do not apply the canonicalization methods neither transforms. Java has native support for XML signatures. You do not need to build them from scratch.

In this post you will find an example using standard Java code and a link to the utilities of your application server(recommended)

Upvotes: 0

Related Questions