xml_security 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: