手动签署SOAP消息Java

时间:2016-08-23 19:18:34

标签: java web-services soap https signature

我必须使用java签署Soap消息,但我不能在我的websphere服务器上使用WSS4J,SAAJ,AXIS2或CXF来解决类路径问题。

我必须签署SOAP调用的正文消息。

我为soap消息正确生成了一个带有body正文的XML,如下所示:

<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>

为获得最佳观点而形成:

<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>

然后我使用Hash值来创建摘要值,使用前面带有body开始和结束标记的XML:

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

XML哈希示例:

<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>

生成teh摘要值后,我创建了一个SignedInfo节点:

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>";

签名的xml如下所示:

<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>

使用此XML和我的X509证书信息,我使用此方法获取符号值:

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

生成所有信息后,我形成了完整的肥皂消息。

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>";

最后我收到了这条肥皂消息:

<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>

当我在端点(https://test..)上使用SoapUI使用此soap消息时。) 始终收到此回复:

<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>

我有一个OK Soap消息,用于在java上生成我的Soap消息,我找不到与我生成的XML相比的结构差异。 正确签署肥皂:

    <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>

请有人帮我告诉我我做错了什么。 感谢大家花时间阅读我的问题:)

亲切的问候。

3 个答案:

答案 0 :(得分:1)

我用我的解决方案回答了我的问题。 @pedrofb告诉我更好的解决问题的方法,但我无法在我的WAS服务器上使用。

我使用私有方法规范化我的XML以创建摘要,然后创建签名:

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

然后我们正确地转换XML以在正确的位置设置名称空间和前缀。我需要的是:

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

我们在创建了signedInfo的body和XML的XML时。不是最好的方法:

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>";

我想分享我如何使用已签名的SOAP消息调用我的Web服务,这与此问题无关,但可能对某人有用:

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

感谢大家,特别是@pedrofb。

亲切的问候。

答案 1 :(得分:0)

您需要执行包含ws-security

的合规XML DSig Signature SOAP消息

您没有正确构建消息摘要,并且您不应用规范化方法也不会转换。 Java本身支持XML signatures。您不需要从头开始构建它们。

在这个post中,您将找到使用标准Java代码和应用程​​序服务器实用程序链接的示例(推荐)

答案 2 :(得分:0)

SOAP Enveloped signature:使用合格的证书签署XML文档。

<?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>

通过使用以下功能,您可以使用证书和私钥Baeldung.cer, Baeldung.p12(密码=“密码”)对XML进行数字签名

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

生成的SOAP签名XML文件:

<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>

使用公共证书验证XML的签名

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

完整示例:此类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);
    }

}