jruby-openssl 0.9.7-java → 0.9.8-java
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.
- checksums.yaml +4 -4
- data/History.md +68 -23
- data/Rakefile +12 -1
- data/lib/jopenssl.jar +0 -0
- data/lib/jopenssl/load.rb +22 -17
- data/lib/jopenssl/version.rb +1 -1
- data/lib/jopenssl18/openssl/ssl-internal.rb +1 -44
- data/lib/jopenssl19/openssl/config.rb +164 -5
- data/lib/jopenssl19/openssl/ssl-internal.rb +15 -51
- data/lib/jopenssl21/openssl/bn.rb +0 -1
- data/lib/jopenssl21/openssl/buffering.rb +1 -449
- data/lib/jopenssl21/openssl/cipher.rb +1 -28
- data/lib/jopenssl21/openssl/config.rb +1 -313
- data/lib/jopenssl21/openssl/digest.rb +1 -49
- data/lib/jopenssl21/openssl/ssl.rb +1 -205
- data/lib/jopenssl22/openssl.rb +22 -0
- data/lib/jopenssl22/openssl/bn.rb +39 -0
- data/lib/jopenssl22/openssl/buffering.rb +456 -0
- data/lib/jopenssl22/openssl/cipher.rb +28 -0
- data/lib/jopenssl22/openssl/config.rb +313 -0
- data/lib/jopenssl22/openssl/digest.rb +54 -0
- data/lib/jopenssl22/openssl/ssl.rb +193 -0
- data/lib/jopenssl22/openssl/x509.rb +139 -0
- data/lib/openssl/bn.rb +8 -6
- data/lib/openssl/buffering.rb +8 -6
- data/lib/openssl/cipher.rb +8 -6
- data/lib/openssl/config.rb +8 -6
- data/lib/openssl/digest.rb +8 -6
- data/lib/openssl/pkcs12.rb +3 -3
- data/lib/openssl/pkcs7.rb +6 -4
- data/lib/openssl/ssl-internal.rb +7 -5
- data/lib/openssl/ssl.rb +8 -6
- data/lib/openssl/x509-internal.rb +7 -5
- data/lib/openssl/x509.rb +8 -6
- metadata +23 -15
@@ -0,0 +1,28 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# $RCSfile$
|
4
|
+
#
|
5
|
+
# = Ruby-space predefined Cipher subclasses
|
6
|
+
#
|
7
|
+
# = Info
|
8
|
+
# 'OpenSSL for Ruby 2' project
|
9
|
+
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# = Licence
|
13
|
+
# This program is licenced under the same licence as Ruby.
|
14
|
+
# (See the file 'LICENCE'.)
|
15
|
+
#
|
16
|
+
# = Version
|
17
|
+
# $Id$
|
18
|
+
#
|
19
|
+
#++
|
20
|
+
|
21
|
+
module OpenSSL
|
22
|
+
class Cipher
|
23
|
+
# This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future.
|
24
|
+
class Cipher < Cipher
|
25
|
+
# add warning
|
26
|
+
end
|
27
|
+
end # Cipher
|
28
|
+
end # OpenSSL
|
@@ -0,0 +1,313 @@
|
|
1
|
+
=begin
|
2
|
+
= Ruby-space definitions that completes C-space funcs for Config
|
3
|
+
|
4
|
+
= Info
|
5
|
+
Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
|
6
|
+
|
7
|
+
= Licence
|
8
|
+
This program is licenced under the same licence as Ruby.
|
9
|
+
(See the file 'LICENCE'.)
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
require 'stringio'
|
14
|
+
|
15
|
+
module OpenSSL
|
16
|
+
class Config
|
17
|
+
include Enumerable
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def parse(str)
|
21
|
+
c = new()
|
22
|
+
parse_config(StringIO.new(str)).each do |section, hash|
|
23
|
+
c[section] = hash
|
24
|
+
end
|
25
|
+
c
|
26
|
+
end
|
27
|
+
|
28
|
+
alias load new
|
29
|
+
|
30
|
+
def parse_config(io)
|
31
|
+
begin
|
32
|
+
parse_config_lines(io)
|
33
|
+
rescue ConfigError => e
|
34
|
+
e.message.replace("error in line #{io.lineno}: " + e.message)
|
35
|
+
raise
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_key_string(data, section, key) # :nodoc:
|
40
|
+
if v = data[section] && data[section][key]
|
41
|
+
return v
|
42
|
+
elsif section == 'ENV'
|
43
|
+
if v = ENV[key]
|
44
|
+
return v
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if v = data['default'] && data['default'][key]
|
48
|
+
return v
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def parse_config_lines(io)
|
55
|
+
section = 'default'
|
56
|
+
data = {section => {}}
|
57
|
+
while definition = get_definition(io)
|
58
|
+
definition = clear_comments(definition)
|
59
|
+
next if definition.empty?
|
60
|
+
if definition[0] == ?[
|
61
|
+
if /\[([^\]]*)\]/ =~ definition
|
62
|
+
section = $1.strip
|
63
|
+
data[section] ||= {}
|
64
|
+
else
|
65
|
+
raise ConfigError, "missing close square bracket"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
|
69
|
+
if $2
|
70
|
+
section = $1
|
71
|
+
key = $2
|
72
|
+
else
|
73
|
+
key = $1
|
74
|
+
end
|
75
|
+
value = unescape_value(data, section, $3)
|
76
|
+
(data[section] ||= {})[key] = value.strip
|
77
|
+
else
|
78
|
+
raise ConfigError, "missing equal sign"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
data
|
83
|
+
end
|
84
|
+
|
85
|
+
# escape with backslash
|
86
|
+
QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
|
87
|
+
# escape with backslash and doubled dq
|
88
|
+
QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
|
89
|
+
# escaped char map
|
90
|
+
ESCAPE_MAP = {
|
91
|
+
"r" => "\r",
|
92
|
+
"n" => "\n",
|
93
|
+
"b" => "\b",
|
94
|
+
"t" => "\t",
|
95
|
+
}
|
96
|
+
|
97
|
+
def unescape_value(data, section, value)
|
98
|
+
scanned = []
|
99
|
+
while m = value.match(/['"\\$]/)
|
100
|
+
scanned << m.pre_match
|
101
|
+
c = m[0]
|
102
|
+
value = m.post_match
|
103
|
+
case c
|
104
|
+
when "'"
|
105
|
+
if m = value.match(QUOTE_REGEXP_SQ)
|
106
|
+
scanned << m[1].gsub(/\\(.)/, '\\1')
|
107
|
+
value = m.post_match
|
108
|
+
else
|
109
|
+
break
|
110
|
+
end
|
111
|
+
when '"'
|
112
|
+
if m = value.match(QUOTE_REGEXP_DQ)
|
113
|
+
scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
|
114
|
+
value = m.post_match
|
115
|
+
else
|
116
|
+
break
|
117
|
+
end
|
118
|
+
when "\\"
|
119
|
+
c = value.slice!(0, 1)
|
120
|
+
scanned << (ESCAPE_MAP[c] || c)
|
121
|
+
when "$"
|
122
|
+
ref, value = extract_reference(value)
|
123
|
+
refsec = section
|
124
|
+
if ref.index('::')
|
125
|
+
refsec, ref = ref.split('::', 2)
|
126
|
+
end
|
127
|
+
if v = get_key_string(data, refsec, ref)
|
128
|
+
scanned << v
|
129
|
+
else
|
130
|
+
raise ConfigError, "variable has no value"
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise 'must not reaced'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
scanned << value
|
137
|
+
scanned.join
|
138
|
+
end
|
139
|
+
|
140
|
+
def extract_reference(value)
|
141
|
+
rest = ''
|
142
|
+
if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
|
143
|
+
value = m[1] || m[2]
|
144
|
+
rest = m.post_match
|
145
|
+
elsif [?(, ?{].include?(value[0])
|
146
|
+
raise ConfigError, "no close brace"
|
147
|
+
end
|
148
|
+
if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
|
149
|
+
return m[0], m.post_match + rest
|
150
|
+
else
|
151
|
+
raise
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def clear_comments(line)
|
156
|
+
# FCOMMENT
|
157
|
+
if m = line.match(/\A([\t\n\f ]*);.*\z/)
|
158
|
+
return m[1]
|
159
|
+
end
|
160
|
+
# COMMENT
|
161
|
+
scanned = []
|
162
|
+
while m = line.match(/[#'"\\]/)
|
163
|
+
scanned << m.pre_match
|
164
|
+
c = m[0]
|
165
|
+
line = m.post_match
|
166
|
+
case c
|
167
|
+
when '#'
|
168
|
+
line = nil
|
169
|
+
break
|
170
|
+
when "'", '"'
|
171
|
+
regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
|
172
|
+
scanned << c
|
173
|
+
if m = line.match(regexp)
|
174
|
+
scanned << m[0]
|
175
|
+
line = m.post_match
|
176
|
+
else
|
177
|
+
scanned << line
|
178
|
+
line = nil
|
179
|
+
break
|
180
|
+
end
|
181
|
+
when "\\"
|
182
|
+
scanned << c
|
183
|
+
scanned << line.slice!(0, 1)
|
184
|
+
else
|
185
|
+
raise 'must not reaced'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
scanned << line
|
189
|
+
scanned.join
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_definition(io)
|
193
|
+
if line = get_line(io)
|
194
|
+
while /[^\\]\\\z/ =~ line
|
195
|
+
if extra = get_line(io)
|
196
|
+
line += extra
|
197
|
+
else
|
198
|
+
break
|
199
|
+
end
|
200
|
+
end
|
201
|
+
return line.strip
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_line(io)
|
206
|
+
if line = io.gets
|
207
|
+
line.gsub(/[\r\n]*/, '')
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def initialize(filename = nil)
|
213
|
+
@data = {}
|
214
|
+
if filename
|
215
|
+
File.open(filename.to_s) do |file|
|
216
|
+
Config.parse_config(file).each do |section, hash|
|
217
|
+
self[section] = hash
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_value(section, key)
|
224
|
+
if section.nil?
|
225
|
+
raise TypeError.new('nil not allowed')
|
226
|
+
end
|
227
|
+
section = 'default' if section.empty?
|
228
|
+
get_key_string(section, key)
|
229
|
+
end
|
230
|
+
|
231
|
+
def value(arg1, arg2 = nil)
|
232
|
+
warn('Config#value is deprecated; use Config#get_value')
|
233
|
+
if arg2.nil?
|
234
|
+
section, key = 'default', arg1
|
235
|
+
else
|
236
|
+
section, key = arg1, arg2
|
237
|
+
end
|
238
|
+
section ||= 'default'
|
239
|
+
section = 'default' if section.empty?
|
240
|
+
get_key_string(section, key)
|
241
|
+
end
|
242
|
+
|
243
|
+
def add_value(section, key, value)
|
244
|
+
check_modify
|
245
|
+
(@data[section] ||= {})[key] = value
|
246
|
+
end
|
247
|
+
|
248
|
+
def [](section)
|
249
|
+
@data[section] || {}
|
250
|
+
end
|
251
|
+
|
252
|
+
def section(name)
|
253
|
+
warn('Config#section is deprecated; use Config#[]')
|
254
|
+
@data[name] || {}
|
255
|
+
end
|
256
|
+
|
257
|
+
def []=(section, pairs)
|
258
|
+
check_modify
|
259
|
+
@data[section] ||= {}
|
260
|
+
pairs.each do |key, value|
|
261
|
+
self.add_value(section, key, value)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def sections
|
266
|
+
@data.keys
|
267
|
+
end
|
268
|
+
|
269
|
+
def to_s
|
270
|
+
ary = []
|
271
|
+
@data.keys.sort.each do |section|
|
272
|
+
ary << "[ #{section} ]\n"
|
273
|
+
@data[section].keys.each do |key|
|
274
|
+
ary << "#{key}=#{@data[section][key]}\n"
|
275
|
+
end
|
276
|
+
ary << "\n"
|
277
|
+
end
|
278
|
+
ary.join
|
279
|
+
end
|
280
|
+
|
281
|
+
def each
|
282
|
+
@data.each do |section, hash|
|
283
|
+
hash.each do |key, value|
|
284
|
+
yield [section, key, value]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def inspect
|
290
|
+
"#<#{self.class.name} sections=#{sections.inspect}>"
|
291
|
+
end
|
292
|
+
|
293
|
+
protected
|
294
|
+
|
295
|
+
def data
|
296
|
+
@data
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
|
301
|
+
def initialize_copy(other)
|
302
|
+
@data = other.data.dup
|
303
|
+
end
|
304
|
+
|
305
|
+
def check_modify
|
306
|
+
raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
|
307
|
+
end
|
308
|
+
|
309
|
+
def get_key_string(section, key)
|
310
|
+
Config.get_key_string(@data, section, key)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# $RCSfile$
|
4
|
+
#
|
5
|
+
# = Ruby-space predefined Digest subclasses
|
6
|
+
#
|
7
|
+
# = Info
|
8
|
+
# 'OpenSSL for Ruby 2' project
|
9
|
+
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# = Licence
|
13
|
+
# This program is licenced under the same licence as Ruby.
|
14
|
+
# (See the file 'LICENCE'.)
|
15
|
+
#
|
16
|
+
# = Version
|
17
|
+
# $Id$
|
18
|
+
#
|
19
|
+
#++
|
20
|
+
|
21
|
+
module OpenSSL
|
22
|
+
class Digest
|
23
|
+
# Deprecated.
|
24
|
+
#
|
25
|
+
# This class is only provided for backwards compatibility.
|
26
|
+
class Digest < Digest # :nodoc:
|
27
|
+
# Deprecated.
|
28
|
+
#
|
29
|
+
# See OpenSSL::Digest.new
|
30
|
+
def initialize(*args)
|
31
|
+
warn('Digest::Digest is deprecated; use Digest')
|
32
|
+
super(*args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end # Digest
|
37
|
+
|
38
|
+
# Returns a Digest subclass by +name+.
|
39
|
+
#
|
40
|
+
# require 'openssl'
|
41
|
+
#
|
42
|
+
# OpenSSL::Digest("MD5")
|
43
|
+
# # => OpenSSL::Digest::MD5
|
44
|
+
#
|
45
|
+
# Digest("Foo")
|
46
|
+
# # => NameError: wrong constant name Foo
|
47
|
+
|
48
|
+
def Digest(name)
|
49
|
+
OpenSSL::Digest.const_get(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
module_function :Digest
|
53
|
+
|
54
|
+
end # OpenSSL
|
@@ -0,0 +1,193 @@
|
|
1
|
+
=begin
|
2
|
+
= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
|
3
|
+
|
4
|
+
= Info
|
5
|
+
'OpenSSL for Ruby 2' project
|
6
|
+
Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
|
7
|
+
All rights reserved.
|
8
|
+
|
9
|
+
= Licence
|
10
|
+
This program is licenced under the same licence as Ruby.
|
11
|
+
(See the file 'LICENCE'.)
|
12
|
+
|
13
|
+
= Version
|
14
|
+
$Id$
|
15
|
+
=end
|
16
|
+
|
17
|
+
require "openssl/buffering"
|
18
|
+
require 'fcntl' # used by OpenSSL::SSL::Nonblock (if loaded)
|
19
|
+
|
20
|
+
module OpenSSL
|
21
|
+
module SSL
|
22
|
+
|
23
|
+
# FIXME: Using the old non-ASN1 logic here because our ASN1 appears to
|
24
|
+
# return the wrong types for some decoded objects.
|
25
|
+
# @see https://github.com/jruby/jruby/issues/1102
|
26
|
+
# @private
|
27
|
+
def verify_certificate_identity(cert, hostname)
|
28
|
+
should_verify_common_name = true
|
29
|
+
cert.extensions.each { |ext|
|
30
|
+
next if ext.oid != "subjectAltName"
|
31
|
+
ext.value.split(/,\s+/).each { |general_name|
|
32
|
+
# MRI 1.9.3 (since we parse ASN.1 differently)
|
33
|
+
# when 2 # dNSName in GeneralName (RFC5280)
|
34
|
+
if /\ADNS:(.*)/ =~ general_name
|
35
|
+
should_verify_common_name = false
|
36
|
+
return true if verify_hostname(hostname, $1)
|
37
|
+
# MRI 1.9.3 (since we parse ASN.1 differently)
|
38
|
+
# when 7 # iPAddress in GeneralName (RFC5280)
|
39
|
+
elsif /\AIP(?: Address)?:(.*)/ =~ general_name
|
40
|
+
should_verify_common_name = false
|
41
|
+
return true if $1 == hostname
|
42
|
+
# NOTE: bellow logic makes little sense as we read exts differently
|
43
|
+
#value = $1 # follows GENERAL_NAME_print() in x509v3/v3_alt.c
|
44
|
+
#if value.size == 4
|
45
|
+
# return true if value.unpack('C*').join('.') == hostname
|
46
|
+
#elsif value.size == 16
|
47
|
+
# return true if value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
|
48
|
+
#end
|
49
|
+
end
|
50
|
+
}
|
51
|
+
}
|
52
|
+
if should_verify_common_name
|
53
|
+
cert.subject.to_a.each { |oid, value|
|
54
|
+
if oid == "CN"
|
55
|
+
return true if verify_hostname(hostname, value)
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
module_function :verify_certificate_identity
|
62
|
+
|
63
|
+
def verify_hostname(hostname, san) # :nodoc:
|
64
|
+
# RFC 5280, IA5String is limited to the set of ASCII characters
|
65
|
+
return false unless san.ascii_only?
|
66
|
+
return false unless hostname.ascii_only?
|
67
|
+
|
68
|
+
# See RFC 6125, section 6.4.1
|
69
|
+
# Matching is case-insensitive.
|
70
|
+
san_parts = san.downcase.split(".")
|
71
|
+
|
72
|
+
# TODO: this behavior should probably be more strict
|
73
|
+
return san == hostname if san_parts.size < 2
|
74
|
+
|
75
|
+
# Matching is case-insensitive.
|
76
|
+
host_parts = hostname.downcase.split(".")
|
77
|
+
|
78
|
+
# RFC 6125, section 6.4.3, subitem 2.
|
79
|
+
# If the wildcard character is the only character of the left-most
|
80
|
+
# label in the presented identifier, the client SHOULD NOT compare
|
81
|
+
# against anything but the left-most label of the reference
|
82
|
+
# identifier (e.g., *.example.com would match foo.example.com but
|
83
|
+
# not bar.foo.example.com or example.com).
|
84
|
+
return false unless san_parts.size == host_parts.size
|
85
|
+
|
86
|
+
# RFC 6125, section 6.4.3, subitem 1.
|
87
|
+
# The client SHOULD NOT attempt to match a presented identifier in
|
88
|
+
# which the wildcard character comprises a label other than the
|
89
|
+
# left-most label (e.g., do not match bar.*.example.net).
|
90
|
+
return false unless verify_wildcard(host_parts.shift, san_parts.shift)
|
91
|
+
|
92
|
+
san_parts.join(".") == host_parts.join(".")
|
93
|
+
end
|
94
|
+
module_function :verify_hostname
|
95
|
+
|
96
|
+
def verify_wildcard(domain_component, san_component) # :nodoc:
|
97
|
+
parts = san_component.split("*", -1)
|
98
|
+
|
99
|
+
return false if parts.size > 2
|
100
|
+
return san_component == domain_component if parts.size == 1
|
101
|
+
|
102
|
+
# RFC 6125, section 6.4.3, subitem 3.
|
103
|
+
# The client SHOULD NOT attempt to match a presented identifier
|
104
|
+
# where the wildcard character is embedded within an A-label or
|
105
|
+
# U-label of an internationalized domain name.
|
106
|
+
return false if domain_component.start_with?("xn--") && san_component != "*"
|
107
|
+
|
108
|
+
parts[0].length + parts[1].length < domain_component.length &&
|
109
|
+
domain_component.start_with?(parts[0]) &&
|
110
|
+
domain_component.end_with?(parts[1])
|
111
|
+
end
|
112
|
+
module_function :verify_wildcard
|
113
|
+
|
114
|
+
class SSLSocket
|
115
|
+
include Buffering
|
116
|
+
include SocketForwarder
|
117
|
+
include Nonblock
|
118
|
+
|
119
|
+
##
|
120
|
+
# Perform hostname verification after an SSL connection is established
|
121
|
+
#
|
122
|
+
# This method MUST be called after calling #connect to ensure that the
|
123
|
+
# hostname of a remote peer has been verified.
|
124
|
+
def post_connection_check(hostname)
|
125
|
+
unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
|
126
|
+
raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
|
127
|
+
end
|
128
|
+
return true
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
|
135
|
+
class SSLServer
|
136
|
+
include SocketForwarder
|
137
|
+
# When true then #accept works exactly the same as TCPServer#accept
|
138
|
+
attr_accessor :start_immediately
|
139
|
+
|
140
|
+
# Creates a new instance of SSLServer.
|
141
|
+
# * +srv+ is an instance of TCPServer.
|
142
|
+
# * +ctx+ is an instance of OpenSSL::SSL::SSLContext.
|
143
|
+
def initialize(svr, ctx)
|
144
|
+
@svr = svr
|
145
|
+
@ctx = ctx
|
146
|
+
unless ctx.session_id_context
|
147
|
+
# see #6137 - session id may not exceed 32 bytes
|
148
|
+
prng = ::Random.new($0.hash)
|
149
|
+
session_id = prng.bytes(16).unpack('H*')[0]
|
150
|
+
@ctx.session_id_context = session_id
|
151
|
+
end
|
152
|
+
@start_immediately = true
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the TCPServer passed to the SSLServer when initialized.
|
156
|
+
def to_io
|
157
|
+
@svr
|
158
|
+
end
|
159
|
+
|
160
|
+
# See TCPServer#listen for details.
|
161
|
+
def listen(backlog=5)
|
162
|
+
@svr.listen(backlog)
|
163
|
+
end
|
164
|
+
|
165
|
+
# See BasicSocket#shutdown for details.
|
166
|
+
def shutdown(how=Socket::SHUT_RDWR)
|
167
|
+
@svr.shutdown(how)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Works similar to TCPServer#accept.
|
171
|
+
def accept
|
172
|
+
# Socket#accept returns [socket, addrinfo].
|
173
|
+
# TCPServer#accept returns a socket.
|
174
|
+
# The following comma strips addrinfo.
|
175
|
+
sock, = @svr.accept
|
176
|
+
begin
|
177
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
178
|
+
ssl.sync_close = true
|
179
|
+
ssl.accept if @start_immediately
|
180
|
+
ssl
|
181
|
+
rescue SSLError => ex
|
182
|
+
sock.close
|
183
|
+
raise ex
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# See IO#close for details.
|
188
|
+
def close
|
189
|
+
@svr.close
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|