ruby-saml 0.8.9 → 0.8.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ruby-saml might be problematic. Click here for more details.

Files changed (42) hide show
  1. data/Gemfile +11 -1
  2. data/Rakefile +0 -14
  3. data/lib/onelogin/ruby-saml/authrequest.rb +84 -18
  4. data/lib/onelogin/ruby-saml/logoutrequest.rb +93 -18
  5. data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -24
  6. data/lib/onelogin/ruby-saml/response.rb +206 -11
  7. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  8. data/lib/onelogin/ruby-saml/settings.rb +73 -12
  9. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
  10. data/lib/onelogin/ruby-saml/utils.rb +169 -0
  11. data/lib/onelogin/ruby-saml/version.rb +1 -1
  12. data/lib/ruby-saml.rb +2 -1
  13. data/lib/xml_security.rb +332 -78
  14. data/test/certificates/ruby-saml-2.crt +15 -0
  15. data/test/certificates/ruby-saml.crt +14 -0
  16. data/test/certificates/ruby-saml.key +15 -0
  17. data/test/logoutrequest_test.rb +177 -44
  18. data/test/logoutresponse_test.rb +23 -28
  19. data/test/request_test.rb +100 -37
  20. data/test/response_test.rb +337 -129
  21. data/test/responses/adfs_response_xmlns.xml +45 -0
  22. data/test/responses/encrypted_new_attack.xml.base64 +1 -0
  23. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  24. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  25. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
  26. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
  27. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
  28. data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
  29. data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
  30. data/test/responses/response_with_signed_assertion_3.xml +30 -0
  31. data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
  32. data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
  33. data/test/responses/response_wrapped.xml.base64 +150 -0
  34. data/test/responses/valid_response.xml.base64 +1 -0
  35. data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
  36. data/test/settings_test.rb +5 -5
  37. data/test/slo_logoutresponse_test.rb +226 -0
  38. data/test/test_helper.rb +117 -12
  39. data/test/utils_test.rb +10 -10
  40. data/test/xml_security_test.rb +354 -68
  41. metadata +64 -18
  42. checksums.yaml +0 -7
@@ -1,5 +1,5 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
- VERSION = '0.8.9'
3
+ VERSION = '0.8.14'
4
4
  end
5
5
  end
@@ -2,10 +2,11 @@ require 'onelogin/ruby-saml/logging'
2
2
  require 'onelogin/ruby-saml/authrequest'
3
3
  require 'onelogin/ruby-saml/logoutrequest'
4
4
  require 'onelogin/ruby-saml/logoutresponse'
5
+ require 'onelogin/ruby-saml/slo_logoutresponse'
5
6
  require 'onelogin/ruby-saml/response'
6
7
  require 'onelogin/ruby-saml/settings'
7
8
  require 'onelogin/ruby-saml/utils'
8
9
  require 'onelogin/ruby-saml/validation_error'
9
10
  require 'onelogin/ruby-saml/metadata'
10
11
  require 'onelogin/ruby-saml/version'
11
- require 'onelogin/ruby-saml/attributes'
12
+ require 'onelogin/ruby-saml/attributes'
@@ -34,89 +34,325 @@ require "onelogin/ruby-saml/utils"
34
34
 
35
35
  module XMLSecurity
36
36
 
37
- class SignedDocument < REXML::Document
38
- C14N = "http://www.w3.org/2001/10/xml-exc-c14n#"
39
- DSIG = "http://www.w3.org/2000/09/xmldsig#"
37
+ class BaseDocument < REXML::Document
38
+ REXML::Document::entity_expansion_limit = 0
40
39
 
41
- attr_accessor :signed_element_id
40
+ C14N = "http://www.w3.org/2001/10/xml-exc-c14n#"
41
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
42
+ NOKOGIRI_OPTIONS = Nokogiri::XML::ParseOptions::STRICT |
43
+ Nokogiri::XML::ParseOptions::NONET
42
44
 
43
- def initialize(response)
44
- super(response)
45
- extract_signed_element_id
45
+ def canon_algorithm(element)
46
+ algorithm = element
47
+ if algorithm.is_a?(REXML::Element)
48
+ algorithm = element.attribute('Algorithm').value
49
+ end
50
+
51
+ case algorithm
52
+ when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
53
+ "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
54
+ Nokogiri::XML::XML_C14N_1_0
55
+ when "http://www.w3.org/2006/12/xml-c14n11",
56
+ "http://www.w3.org/2006/12/xml-c14n11#WithComments"
57
+ Nokogiri::XML::XML_C14N_1_1
58
+ else
59
+ Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
60
+ end
46
61
  end
47
62
 
48
- def validate_document(idp_cert_fingerprint, soft = true)
49
- # get cert from response
50
- cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
51
- raise OneLogin::RubySaml::ValidationError.new("Certificate element missing in response (ds:X509Certificate)") unless cert_element
52
- base64_cert = OneLogin::RubySaml::Utils.element_text(cert_element)
53
- cert_text = Base64.decode64(base64_cert)
54
- cert = OpenSSL::X509::Certificate.new(cert_text)
63
+ def algorithm(element)
64
+ algorithm = element
65
+ if algorithm.is_a?(REXML::Element)
66
+ algorithm = element.attribute("Algorithm").value
67
+ end
55
68
 
56
- # check cert matches registered idp cert
57
- fingerprint = Digest::SHA1.hexdigest(cert.to_der)
69
+ algorithm = algorithm && algorithm =~ /(rsa-)?sha(.*?)$/i && $2.to_i
58
70
 
59
- if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
60
- return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Fingerprint mismatch"))
71
+ case algorithm
72
+ when 256 then OpenSSL::Digest::SHA256
73
+ when 384 then OpenSSL::Digest::SHA384
74
+ when 512 then OpenSSL::Digest::SHA512
75
+ else
76
+ OpenSSL::Digest::SHA1
61
77
  end
78
+ end
62
79
 
63
- validate_signature(base64_cert, soft)
80
+ end
81
+
82
+ class Document < BaseDocument
83
+ RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
84
+ RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
85
+ RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
86
+ RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
87
+ SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
88
+ SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'
89
+ SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384"
90
+ SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'
91
+ ENVELOPED_SIG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
92
+ INC_PREFIX_LIST = "#default samlp saml ds xs xsi md"
93
+
94
+ attr_writer :uuid
95
+
96
+ def uuid
97
+ @uuid ||= begin
98
+ document.root.nil? ? nil : document.root.attributes['ID']
99
+ end
64
100
  end
65
101
 
66
- def validate_signature(base64_cert, soft = true)
67
- # validate references
102
+ #<Signature>
103
+ #<SignedInfo>
104
+ #<CanonicalizationMethod />
105
+ #<SignatureMethod />
106
+ #<Reference>
107
+ #<Transforms>
108
+ #<DigestMethod>
109
+ #<DigestValue>
110
+ #</Reference>
111
+ #<Reference /> etc.
112
+ #</SignedInfo>
113
+ #<SignatureValue />
114
+ #<KeyInfo />
115
+ #<Object />
116
+ #</Signature>
117
+ def sign_document(private_key, certificate, signature_method = RSA_SHA1, digest_method = SHA1)
118
+ noko = Nokogiri::XML(self.to_s) do |config|
119
+ config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
120
+ end
68
121
 
69
- # check for inclusive namespaces
70
- inclusive_namespaces = extract_inclusive_namespaces
122
+ signature_element = REXML::Element.new("ds:Signature").add_namespace('ds', DSIG)
123
+ signed_info_element = signature_element.add_element("ds:SignedInfo")
124
+ signed_info_element.add_element("ds:CanonicalizationMethod", {"Algorithm" => C14N})
125
+ signed_info_element.add_element("ds:SignatureMethod", {"Algorithm" => signature_method})
71
126
 
72
- document = Nokogiri.parse(self.to_s)
127
+ # Add Reference
128
+ reference_element = signed_info_element.add_element("ds:Reference", {"URI" => "##{uuid}"})
73
129
 
74
- # create a working copy so we don't modify the original
75
- @working_copy ||= REXML::Document.new(self.to_s).root
130
+ # Add Transforms
131
+ transforms_element = reference_element.add_element("ds:Transforms")
132
+ transforms_element.add_element("ds:Transform", {"Algorithm" => ENVELOPED_SIG})
133
+ c14element = transforms_element.add_element("ds:Transform", {"Algorithm" => C14N})
134
+ c14element.add_element("ec:InclusiveNamespaces", {"xmlns:ec" => C14N, "PrefixList" => INC_PREFIX_LIST})
76
135
 
77
- # store and remove signature node
78
- @sig_element ||= begin
79
- element = REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
80
- element.remove
136
+ digest_method_element = reference_element.add_element("ds:DigestMethod", {"Algorithm" => digest_method})
137
+ inclusive_namespaces = INC_PREFIX_LIST.split(" ")
138
+ canon_doc = noko.canonicalize(canon_algorithm(C14N), inclusive_namespaces)
139
+ reference_element.add_element("ds:DigestValue").text = compute_digest(canon_doc, algorithm(digest_method_element))
140
+
141
+ # add SignatureValue
142
+ noko_sig_element = Nokogiri::XML(signature_element.to_s) do |config|
143
+ config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
81
144
  end
82
145
 
146
+ noko_signed_info_element = noko_sig_element.at_xpath('//ds:Signature/ds:SignedInfo', 'ds' => DSIG)
147
+ canon_string = noko_signed_info_element.canonicalize(canon_algorithm(C14N))
83
148
 
84
- # verify signature
85
- signed_info_element = REXML::XPath.first(@sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
86
- noko_sig_element = document.at_xpath('//ds:Signature', 'ds' => DSIG)
87
- noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
88
- canon_algorithm = canon_algorithm REXML::XPath.first(@sig_element, '//ds:CanonicalizationMethod', 'ds' => DSIG)
89
- canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
90
- noko_sig_element.remove
149
+ signature = compute_signature(private_key, algorithm(signature_method).new, canon_string)
150
+ signature_element.add_element("ds:SignatureValue").text = signature
91
151
 
92
- # check digests
93
- REXML::XPath.each(@sig_element, "//ds:Reference", {"ds"=>DSIG}) do |ref|
94
- uri = ref.attributes.get_attribute("URI").value
152
+ # add KeyInfo
153
+ key_info_element = signature_element.add_element("ds:KeyInfo")
154
+ x509_element = key_info_element.add_element("ds:X509Data")
155
+ x509_cert_element = x509_element.add_element("ds:X509Certificate")
156
+ if certificate.is_a?(String)
157
+ certificate = OpenSSL::X509::Certificate.new(certificate)
158
+ end
159
+ x509_cert_element.text = Base64.encode64(certificate.to_der).gsub(/\n/, "")
160
+
161
+ # add the signature
162
+ issuer_element = self.elements["//saml:Issuer"]
163
+ if issuer_element
164
+ self.root.insert_after issuer_element, signature_element
165
+ else
166
+ if sp_sso_descriptor = self.elements["/md:EntityDescriptor"]
167
+ self.root.insert_before sp_sso_descriptor, signature_element
168
+ else
169
+ self.root.add_element(signature_element)
170
+ end
171
+ end
172
+ end
173
+
174
+ protected
175
+
176
+ def compute_signature(private_key, signature_algorithm, document)
177
+ Base64.encode64(private_key.sign(signature_algorithm, document)).gsub(/\n/, "")
178
+ end
95
179
 
96
- hashed_element = document.at_xpath("//*[@ID='#{uri[1..-1]}']")
97
- canon_algorithm = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod', 'ds' => DSIG)
98
- canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces)
180
+ def compute_digest(document, digest_algorithm)
181
+ digest = digest_algorithm.digest(document)
182
+ Base64.encode64(digest).strip!
183
+ end
184
+
185
+ end
186
+
187
+ class SignedDocument < BaseDocument
188
+
189
+ attr_writer :signed_element_id
190
+
191
+ def signed_element_id
192
+ @signed_element_id ||= extract_signed_element_id
193
+ end
99
194
 
100
- digest_algorithm = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod", 'ds' => DSIG))
195
+ def validate_document(idp_cert_fingerprint, soft = true, options = {})
196
+ # get cert from response
197
+ cert_element = REXML::XPath.first(
198
+ self,
199
+ "//ds:X509Certificate",
200
+ { "ds"=>DSIG }
201
+ )
202
+
203
+ if cert_element
204
+ base64_cert = OneLogin::RubySaml::Utils.element_text(cert_element)
205
+ cert_text = Base64.decode64(base64_cert)
206
+ begin
207
+ cert = OpenSSL::X509::Certificate.new(cert_text)
208
+ rescue OpenSSL::X509::CertificateError => _e
209
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Certificate Error"))
210
+ end
211
+
212
+ if options[:fingerprint_alg]
213
+ fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(options[:fingerprint_alg]).new
214
+ else
215
+ fingerprint_alg = OpenSSL::Digest::SHA1.new
216
+ end
217
+ fingerprint = fingerprint_alg.hexdigest(cert.to_der)
218
+
219
+ # check cert matches registered idp cert
220
+ if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
221
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Fingerprint mismatch"))
222
+ end
223
+ else
224
+ if options[:cert]
225
+ base64_cert = Base64.encode64(options[:cert].to_pem)
226
+ else
227
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Certificate element missing in response (ds:X509Certificate) and not cert provided at settings"))
228
+ end
229
+ end
230
+ validate_signature(base64_cert, soft)
231
+ end
101
232
 
102
- hash = digest_algorithm.digest(canon_hashed_element)
103
- digest_value = Base64.decode64(OneLogin::RubySaml::Utils.element_text(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG})))
233
+ def validate_document_with_cert(idp_cert, soft = true)
234
+ # get cert from response
235
+ cert_element = REXML::XPath.first(
236
+ self,
237
+ "//ds:X509Certificate",
238
+ { "ds"=>DSIG }
239
+ )
240
+
241
+ if cert_element
242
+ base64_cert = OneLogin::RubySaml::Utils.element_text(cert_element)
243
+ cert_text = Base64.decode64(base64_cert)
244
+ begin
245
+ cert = OpenSSL::X509::Certificate.new(cert_text)
246
+ rescue OpenSSL::X509::CertificateError => _e
247
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Certificate Error"))
248
+ end
104
249
 
105
- unless digests_match?(hash, digest_value)
106
- return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Digest mismatch"))
250
+ # check saml response cert matches provided idp cert
251
+ if idp_cert.to_pem != cert.to_pem
252
+ return false
107
253
  end
254
+ elsif not idp_cert
255
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Certificate element missing in response (ds:X509Certificate) and not cert provided at settings"))
256
+ else
257
+ base64_cert = Base64.encode64(idp_cert.to_pem)
108
258
  end
259
+ validate_signature(base64_cert, true)
260
+ end
261
+
262
+ def validate_signature(base64_cert, soft = true)
109
263
 
110
- base64_signature = OneLogin::RubySaml::Utils.element_text(REXML::XPath.first(@sig_element, "//ds:SignatureValue", {"ds"=>DSIG}))
111
- signature = Base64.decode64(base64_signature)
264
+ document = Nokogiri::XML(self.to_s) do |config|
265
+ config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
266
+ end
112
267
 
113
- # get certificate object
114
- cert_text = Base64.decode64(base64_cert)
115
- cert = OpenSSL::X509::Certificate.new(cert_text)
268
+ # create a rexml document
269
+ @working_copy ||= REXML::Document.new(self.to_s).root
270
+
271
+ # get signature node
272
+ sig_element = REXML::XPath.first(
273
+ @working_copy,
274
+ "//ds:Signature",
275
+ {"ds"=>DSIG}
276
+ )
277
+
278
+ if sig_element.nil?
279
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("No Signature Node"))
280
+ end
116
281
 
117
282
  # signature method
118
- signature_algorithm = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
283
+ sig_alg_value = REXML::XPath.first(
284
+ sig_element,
285
+ "./ds:SignedInfo/ds:SignatureMethod",
286
+ {"ds"=>DSIG}
287
+ )
288
+ signature_algorithm = algorithm(sig_alg_value)
289
+
290
+ # get signature
291
+ base64_signature = REXML::XPath.first(
292
+ sig_element,
293
+ "./ds:SignatureValue",
294
+ {"ds" => DSIG}
295
+ )
296
+
297
+ if base64_signature.nil?
298
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("SignatureValue not found"))
299
+ end
300
+
301
+ signature = Base64.decode64(OneLogin::RubySaml::Utils.element_text(base64_signature))
302
+
303
+ # canonicalization method
304
+ canon_algorithm = canon_algorithm REXML::XPath.first(
305
+ sig_element,
306
+ './ds:SignedInfo/ds:CanonicalizationMethod',
307
+ 'ds' => DSIG
308
+ )
309
+
310
+ noko_sig_element = document.at_xpath('//ds:Signature', 'ds' => DSIG)
311
+ noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
312
+
313
+ canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
314
+ noko_sig_element.remove
119
315
 
316
+ # get inclusive namespaces
317
+ inclusive_namespaces = extract_inclusive_namespaces
318
+
319
+ # check digests
320
+ ref = REXML::XPath.first(sig_element, "//ds:Reference", {"ds"=>DSIG})
321
+
322
+ hashed_element = document.at_xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
323
+
324
+ canon_algorithm = canon_algorithm REXML::XPath.first(
325
+ ref,
326
+ '//ds:CanonicalizationMethod',
327
+ { "ds" => DSIG }
328
+ )
329
+
330
+ canon_algorithm = process_transforms(ref, canon_algorithm)
331
+
332
+ canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces)
333
+
334
+ digest_algorithm = algorithm(REXML::XPath.first(
335
+ ref,
336
+ "//ds:DigestMethod",
337
+ { "ds" => DSIG }
338
+ ))
339
+ hash = digest_algorithm.digest(canon_hashed_element)
340
+ encoded_digest_value = REXML::XPath.first(
341
+ ref,
342
+ "//ds:DigestValue",
343
+ { "ds" => DSIG }
344
+ )
345
+ digest_value = Base64.decode64(OneLogin::RubySaml::Utils.element_text(encoded_digest_value))
346
+
347
+ unless digests_match?(hash, digest_value)
348
+ return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Digest mismatch"))
349
+ end
350
+
351
+ # get certificate object
352
+ cert_text = Base64.decode64(base64_cert)
353
+ cert = OpenSSL::X509::Certificate.new(cert_text)
354
+
355
+ # verify signature
120
356
  unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
121
357
  return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Key validation error"))
122
358
  end
@@ -126,43 +362,61 @@ module XMLSecurity
126
362
 
127
363
  private
128
364
 
365
+ def process_transforms(ref, canon_algorithm)
366
+ transforms = REXML::XPath.match(
367
+ ref,
368
+ "//ds:Transforms/ds:Transform",
369
+ { "ds" => DSIG }
370
+ )
371
+
372
+ transforms.each do |transform_element|
373
+ if transform_element.attributes && transform_element.attributes["Algorithm"]
374
+ algorithm = transform_element.attributes["Algorithm"]
375
+ case algorithm
376
+ when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
377
+ "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
378
+ canon_algorithm = Nokogiri::XML::XML_C14N_1_0
379
+ when "http://www.w3.org/2006/12/xml-c14n11",
380
+ "http://www.w3.org/2006/12/xml-c14n11#WithComments"
381
+ canon_algorithm = Nokogiri::XML::XML_C14N_1_1
382
+ when "http://www.w3.org/2001/10/xml-exc-c14n#",
383
+ "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
384
+ canon_algorithm = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
385
+ end
386
+ end
387
+ end
388
+
389
+ canon_algorithm
390
+ end
391
+
129
392
  def digests_match?(hash, digest_value)
130
393
  hash == digest_value
131
394
  end
132
395
 
133
396
  def extract_signed_element_id
134
- reference_element = REXML::XPath.first(self, "//ds:Signature/ds:SignedInfo/ds:Reference", {"ds"=>DSIG})
135
- self.signed_element_id = reference_element.attribute("URI").value[1..-1] unless reference_element.nil?
136
- end
397
+ reference_element = REXML::XPath.first(
398
+ self,
399
+ "//ds:Signature/ds:SignedInfo/ds:Reference",
400
+ {"ds"=>DSIG}
401
+ )
137
402
 
138
- def canon_algorithm(element)
139
- algorithm = element.attribute('Algorithm').value if element
140
- case algorithm
141
- when "http://www.w3.org/2001/10/xml-exc-c14n#" then Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
142
- when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then Nokogiri::XML::XML_C14N_1_0
143
- when "http://www.w3.org/2006/12/xml-c14n11" then Nokogiri::XML::XML_C14N_1_1
144
- else Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
145
- end
146
- end
403
+ return nil if reference_element.nil?
147
404
 
148
- def algorithm(element)
149
- algorithm = element.attribute("Algorithm").value if element
150
- algorithm = algorithm && algorithm =~ /sha(.*?)$/i && $1.to_i
151
- case algorithm
152
- when 256 then OpenSSL::Digest::SHA256
153
- when 384 then OpenSSL::Digest::SHA384
154
- when 512 then OpenSSL::Digest::SHA512
155
- else
156
- OpenSSL::Digest::SHA1
157
- end
405
+ sei = reference_element.attribute("URI").value[1..-1]
406
+ sei.nil? ? reference_element.parent.parent.parent.attribute("ID").value : sei
158
407
  end
159
408
 
160
409
  def extract_inclusive_namespaces
161
- if element = REXML::XPath.first(self, "//ec:InclusiveNamespaces", { "ec" => C14N })
410
+ element = REXML::XPath.first(
411
+ self,
412
+ "//ec:InclusiveNamespaces",
413
+ { "ec" => C14N }
414
+ )
415
+ if element
162
416
  prefix_list = element.attributes.get_attribute("PrefixList").value
163
417
  prefix_list.split(" ")
164
418
  else
165
- []
419
+ nil
166
420
  end
167
421
  end
168
422