xlgmokha / xml-kit

MIT License
3 stars 2 forks source link

XML signing fails when using "Id" instead of "ID" for xml.Object builder elements #75

Open cbochs opened 2 years ago

cbochs commented 2 years ago

Describe the bug

The xml-kit gem fails when an XML enveloping signature uses the correct casing for an Object's ID field. When a builder file contains xml.Object ID: "reference" ..., the signing works as expected. However, if the builder file contains xml.Object Id: "reference, the following error is reported:

irb(main):117:0> EnvelopingSignature.new('<data>123</data>', signing_key_pair).to_xml
Traceback (most recent call last):
       16: from /Users/.../ruby/2.7.4/lib/ruby/2.7.0/bundler/cli/exec.rb:63:in `load'
       15: from /Users/.../ruby/2.7.4/bin/irb:23:in `<top (required)>'
       14: from /Users/.../ruby/2.7.4/bin/irb:23:in `load'
       13: from /Users/.../ruby/2.7.4/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
       12: from (irb):117
       11: from /Users/.../test/local_gems/ruby/2.7.0/gems/xml-kit-0.4.0/lib/xml/kit/templatable.rb:30:in `to_xml'
       10: from /Users/.../test/local_gems/ruby/2.7.0/gems/xml-kit-0.4.0/lib/xml/kit/signatures.rb:38:in `complete'
        9: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signed_document.rb:21:in `sign'
        8: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signed_document.rb:21:in `each'
        7: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signed_document.rb:22:in `block in sign'
        6: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signature.rb:22:in `sign'
        5: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signature.rb:22:in `each'
        4: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/signature.rb:22:in `block in sign'
        3: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/reference.rb:20:in `sign'
        2: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/reference.rb:62:in `calculate_digest_value'
        1: from /Users/.../test/local_gems/ruby/2.7.0/gems/xmldsig-0.7.0/lib/xmldsig/reference.rb:42:in `referenced_node'
Xmldsig::Reference::ReferencedNodeNotFound (Could not find the referenced node obj-EemEkjoVLi')

According to the XML Digital Signature specification, section 4.6 The Object Element (https://www.w3.org/TR/xmldsig-core/#sec-Object) the casing for an Object'd ID field should be Id instead of ID.

To Reproduce Steps to reproduce the behavior:

  1. Execute the following lines in irb with the following Envelope template class and builder below:
> cert = nil
> key = OpenSSL::PKey::RSA.new(2048)
> passphrase = nil
> signing_key_pair = ::Xml::Kit::KeyPair.new(cert, key, passphrase, :signing)
# NOTE: THERE IS AN ERROR HERE (TypeError) which is another issue, but the one found here. The signing_key_pair will have been successfully created here

> Envelope.new("<data>123</data>", signing_key_pair).to_xml

Envelope class

class Envelope
  include ::Xml::Kit::Templatable

  def initialize(raw_xml, signing_key_pair)
    @reference_id = "obj-#{SecureRandom.alphanumeric(10)}"
    @raw_xml = raw_xml
    sign_with(signing_key_pair)
  end

  def template_path
    "<path_to_builder_file>"
  end
end

Example builder

xml.Signature 'xmlns' => ::Xml::Kit::Namespaces::XMLDSIG do
  xml.SignedInfo do
    xml.CanonicalizationMethod Algorithm: 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
    xml.SignatureMethod Algorithm: ::Xml::Kit::Namespaces::RSA_SHA256 # signature_method
    xml.Reference URI: "##{reference_id}" do
      xml.Transforms do
        xml.Transform Algorithm: 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315' # TODO: add constant in xml-kit
      end
      xml.DigestMethod Algorithm: ::Xml::Kit::Namespaces::SHA256 # digest_method
      xml.DigestValue ''
    end
  end
  xml.SignatureValue ''
  xml.Object Id: reference_id do |object_xml|
    object_xml << raw_xml
  end
end
  1. Error produced: Xmldsig::Reference::ReferencedNodeNotFound

Expected behavior

The reference node should be able to be found using the correct casing for an Object's ID field (Id)

Screenshots

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context

cbochs commented 2 years ago

After some further digging, it appears that the xmldsig gem searches for either attribute called ID or a wsu-namespaced attribute called wsu:Id. The xmldsig gem uses the following URI to declare the wsu namespace

http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd

The difference between the use of ID and wsu:Id is documented in https://docs.oracle.com/cd/E24191_01/common/tutorials/common_what_must_be_signed.html.

It would be useful - since this is part of the signing process - for xml-kit to provide/expose the wsu namespace under Xml::Kit::Namespaces.