openssl-custom 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/BSDL +22 -0
  3. data/CONTRIBUTING.md +132 -0
  4. data/History.md +485 -0
  5. data/LICENSE.txt +56 -0
  6. data/README.md +66 -0
  7. data/ext/openssl/extconf.rb +190 -0
  8. data/ext/openssl/openssl_missing.c +106 -0
  9. data/ext/openssl/openssl_missing.h +257 -0
  10. data/ext/openssl/ossl.c +1282 -0
  11. data/ext/openssl/ossl.h +181 -0
  12. data/ext/openssl/ossl_asn1.c +1878 -0
  13. data/ext/openssl/ossl_asn1.h +62 -0
  14. data/ext/openssl/ossl_bio.c +42 -0
  15. data/ext/openssl/ossl_bio.h +16 -0
  16. data/ext/openssl/ossl_bn.c +1270 -0
  17. data/ext/openssl/ossl_bn.h +26 -0
  18. data/ext/openssl/ossl_cipher.c +1075 -0
  19. data/ext/openssl/ossl_cipher.h +20 -0
  20. data/ext/openssl/ossl_config.c +89 -0
  21. data/ext/openssl/ossl_config.h +19 -0
  22. data/ext/openssl/ossl_digest.c +425 -0
  23. data/ext/openssl/ossl_digest.h +20 -0
  24. data/ext/openssl/ossl_engine.c +567 -0
  25. data/ext/openssl/ossl_engine.h +19 -0
  26. data/ext/openssl/ossl_hmac.c +389 -0
  27. data/ext/openssl/ossl_hmac.h +18 -0
  28. data/ext/openssl/ossl_kdf.c +303 -0
  29. data/ext/openssl/ossl_kdf.h +6 -0
  30. data/ext/openssl/ossl_ns_spki.c +405 -0
  31. data/ext/openssl/ossl_ns_spki.h +19 -0
  32. data/ext/openssl/ossl_ocsp.c +2013 -0
  33. data/ext/openssl/ossl_ocsp.h +23 -0
  34. data/ext/openssl/ossl_pkcs12.c +257 -0
  35. data/ext/openssl/ossl_pkcs12.h +13 -0
  36. data/ext/openssl/ossl_pkcs7.c +1098 -0
  37. data/ext/openssl/ossl_pkcs7.h +36 -0
  38. data/ext/openssl/ossl_pkey.c +673 -0
  39. data/ext/openssl/ossl_pkey.h +241 -0
  40. data/ext/openssl/ossl_pkey_dh.c +650 -0
  41. data/ext/openssl/ossl_pkey_dsa.c +664 -0
  42. data/ext/openssl/ossl_pkey_ec.c +1827 -0
  43. data/ext/openssl/ossl_pkey_rsa.c +966 -0
  44. data/ext/openssl/ossl_rand.c +200 -0
  45. data/ext/openssl/ossl_rand.h +18 -0
  46. data/ext/openssl/ossl_ssl.c +3080 -0
  47. data/ext/openssl/ossl_ssl.h +36 -0
  48. data/ext/openssl/ossl_ssl_session.c +332 -0
  49. data/ext/openssl/ossl_ts.c +1524 -0
  50. data/ext/openssl/ossl_ts.h +16 -0
  51. data/ext/openssl/ossl_x509.c +262 -0
  52. data/ext/openssl/ossl_x509.h +115 -0
  53. data/ext/openssl/ossl_x509attr.c +324 -0
  54. data/ext/openssl/ossl_x509cert.c +846 -0
  55. data/ext/openssl/ossl_x509crl.c +542 -0
  56. data/ext/openssl/ossl_x509ext.c +491 -0
  57. data/ext/openssl/ossl_x509name.c +590 -0
  58. data/ext/openssl/ossl_x509req.c +441 -0
  59. data/ext/openssl/ossl_x509revoked.c +300 -0
  60. data/ext/openssl/ossl_x509store.c +902 -0
  61. data/ext/openssl/ruby_missing.h +24 -0
  62. data/lib/openssl/bn.rb +40 -0
  63. data/lib/openssl/buffering.rb +478 -0
  64. data/lib/openssl/cipher.rb +67 -0
  65. data/lib/openssl/config.rb +501 -0
  66. data/lib/openssl/digest.rb +73 -0
  67. data/lib/openssl/hmac.rb +13 -0
  68. data/lib/openssl/marshal.rb +30 -0
  69. data/lib/openssl/pkcs5.rb +22 -0
  70. data/lib/openssl/pkey.rb +42 -0
  71. data/lib/openssl/ssl.rb +542 -0
  72. data/lib/openssl/version.rb +5 -0
  73. data/lib/openssl/x509.rb +369 -0
  74. data/lib/openssl.rb +38 -0
  75. metadata +196 -0
@@ -0,0 +1,542 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ = Info
4
+ 'OpenSSL for Ruby 2' project
5
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
6
+ All rights reserved.
7
+
8
+ = Licence
9
+ This program is licensed under the same licence as Ruby.
10
+ (See the file 'LICENCE'.)
11
+ =end
12
+
13
+ require "openssl/buffering"
14
+ require "io/nonblock"
15
+ require "ipaddr"
16
+ require "socket"
17
+
18
+ module OpenSSL
19
+ module SSL
20
+ class SSLContext
21
+ DEFAULT_PARAMS = { # :nodoc:
22
+ :min_version => OpenSSL::SSL::TLS1_VERSION,
23
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
24
+ :verify_hostname => true,
25
+ :options => -> {
26
+ opts = OpenSSL::SSL::OP_ALL
27
+ opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
28
+ opts |= OpenSSL::SSL::OP_NO_COMPRESSION
29
+ opts
30
+ }.call
31
+ }
32
+
33
+ if defined?(OpenSSL::PKey::DH)
34
+ DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
35
+ -----BEGIN DH PARAMETERS-----
36
+ MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
37
+ JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
38
+ VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
39
+ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
40
+ 1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
41
+ 7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
42
+ -----END DH PARAMETERS-----
43
+ _end_of_pem_
44
+ private_constant :DEFAULT_2048
45
+
46
+ DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
47
+ warn "using default DH parameters." if $VERBOSE
48
+ DEFAULT_2048
49
+ }
50
+ end
51
+
52
+ if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") &&
53
+ OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000)
54
+ DEFAULT_PARAMS.merge!(
55
+ ciphers: %w{
56
+ ECDHE-ECDSA-AES128-GCM-SHA256
57
+ ECDHE-RSA-AES128-GCM-SHA256
58
+ ECDHE-ECDSA-AES256-GCM-SHA384
59
+ ECDHE-RSA-AES256-GCM-SHA384
60
+ DHE-RSA-AES128-GCM-SHA256
61
+ DHE-DSS-AES128-GCM-SHA256
62
+ DHE-RSA-AES256-GCM-SHA384
63
+ DHE-DSS-AES256-GCM-SHA384
64
+ ECDHE-ECDSA-AES128-SHA256
65
+ ECDHE-RSA-AES128-SHA256
66
+ ECDHE-ECDSA-AES128-SHA
67
+ ECDHE-RSA-AES128-SHA
68
+ ECDHE-ECDSA-AES256-SHA384
69
+ ECDHE-RSA-AES256-SHA384
70
+ ECDHE-ECDSA-AES256-SHA
71
+ ECDHE-RSA-AES256-SHA
72
+ DHE-RSA-AES128-SHA256
73
+ DHE-RSA-AES256-SHA256
74
+ DHE-RSA-AES128-SHA
75
+ DHE-RSA-AES256-SHA
76
+ DHE-DSS-AES128-SHA256
77
+ DHE-DSS-AES256-SHA256
78
+ DHE-DSS-AES128-SHA
79
+ DHE-DSS-AES256-SHA
80
+ AES128-GCM-SHA256
81
+ AES256-GCM-SHA384
82
+ AES128-SHA256
83
+ AES256-SHA256
84
+ AES128-SHA
85
+ AES256-SHA
86
+ }.join(":"),
87
+ )
88
+ end
89
+
90
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
91
+ DEFAULT_CERT_STORE.set_default_paths
92
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
93
+
94
+ # A callback invoked when DH parameters are required.
95
+ #
96
+ # The callback is invoked with the Session for the key exchange, an
97
+ # flag indicating the use of an export cipher and the keylength
98
+ # required.
99
+ #
100
+ # The callback must return an OpenSSL::PKey::DH instance of the correct
101
+ # key length.
102
+
103
+ attr_accessor :tmp_dh_callback
104
+
105
+ # A callback invoked at connect time to distinguish between multiple
106
+ # server names.
107
+ #
108
+ # The callback is invoked with an SSLSocket and a server name. The
109
+ # callback must return an SSLContext for the server name or nil.
110
+ attr_accessor :servername_cb
111
+
112
+ # call-seq:
113
+ # SSLContext.new -> ctx
114
+ # SSLContext.new(:TLSv1) -> ctx
115
+ # SSLContext.new("SSLv23") -> ctx
116
+ #
117
+ # Creates a new SSL context.
118
+ #
119
+ # If an argument is given, #ssl_version= is called with the value. Note
120
+ # that this form is deprecated. New applications should use #min_version=
121
+ # and #max_version= as necessary.
122
+ def initialize(version = nil)
123
+ self.options |= OpenSSL::SSL::OP_ALL
124
+ self.ssl_version = version if version
125
+ end
126
+
127
+ ##
128
+ # call-seq:
129
+ # ctx.set_params(params = {}) -> params
130
+ #
131
+ # Sets saner defaults optimized for the use with HTTP-like protocols.
132
+ #
133
+ # If a Hash _params_ is given, the parameters are overridden with it.
134
+ # The keys in _params_ must be assignment methods on SSLContext.
135
+ #
136
+ # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
137
+ # cert_store are not set then the system default certificate store is
138
+ # used.
139
+ def set_params(params={})
140
+ params = DEFAULT_PARAMS.merge(params)
141
+ self.options = params.delete(:options) # set before min_version/max_version
142
+ params.each{|name, value| self.__send__("#{name}=", value) }
143
+ if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
144
+ unless self.ca_file or self.ca_path or self.cert_store
145
+ self.cert_store = DEFAULT_CERT_STORE
146
+ end
147
+ end
148
+ return params
149
+ end
150
+
151
+ # call-seq:
152
+ # ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
153
+ # ctx.min_version = :TLS1_2
154
+ # ctx.min_version = nil
155
+ #
156
+ # Sets the lower bound on the supported SSL/TLS protocol version. The
157
+ # version may be specified by an integer constant named
158
+ # OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version".
159
+ #
160
+ # Be careful that you don't overwrite OpenSSL::SSL::OP_NO_{SSL,TLS}v*
161
+ # options by #options= once you have called #min_version= or
162
+ # #max_version=.
163
+ #
164
+ # === Example
165
+ # ctx = OpenSSL::SSL::SSLContext.new
166
+ # ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION
167
+ # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
168
+ #
169
+ # sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx)
170
+ # sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2
171
+ def min_version=(version)
172
+ set_minmax_proto_version(version, @max_proto_version ||= nil)
173
+ @min_proto_version = version
174
+ end
175
+
176
+ # call-seq:
177
+ # ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
178
+ # ctx.max_version = :TLS1_2
179
+ # ctx.max_version = nil
180
+ #
181
+ # Sets the upper bound of the supported SSL/TLS protocol version. See
182
+ # #min_version= for the possible values.
183
+ def max_version=(version)
184
+ set_minmax_proto_version(@min_proto_version ||= nil, version)
185
+ @max_proto_version = version
186
+ end
187
+
188
+ # call-seq:
189
+ # ctx.ssl_version = :TLSv1
190
+ # ctx.ssl_version = "SSLv23"
191
+ #
192
+ # Sets the SSL/TLS protocol version for the context. This forces
193
+ # connections to use only the specified protocol version. This is
194
+ # deprecated and only provided for backwards compatibility. Use
195
+ # #min_version= and #max_version= instead.
196
+ #
197
+ # === History
198
+ # As the name hints, this used to call the SSL_CTX_set_ssl_version()
199
+ # function which sets the SSL method used for connections created from
200
+ # the context. As of Ruby/OpenSSL 2.1, this accessor method is
201
+ # implemented to call #min_version= and #max_version= instead.
202
+ def ssl_version=(meth)
203
+ meth = meth.to_s if meth.is_a?(Symbol)
204
+ if /(?<type>_client|_server)\z/ =~ meth
205
+ meth = $`
206
+ if $VERBOSE
207
+ warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored"
208
+ end
209
+ end
210
+ version = METHODS_MAP[meth.intern] or
211
+ raise ArgumentError, "unknown SSL method `%s'" % meth
212
+ set_minmax_proto_version(version, version)
213
+ @min_proto_version = @max_proto_version = version
214
+ end
215
+
216
+ METHODS_MAP = {
217
+ SSLv23: 0,
218
+ SSLv2: OpenSSL::SSL::SSL2_VERSION,
219
+ SSLv3: OpenSSL::SSL::SSL3_VERSION,
220
+ TLSv1: OpenSSL::SSL::TLS1_VERSION,
221
+ TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,
222
+ TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,
223
+ }.freeze
224
+ private_constant :METHODS_MAP
225
+
226
+ # The list of available SSL/TLS methods. This constant is only provided
227
+ # for backwards compatibility.
228
+ METHODS = METHODS_MAP.flat_map { |name,|
229
+ [name, :"#{name}_client", :"#{name}_server"]
230
+ }.freeze
231
+ deprecate_constant :METHODS
232
+ end
233
+
234
+ module SocketForwarder
235
+ # The file descriptor for the socket.
236
+ def fileno
237
+ to_io.fileno
238
+ end
239
+
240
+ def addr
241
+ to_io.addr
242
+ end
243
+
244
+ def peeraddr
245
+ to_io.peeraddr
246
+ end
247
+
248
+ def setsockopt(level, optname, optval)
249
+ to_io.setsockopt(level, optname, optval)
250
+ end
251
+
252
+ def getsockopt(level, optname)
253
+ to_io.getsockopt(level, optname)
254
+ end
255
+
256
+ def fcntl(*args)
257
+ to_io.fcntl(*args)
258
+ end
259
+
260
+ def closed?
261
+ to_io.closed?
262
+ end
263
+
264
+ def do_not_reverse_lookup=(flag)
265
+ to_io.do_not_reverse_lookup = flag
266
+ end
267
+ end
268
+
269
+ def verify_certificate_identity(cert, hostname)
270
+ should_verify_common_name = true
271
+ cert.extensions.each{|ext|
272
+ next if ext.oid != "subjectAltName"
273
+ ostr = OpenSSL::ASN1.decode(ext.to_der).value.last
274
+ sequence = OpenSSL::ASN1.decode(ostr.value)
275
+ sequence.value.each{|san|
276
+ case san.tag
277
+ when 2 # dNSName in GeneralName (RFC5280)
278
+ should_verify_common_name = false
279
+ return true if verify_hostname(hostname, san.value)
280
+ when 7 # iPAddress in GeneralName (RFC5280)
281
+ should_verify_common_name = false
282
+ if san.value.size == 4 || san.value.size == 16
283
+ begin
284
+ return true if san.value == IPAddr.new(hostname).hton
285
+ rescue IPAddr::InvalidAddressError
286
+ end
287
+ end
288
+ end
289
+ }
290
+ }
291
+ if should_verify_common_name
292
+ cert.subject.to_a.each{|oid, value|
293
+ if oid == "CN"
294
+ return true if verify_hostname(hostname, value)
295
+ end
296
+ }
297
+ end
298
+ return false
299
+ end
300
+ module_function :verify_certificate_identity
301
+
302
+ def verify_hostname(hostname, san) # :nodoc:
303
+ # RFC 5280, IA5String is limited to the set of ASCII characters
304
+ return false unless san.ascii_only?
305
+ return false unless hostname.ascii_only?
306
+
307
+ # See RFC 6125, section 6.4.1
308
+ # Matching is case-insensitive.
309
+ san_parts = san.downcase.split(".")
310
+
311
+ # TODO: this behavior should probably be more strict
312
+ return san == hostname if san_parts.size < 2
313
+
314
+ # Matching is case-insensitive.
315
+ host_parts = hostname.downcase.split(".")
316
+
317
+ # RFC 6125, section 6.4.3, subitem 2.
318
+ # If the wildcard character is the only character of the left-most
319
+ # label in the presented identifier, the client SHOULD NOT compare
320
+ # against anything but the left-most label of the reference
321
+ # identifier (e.g., *.example.com would match foo.example.com but
322
+ # not bar.foo.example.com or example.com).
323
+ return false unless san_parts.size == host_parts.size
324
+
325
+ # RFC 6125, section 6.4.3, subitem 1.
326
+ # The client SHOULD NOT attempt to match a presented identifier in
327
+ # which the wildcard character comprises a label other than the
328
+ # left-most label (e.g., do not match bar.*.example.net).
329
+ return false unless verify_wildcard(host_parts.shift, san_parts.shift)
330
+
331
+ san_parts.join(".") == host_parts.join(".")
332
+ end
333
+ module_function :verify_hostname
334
+
335
+ def verify_wildcard(domain_component, san_component) # :nodoc:
336
+ parts = san_component.split("*", -1)
337
+
338
+ return false if parts.size > 2
339
+ return san_component == domain_component if parts.size == 1
340
+
341
+ # RFC 6125, section 6.4.3, subitem 3.
342
+ # The client SHOULD NOT attempt to match a presented identifier
343
+ # where the wildcard character is embedded within an A-label or
344
+ # U-label of an internationalized domain name.
345
+ return false if domain_component.start_with?("xn--") && san_component != "*"
346
+
347
+ parts[0].length + parts[1].length < domain_component.length &&
348
+ domain_component.start_with?(parts[0]) &&
349
+ domain_component.end_with?(parts[1])
350
+ end
351
+ module_function :verify_wildcard
352
+
353
+ class SSLSocket
354
+ include Buffering
355
+ include SocketForwarder
356
+
357
+ attr_reader :hostname
358
+
359
+ # The underlying IO object.
360
+ attr_reader :io
361
+ alias :to_io :io
362
+
363
+ # The SSLContext object used in this connection.
364
+ attr_reader :context
365
+
366
+ # Whether to close the underlying socket as well, when the SSL/TLS
367
+ # connection is shut down. This defaults to +false+.
368
+ attr_accessor :sync_close
369
+
370
+ # call-seq:
371
+ # ssl.sysclose => nil
372
+ #
373
+ # Sends "close notify" to the peer and tries to shut down the SSL
374
+ # connection gracefully.
375
+ #
376
+ # If sync_close is set to +true+, the underlying IO is also closed.
377
+ def sysclose
378
+ return if closed?
379
+ stop
380
+ io.close if sync_close
381
+ end
382
+
383
+ # call-seq:
384
+ # ssl.post_connection_check(hostname) -> true
385
+ #
386
+ # Perform hostname verification following RFC 6125.
387
+ #
388
+ # This method MUST be called after calling #connect to ensure that the
389
+ # hostname of a remote peer has been verified.
390
+ def post_connection_check(hostname)
391
+ if peer_cert.nil?
392
+ msg = "Peer verification enabled, but no certificate received."
393
+ if using_anon_cipher?
394
+ msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \
395
+ "Anonymous suites must be disabled to use peer verification."
396
+ end
397
+ raise SSLError, msg
398
+ end
399
+
400
+ unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
401
+ raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
402
+ end
403
+ return true
404
+ end
405
+
406
+ # call-seq:
407
+ # ssl.session -> aSession
408
+ #
409
+ # Returns the SSLSession object currently used, or nil if the session is
410
+ # not established.
411
+ def session
412
+ SSL::Session.new(self)
413
+ rescue SSL::Session::SessionError
414
+ nil
415
+ end
416
+
417
+ private
418
+
419
+ def using_anon_cipher?
420
+ ctx = OpenSSL::SSL::SSLContext.new
421
+ ctx.ciphers = "aNULL"
422
+ ctx.ciphers.include?(cipher)
423
+ end
424
+
425
+ def client_cert_cb
426
+ @context.client_cert_cb
427
+ end
428
+
429
+ def tmp_dh_callback
430
+ @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
431
+ end
432
+
433
+ def tmp_ecdh_callback
434
+ @context.tmp_ecdh_callback
435
+ end
436
+
437
+ def session_new_cb
438
+ @context.session_new_cb
439
+ end
440
+
441
+ def session_get_cb
442
+ @context.session_get_cb
443
+ end
444
+
445
+ class << self
446
+
447
+ # call-seq:
448
+ # open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
449
+ #
450
+ # Creates a new instance of SSLSocket.
451
+ # _remote\_host_ and _remote\_port_ are used to open TCPSocket.
452
+ # If _local\_host_ and _local\_port_ are specified,
453
+ # then those parameters are used on the local end to establish the connection.
454
+ # If _context_ is provided,
455
+ # the SSL Sockets initial params will be taken from the context.
456
+ #
457
+ # === Examples
458
+ #
459
+ # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443)
460
+ # sock.connect # Initiates a connection to localhost:443
461
+ #
462
+ # with SSLContext:
463
+ #
464
+ # ctx = OpenSSL::SSL::SSLContext.new
465
+ # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443, context: ctx)
466
+ # sock.connect # Initiates a connection to localhost:443 with SSLContext
467
+ def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
468
+ sock = ::TCPSocket.open(remote_host, remote_port, local_host, local_port)
469
+ if context.nil?
470
+ return OpenSSL::SSL::SSLSocket.new(sock)
471
+ else
472
+ return OpenSSL::SSL::SSLSocket.new(sock, context)
473
+ end
474
+ end
475
+ end
476
+ end
477
+
478
+ ##
479
+ # SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
480
+ class SSLServer
481
+ include SocketForwarder
482
+ # When true then #accept works exactly the same as TCPServer#accept
483
+ attr_accessor :start_immediately
484
+
485
+ # Creates a new instance of SSLServer.
486
+ # * _srv_ is an instance of TCPServer.
487
+ # * _ctx_ is an instance of OpenSSL::SSL::SSLContext.
488
+ def initialize(svr, ctx)
489
+ @svr = svr
490
+ @ctx = ctx
491
+ unless ctx.session_id_context
492
+ # see #6137 - session id may not exceed 32 bytes
493
+ prng = ::Random.new($0.hash)
494
+ session_id = prng.bytes(16).unpack('H*')[0]
495
+ @ctx.session_id_context = session_id
496
+ end
497
+ @start_immediately = true
498
+ end
499
+
500
+ # Returns the TCPServer passed to the SSLServer when initialized.
501
+ def to_io
502
+ @svr
503
+ end
504
+
505
+ # See TCPServer#listen for details.
506
+ def listen(backlog=Socket::SOMAXCONN)
507
+ @svr.listen(backlog)
508
+ end
509
+
510
+ # See BasicSocket#shutdown for details.
511
+ def shutdown(how=Socket::SHUT_RDWR)
512
+ @svr.shutdown(how)
513
+ end
514
+
515
+ # Works similar to TCPServer#accept.
516
+ def accept
517
+ # Socket#accept returns [socket, addrinfo].
518
+ # TCPServer#accept returns a socket.
519
+ # The following comma strips addrinfo.
520
+ sock, = @svr.accept
521
+ begin
522
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
523
+ ssl.sync_close = true
524
+ ssl.accept if @start_immediately
525
+ ssl
526
+ rescue Exception => ex
527
+ if ssl
528
+ ssl.close
529
+ else
530
+ sock.close
531
+ end
532
+ raise ex
533
+ end
534
+ end
535
+
536
+ # See IO#close for details.
537
+ def close
538
+ @svr.close
539
+ end
540
+ end
541
+ end
542
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenSSL
4
+ VERSION = "2.2.2"
5
+ end