Manually sign SOAP message Java

 ̄綄美尐妖づ 提交于 2021-02-07 10:12:51

问题


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.


回答1:


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.




回答2:


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)




回答3:


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);
    }

}


来源:https://stackoverflow.com/questions/39109111/manually-sign-soap-message-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!