jruby-openssl 0.11.0-java → 0.12.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +20 -0
- data/Mavenfile +21 -26
- data/README.md +3 -0
- data/Rakefile +21 -35
- data/lib/jopenssl/load.rb +0 -14
- data/lib/jopenssl/version.rb +1 -1
- data/lib/jopenssl.jar +0 -0
- data/lib/openssl/bn.rb +40 -9
- data/lib/openssl/buffering.rb +478 -9
- data/lib/openssl/cipher.rb +67 -9
- data/lib/openssl/config.rb +496 -12
- data/lib/openssl/digest.rb +73 -9
- data/lib/openssl/hmac.rb +13 -0
- data/lib/openssl/marshal.rb +30 -0
- data/lib/openssl/pkcs5.rb +3 -3
- data/lib/openssl/pkey.rb +42 -5
- data/lib/openssl/ssl.rb +543 -9
- data/lib/openssl/x509.rb +369 -9
- data/lib/openssl.rb +43 -1
- data/pom.xml +35 -127
- metadata +8 -42
- data/lib/jopenssl19/openssl/bn.rb +0 -29
- data/lib/jopenssl19/openssl/buffering.rb +0 -449
- data/lib/jopenssl19/openssl/cipher.rb +0 -28
- data/lib/jopenssl19/openssl/config.rb +0 -472
- data/lib/jopenssl19/openssl/digest.rb +0 -32
- data/lib/jopenssl19/openssl/ssl-internal.rb +0 -223
- data/lib/jopenssl19/openssl/ssl.rb +0 -2
- data/lib/jopenssl19/openssl/x509-internal.rb +0 -115
- data/lib/jopenssl19/openssl/x509.rb +0 -2
- data/lib/jopenssl19/openssl.rb +0 -22
- data/lib/jopenssl21/openssl/bn.rb +0 -28
- data/lib/jopenssl21/openssl/buffering.rb +0 -1
- data/lib/jopenssl21/openssl/cipher.rb +0 -1
- data/lib/jopenssl21/openssl/config.rb +0 -1
- data/lib/jopenssl21/openssl/digest.rb +0 -1
- data/lib/jopenssl21/openssl/ssl.rb +0 -1
- data/lib/jopenssl21/openssl/x509.rb +0 -119
- data/lib/jopenssl21/openssl.rb +0 -22
- data/lib/jopenssl22/openssl/bn.rb +0 -39
- data/lib/jopenssl22/openssl/buffering.rb +0 -456
- data/lib/jopenssl22/openssl/cipher.rb +0 -28
- data/lib/jopenssl22/openssl/config.rb +0 -313
- data/lib/jopenssl22/openssl/digest.rb +0 -54
- data/lib/jopenssl22/openssl/ssl.rb +0 -330
- data/lib/jopenssl22/openssl/x509.rb +0 -139
- data/lib/jopenssl22/openssl.rb +0 -22
- data/lib/jopenssl23/openssl/bn.rb +0 -38
- data/lib/jopenssl23/openssl/buffering.rb +0 -455
- data/lib/jopenssl23/openssl/cipher.rb +0 -25
- data/lib/jopenssl23/openssl/config.rb +0 -474
- data/lib/jopenssl23/openssl/digest.rb +0 -43
- data/lib/jopenssl23/openssl/pkey.rb +0 -25
- data/lib/jopenssl23/openssl/ssl.rb +0 -508
- data/lib/jopenssl23/openssl/x509.rb +0 -208
- data/lib/jopenssl23/openssl.rb +0 -19
- data/lib/openssl/ssl-internal.rb +0 -5
- data/lib/openssl/x509-internal.rb +0 -5
data/lib/openssl/ssl.rb
CHANGED
@@ -1,9 +1,543 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
543
|
+
end
|