@@ -14,8 +14,13 @@ class InvalidSignedValue < RuntimeError; end
1414
1515 attr_reader :document
1616
17- def initialize ( xml )
17+ # @param xml [String] The XML document to verify
18+ # @param decrypted_attachments [Hash] A hash of decrypted attachments: { 'id' => 'decrypted_string' }
19+ # For example: the decrypted_attachments of a gzipped xml is the gzipped base64 string, the result of the decryption
20+ # { 'phase4-att-1f34-4d68a..' => 'kZ\xB4\xCD}\xCB..' }
21+ def initialize ( xml , decrypted_attachments : { } )
1822 @document = Nokogiri ::XML ( xml . to_s , &:noblanks )
23+ @decrypted_attachments = decrypted_attachments
1924 end
2025
2126 # Returns XML namespaces that are used internally for document querying.
@@ -78,14 +83,19 @@ def digesters
7883
7984 def verify
8085 document . xpath ( '//wse:Security/ds:Signature/ds:SignedInfo/ds:Reference' , namespaces ) . each do |ref |
81- next unless ref . attributes [ 'URI' ] . value . start_with? ( '#' )
82-
8386 digest_algorithm = ref . at_xpath ( '//ds:DigestMethod' , namespaces ) [ 'Algorithm' ]
8487
8588 transform_inclusive_ns = inclusive_namespaces ( ref , './/ds:Transforms/ds:Transform/ec:InclusiveNamespaces' )
8689
87- element_id = ref . attributes [ 'URI' ] . value [ 1 ..-1 ] # strip leading '#'
88- element = document . at_xpath ( %(//*[@wsu:Id="#{ element_id } "]) , namespaces )
90+ ref_uri = ref . attributes [ 'URI' ] . value
91+ if ref_uri . start_with? ( "#" )
92+ element_id = ref_uri . sub ( /^#/ , '' )
93+ element = document . at_xpath ( %(//*[@wsu:Id="#{ element_id } "]) , namespaces )
94+ else
95+ element_id = ref_uri . sub ( /^cid:/ , '' )
96+ element = @decrypted_attachments [ element_id ]
97+ end
98+
8999 unless supplied_digest ( element ) == generate_digest ( element , digest_algorithm , transform_inclusive_ns )
90100 raise InvalidDigest , "Invalid Digest for #{ element_id } "
91101 end
@@ -118,19 +128,14 @@ def generate_digest(element, algorithm, inclusive_namespaces = nil)
118128 end
119129
120130 def supplied_digest ( element )
121- element = document . at_xpath ( element , namespaces ) if element . is_a? String
122- find_digest_value element . attributes [ 'Id' ] . value
131+ element . at_xpath ( './/ds:DigestValue' , namespaces ) . text
123132 end
124133
125134 def signature_value
126135 element = document . at_xpath ( '//wse:Security/ds:Signature/ds:SignatureValue' , namespaces )
127136 element ? element . text : ""
128137 end
129138
130- def find_digest_value ( id )
131- document . at_xpath ( %(//wse:Security/ds:Signature/ds:SignedInfo/ds:Reference[@URI="##{ id } "]/ds:DigestValue) , namespaces ) . text
132- end
133-
134139 # Calculate digest for string with given algorithm URL and Base64 encodes it.
135140 def digest ( string , algorithm )
136141 Base64 . encode64 digester ( algorithm ) . digest ( string )
0 commit comments