packetgen 1.4.3 → 2.0.0

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.
@@ -248,13 +248,13 @@ module PacketGen
248
248
  flags = [:qr, :aa, :tc, :rd, :ra].select! { |attr| send "#{attr}?" }.
249
249
  map(&:to_s).join(',')
250
250
  str << Inspect.shift_level(2)
251
- str << Inspect::INSPECT_FMT_ATTR % ['Flags', 'flags', flags]
251
+ str << Inspect::FMT_ATTR % ['Flags', 'flags', flags]
252
252
  opcode = '%-10s (%u)' % [OPCODES.key(self.opcode), self.opcode]
253
253
  str << Inspect.shift_level(2)
254
- str << Inspect::INSPECT_FMT_ATTR % ['Integer', 'opcode', opcode]
254
+ str << Inspect::FMT_ATTR % ['Integer', 'opcode', opcode]
255
255
  rcode = '%-10s (%u)' % [RCODES.key(self.rcode), self.rcode]
256
256
  str << Inspect.shift_level(2)
257
- str << Inspect::INSPECT_FMT_ATTR % ['Integer', 'rcode', rcode]
257
+ str << Inspect::FMT_ATTR % ['Integer', 'rcode', rcode]
258
258
  else
259
259
  str << Inspect.inspect_attribute(attr, value, 2)
260
260
  end
@@ -133,6 +133,11 @@ module PacketGen
133
133
  # * a {#ht_ctrl} ({Types::Int32}),
134
134
  # * a {#body} (a {Types::String} or another {Base} class),
135
135
  # * a Frame check sequence ({#fcs}, of type {Types::Int32le})
136
+ #
137
+ # == header accessors
138
+ # As Dot11 header types are defined under Dot11 namespace, Dot11 header accessors
139
+ # have a specific name. By example, to access to a {Dot11::Beacon} header,
140
+ # accessor is +#dot11_beacon+.
136
141
  # @author Sylvain Daubert
137
142
  class Dot11 < Base
138
143
 
@@ -1,9 +1,6 @@
1
1
  module PacketGen
2
2
  module Header
3
3
 
4
- # Error about enciphering/deciphering was encountered
5
- class CipherError < Error;end
6
-
7
4
  # A ESP header consists of:
8
5
  # * a Security Parameters Index (#{spi}, {Types::Int32} type),
9
6
  # * a Sequence Number ({#sn}, +Int32+ type),
@@ -48,14 +45,14 @@ module PacketGen
48
45
  #
49
46
  # # encrypt ESP payload
50
47
  # cipher = OpenSSL::Cipher.new('aes-128-gcm')
51
- # cipher.encrypt!
48
+ # cipher.encrypt
52
49
  # cipher.key = 16bytes_key
53
50
  # iv = 8bytes_iv
54
51
  # esp.esp.encrypt! cipher, iv, salt: 4bytes_gcm_salt
55
52
  #
56
53
  # === Decrypt a ESP packet using CBC mode and HMAC-SHA-256
57
54
  # cipher = OpenSSL::Cipher.new('aes-128-cbc')
58
- # cipher.decrypt!
55
+ # cipher.decrypt
59
56
  # cipher.key = 16bytes_key
60
57
  #
61
58
  # hmac = OpenSSL::HMAC.new(hmac_key, OpenSSL::Digest::SHA256.new)
@@ -63,6 +60,7 @@ module PacketGen
63
60
  # pkt.esp.decrypt! cipher, intmode: hmac # => true if ICV check OK
64
61
  # @author Sylvain Daubert
65
62
  class ESP < Base
63
+ include Crypto
66
64
 
67
65
  # IP protocol number for ESP
68
66
  IP_PROTOCOL = 50
@@ -292,43 +290,6 @@ module PacketGen
292
290
 
293
291
  private
294
292
 
295
- def set_crypto(conf, intg)
296
- @conf, @intg = conf, intg
297
- end
298
-
299
- def confidentiality_mode
300
- mode = @conf.name.match(/-([^-]*)$/)[1]
301
- raise CipherError, 'unknown cipher mode' if mode.nil?
302
- mode.downcase
303
- end
304
-
305
- def authenticated?
306
- @conf.authenticated? or !!@intg
307
- end
308
-
309
- def authenticate!
310
- @conf.final
311
- if @intg
312
- @intg.update @esn.to_s if @esn
313
- @intg.digest[0, @icv_length] == @icv
314
- else
315
- true
316
- end
317
- rescue OpenSSL::Cipher::CipherError
318
- false
319
- end
320
-
321
- def encipher(data)
322
- enciphered_data = @conf.update(data)
323
- @intg.update(enciphered_data) if @intg
324
- enciphered_data
325
- end
326
-
327
- def decipher(data)
328
- @intg.update(data) if @intg
329
- @conf.update(data)
330
- end
331
-
332
293
  def get_auth_data(opt)
333
294
  ad = self[:spi].to_s
334
295
  if opt[:esn]
@@ -431,7 +392,10 @@ module PacketGen
431
392
 
432
393
  IP.bind_header ESP, protocol: ESP::IP_PROTOCOL
433
394
  IPv6.bind_header ESP, next: ESP::IP_PROTOCOL
434
- UDP.bind_header ESP, dport: ESP::UDP_PORT, sport: ESP::UDP_PORT
395
+ UDP.bind_header ESP, procs: [ ->(f) { f.dport = f.sport = ESP::UDP_PORT },
396
+ ->(f) { (f.dport == ESP::UDP_PORT ||
397
+ f.sport == ESP::UDP_PORT) &&
398
+ Types::Int32.new.read(f.body[0..3]).to_i > 0 }]
435
399
  ESP.bind_header IP, next: 4
436
400
  ESP.bind_header IPv6, next: 41
437
401
  ESP.bind_header TCP, next: TCP::IP_PROTOCOL
@@ -0,0 +1,235 @@
1
+ module PacketGen
2
+ module Header
3
+
4
+ # This class handles a pseudo-header used to differentiate ESP from IKE headers
5
+ # in a UDP datagram with port 4500.
6
+ # @author Sylvain Daubert
7
+ # @since 2.0.0
8
+ class NonESPMarker < Base
9
+ # @!attribute non_esp_marker
10
+ # 32-bit zero marker to differentiate IKE packet over UDP port 4500 from ESP ones
11
+ # @return [Integer]
12
+ define_field :non_esp_marker, Types::Int32, default: 0
13
+ # @!attribute body
14
+ # @return [Types::String,Header::Base]
15
+ define_field :body, Types::String
16
+
17
+ # Check non_esp_marker field
18
+ # @see [Base#parse?]
19
+ def parse?
20
+ non_esp_marker == 0
21
+ end
22
+ end
23
+
24
+ # IKE is the Internet Key Exchange protocol (RFC 7296). Ony IKEv2 is supported.
25
+ #
26
+ # A IKE header consists of a header, and a set of payloads. This class
27
+ # handles IKE header. For payloads, see {IKE::Payload}.
28
+ #
29
+ # == IKE header
30
+ # The format of a IKE header is shown below:
31
+ # 1 2 3
32
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
33
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
+ # | IKE SA Initiator's SPI |
35
+ # | |
36
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37
+ # | IKE SA Responder's SPI |
38
+ # | |
39
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40
+ # | Next Payload | MjVer | MnVer | Exchange Type | Flags |
41
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42
+ # | Message ID |
43
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44
+ # | Length |
45
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
+ # A IKE header consists of:
47
+ # * a IKE SA initiator SPI ({#init_spi}, {Types::Int64} type),
48
+ # * a IKE SA responder SPI ({#resp_spi}, {Types::Int64} type),
49
+ # * a Next Payload field ({#next}, {Types::Int8} type),
50
+ # * a Version field ({#version}, {Types::Int8} type, with first 4-bit field
51
+ # as major number, and last 4-bit field as minor number),
52
+ # * a Exchange type ({#exchange_type}, {Types::Int8} type),
53
+ # * a {#flags} field ({Types::Int8} type),
54
+ # * a Message ID ({#message_id}, {Types::Int32} type),
55
+ # * and a {#length} ({Types::Int32} type).
56
+ #
57
+ # == Create a IKE header
58
+ # === Standalone
59
+ # ike = PacketGen::Header::IKE.new
60
+ # === Classical IKE packet
61
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
62
+ # # access to IKE header
63
+ # pkt.ike # => PacketGen::Header::IKE
64
+ # === NAT-T IKE packet
65
+ # # NonESPMarker is used to insert a 32-bit null field between UDP header
66
+ # # and IKE one to differentiate it from ESP-in-UDP (see RFC 3948)
67
+ # pkt = PacketGen.gen('IP').add('UDP').add('NonESPMarker').add('IKE)
68
+ # @author Sylvain Daubert
69
+ # @since 2.0.0
70
+ class IKE < Base
71
+
72
+ # Classical well-known UDP port for IKE
73
+ UDP_PORT1 = 500
74
+ # Well-known UDP port for IKE when NAT is detected
75
+ UDP_PORT2 = 4500
76
+
77
+ PROTO_IKE = 1
78
+ PROTO_AH = 2
79
+ PROTO_ESP = 3
80
+
81
+ TYPE_IKE_SA_INIT = 34
82
+ TYPE_IKE_AUTH = 35
83
+ TYPE_CREATE_CHILD_SA = 36
84
+ TYPE_INFORMATIONAL = 37
85
+
86
+ # @!attribute init_spi
87
+ # 64-bit initiator SPI
88
+ # @return [Integer]
89
+ define_field :init_spi, Types::Int64
90
+ # @!attribute resp_spi
91
+ # 64-bit responder SPI
92
+ # @return [Integer]
93
+ define_field :resp_spi, Types::Int64
94
+ # @!attribute next
95
+ # 8-bit next payload type
96
+ # @return [Integer]
97
+ define_field :next, Types::Int8
98
+ # @!attribute version
99
+ # 8-bit IKE version
100
+ # @return [Integer]
101
+ define_field :version, Types::Int8, default: 0x20
102
+ # @!attribute [r] exchange_type
103
+ # 8-bit exchange type
104
+ # @return [Integer]
105
+ define_field :exchange_type, Types::Int8
106
+ # @!attribute flags
107
+ # 8-bit flags
108
+ # @return [Integer]
109
+ define_field :flags, Types::Int8
110
+ # @!attribute message_id
111
+ # 32-bit message ID
112
+ # @return [Integer]
113
+ define_field :message_id, Types::Int32
114
+ # @!attribute length
115
+ # 32-bit length of total message (header + payloads)
116
+ # @return [Integer]
117
+ define_field :length, Types::Int32
118
+
119
+ # Defining a body permits using Packet#parse to parse IKE payloads.
120
+ # But this method is hidden as prefered way to access payloads is via #payloads
121
+ define_field :body, Types::String
122
+
123
+ # @!attribute mjver
124
+ # 4-bit major version value
125
+ # @return [Integer]
126
+ # @!attribute mnver
127
+ # 4-bit minor version value
128
+ # @return [Integer]
129
+ define_bit_fields_on :version, :mjver, 4, :mnver, 4
130
+
131
+ # @!attribute rsv1
132
+ # @return [Integer]
133
+ # @!attribute rsv2
134
+ # @return [Integer]
135
+ # @!attribute flag_i
136
+ # bit set in message sent by the original initiator
137
+ # @return [Boolean]
138
+ # @!attribute flag_r
139
+ # indicate this message is a response to a message containing the same Message ID
140
+ # @return [Boolean]
141
+ # @!attribute flag_v
142
+ # version flag. Ignored by IKEv2 peers, and should be set to 0
143
+ # @return [Boolean]
144
+ define_bit_fields_on :flags, :rsv1, 2, :flag_r, :flag_v, :flag_i, :rsv2, 3
145
+
146
+ # @param [Hash] options
147
+ # @see Base#initialize
148
+ def initialize(options={})
149
+ super
150
+ calc_length unless options[:length]
151
+ self.type = options[:type] if options[:type]
152
+ self.type = options[:exchange_type] if options[:exchange_type]
153
+ end
154
+
155
+ # Set exchange type
156
+ # @param [Integer,String] value
157
+ # @return [Integer]
158
+ def exchange_type=(value)
159
+ type = case value
160
+ when Integer
161
+ value
162
+ else
163
+ c = self.class.constants.grep(/TYPE_#{value}/).first
164
+ c ? self.class.const_get(c) : nil
165
+ end
166
+ raise ArgumentError, "unknown exchange type #{value.inspect}" unless type
167
+ self[:exchange_type].value = type
168
+ end
169
+ alias type exchange_type
170
+ alias type= exchange_type=
171
+
172
+ # Get exchange type name
173
+ # @return [String
174
+ def human_exchange_type
175
+ name = self.class.constants.grep(/TYPE_/).
176
+ select { |c| self.class.const_get(c) == type }.
177
+ first || "type #{type}"
178
+ name.to_s.sub(/TYPE_/, '')
179
+ end
180
+ alias human_type human_exchange_type
181
+
182
+ # Calculate length field
183
+ # @return [Integer]
184
+ def calc_length
185
+ self[:length].value = self.sz
186
+ end
187
+
188
+ # IKE payloads
189
+ # @return [Array<Payload>]
190
+ def payloads
191
+ payloads = []
192
+ body = self.body
193
+ while body.is_a?(Payload) do
194
+ payloads << body
195
+ body = body.body
196
+ end
197
+ payloads
198
+ end
199
+
200
+ # @return [String]
201
+ def inspect
202
+ str = Inspect.dashed_line(self.class, 2)
203
+ to_h.each do |attr, value|
204
+ next if attr == :body
205
+ case attr
206
+ when :flags
207
+ str_flags = ''
208
+ %w(r v i).each do |flag|
209
+ str_flags << (send("flag_#{flag}?") ? flag.upcase : '.')
210
+ end
211
+ str << Inspect.shift_level(2)
212
+ str << Inspect::FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr,
213
+ str_flags]
214
+ when :exchange_type
215
+ str << Inspect.shift_level(2)
216
+ str << Inspect::FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr,
217
+ human_exchange_type]
218
+ else
219
+ str << Inspect.inspect_attribute(attr, value, 2)
220
+ end
221
+ end
222
+ str
223
+ end
224
+ end
225
+
226
+ self.add_class IKE
227
+ self.add_class NonESPMarker
228
+
229
+ UDP.bind_header IKE, dport: IKE::UDP_PORT1, sport: IKE::UDP_PORT1
230
+ UDP.bind_header NonESPMarker, dport: IKE::UDP_PORT2, sport: IKE::UDP_PORT2
231
+ NonESPMarker.bind_header IKE
232
+ end
233
+ end
234
+
235
+ require_relative 'ike/payload'
@@ -0,0 +1,197 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Authentication payloads.
7
+ #
8
+ # A AUTH payload consists of the IKE generic payload header (see {Payload})
9
+ # and some specific fields:
10
+ # 1 2 3
11
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Auth Method | RESERVED |
16
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17
+ # | |
18
+ # ~ Authentication Data ~
19
+ # | |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # These specific fields are:
22
+ # * {#type} (ID type),
23
+ # * {#reserved},
24
+ # * and {#content} (Identification Data).
25
+ #
26
+ # == Create a KE payload
27
+ # # create a IKE packet with a Auth payload
28
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Auth', method: 'SHARED_KEY')
29
+ # pkt.calc_length
30
+ # @author Sylvain Daubert
31
+ class Auth < Payload
32
+
33
+ # Payload type number
34
+ PAYLOAD_TYPE = 39
35
+
36
+ METHOD_RSA_SIGNATURE = 1
37
+ METHOD_SHARED_KEY = 2
38
+ METHOD_DSA_SIGNATURE = 3
39
+ METHOD_ECDSA256 = 9
40
+ METHOD_ECDSA384 = 10
41
+ METHOD_ECDSA512 = 11
42
+ METHOD_PASSWORD = 12
43
+ METHOD_NULL = 13
44
+ METHOD_DIGITAL_SIGNATURE = 14
45
+
46
+ # @attribute :u32
47
+ # 32-bit word including ID Type and RESERVED fields
48
+ # @return [Integer]
49
+ define_field_before :content, :u32, Types::Int32
50
+ # @attribute [r] method
51
+ # 8-bit Auth Method
52
+ # @return [Integer]
53
+ # @attribute reserved
54
+ # 24-bit reserved field
55
+ # @return [Integer]
56
+ define_bit_fields_on :u32, :method, 8, :reserved, 24
57
+
58
+ # Check authentication (see RFC 7296 §2.15)
59
+ # @param [Packet] init_msg first IKE message sent by peer
60
+ # @param [String] nonce my nonce, sent in first message
61
+ # @param [String] sk_p secret key used to compute prf(SK_px, IDx')
62
+ # @param [Integer] prf PRF type to use (see {Transform}+::PRF_*+ constants)
63
+ # @param [String] shared_secret shared secret to use as PSK (shared secret
64
+ # method only)
65
+ # @param [OpenSSL::X509::Certificate] cert certificate to check AUTH signature,
66
+ # if not embedded in IKE message
67
+ # @return [Boolean]
68
+ # @note For now, only NULL, SHARED_KEY and RSA, DSA and ECDSA signatures are
69
+ # supported.
70
+ # @note For certificates, only check AUTH authenticity with given (or guessed
71
+ # from packet) certificate, but certificate chain is not verified.
72
+ def check?(init_msg: nil, nonce: '', sk_p: '', prf: 1, shared_secret: '',
73
+ cert: nil)
74
+ raise TypeError, 'init_msg should be a Packet' unless init_msg.is_a?(Packet)
75
+ signed_octets = init_msg.ike.to_s
76
+ signed_octets << nonce
77
+ id = packet.ike.flag_i? ? packet.ike_idi : packet.ike_idr
78
+ signed_octets << prf(prf, sk_p, id.to_s[4, id.length - 4])
79
+
80
+ case method
81
+ when METHOD_SHARED_KEY
82
+ auth = prf(prf(shared_secret, 'Key Pad for IKEv2'), signed_octets)
83
+ auth == content
84
+ when METHOD_RSA_SIGNATURE, METHOD_ECDSA256, METHOD_ECDSA384, METHOD_ECDSA512
85
+ if packet.ike_cert
86
+ # FIXME: Expect a ENCODING_X509_CERT_SIG
87
+ # Others types not supported for now...
88
+ cert = OpenSSL::X509::Certificate.new(packet.ike_cert.content)
89
+ elsif cert.nil?
90
+ raise CryptoError, 'a certificate should be provided'
91
+ end
92
+
93
+ text = cert.to_text
94
+ m = text.match(/Public Key Algorithm: ([a-zA-Z0-9-]+)/)
95
+ digest = case m[1]
96
+ when 'id-ecPublicKey'
97
+ m2 = text.match(/Public-Key: \((\d+) bit\)/)
98
+ case m2[1]
99
+ when '256'
100
+ OpenSSL::Digest::SHA256.new
101
+ when '384'
102
+ OpenSSL::Digest::SHA384.new
103
+ when '521'
104
+ OpenSSL::Digest::SHA512.new
105
+ end
106
+ when /sha([235]\d+)/
107
+ OpenSSL::Digest.const_get("SHA#{$1}").new
108
+ when /sha1/, 'rsaEncryption'
109
+ OpenSSL::Digest::SHA1.new
110
+ end
111
+ signature = format_signature(cert.public_key, content.to_s)
112
+ cert.public_key.verify(digest, signature, signed_octets)
113
+ when METHOD_NULL
114
+ true
115
+ else
116
+ raise NotImplementedError, "unsupported method #{human_method}"
117
+ end
118
+ end
119
+
120
+ # Set Auth method
121
+ # @param [Integer,String] value
122
+ # @return [Integer]
123
+ def method=(value)
124
+ method = case value
125
+ when Integer
126
+ value
127
+ else
128
+ c = self.class.constants.grep(/METHOD_#{value}/).first
129
+ c ? self.class.const_get(c) : nil
130
+ end
131
+ raise ArgumentError, "unknown auth method #{value.inspect}" unless method
132
+ self[:u32].value = (self[:u32].to_i & 0xffffff) | (method << 24)
133
+ end
134
+
135
+ # Get authentication method name
136
+ # @return [String]
137
+ def human_method
138
+ name = self.class.constants.grep(/METHOD_/).
139
+ select { |c| self.class.const_get(c) == method }.
140
+ first || "method #{method}"
141
+ name.to_s.sub(/METHOD_/, '')
142
+ end
143
+
144
+ # @return [String]
145
+ def inspect
146
+ str = Inspect.dashed_line(self.class, 2)
147
+ fields.each do |attr|
148
+ case attr
149
+ when :body
150
+ next
151
+ when :u32
152
+ str << Inspect.shift_level(2)
153
+ str << Inspect::FMT_ATTR % ['Int8', :method, human_method]
154
+ str << Inspect.inspect_attribute(:reserved, self.reserved, 2)
155
+ else
156
+ str << Inspect.inspect_attribute(attr, self[attr], 2)
157
+ end
158
+ end
159
+ str
160
+ end
161
+
162
+ private
163
+
164
+ def prf(type, key, msg)
165
+ case type
166
+ when Transform::PRF_HMAC_MD5, Transform::PRF_HMAC_SHA1,
167
+ Transform::PRF_HMAC_SHA2_256, Transform::PRF_HMAC_SHA2_384,
168
+ Transform::PRF_HMAC_SHA2_512
169
+ digestname = Transform.constants.grep(/PRF_/).
170
+ select { |c| Transform.const_get(c) == type }.first.
171
+ to_s.sub(/^PRF_HMAC_/, '').sub(/2_/, '')
172
+ digest = OpenSSL::Digest.const_get(digestname).new
173
+ else
174
+ raise NotImplementedError, 'for now, only HMAC-based PRF are supported'
175
+ end
176
+ hmac = OpenSSL::HMAC.new(key, digest)
177
+ hmac << msg
178
+ hmac.digest
179
+ end
180
+
181
+ def format_signature(pkey, sig)
182
+ if pkey.is_a?(OpenSSL::PKey::EC)
183
+ # PKey::EC need a signature as a DER string representing a sequence of
184
+ # 2 integers: r and s
185
+ r = OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(sig[0, sig.size / 2], 2).to_i)
186
+ s = OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(sig[sig.size / 2,
187
+ sig.size / 2], 2).to_i)
188
+ OpenSSL::ASN1::Sequence.new([r, s]).to_der
189
+ else
190
+ sig
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+