xml_security 0.0.1

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/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # XML may not be fun, but at least we can make it secure!
2
+
3
+ [![Build Status](https://travis-ci.org/phinze/xml_security.png?branch=master)](https://travis-ci.org/phinze/xml_security)
4
+
5
+ ```xml
6
+ <secrets keep-them="safe" with="xml!" />
7
+ ```
8
+
9
+ You too can enjoy all the glory of `xmlsec` brought to your ruby runtime!
10
+
11
+ This library is being built with an eye towards building it in a proper SAML
12
+ integration on a Ruby-based platform.
13
+
14
+ ## Working features
15
+
16
+ * Basic XML Document Signing
17
+ * Basic XML Signature Verification
18
+ * Basic XML Document Decryption
19
+
20
+ ## Lots left to do!
21
+
22
+ * XML Encryption
23
+ * Non-happy-path testing.
24
+ * Memory leak squashing.
25
+ * Testing with a SAML-layer library
26
+ * We'll need TONS of cleanup at the Ruby/C API layer. Goal is to connect the dots, then make the constellations beautiful.
27
+
28
+ ## References
29
+
30
+ * Using FFI for ruby/c interop: https://github.com/ffi/ffi.git
31
+ * Wrapping XMLSec: http://www.aleksey.com/xmlsec/
32
+ * XMLSec also used libXML2: http://www.xmlsoft.org/
33
+
@@ -0,0 +1,48 @@
1
+ require 'ffi'
2
+ require 'ffi/libc'
3
+
4
+ module XMLSecurity
5
+ module C
6
+ module LibXML
7
+ extend FFI::Library
8
+ ffi_lib 'libxml2'
9
+
10
+ # libxml functions
11
+ attach_function :xmlInitParser, [], :void
12
+ attach_function :xmlDocGetRootElement, [ :pointer ], :pointer
13
+ attach_function :xmlDocDumpFormatMemory, [ :pointer, :pointer, :pointer, :int ], :void
14
+ attach_function :xmlFreeDoc, [ :pointer ], :void
15
+ attach_function :xmlParseFile, [ :string ], :pointer
16
+ attach_function :xmlParseMemory, [ :pointer, :int ], :pointer
17
+ attach_function :xmlAddChild, [ :pointer, :pointer ], :pointer
18
+ attach_function :xmlCleanupParser, [], :void
19
+ attach_function :xmlNodeGetContent, [ :pointer ], :pointer # xmlChar *
20
+
21
+ #
22
+ # Patching over to straight libc malloc/free until we can figure out why
23
+ # xml{Malloc,Free} cause ruby to blow up so spectacularly. See the
24
+ # following thread for more info:
25
+ #
26
+ # https://groups.google.com/d/topic/ruby-ffi/wClez3YsLQE/discussion
27
+ #
28
+ # attach_function :xmlFree, [ :pointer ], :void
29
+ # attach_function :xmlMalloc, [ :int ], :pointer
30
+
31
+ def self.xmlMalloc(*args)
32
+ FFI::LibC.malloc(*args)
33
+ end
34
+
35
+ def self.xmlFree(*args)
36
+ FFI::LibC.free(*args)
37
+ end
38
+
39
+ def self.init
40
+ xmlInitParser
41
+ end
42
+
43
+ def self.shutdown
44
+ xmlCleanupParser
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,259 @@
1
+ require 'ffi'
2
+
3
+ module XMLSecurity
4
+ module C
5
+ module XMLSec
6
+ extend FFI::Library
7
+ ffi_lib_flags :now, :global
8
+ ffi_lib 'xmlsec1-openssl'
9
+
10
+ enum :xmlSecKeyDataFormat, [
11
+ :xmlSecKeyDataFormatUnknown,
12
+ :xmlSecKeyDataFormatBinary,
13
+ :xmlSecKeyDataFormatPem,
14
+ :xmlSecKeyDataFormatDer,
15
+ :xmlSecKeyDataFormatPkcs8Pem,
16
+ :xmlSecKeyDataFormatPkcs8Der,
17
+ :xmlSecKeyDataFormatPkcs12,
18
+ :xmlSecKeyDataFormatCertPem,
19
+ :xmlSecKeyDataFormatCertDer
20
+ ]
21
+
22
+ enum :xmlSecKeyInfoMode, [
23
+ :xmlSecKeyInfoModeRead,
24
+ :xmlSecKeyInfoModeWrite
25
+ ]
26
+
27
+ enum :xmlSecAllocMode, [
28
+ :xmlSecAllocModeExact,
29
+ :xmlSecAllocModeDouble
30
+ ]
31
+
32
+ enum :xmlSecTransformStatus, [
33
+ :xmlSecTransformStatusNone,
34
+ :xmlSecTransformStatusWorking,
35
+ :xmlSecTransformStatusFinished,
36
+ :xmlSecTransformStatusOk,
37
+ :xmlSecTransformStatusFail
38
+ ]
39
+
40
+ enum :xmlSecTransformOperation, [
41
+ :xmlSecTransformOperationNone, 0,
42
+ :xmlSecTransformOperationEncode,
43
+ :xmlSecTransformOperationDecode,
44
+ :xmlSecTransformOperationSign,
45
+ :xmlSecTransformOperationVerify,
46
+ :xmlSecTransformOperationEncrypt,
47
+ :xmlSecTransformOperationDecrypt
48
+ ]
49
+
50
+ enum :xmlSecDSigStatus, [
51
+ :xmlSecDSigStatusUnknown, 0,
52
+ :xmlSecDSigStatusSucceeded,
53
+ :xmlSecDSigStatusInvalid
54
+ ]
55
+
56
+ class XmlSecPtrList < FFI::Struct
57
+ layout \
58
+ :id, :string,
59
+ :data, :pointer, # xmlSecPtr*
60
+ :use, :uint,
61
+ :max, :uint,
62
+ :allocMode, :xmlSecAllocMode
63
+ end
64
+
65
+ class XmlSecKeyReq < FFI::Struct
66
+ layout \
67
+ :keyId, :string, # xmlSecKeyDataId
68
+ :keyType, :uint, # xmlSecKeyDataType
69
+ :keyUsage, :uint, # xmlSecKeyUsage
70
+ :keyBitsSize, :uint, # xmlSecSize
71
+ :keyUseWithList, XmlSecPtrList,
72
+ :reserved1, :pointer, # void *
73
+ :reserved2, :pointer # void *
74
+ end
75
+
76
+ class XmlSecTransformCtx < FFI::Struct
77
+ layout \
78
+ :userData, :pointer, # void *
79
+ :flags, :uint,
80
+ :flags2, :uint,
81
+ :enabledUris, :uint,
82
+ :enabledTransforms, XmlSecPtrList,
83
+ :preExecCallback, :pointer, # xmlSecTransformCtxPreExecuteCallback
84
+ :result, :pointer, # xmlSecBufferPtr
85
+ :status, :xmlSecTransformStatus,
86
+ :uri, :string,
87
+ :xptrExpr, :string,
88
+ :first, :pointer, # xmlSecTransformPtr
89
+ :last, :pointer, # xmlSecTransformPtr
90
+ :reserved0, :pointer, # void *
91
+ :reserved1, :pointer # void *
92
+ end
93
+
94
+ class XmlSecKeyInfoCtx < FFI::Struct
95
+ layout \
96
+ :userDate, :pointer,
97
+ :flags, :uint,
98
+ :flags2, :uint,
99
+ :keysMngr, :pointer,
100
+ :mode, :xmlSecKeyInfoMode,
101
+ :enabledKeyData, XmlSecPtrList,
102
+ :base64LineSize, :int,
103
+ :retrievalMethodCtx, XmlSecTransformCtx,
104
+ :maxRetrievalMethodLevel, :int,
105
+ :encCtx, :pointer,
106
+ :maxEncryptedKeyLevel, :int,
107
+ :certsVerificationTime, :time_t,
108
+ :certsVerificationDepth, :int,
109
+ :pgpReserved, :pointer,
110
+ :curRetrievalMethodLevel, :int,
111
+ :curEncryptedKeyLevel, :int,
112
+ :keyReq, XmlSecKeyReq,
113
+ :reserved0, :pointer,
114
+ :reserved1, :pointer
115
+ end
116
+
117
+ # Would like to use this eventually, but something is wrong below; get segfaults when trying to use it.
118
+ class XmlSecKeyPtr < FFI::Struct
119
+ layout \
120
+ :name, :string, # xmlChar *
121
+ :value, :pointer, # xmlSecKeyDataPtr
122
+ :dataList, :pointer, # xmlSecPtrListPtr
123
+ :usage, :pointer, # xmlSecKeyUsage
124
+ :notValidBefore, :pointer, # time_t
125
+ :notValidAfter, :pointer # time_t
126
+ end
127
+
128
+ class XmlSecDSigCtx < FFI::Struct
129
+ layout \
130
+ :userData, :pointer, # void *
131
+ :flags, :uint,
132
+ :flags2, :uint,
133
+ :keyInfoReadCtx, XmlSecKeyInfoCtx.by_value,
134
+ :keyInfoWriteCtx, XmlSecKeyInfoCtx.by_value,
135
+ :transformCtx, XmlSecTransformCtx.by_value,
136
+ :enabledReferenceUris, :uint, # xmlSecTransformUriType
137
+ :enabledReferenceTransforms, :pointer, # xmlSecPtrListPtr
138
+ :referencePreExecuteCallback, :pointer, # xmlSecTransformCtxPreExecuteCallback
139
+ :defSignMethodId, :string, # xmlSecTransformId
140
+ :defC14NMethodId, :string, # xmlSecTransformId
141
+ :defDigestMethodId, :string, # xmlSecTransformId
142
+
143
+ :signKey, :pointer, # xmlSecKeyPtr
144
+ :operation, :xmlSecTransformOperation,
145
+ :result, :pointer, # xmlSecBufferPtr
146
+ :status, :xmlSecDSigStatus,
147
+ :signMethod, :pointer, # xmlSecTransformPtr
148
+ :c14nMethod, :pointer, # xmlSecTransformPtr
149
+ :preSignMemBufMethod, :pointer, # xmlSecTransformPtr
150
+ :signValueNode, :pointer, # xmlNodePtr
151
+ :id, :string,
152
+ :signedInfoReferences, XmlSecPtrList,
153
+ :manifestReferences, XmlSecPtrList,
154
+ :reserved0, :pointer,
155
+ :reserved1, :pointer
156
+ end
157
+
158
+ # xmlsec functions
159
+ attach_function :xmlSecInit, [], :int
160
+ attach_function :xmlSecParseMemory, [ :pointer, :uint, :int ], :pointer
161
+ attach_function :xmlSecFindNode, [ :pointer, :string, :string ], :pointer
162
+ attach_function :xmlSecFindChild, [ :pointer, :string, :string ], :pointer
163
+ attach_function :xmlSecDSigCtxCreate, [ :pointer ], XmlSecDSigCtx.by_ref
164
+ attach_function :xmlSecDSigCtxVerify, [ XmlSecDSigCtx.by_ref, :pointer ], :int
165
+ attach_function :xmlSecOpenSSLInit, [], :int
166
+ attach_function :xmlSecOpenSSLShutdown, [], :int
167
+ attach_function :xmlSecOpenSSLAppShutdown, [], :int
168
+ attach_function :xmlSecOpenSSLAppInit, [ :pointer ], :int
169
+ attach_function :xmlSecAddIDs, [ :pointer, :pointer, :pointer ], :void
170
+ attach_function :xmlSecDSigCtxDestroy, [ XmlSecDSigCtx.by_ref ], :void
171
+
172
+ attach_function :xmlSecKeysMngrCreate, [], :pointer
173
+ attach_function :xmlSecOpenSSLAppDefaultKeysMngrInit, [ :pointer ], :int
174
+ attach_function :xmlSecOpenSSLAppKeyLoad, [ :string, :xmlSecKeyDataFormat, :pointer, :pointer, :pointer ], :pointer
175
+ attach_function :xmlSecOpenSSLAppKeyLoadMemory, [ :pointer, :uint, :xmlSecKeyDataFormat, :pointer, :pointer, :pointer ], :pointer
176
+ attach_function :xmlSecOpenSSLAppKeysMngrCertLoadMemory, [ :pointer, :pointer, :uint, :xmlSecKeyDataFormat, :uint ], :int
177
+
178
+ attach_function :xmlSecOpenSSLAppDefaultKeysMngrAdoptKey, [ :pointer, :pointer ], :int
179
+ attach_function :xmlSecKeysMngrDestroy, [ :pointer ], :void
180
+
181
+ attach_function :xmlSecEncCtxCreate, [ :pointer ], :pointer
182
+ attach_function :xmlSecEncCtxDecrypt, [ :pointer, :pointer ], :int
183
+ attach_function :xmlSecEncCtxDestroy, [ :pointer ], :void
184
+
185
+ attach_function :xmlSecTmplSignatureCreate, [ :pointer, :pointer, :pointer, :string ], :pointer
186
+ attach_function :xmlSecTmplSignatureAddReference, [ :pointer, :pointer, :pointer, :pointer, :pointer ], :pointer
187
+
188
+ attach_function :xmlSecTransformExclC14NGetKlass, [], :pointer
189
+ attach_function :xmlSecOpenSSLTransformRsaSha1GetKlass, [], :pointer
190
+ attach_function :xmlSecOpenSSLTransformSha1GetKlass, [], :pointer
191
+ attach_function :xmlSecTransformEnvelopedGetKlass, [], :pointer
192
+ attach_function :xmlSecTmplSignatureEnsureKeyInfo, [ :pointer, :pointer ], :pointer
193
+
194
+ attach_function :xmlSecTmplReferenceAddTransform, [ :pointer, :pointer ], :pointer
195
+
196
+ attach_function :xmlSecKeySetName, [ :pointer, :string ], :int
197
+
198
+ attach_function :xmlSecDSigCtxSign, [ :pointer, :pointer ], :int
199
+
200
+ attach_function :xmlSecTmplKeyInfoAddKeyName, [ :pointer, :pointer ], :pointer
201
+ attach_function :xmlSecKeyInfoCtxCreate, [ :pointer ], XmlSecKeyInfoCtx.by_ref
202
+ attach_function :xmlSecKeyInfoCtxDestroy, [ XmlSecKeyInfoCtx.by_ref ], :void
203
+ attach_function :xmlSecKeyInfoNodeRead, [ :pointer, :pointer, :pointer ], :int
204
+
205
+ attach_function :xmlSecKeyCreate, [], :pointer
206
+ attach_function :xmlSecKeyDestroy, [ :pointer ], :void
207
+
208
+ attach_function :xmlSecBase64Decode, [ :pointer, :pointer, :uint ], :int
209
+
210
+ attach_function :xmlSecShutdown, [], :void
211
+
212
+ XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS = 0x00000200
213
+
214
+ def self.xmlSecNodeSignature
215
+ 'Signature'
216
+ end
217
+
218
+ def self.xmlSecNodeKeyInfo
219
+ 'KeyInfo'
220
+ end
221
+
222
+ def self.xmlSecNodeX509Certificate
223
+ 'X509Certificate'
224
+ end
225
+
226
+ def self.xmlSecDSigNs
227
+ 'http://www.w3.org/2000/09/xmldsig#'
228
+ end
229
+
230
+ def self.xmlSecEncNs
231
+ 'http://www.w3.org/2001/04/xmlenc#'
232
+ end
233
+
234
+ def self.xmlSecKeyDataTypeTrusted
235
+ 0x0100
236
+ end
237
+
238
+ def self.xmlSecNodeEncryptedData
239
+ 'EncryptedData'
240
+ end
241
+
242
+ def self.xmlSecNodeX509Certificate
243
+ 'X509Certificate'
244
+ end
245
+
246
+ def self.init
247
+ raise "Failed initializing XMLSec" if xmlSecInit < 0
248
+ raise "Failed initializing app crypto" if xmlSecOpenSSLAppInit(nil) < 0
249
+ raise "Failed initializing crypto" if xmlSecOpenSSLInit < 0
250
+ end
251
+
252
+ def self.shutdown
253
+ xmlSecOpenSSLShutdown
254
+ xmlSecOpenSSLAppShutdown
255
+ xmlSecShutdown
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,250 @@
1
+ # The contents of this file are subject to the terms
2
+ # of the Common Development and Distribution License
3
+ # (the License). You may not use this file except in
4
+ # compliance with the License.
5
+ #
6
+ # You can obtain a copy of the License at
7
+ # https://opensso.dev.java.net/public/CDDLv1.0.html or
8
+ # opensso/legal/CDDLv1.0.txt
9
+ # See the License for the specific language governing
10
+ # permission and limitations under the License.
11
+ #
12
+ # When distributing Covered Code, include this CDDL
13
+ # Header Notice in each file and include the License file
14
+ # at opensso/legal/CDDLv1.0.txt.
15
+ # If applicable, add the following below the CDDL Header,
16
+ # with the fields enclosed by brackets [] replaced by
17
+ # your own identifying information:
18
+ # "Portions Copyrighted [year] [name of copyright owner]"
19
+ #
20
+ # $Id: xml_sec.rb,v 1.6 2007/10/24 00:28:41 todddd Exp $
21
+ #
22
+ # Copyright 2007 Sun Microsystems Inc. All Rights Reserved
23
+ # Portions Copyrighted 2007 Todd W Saxton.
24
+ #
25
+ require 'rubygems'
26
+ require 'ffi'
27
+
28
+ require 'xml_security/c/lib_xml'
29
+ require 'xml_security/c/xml_sec'
30
+
31
+ require 'ruby-debug'
32
+
33
+ module XMLSecurity
34
+ NAMESPACES = {
35
+ "xenc" => "http://www.w3.org/2001/04/xmlenc#",
36
+ "ds" => "http://www.w3.org/2000/09/xmldsig#"
37
+ }
38
+
39
+ def self.init
40
+ unless initialized?
41
+ C::LibXML.init
42
+ C::XMLSec.init
43
+ @initialized = true
44
+ end
45
+ end
46
+
47
+ def self.shutdown
48
+ if initialized?
49
+ C::XMLSec.shutdown
50
+ C::LibXML.shutdown
51
+ @initialized = false
52
+ end
53
+ end
54
+
55
+ def self.initialized?
56
+ !!@initialized
57
+ end
58
+
59
+ def self.sign(xml_document, private_key)
60
+ init
61
+
62
+ doc = C::LibXML.xmlParseMemory(xml_document, xml_document.size)
63
+ raise "could not parse XML document" if doc.null?
64
+
65
+ canonicalization_method_id = C::XMLSec.xmlSecTransformExclC14NGetKlass
66
+ sign_method_id = C::XMLSec.xmlSecOpenSSLTransformRsaSha1GetKlass
67
+
68
+ sign_node = C::XMLSec.xmlSecTmplSignatureCreate(doc, canonicalization_method_id, sign_method_id, nil)
69
+
70
+ raise "failed to create signature template" if sign_node.null?
71
+ C::LibXML.xmlAddChild(C::LibXML.xmlDocGetRootElement(doc), sign_node)
72
+
73
+ ref_node = C::XMLSec.xmlSecTmplSignatureAddReference(sign_node, C::XMLSec.xmlSecOpenSSLTransformSha1GetKlass, nil, nil, nil)
74
+ raise "failed to add a reference" if ref_node.null?
75
+
76
+ envelope_result = C::XMLSec.xmlSecTmplReferenceAddTransform(ref_node, C::XMLSec.xmlSecTransformEnvelopedGetKlass)
77
+ raise "failed to add envelope transform to reference" if envelope_result.null?
78
+
79
+ key_info_node = C::XMLSec.xmlSecTmplSignatureEnsureKeyInfo(sign_node, nil)
80
+ raise "failed to add key info" if key_info_node.null?
81
+
82
+ digital_signature_context = C::XMLSec.xmlSecDSigCtxCreate(nil)
83
+ raise "failed to create signature context" if digital_signature_context.null?
84
+
85
+ digital_signature_context[:signKey] = C::XMLSec.xmlSecOpenSSLAppKeyLoad(private_key, :xmlSecKeyDataFormatPem, nil, nil, nil)
86
+ raise "failed to load private pem ley from #{private_key}" if digital_signature_context[:signKey].null?
87
+
88
+ if C::XMLSec.xmlSecKeySetName(digital_signature_context[:signKey], File.basename(private_key)) < 0
89
+ raise "failed to set key name for key of #{private_key}"
90
+ end
91
+
92
+ if C::XMLSec.xmlSecTmplKeyInfoAddKeyName(key_info_node, nil).null?
93
+ raise "failed to add key info"
94
+ end
95
+
96
+ if C::XMLSec.xmlSecDSigCtxSign(digital_signature_context, sign_node) < 0
97
+ raise "signature failed!"
98
+ end
99
+
100
+ _dump_doc(doc)
101
+ ensure
102
+ C::LibXML.xmlFreeDoc(doc) if defined?(doc) && !doc.null?
103
+ C::XMLSec.xmlSecDSigCtxDestroy(digital_signature_context) if defined?(digital_signature_context) && !digital_signature_context.null?
104
+ end
105
+
106
+ def self.verify_signature(signed_xml_document, cert_fingerprint=nil)
107
+ init
108
+ if cert_fingerprint
109
+ return false unless _fingerprint_matches?(cert_fingerprint, cert)
110
+ end
111
+
112
+ doc = C::LibXML.xmlParseMemory(signed_xml_document, signed_xml_document.size)
113
+ raise "could not parse XML document" if doc.null?
114
+
115
+ doc_root = C::LibXML.xmlDocGetRootElement(doc)
116
+ raise "could not get doc root" if doc_root.null?
117
+
118
+ keys_manager = _init_keys_manager
119
+
120
+ digital_signature_context = C::XMLSec.xmlSecDSigCtxCreate(keys_manager)
121
+ raise "failed to create signature context" if digital_signature_context.null?
122
+
123
+ key_info_context = C::XMLSec.xmlSecKeyInfoCtxCreate(keys_manager)
124
+ raise "could not create key info context" if key_info_context.null?
125
+
126
+ signature_node = C::XMLSec.xmlSecFindNode(doc_root, C::XMLSec.xmlSecNodeSignature, C::XMLSec.xmlSecDSigNs)
127
+ raise "signature node not found" if signature_node.null?
128
+
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
+ certificate_node = C::XMLSec.xmlSecFindNode(signature_node, C::XMLSec.xmlSecNodeX509Certificate, C::XMLSec.xmlSecDSigNs)
133
+ raise "certificate node not found" if certificate_node.null?
134
+
135
+ key = C::XMLSec.xmlSecKeyCreate
136
+ raise "error while allocating security key" if key.null?
137
+
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)
142
+
143
+ certptr = FFI::MemoryPointer.new(:uchar, cert64.size)
144
+
145
+ bytesout = C::XMLSec.xmlSecBase64Decode(cert64, certptr, certptr.size)
146
+ cert = certptr.read_bytes(bytesout)
147
+
148
+ key_add_result = C::XMLSec.xmlSecOpenSSLAppKeysMngrCertLoadMemory(keys_manager, cert, cert.size, :xmlSecKeyDataFormatDer, C::XMLSec.xmlSecKeyDataTypeTrusted)
149
+ raise "failed to add key to keys manager" if key_add_result < 0
150
+
151
+ if C::XMLSec.xmlSecDSigCtxVerify(digital_signature_context, signature_node) < 0
152
+ raise "error during signature verification"
153
+ end
154
+
155
+ digital_signature_context[:status] == :xmlSecDSigStatusSucceeded
156
+ ensure
157
+ C::LibXML.xmlFreeDoc(doc) if defined?(doc) && doc && !doc.null?
158
+ C::XMLSec.xmlSecDSigCtxDestroy(digital_signature_context) if defined?(digital_signature_context) && digital_signature_context && !digital_signature_context.null?
159
+ C::XMLSec.xmlSecKeysMngrDestroy(keys_manager) if defined?(keys_manager) && keys_manager && !keys_manager.null?
160
+ C::XMLSec.xmlSecKeyInfoCtxDestroy(key_info_context) if defined?(key_info_context) && key_info_context && !key_info_context.null?
161
+ C::XMLSec.xmlSecKeyDestroy(key) if defined?(key) && key && !key.null?
162
+ end
163
+
164
+ def self.decrypt(encrypted_xml, private_key)
165
+ init
166
+
167
+ keys_manager = _init_keys_manager
168
+
169
+ key = C::XMLSec.xmlSecOpenSSLAppKeyLoad(private_key, :xmlSecKeyDataFormatPem, nil, nil, nil)
170
+ raise "failed to load private pem ley from #{private_key}" if key.null?
171
+
172
+ key_add_result = C::XMLSec.xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(keys_manager, key)
173
+ raise "failed to add key to keys manager" if key_add_result < 0
174
+
175
+ doc = C::LibXML.xmlParseMemory(encrypted_xml, encrypted_xml.size)
176
+ raise "could not parse XML document" if doc.null?
177
+
178
+ doc_root = C::LibXML.xmlDocGetRootElement(doc)
179
+ raise "could not get root element" if doc_root.null?
180
+
181
+ start_node = C::XMLSec.xmlSecFindNode(doc_root, C::XMLSec.xmlSecNodeEncryptedData, C::XMLSec.xmlSecEncNs)
182
+ raise "start node not found" if start_node.null?
183
+
184
+ encryption_context = C::XMLSec.xmlSecEncCtxCreate(keys_manager)
185
+ raise "failed to create encryption context" if encryption_context.null?
186
+
187
+ encryption_result = C::XMLSec.xmlSecEncCtxDecrypt(encryption_context, start_node)
188
+ raise "decryption failed" if (encryption_result < 0)
189
+
190
+ _dump_doc(doc)
191
+ end
192
+
193
+ def self._init_keys_manager
194
+ keys_manager = C::XMLSec.xmlSecKeysMngrCreate
195
+ raise "failed to create keys manager" if keys_manager.null?
196
+
197
+ if C::XMLSec.xmlSecOpenSSLAppDefaultKeysMngrInit(keys_manager) < 0
198
+ raise "failed to init and load default openssl keys into keys manager"
199
+ end
200
+
201
+ keys_manager
202
+ end
203
+
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
+ 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
235
+ end
236
+
237
+ def self._dump_doc(doc)
238
+ ptr = FFI::MemoryPointer.new(:pointer, 1)
239
+ sizeptr = FFI::MemoryPointer.new(:pointer, 1)
240
+ C::LibXML.xmlDocDumpFormatMemory(doc, ptr, sizeptr, 1)
241
+ strptr = ptr.read_pointer
242
+ result = strptr.null? ? nil : strptr.read_string
243
+
244
+ result
245
+ ensure
246
+ ptr.free if defined?(ptr) && ptr
247
+ sizeptr.free if defined?(sizeptr) && sizeptr
248
+ C::LibXML.xmlFree(strptr) if defined?(strptr) && strptr && !strptr.null?
249
+ end
250
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xml_security
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Hinze
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
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
+ description: See http://github.com/phinze/xml_security
63
+ email: paul.t.hinze@gmail.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - README.md
69
+ - lib/xml_security/c/lib_xml.rb
70
+ - lib/xml_security/c/xml_sec.rb
71
+ - lib/xml_security.rb
72
+ homepage: http://github.com/phinze/xml_security
73
+ licenses: []
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 1.8.23
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Ruby bindings into the XMLSec library using ffi.
96
+ test_files: []
97
+ has_rdoc: