How to Sign a SOAP request with WS-Security, and specific KeyInfo format

desarrollo
Participant I

Hi, @Dino-at-Google

I have a requirement that requires signing the SOAP request, through a .jks certificate,i try to use this ApigeeEdge-Java-WsSec-Signature-2, but the legacy is answering that it cannot validate the signature, however I think it is because of the prefixes that are generated since apigee are different with this callout, attached the request that comes out of apigee and the one that expects to receive the endpoint, as you can see, are also different than the way it is sent from apigee is not the same.

Request Expected:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.legalcheck.cifin.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv: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"><wsu:Timestamp wsu:Id="TS-2795B41DA34FD80A771574109162742128"><wsu:Created>2019-11-18T20:32:42.742Z</wsu:Created><wsu:Expires>2019-11-18T23:19:22.742Z</wsu:Expires></wsu:Timestamp><ds:Signature Id="SIG-2795B41DA34FD80A771574109162617127" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces PrefixList="soapenv ws xsd xsi" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#id-2795B41DA34FD80A771574109162615126"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces PrefixList="ws xsd xsi" xmlns:ec="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:DigestValue>6trQTlSQLxzB76UQVloueYy/FpI=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>i3vbBMSTsfbcWeZyuvcdhCDfqpYdaiABQl4V5Y16sWAizmyj3sts3HZ5yKqqkC49hcpPAb87hbM3
9dAqzWKDXRpUKkXH3MuwyMBVJiQ5+radnkCaR/9WHp9Gv6Md6a7F0tR6I8RzafOBMCV5uqPY9jnT
8fglapPvKZZIezyjP81rm/58EC8QAouRFvqr7y+zne3VhBaNtOL24OFwgIgkP17ZNMTFTOKIFPwF
p+5ulgjUC+HVuI7rfkMEJUy0wpWz7jt4RPQ+jzOx5S4i/cwebjr0EaaaySjeEezPpT27kSA4OPjh
vqkQGH2u5kkcTBDGi8fHJwISb3MIAXnuw6TigQ==</ds:SignatureValue><ds:KeyInfo Id="KI-2795B41DA34FD80A771574109162615124"><wsse:SecurityTokenReference wsu:Id="STR-2795B41DA34FD80A771574109162615125"><ds:X509Data><ds:X509IssuerSerial><ds:X509IssuerName>CN=creditoexpress</ds:X509IssuerName><ds:X509SerialNumber>1323432320</ds:X509SerialNumber></ds:X509IssuerSerial></ds:X509Data></wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature></wsse:Security></soapenv:Header><soapenv:Body wsu:Id="id-2795B41DA34FD80A771574109162615126" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><ws:consultaLegalCheckV2Xml soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><parametrosConsultaLegalCheck xsi:type="dto:ParametrosConsultaLegalCheckDTO" xmlns:dto="http://dto.legalcheck.cifin.com"><codigoInformacion xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">5698</codigoInformacion><numeroIdentificacion xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">14871281</numeroIdentificacion><password xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">WGPt3R</password><tipoIdentificacion xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</tipoIdentificacion><userId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">478867</userId></parametrosConsultaLegalCheck></ws:consultaLegalCheckV2Xml></soapenv:Body></soapenv:Envelope>

There is the request that a sign with a java callaout from apigee:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wssec="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" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ws="http://ws.legalcheck.cifin.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Header><wssec:Security soapenv:mustUnderstand="1"><wsu:Timestamp wsu:Id="Timestamp-0f6815c8-c511-40c6-8464-cfcc9820f49b"><wsu:Created>2019-11-18T22:26:27Z</wsu:Created><wsu:Expires>2019-11-19T01:26:27Z</wsu:Expires></wsu:Timestamp><wssec:BinarySecurityToken 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" wsu:Id="SecurityToken-e828bfab-bb52-4429-b6a4-755b26abc387">MIIC0zCCAbugAwIBAgIETuH5gDANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5jcmVkaXRvZXhwcmVzczAgFw0xOTA5MTExNTU2NTJaGA8yMjE2MTAyODE1NTY1MlowGTEXMBUGA1UEAxMOY3JlZGl0b2V4cHJlc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqQqeXnqqUN5BOi9qj+jXPxTJO3/Eg2+xxUUaKwDhnAsLL14Y6ejBiRnNIctsK0pJNzzF5rHpRS4hM1jtxLm3jVMtmg8oN3FSqShaxOgYSRzyPw8qI9ABdm6XMeGYsYWyYcrp8y3nkAq6hqxUZXGT34tePFeKul1itcwE3ukJVNwB9ER0yNduToRENDRxa5EF9NgKnVm6eD5o8Y2CwrSzSz2y1IJTKDs721qNhhRCsedO3BdS4idbQrff55rfWrrKdp5b1RLJniSmjC5ZKlAJJZr6Y5jDRxpX1PvRq+VjGs5c0fugDLDrj77pMhGnVgWbWTcbnlsULqdlfoXro0zaJAgMBAAGjITAfMB0GA1UdDgQWBBQPzOJty959stMf2TZ8o8Xp54ku2TANBgkqhkiG9w0BAQsFAAOCAQEAYbWhKhl3D5QlSd+aK59/RFHWxAKUtU/7Z1v9YUvCT/L3/+vR/4qF9/AohYtX3AT5AbnkIZaG32BgFOp6xqc8Nh1Dg0XOY4Sk+Pi6Cy9qAn6cxLurssxkBxNNehzaDHIuxlejjOQWxg40ziAKgxi7FeRHEwjhVQAB86gUY1UA1MgXgt4DCV5bO9fVRUTc2v6lMpyH/TpM/OMH5tIdljJ3Md38ybj6jlO4Fm4ifc/jEcEkin6nI6m6TxtuL48l8pM+/DKJVlF1pM2pXRwAB/BY5tz+eqLR9SzcwneKs2IIUelkNYrgPHJpp/WyRcplA4NbVxTZTdyNpHaHl3EiL69DGQ==</wssec:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ReferenceURI="#Body-d558d1e3-9bc1-4adb-b817-e162289bafcd"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>Ojlq6f+4sLxVrsFJ//3pFhe7ex6NeUBlLiKXMdL0xh4=</DigestValue></Reference><Reference URI="#Timestamp-0f6815c8-c511-40c6-8464-cfcc9820f49b"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>/02v0jJrVw0z8nj5HpfkBcVrY+WvKxPe/k2R9cpv6+Y=</DigestValue></Reference></SignedInfo><SignatureValue>pFI2YmNQtWeh60Jcy7HXRhrXpHbnQH1tsGM1Ht6dPyJl5yHlH3o0F95moNJcSyP54LY/OHBx5RqC W7aq9jeGXDzbd8sn2nVlx3DSIy9LoxRuzk/4T4rG2WnAJpu8JQWGtz1Z1TEcNCRZhN3FVDu59Jr9 quaz3GHdO51az6nBIC2UtDRUhVgaTi5851sHzjPFAKxf1vh+Bpsxm2l5aqfR1Pf2dKVZBRWGrbwv N5RCDuZfwLjaMgoWyoRwoo+2OuCkuYdqgRqBtJL9AY4oWcAyDH8q2xTxcMlZG9smI7frJ1cHfS5i i+ayeeW3tdqsmAVxZFawvScfTEwcD+fD+DcgEg==</SignatureValue><KeyInfo><wssec:SecurityTokenReference><wssec:Reference URI="#SecurityToken-e828bfab-bb52-4429-b6a4-755b26abc387" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wssec:SecurityTokenReference></KeyInfo></Signature></wssec:Security></soapenv:Header><soapenv:Body wsu:Id="Body-d558d1e3-9bc1-4adb-b817-e162289bafcd"><ws:consultaLegalCheckV2Xml soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><parametrosConsultaLegalCheck xmlns:dto="http://dto.legalcheck.cifin.com" xsi:type="dto:ParametrosConsultaLegalCheckDTO"><codigoInformacion xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:string">5698</codigoInformacion><numeroIdentificacion xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:string">14871281</numeroIdentificacion><password xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:string">WGPt3R</password><tipoIdentificacion xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:string">1</tipoIdentificacion><userId xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:string">478867</userId></parametrosConsultaLegalCheck></ws:consultaLegalCheckV2Xml></soapenv:Body></soapenv:Envelope>

Is there any way that, with that JavaCallout, the request can be signed as my requirement needs it?

Solved Solved
1 2 4,060
1 ACCEPTED SOLUTION

I think it is because of the prefixes that are generated since Apigee are different with this callout,

Just looking at the two documents (thanks for including them), if I had to guess I would say that the material difference is not the prefixes, but the difference in SecurityTokenReference

As with all things WS-SEC, there are 79 ways to do everything. As of October 2019, the Apigee callout you cited always embeds the x509v3 cert into the signed message. (Look for the BinarySecurityToken element in the WS-Security header). Your example shows that the signed message refers to an external x509v3 cert by serial number and IssuerName. There is no way, today, to configure the Apigee callout to use the latter form for SecurityTokenReference.

Now, it *may* be the case that the backend system is ALSO complaining about the difference in namespace prefixes. That would be more surprising but I guess it is possible.

If I were working on this, I'd want to solve the first issue, and then see if THAT worked. The source code for that callout is open; you could modify it to embed not the BinarySecurityToken but just the reference to Issuer name and serial number as shown in your "known good" message. That would be pretty easy to do. Can you try and see?

I could try it but I don't have access to your working upstream system, so I won't be able to test my work!

---

EDIT: 2019 November 20: I've updated the callout to add a new property that may help. You need to re-download the JAR.

I've updated the readme, too. https://github.com/DinoChiesa/ApigeeEdge-Java-WsSec-Signature-2

The property I added is key-identifier-type. The default behavior when signing is to embed a BinarySecurityToken element in the signed document and then insert a SecurityTokenReference in the KeyInfo element that points to that BST.

Now you can set that key-identifer-type to have the value 'issuer_serial'. This configuration looks like this:

<JavaCallout name='Java-WSSEC-Sign-2'>
  <Properties>
    <Property name='source'>message.content</Property>
    <Property name='output-variable'>output</Property>
    <Property name='signing-method'>rsa-sha1</Property>
    <Property name='digest-method'>sha1</Property>
    <Property name='key-identifier-type'>issuer_serial</Property>
    <Property name='expiry'>5m</Property>
    <Property name='private-key'>{my_private_key}</Property>
    <Property name='certificate'>{my_certificate}</Property>
  </Properties>
  <ClassName>com.google.apigee.edgecallouts.wssecdsig.Sign</ClassName>
  <ResourceURL>java://edge-wssecdsig-20191120.jar</ResourceURL>
</JavaCallout>

This will embed the key info in the way your system expects it. Like this:

<KeyInfo>
  <wsse:SecurityTokenReference>
    <X509Data>
      <X509IssuerSerial>
        <X509IssuerName>CN=common.name.on.cert</X509IssuerName>
        <X509SerialNumber>837113432321</X509SerialNumber>
      </X509IssuerSerial>
    </X509Data>
  </wsse:SecurityTokenReference>
</KeyInfo>

You may want to omit the timestamp from the signature. In your example "goal" document, only the Body element is signed, though there is a timestamp. This makes the timestamp element effectively useless, but ... if that's what your upstream system requires, then .. I guess that's what you should do. You can use the "elements-to-sign" property to affect that.

ONE ADDITIONAL NOTE:

I noticed that both the SignatureMethod and the DigestMethod in your "goal" document are different from the document generated by the Apigee callout. Your doc uses rsa-sha1 and sha1, while the Apigee callout defaults to rsa-sha256 and sha256. You probably need to use the appropriate properties (see the README, or the example I gave above) to set the signing-method and digest-method to the appropriate values. Or just omit them. The sha1 values are the default.

Editorial comment: SOAP Canonicalization inclusive of namespaces is.. . such a bad idea.

View solution in original post

2 REPLIES 2

I think it is because of the prefixes that are generated since Apigee are different with this callout,

Just looking at the two documents (thanks for including them), if I had to guess I would say that the material difference is not the prefixes, but the difference in SecurityTokenReference

As with all things WS-SEC, there are 79 ways to do everything. As of October 2019, the Apigee callout you cited always embeds the x509v3 cert into the signed message. (Look for the BinarySecurityToken element in the WS-Security header). Your example shows that the signed message refers to an external x509v3 cert by serial number and IssuerName. There is no way, today, to configure the Apigee callout to use the latter form for SecurityTokenReference.

Now, it *may* be the case that the backend system is ALSO complaining about the difference in namespace prefixes. That would be more surprising but I guess it is possible.

If I were working on this, I'd want to solve the first issue, and then see if THAT worked. The source code for that callout is open; you could modify it to embed not the BinarySecurityToken but just the reference to Issuer name and serial number as shown in your "known good" message. That would be pretty easy to do. Can you try and see?

I could try it but I don't have access to your working upstream system, so I won't be able to test my work!

---

EDIT: 2019 November 20: I've updated the callout to add a new property that may help. You need to re-download the JAR.

I've updated the readme, too. https://github.com/DinoChiesa/ApigeeEdge-Java-WsSec-Signature-2

The property I added is key-identifier-type. The default behavior when signing is to embed a BinarySecurityToken element in the signed document and then insert a SecurityTokenReference in the KeyInfo element that points to that BST.

Now you can set that key-identifer-type to have the value 'issuer_serial'. This configuration looks like this:

<JavaCallout name='Java-WSSEC-Sign-2'>
  <Properties>
    <Property name='source'>message.content</Property>
    <Property name='output-variable'>output</Property>
    <Property name='signing-method'>rsa-sha1</Property>
    <Property name='digest-method'>sha1</Property>
    <Property name='key-identifier-type'>issuer_serial</Property>
    <Property name='expiry'>5m</Property>
    <Property name='private-key'>{my_private_key}</Property>
    <Property name='certificate'>{my_certificate}</Property>
  </Properties>
  <ClassName>com.google.apigee.edgecallouts.wssecdsig.Sign</ClassName>
  <ResourceURL>java://edge-wssecdsig-20191120.jar</ResourceURL>
</JavaCallout>

This will embed the key info in the way your system expects it. Like this:

<KeyInfo>
  <wsse:SecurityTokenReference>
    <X509Data>
      <X509IssuerSerial>
        <X509IssuerName>CN=common.name.on.cert</X509IssuerName>
        <X509SerialNumber>837113432321</X509SerialNumber>
      </X509IssuerSerial>
    </X509Data>
  </wsse:SecurityTokenReference>
</KeyInfo>

You may want to omit the timestamp from the signature. In your example "goal" document, only the Body element is signed, though there is a timestamp. This makes the timestamp element effectively useless, but ... if that's what your upstream system requires, then .. I guess that's what you should do. You can use the "elements-to-sign" property to affect that.

ONE ADDITIONAL NOTE:

I noticed that both the SignatureMethod and the DigestMethod in your "goal" document are different from the document generated by the Apigee callout. Your doc uses rsa-sha1 and sha1, while the Apigee callout defaults to rsa-sha256 and sha256. You probably need to use the appropriate properties (see the README, or the example I gave above) to set the signing-method and digest-method to the appropriate values. Or just omit them. The sha1 values are the default.

Editorial comment: SOAP Canonicalization inclusive of namespaces is.. . such a bad idea.

Have you got any feedback for me on this change?