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 +33 -46
- data/lib/xml_security/c/lib_xml.rb +23 -5
- data/lib/xml_security/c/libc.rb +11 -0
- data/lib/xml_security/c/xml_sec.rb +5 -2
- metadata +3 -34
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 '
|
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,
|
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
|
-
|
139
|
-
raise "error while reading certificate node" if
|
140
|
-
cert64 =
|
141
|
-
|
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
|
-
|
146
|
+
cert = Base64.decode64(cert64)
|
144
147
|
|
145
|
-
|
146
|
-
|
148
|
+
if options.has_key? :cert_fingerprint
|
149
|
+
return false unless _fingerprint_matches?(options[:cert_fingerprint], cert)
|
150
|
+
end
|
147
151
|
|
148
|
-
|
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
|
225
|
-
expected_fingerprint =
|
226
|
-
return
|
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
|
-
|
50
|
+
C::LibC.malloc(*args)
|
33
51
|
end
|
34
52
|
|
35
53
|
def self.xmlFree(*args)
|
36
|
-
|
54
|
+
C::LibC.free(*args)
|
37
55
|
end
|
38
56
|
|
39
57
|
def self.init
|
@@ -147,7 +147,7 @@ module XMLSecurity
|
|
147
147
|
:signMethod, :pointer, # xmlSecTransformPtr
|
148
148
|
:c14nMethod, :pointer, # xmlSecTransformPtr
|
149
149
|
:preSignMemBufMethod, :pointer, # xmlSecTransformPtr
|
150
|
-
:signValueNode,
|
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 ],
|
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.
|
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-
|
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
|