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