xml_security 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/xml_security.rb CHANGED
@@ -25,10 +25,13 @@
25
25
  require 'rubygems'
26
26
  require 'ffi'
27
27
 
28
+ require 'xml_security/c/libc'
28
29
  require 'xml_security/c/lib_xml'
29
30
  require 'xml_security/c/xml_sec'
30
31
 
31
- require 'ruby-debug'
32
+ require 'time'
33
+ require 'base64'
34
+ require 'digest/sha1'
32
35
 
33
36
  module XMLSecurity
34
37
  NAMESPACES = {
@@ -103,11 +106,8 @@ module XMLSecurity
103
106
  C::XMLSec.xmlSecDSigCtxDestroy(digital_signature_context) if defined?(digital_signature_context) && !digital_signature_context.null?
104
107
  end
105
108
 
106
- def self.verify_signature(signed_xml_document, cert_fingerprint=nil)
109
+ def self.verify_signature(signed_xml_document, options={})
107
110
  init
108
- if cert_fingerprint
109
- return false unless _fingerprint_matches?(cert_fingerprint, cert)
110
- end
111
111
 
112
112
  doc = C::LibXML.xmlParseMemory(signed_xml_document, signed_xml_document.size)
113
113
  raise "could not parse XML document" if doc.null?
@@ -115,6 +115,12 @@ module XMLSecurity
115
115
  doc_root = C::LibXML.xmlDocGetRootElement(doc)
116
116
  raise "could not get doc root" if doc_root.null?
117
117
 
118
+ # add the ID attribute as an id. yeah, hacky
119
+ idary = FFI::MemoryPointer.new(:pointer, 2)
120
+ idary[0].put_pointer(0, FFI::MemoryPointer.from_string("ID"))
121
+ idary[1].put_pointer(0, nil)
122
+ C::XMLSec.xmlSecAddIDs(doc, doc_root, idary)
123
+
118
124
  keys_manager = _init_keys_manager
119
125
 
120
126
  digital_signature_context = C::XMLSec.xmlSecDSigCtxCreate(keys_manager)
@@ -126,26 +132,28 @@ module XMLSecurity
126
132
  signature_node = C::XMLSec.xmlSecFindNode(doc_root, C::XMLSec.xmlSecNodeSignature, C::XMLSec.xmlSecDSigNs)
127
133
  raise "signature node not found" if signature_node.null?
128
134
 
129
- key_info_node = C::XMLSec.xmlSecFindNode(signature_node, C::XMLSec.xmlSecNodeKeyInfo, C::XMLSec.xmlSecDSigNs)
130
- raise "key_info node not found" if key_info_node.null?
131
-
132
135
  certificate_node = C::XMLSec.xmlSecFindNode(signature_node, C::XMLSec.xmlSecNodeX509Certificate, C::XMLSec.xmlSecDSigNs)
133
136
  raise "certificate node not found" if certificate_node.null?
134
137
 
135
138
  key = C::XMLSec.xmlSecKeyCreate
136
139
  raise "error while allocating security key" if key.null?
137
140
 
138
- certptr = C::LibXML.xmlNodeGetContent(certificate_node)
139
- raise "error while reading certificate node" if certptr.null?
140
- cert64 = certptr.read_string
141
- # C::LibXML.xmlFree(certptr)
141
+ cert64ptr = C::LibXML.xmlNodeGetContent(certificate_node)
142
+ raise "error while reading certificate node" if cert64ptr.null?
143
+ cert64 = cert64ptr.read_string
144
+ C::LibXML.xmlFree(cert64ptr)
142
145
 
143
- certptr = FFI::MemoryPointer.new(:uchar, cert64.size)
146
+ cert = Base64.decode64(cert64)
144
147
 
145
- bytesout = C::XMLSec.xmlSecBase64Decode(cert64, certptr, certptr.size)
146
- cert = certptr.read_bytes(bytesout)
148
+ if options.has_key? :cert_fingerprint
149
+ return false unless _fingerprint_matches?(options[:cert_fingerprint], cert)
150
+ end
147
151
 
148
- key_add_result = C::XMLSec.xmlSecOpenSSLAppKeysMngrCertLoadMemory(keys_manager, cert, cert.size, :xmlSecKeyDataFormatDer, C::XMLSec.xmlSecKeyDataTypeTrusted)
152
+ if options.has_key? :as_of
153
+ digital_signature_context[:keyInfoReadCtx][:certsVerificationTime] = Time.parse(options[:as_of]).to_i
154
+ end
155
+
156
+ key_add_result = C::XMLSec.xmlSecOpenSSLAppKeysMngrCertLoadMemory(keys_manager, cert, cert.size, :xmlSecKeyDataFormatCertDer, C::XMLSec.xmlSecKeyDataTypeTrusted)
149
157
  raise "failed to add key to keys manager" if key_add_result < 0
150
158
 
151
159
  if C::XMLSec.xmlSecDSigCtxVerify(digital_signature_context, signature_node) < 0
@@ -190,6 +198,12 @@ module XMLSecurity
190
198
  _dump_doc(doc)
191
199
  end
192
200
 
201
+ def self.mute(&block)
202
+ C::XMLSec.xmlSecErrorsDefaultCallbackEnableOutput(false)
203
+ block.call
204
+ C::XMLSec.xmlSecErrorsDefaultCallbackEnableOutput(true)
205
+ end
206
+
193
207
  def self._init_keys_manager
194
208
  keys_manager = C::XMLSec.xmlSecKeysMngrCreate
195
209
  raise "failed to create keys manager" if keys_manager.null?
@@ -201,37 +215,10 @@ module XMLSecurity
201
215
  keys_manager
202
216
  end
203
217
 
204
- def self._format_cert(cert)
205
- # re-encode the certificate in the proper format
206
- # this snippet is from http://bugs.ruby-lang.org/issues/4421
207
- rsa = cert.public_key
208
- modulus = rsa.n
209
- exponent = rsa.e
210
- oid = OpenSSL::ASN1::ObjectId.new("rsaEncryption")
211
- alg_id = OpenSSL::ASN1::Sequence.new([oid, OpenSSL::ASN1::Null.new(nil)])
212
- ary = [OpenSSL::ASN1::Integer.new(modulus), OpenSSL::ASN1::Integer.new(exponent)]
213
- pub_key = OpenSSL::ASN1::Sequence.new(ary)
214
- enc_pk = OpenSSL::ASN1::BitString.new(pub_key.to_der)
215
- subject_pk_info = OpenSSL::ASN1::Sequence.new([alg_id, enc_pk])
216
- base64 = Base64.encode64(subject_pk_info.to_der)
217
-
218
- # This is the equivalent to the X.509 encoding used in >= 1.9.3
219
- "-----BEGIN PUBLIC KEY-----\n#{base64}-----END PUBLIC KEY-----"
220
- end
221
-
222
-
223
218
  def self._fingerprint_matches?(expected_fingerprint, cert)
224
- cert_fingerprint = Digest::SHA1.hexdigest(cert.to_der)
225
- expected_fingerprint = idp_cert_fingerprint.gsub(":", "").downcase
226
- return fingerprint == expected_fingerprint
227
- end
228
-
229
- def self._extract_embedded_certificate(xml_document)
230
- parsed_document = LibXML::XML::Parser.string(xml_document).parse
231
- base64_cert = parsed_document.find_first("//ds:X509Certificate", NAMESPACES).content
232
- cert_text = Base64.decode64(base64_cert)
233
- cert = OpenSSL::X509::Certificate.new(cert_text)
234
- cert
219
+ cert_fingerprint = Digest::SHA1.hexdigest(cert)
220
+ expected_fingerprint = expected_fingerprint.gsub(":", "").downcase
221
+ return cert_fingerprint == expected_fingerprint
235
222
  end
236
223
 
237
224
  def self._dump_doc(doc)
@@ -1,12 +1,30 @@
1
- require 'ffi'
2
- require 'ffi/libc'
3
-
4
1
  module XMLSecurity
5
2
  module C
6
3
  module LibXML
7
4
  extend FFI::Library
8
5
  ffi_lib 'libxml2'
9
6
 
7
+ class XmlNode < FFI::Struct
8
+ layout \
9
+ :_private, :pointer,
10
+ :type, :int, # <- cheating, actually an xmlElementType enum
11
+ :name, :string,
12
+ :children, XmlNode.by_ref,
13
+ :last, :pointer,
14
+ :parent, :pointer,
15
+ :next, :pointer,
16
+ :prev, :pointer,
17
+ :doc, :pointer,
18
+
19
+ :ns, :pointer,
20
+ :content, :string,
21
+ :properties, :pointer,
22
+ :nsDef, :pointer,
23
+ :psvi, :pointer,
24
+ :line, :ushort,
25
+ :extra, :ushort
26
+ end
27
+
10
28
  # libxml functions
11
29
  attach_function :xmlInitParser, [], :void
12
30
  attach_function :xmlDocGetRootElement, [ :pointer ], :pointer
@@ -29,11 +47,11 @@ module XMLSecurity
29
47
  # attach_function :xmlMalloc, [ :int ], :pointer
30
48
 
31
49
  def self.xmlMalloc(*args)
32
- FFI::LibC.malloc(*args)
50
+ C::LibC.malloc(*args)
33
51
  end
34
52
 
35
53
  def self.xmlFree(*args)
36
- FFI::LibC.free(*args)
54
+ C::LibC.free(*args)
37
55
  end
38
56
 
39
57
  def self.init
@@ -0,0 +1,11 @@
1
+ module XMLSecurity
2
+ module C
3
+ module LibC
4
+ extend FFI::Library
5
+ ffi_lib [FFI::CURRENT_PROCESS, 'c']
6
+
7
+ attach_function :malloc, [:size_t], :pointer
8
+ attach_function :free, [:pointer], :void
9
+ end
10
+ end
11
+ end
@@ -147,7 +147,7 @@ module XMLSecurity
147
147
  :signMethod, :pointer, # xmlSecTransformPtr
148
148
  :c14nMethod, :pointer, # xmlSecTransformPtr
149
149
  :preSignMemBufMethod, :pointer, # xmlSecTransformPtr
150
- :signValueNode, :pointer, # xmlNodePtr
150
+ :signValueNode, LibXML::XmlNode.by_ref, # xmlNodePtr
151
151
  :id, :string,
152
152
  :signedInfoReferences, XmlSecPtrList,
153
153
  :manifestReferences, XmlSecPtrList,
@@ -158,7 +158,7 @@ module XMLSecurity
158
158
  # xmlsec functions
159
159
  attach_function :xmlSecInit, [], :int
160
160
  attach_function :xmlSecParseMemory, [ :pointer, :uint, :int ], :pointer
161
- attach_function :xmlSecFindNode, [ :pointer, :string, :string ], :pointer
161
+ attach_function :xmlSecFindNode, [ :pointer, :string, :string ], LibXML::XmlNode.by_ref
162
162
  attach_function :xmlSecFindChild, [ :pointer, :string, :string ], :pointer
163
163
  attach_function :xmlSecDSigCtxCreate, [ :pointer ], XmlSecDSigCtx.by_ref
164
164
  attach_function :xmlSecDSigCtxVerify, [ XmlSecDSigCtx.by_ref, :pointer ], :int
@@ -209,7 +209,10 @@ module XMLSecurity
209
209
 
210
210
  attach_function :xmlSecShutdown, [], :void
211
211
 
212
+ attach_function :xmlSecErrorsDefaultCallbackEnableOutput, [ :bool ], :void
213
+
212
214
  XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS = 0x00000200
215
+ XMLSEC_KEYINFO_FLAGS_X509DATA_SKIP_STRICT_CHECKS = 0x00004000
213
216
 
214
217
  def self.xmlSecNodeSignature
215
218
  'Signature'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xml_security
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-06 00:00:00.000000000 Z
12
+ date: 2013-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
@@ -27,38 +27,6 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: ruby-debug
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: rspec
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - '='
52
- - !ruby/object:Gem::Version
53
- version: 1.3.2
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - '='
60
- - !ruby/object:Gem::Version
61
- version: 1.3.2
62
30
  description: See http://github.com/phinze/xml_security
63
31
  email: paul.t.hinze@gmail.com
64
32
  executables: []
@@ -67,6 +35,7 @@ extra_rdoc_files: []
67
35
  files:
68
36
  - README.md
69
37
  - lib/xml_security/c/lib_xml.rb
38
+ - lib/xml_security/c/libc.rb
70
39
  - lib/xml_security/c/xml_sec.rb
71
40
  - lib/xml_security.rb
72
41
  homepage: http://github.com/phinze/xml_security