xml_security 0.0.1 → 0.0.3

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.
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