Search code examples
rubysoapopensslx509certificatews-security

Ruby SOAP response with X509 certificates failing XML SignatureValue validation


I've been reading up A LOT on everything related with XML signatures, and it's a painful, painful world as it is today.

I'm able to make a SOAP request to a remote WSDL (https://tbk.orangepeople.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl), and I'm supposed to validate their responses as well (naturally!), however I can't seem to figure out how to properly verify the XML SignatureValue.

I also couldn't verify this signature on a Terminal (MAC OSX 10.11.1) using openssl (OpenSSL 0.9.8zg 14 July 2015), although I'm not confident enough that my file inputs and commands were 100% right to give a positive result.

The entity which provided me with the public certificate assured me this is the correct one, so no luck there. I also created a SoapUI project properly configured with Outgoing & Incoming WSS to back up this claim.

For anyone who's curious, I'm using Signer with Nokogiri::XML::Builder to produce the signed XML for my request, Savon to process the requests themselves, and in the code below I'm using Akami::WSSE::VerifySignature separately to process the response.

Here's what I have so far:

XML(response):

<?xml version="1.0"?>
<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#" Id="SIG-1426">
        <ds:SignedInfo>
          <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"/>
          </ds:CanonicalizationMethod>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#id-1425">
            <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=""/>
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>o6RiSp7nGmMWf01mYh3FGNpK80A=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>irR3w9BKEf64eN9FJRnCBqHEj5kWZu+Bn5QlNrBTxp/tbGxgU1ViTLFNu6kQJFfxEFB1AoN7Ks5c
QKOK5eBwbA3j6486XQPMoYOvOWxtr73PS09LVFp6P1aZ0y5wHTf7dQ89GJ35Zb0JemvkeSN0XWQt
X3USE7A6z4t04jx95FX+Me6dTAFyf3ealyISfrfYkIsasqU6W/orhRgyKunq6N1aTZ7HmphaSgtu
EEncUiKS6aEdvD0NjwKWXlTr/5NT5BQ7T9cmWS00QYjlRlF2SGww44SAehNojwqFy40SEpuVPVJv
DH9GH4ITsy72DeY/PXkHkaEpDIPM32EUfobE1zRM0zwPLGQysGcELSRfzAWR9QWO1NmPecABymZ8
qMNQRxUK5MkX2S/O29Jpmq/8q/VWQQhnMmj6YdL8NAE1RmjH11wNXdWHRM+3iLndMk5EpiDtFZSo
fDmtNBWhiBzE3g/OZYBbZVM9MvQjMj0x2aK8rZK/qRylbVjhYaJI8hEOiAJZeAHErwuynjP01ONI
bXeyqZik5x54zamdsQs5UlXaGYRAqVInKr1j4+trJTstAqP7C22cEUULyKO2jkBj/wWpRhucjbJH
4XXHuVHQWP2myvnImaOHuAC8TFSCsV6/hOx206G4Yd1cyHSfNM3XEQURVlOaO0an582OlFxFvnU=</ds:SignatureValue>
        <ds:KeyInfo Id="KI-FBCFA2CE61C97ADD4A14467251913442138">
          <wsse:SecurityTokenReference wsu:Id="STR-FBCFA2CE61C97ADD4A14467251913442139">
            <ds:X509Data>
              <ds:X509IssuerSerial>
                <ds:X509IssuerName>CN=10,OU=ExperTI,O=ExperTI,L=Santiago,ST=Santiago,C=CL,1.2.840.113549.1.9.1=#16116a636572646140657870657274692e636c</ds:X509IssuerName>
                <ds:X509SerialNumber>1401281826</ds:X509SerialNumber>
              </ds:X509IssuerSerial>
            </ds:X509Data>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
    </wsse:Security>
  </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-1425">
    <ns2:initTransactionResponse xmlns:ns2="http://service.wswebpay.webpay.transbank.com/">
      <return>
        <token>e30965b17f7854b21bf77f313cb9a117214e62fb5d98c6ff2580e859d013ed32</token>
        <url>https://tbk.orangepeople.cl/filtroUnificado/initTransaction</url>
      </return>
    </ns2:initTransactionResponse>
  </soap:Body>
</soap:Envelope>

Certificate (certificate_server.crt):

-----BEGIN CERTIFICATE-----
MIIFhTCCA20CBFOF3SIwDQYJKoZIhvcNAQEFBQAwgYYxIDAeBgkqhkiG9w0BCQEW
EWpjZXJkYUBleHBlcnRpLmNsMQswCQYDVQQGEwJDTDERMA8GA1UECAwIU2FudGlh
Z28xETAPBgNVBAcMCFNhbnRpYWdvMRAwDgYDVQQKDAdFeHBlclRJMRAwDgYDVQQL
DAdFeHBlclRJMQswCQYDVQQDDAIxMDAeFw0xNDA1MjgxMjU3MDZaFw0xNjA1Mjcx
MjU3MDZaMIGGMSAwHgYJKoZIhvcNAQkBFhFqY2VyZGFAZXhwZXJ0aS5jbDELMAkG
A1UEBhMCQ0wxETAPBgNVBAgMCFNhbnRpYWdvMREwDwYDVQQHDAhTYW50aWFnbzEQ
MA4GA1UECgwHRXhwZXJUSTEQMA4GA1UECwwHRXhwZXJUSTELMAkGA1UEAwwCMTAw
ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCX1t11QZSgfodg+NPwKdof
lakbpxsFmCvjbY3Vpp6/bTv56XIZe/Z3gBlU4zeGslEaqzs1k4cGAcdZPHxSMydC
oLxmyXpdS2hVFUZTYAeanXHhQzUKmNlgYj3uObprPEEQzD/vEuqpwz2/ZGyaHsWs
exu9aeuLAUUSNne0yqobrzRfEp2FqCp4sJB80cXgGfPA4Cr5jROHqUi8sVWpWRy5
ai5ZaiXRPo3YKF1336twuw9lRS3cRtJh9/AoJElGT7G7BMDpxyTTa08y1iRliDGu
mwWivQMHoKqEs0lCtF9Uz8cFdmiIoRPTt6McpmLoapL9v19xjNnim4lke6DPvtcg
uato7T+frDqA5Cj5GRP/8jbe90Y+YjHuJTkw+fkV6gDTRmJ3wCWDIw/07aY6nZ+H
24Imu6N2YBsMEsa8j9OW04mNgtppRC4dFBh0FIKXC35kJgN38y+6T7MsQThX1XZS
SlK0FygJJADVGelmxtsrRRfnp4yLYRjwdkRGExRjVs/+fkOyKI+fX0o68z6MEDyA
5epVHpgwJ/Yz3Lo7cgXy0hO5a/MfZc0Y0ofb29g8sJMJ8j/SSR85i4pFxudn+HH0
SmkkzE/P10adF/X+pqjscOE+aXwnX09lUUQ9TIlpYaR3hUhONsuefYJ2sHz2z+vt
K5btQwN7u9+QeXLgb20PMwIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQAqCepOSFi7
8d6lKTfWpMuj5ygpplBa3Bj81AKkNfSGDN7zkNX2sCbqn9aEjniIPtldG6I2fgCs
FYTZE9oEPNiuEuH7PNtAjTExIUi9Jzm7bqjCdSs7Ioek1cPePgst017zJ6NSTkaM
r7pUDaS3855xO92uaJskppAeegwz9Dv3d5wY+wVViqUki4pZyxa95IvBJz4NR1Xr
cO6XtUUT9M0wbd0jAkRp7DPQfkihZj8vLSvlUYTRdlF2swIBE/ME2T3NCa0/kt1c
IA1Aq/zn7t0yKvyaJ/O//LrHA1Lfa/uC61O/9P3t+eXDsYl73CeGQdSYZp2DAZmA
Ek3tzwhFa6HR+POIo8MptWMT3DQ0ISHH+EW1Xp8GHIGsk2ELsXuA6XTNwpfz9yvl
9d7IGsq4cdX88cNUCbXm4tj7F3s6i8pNWeCImaYcXKGCBdsLM+lbmqbuV7o3d1Ei
efbR1TQkCxRBNCMUI0pF7NW8PvY3QER9/jEnN52SX+tuQRVdpgl+PyTdSASr4FhV
+HHmgeOgeOewXDnZ7aA1F6f8+CY8Niv4FGZIAptdxTqdynY4nUy/wFowBouO3LEF
6nIcQ3Jx1pDXoEmcLa03JaL7qQNSHyqSe/YEl8E5fdDr7vApzw9pvpAjj1aslidL
bNd4l1YGlL2vbGsIXZlbdBLiblXRi78AyQ==
-----END CERTIFICATE-----

Ruby source code (a little modified, OpenSSL::Digest::SHA1.new is used instead of a digester mapping method to simplify):

# load certificate
certificate_server = OpenSSL::X509::Certificate.new(File.read("certificate_server.crt"))

# CERT INFORMATION IS VERIFIED SUCCESSFULLY HERE
# DIGEST IS VERIFIED SUCCESSFULLY HERE

# certificate signature initialization
response_signature = Akami::WSSE::VerifySignature.new(response)
document = response_signature.document
namespaces = response_signature.namespaces

# retrieve Signature data & digest value
data = document.at_xpath('//wse:Security/ds:Signature/ds:SignedInfo', namespaces).canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
signature = Base64.decode64(document.at_xpath('//wse:Security/ds:Signature/ds:SignatureValue', namespaces).text)

# check if Signature is valid
return false unless certificate_server.public_key.verify(OpenSSL::Digest::SHA1.new, signature, data)

true

This only fails in the last line:

certificate_server.public_key.verify(signature_digester, signature, data)

If anyone can spot the error/bug/missing code, or maybe provide a working example, I would be very grateful.


Solution

  • Had to verify this by making new requests using PHP xmlseclibs, but it turned out to be missing '\n's on the signature field and a missing namespace from the root Envelope XML tag on the data field of the following line:

    certificate_server.public_key.verify(signature_digester, signature, data)
    

    For this case in particular, the element SignedInfo in data needed to be verified while also having the following namespace, which was not included by the 'canonicalize' method:

    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    

    Hope this helps someone in the future!