openssl-custom 2.2.2

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.
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