XML digital signature. How to add ds namespace to Signature node using signer gem?

806 Views Asked by At

I need to envelope xml in soap message, digest data from original xml and sign it. Actual algorithm of signing or digesting does not matter for now.

Example of original xml:

<TransferMsg>
   <Data>Super Important Data</Data>
</TransferMsg>

Final result must be something like that:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope 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">
    <soap:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse: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="CertId">MIIIRzCCB/agAwIBAgIKSchnBgAAAAGKvDAIBgYqhQMCAgMwggFOMRgwFgYFKoUDZAESDTEwMjc3MDcwMTM4MDYxGjAYBggqhQMDgQMBARIMMDA3NzA3MzE0MDI5MTwwOgYDVQQJDDPQkS7QodGD0YXQsNGA0LXQstGB0LrQuNC5INC/0LXRgCzQtDExLNGB0YLRgDEs0L7RhDYxIzAhBgkqhkiG9w0BCQEWFGUtbW9za3ZhQGUtbW9za3ZhLnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMTUwMwYDVQQKDCzQntCQ0J4gItCt0LvQtd=</wsse:BinarySecurityToken>
            <ds:Signature>
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
                </ds:SignedInfo>
                <ds:SignatureValue>vnjz04yWa7DbRtC5vJAt/tsCR5m31i3e8FMxG2eOIo4DtsGhm1FgZ8wKLEEzvbYuolrosc2OKkFafqJinsTWsg==</SignatureValue>
                <ds:KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#CertId" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </Signature>
        </wsse:Security>
    </soap:Header>
    <soap:Body wsu:Id="body">
        <soap:TransferMsg>
            <soap:DataToDigest>Super Important Data</soap:DataToDigest>
        </soap:TransferMsg>
    </soap:Body>
</soap:Envelope>

Right now I'm using signer builtin sign! and digest! methods like this:

require 'openssl'
require 'signer'

class MySigner
  def initialize
    @soap_envelope = File.open('./data/soap_envelope.xml') { |f| Nokogiri::XML(f) }
  end

  def sign(xml_to_sign)
    signer = Signer.new(put_in_envelope(xml_to_sign))
    signer.cert = OpenSSL::X509::Certificate.new(File.read("./data/cert.pem"))
    signer.private_key = OpenSSL::PKey.read(File.read("./data/key.pem"), "PASSWORD")
    signer.security_token_id = 'CertId'

    namespaces = {
      'soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
      'ds' => 'http://www.w3.org/2000/09/xmldsig#'
    }

    # Digest soap:Body tag
    signer.document.xpath('//TransferMsg', namespaces).each do |node|
      signer.digest!(node, id: 'body')
    end

    # Sign document itself
    signer.sign!(security_token: true, enveloped: true)

    signer.to_xml
  end

  def put_in_envelope(xml)
    xml_object = Nokogiri::XML(xml)
    valuable_data = xml_object.xpath('/TransferMsg').to_s
    @soap_envelope.xpath('//soap:Body').children.first.add_next_sibling(valuable_data)
    @soap_envelope
  end
end  

soap_envelope.xml:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope 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"
                   xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    </wsse:Security>
  </soap:Header>
  <soap:Body wsu:Id="body">
  </soap:Body>
</soap:Envelope>

But resulted code has <Signature xmlns='http://www.w3.org/2000/09/xmldsig#'> instead of <ds:Signature>:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope 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">
    <soap:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse: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="CertId">MIIIRzCCB/agAwIBAgIKSchnBgAAAAGKvDAIBgYqhQMCAgMwggFOMRgwFgYFKoUDZAESDTEwMjc3MDcwMTM4MDYxGjAYBggqhQMDgQMBARIMMDA3NzA3MzE0MDI5MTwwOgYDVQQJDDPQkS7QodGD0YXQsNGA0LXQstGB0LrQuNC5INC/0LXRgCzQtDExLNGB0YLRgDEs0L7RhDYxIzAhBgkqhkiG9w0BCQEWFGUtbW9za3ZhQGUtbW9za3ZhLnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMTUwMwYDVQQKDCzQntCQ0J4gItCt0LvQtd=</wsse: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#gostr34102001-gostr3411"/>
                </SignedInfo>
                <SignatureValue>vnjz04yWa7DbRtC5vJAt/tsCR5m31i3e8FMxG2eOIo4DtsGhm1FgZ8wKLEEzvbYuolrosc2OKkFafqJinsTWsg==</SignatureValue>
                <KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#CertId" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </wsse:Security>
    </soap:Header>
    <soap:Body wsu:Id="body">
        <soap:TransferMsg>
            <soap:DataToDigest>Super Important Data</soap:DataToDigest>
        </soap:TransferMsg>
    </soap:Body>
</soap:Envelope>

Of course I can manually change Signature node namespace and remove xmlns with nokogiri, but I prefer more automatic way to do it. Am I missing something in the docs?

0

There are 0 best solutions below