openssl-custom 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/BSDL +22 -0
- data/CONTRIBUTING.md +132 -0
- data/History.md +485 -0
- data/LICENSE.txt +56 -0
- data/README.md +66 -0
- data/ext/openssl/extconf.rb +190 -0
- data/ext/openssl/openssl_missing.c +106 -0
- data/ext/openssl/openssl_missing.h +257 -0
- data/ext/openssl/ossl.c +1282 -0
- data/ext/openssl/ossl.h +181 -0
- data/ext/openssl/ossl_asn1.c +1878 -0
- data/ext/openssl/ossl_asn1.h +62 -0
- data/ext/openssl/ossl_bio.c +42 -0
- data/ext/openssl/ossl_bio.h +16 -0
- data/ext/openssl/ossl_bn.c +1270 -0
- data/ext/openssl/ossl_bn.h +26 -0
- data/ext/openssl/ossl_cipher.c +1075 -0
- data/ext/openssl/ossl_cipher.h +20 -0
- data/ext/openssl/ossl_config.c +89 -0
- data/ext/openssl/ossl_config.h +19 -0
- data/ext/openssl/ossl_digest.c +425 -0
- data/ext/openssl/ossl_digest.h +20 -0
- data/ext/openssl/ossl_engine.c +567 -0
- data/ext/openssl/ossl_engine.h +19 -0
- data/ext/openssl/ossl_hmac.c +389 -0
- data/ext/openssl/ossl_hmac.h +18 -0
- data/ext/openssl/ossl_kdf.c +303 -0
- data/ext/openssl/ossl_kdf.h +6 -0
- data/ext/openssl/ossl_ns_spki.c +405 -0
- data/ext/openssl/ossl_ns_spki.h +19 -0
- data/ext/openssl/ossl_ocsp.c +2013 -0
- data/ext/openssl/ossl_ocsp.h +23 -0
- data/ext/openssl/ossl_pkcs12.c +257 -0
- data/ext/openssl/ossl_pkcs12.h +13 -0
- data/ext/openssl/ossl_pkcs7.c +1098 -0
- data/ext/openssl/ossl_pkcs7.h +36 -0
- data/ext/openssl/ossl_pkey.c +673 -0
- data/ext/openssl/ossl_pkey.h +241 -0
- data/ext/openssl/ossl_pkey_dh.c +650 -0
- data/ext/openssl/ossl_pkey_dsa.c +664 -0
- data/ext/openssl/ossl_pkey_ec.c +1827 -0
- data/ext/openssl/ossl_pkey_rsa.c +966 -0
- data/ext/openssl/ossl_rand.c +200 -0
- data/ext/openssl/ossl_rand.h +18 -0
- data/ext/openssl/ossl_ssl.c +3080 -0
- data/ext/openssl/ossl_ssl.h +36 -0
- data/ext/openssl/ossl_ssl_session.c +332 -0
- data/ext/openssl/ossl_ts.c +1524 -0
- data/ext/openssl/ossl_ts.h +16 -0
- data/ext/openssl/ossl_x509.c +262 -0
- data/ext/openssl/ossl_x509.h +115 -0
- data/ext/openssl/ossl_x509attr.c +324 -0
- data/ext/openssl/ossl_x509cert.c +846 -0
- data/ext/openssl/ossl_x509crl.c +542 -0
- data/ext/openssl/ossl_x509ext.c +491 -0
- data/ext/openssl/ossl_x509name.c +590 -0
- data/ext/openssl/ossl_x509req.c +441 -0
- data/ext/openssl/ossl_x509revoked.c +300 -0
- data/ext/openssl/ossl_x509store.c +902 -0
- data/ext/openssl/ruby_missing.h +24 -0
- data/lib/openssl/bn.rb +40 -0
- data/lib/openssl/buffering.rb +478 -0
- data/lib/openssl/cipher.rb +67 -0
- data/lib/openssl/config.rb +501 -0
- data/lib/openssl/digest.rb +73 -0
- data/lib/openssl/hmac.rb +13 -0
- data/lib/openssl/marshal.rb +30 -0
- data/lib/openssl/pkcs5.rb +22 -0
- data/lib/openssl/pkey.rb +42 -0
- data/lib/openssl/ssl.rb +542 -0
- data/lib/openssl/version.rb +5 -0
- data/lib/openssl/x509.rb +369 -0
- data/lib/openssl.rb +38 -0
- metadata +196 -0
data/lib/openssl/ssl.rb
ADDED
@@ -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
|