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.
- data/Gemfile +11 -1
- data/Rakefile +0 -14
- data/lib/onelogin/ruby-saml/authrequest.rb +84 -18
- data/lib/onelogin/ruby-saml/logoutrequest.rb +93 -18
- data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -24
- data/lib/onelogin/ruby-saml/response.rb +206 -11
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +73 -12
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
- data/lib/onelogin/ruby-saml/utils.rb +169 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +2 -1
- data/lib/xml_security.rb +332 -78
- data/test/certificates/ruby-saml-2.crt +15 -0
- data/test/certificates/ruby-saml.crt +14 -0
- data/test/certificates/ruby-saml.key +15 -0
- data/test/logoutrequest_test.rb +177 -44
- data/test/logoutresponse_test.rb +23 -28
- data/test/request_test.rb +100 -37
- data/test/response_test.rb +337 -129
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/encrypted_new_attack.xml.base64 +1 -0
- data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
- data/test/responses/invalids/no_signature.xml.base64 +1 -0
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
- data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/response_with_signed_assertion_3.xml +30 -0
- data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
- data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
- data/test/responses/response_wrapped.xml.base64 +150 -0
- data/test/responses/valid_response.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +5 -5
- data/test/slo_logoutresponse_test.rb +226 -0
- data/test/test_helper.rb +117 -12
- data/test/utils_test.rb +10 -10
- data/test/xml_security_test.rb +354 -68
- metadata +64 -18
- checksums.yaml +0 -7
data/lib/ruby-saml.rb
CHANGED
@@ -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'
|
data/lib/xml_security.rb
CHANGED
@@ -34,89 +34,325 @@ require "onelogin/ruby-saml/utils"
|
|
34
34
|
|
35
35
|
module XMLSecurity
|
36
36
|
|
37
|
-
class
|
38
|
-
|
39
|
-
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
37
|
+
class BaseDocument < REXML::Document
|
38
|
+
REXML::Document::entity_expansion_limit = 0
|
40
39
|
|
41
|
-
|
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
|
44
|
-
|
45
|
-
|
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
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
57
|
-
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
|
69
|
+
algorithm = algorithm && algorithm =~ /(rsa-)?sha(.*?)$/i && $2.to_i
|
58
70
|
|
59
|
-
|
60
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
127
|
+
# Add Reference
|
128
|
+
reference_element = signed_info_element.add_element("ds:Reference", {"URI" => "##{uuid}"})
|
73
129
|
|
74
|
-
#
|
75
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
85
|
-
|
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
|
-
#
|
93
|
-
|
94
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
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
|
-
|
103
|
-
|
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
|
-
|
106
|
-
|
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
|
-
|
111
|
-
|
264
|
+
document = Nokogiri::XML(self.to_s) do |config|
|
265
|
+
config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
|
266
|
+
end
|
112
267
|
|
113
|
-
#
|
114
|
-
|
115
|
-
|
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
|
-
|
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
|
135
|
-
|
136
|
-
|
397
|
+
reference_element = REXML::XPath.first(
|
398
|
+
self,
|
399
|
+
"//ds:Signature/ds:SignedInfo/ds:Reference",
|
400
|
+
{"ds"=>DSIG}
|
401
|
+
)
|
137
402
|
|
138
|
-
|
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
|
-
|
149
|
-
|
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
|
-
|
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
|
|