Skip to content

Commit cd47562

Browse files
committed
update openssl/ssl.rb based on MRI 2.2's version
1 parent 5a1575a commit cd47562

File tree

1 file changed

+155
-18
lines changed

1 file changed

+155
-18
lines changed

lib/jopenssl22/openssl/ssl.rb

Lines changed: 155 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,154 @@
1515
=end
1616

1717
require "openssl/buffering"
18-
require 'fcntl' # used by OpenSSL::SSL::Nonblock (if loaded)
18+
require "fcntl"
1919

2020
module OpenSSL
2121
module SSL
22+
class SSLContext
23+
DEFAULT_PARAMS = {
24+
:ssl_version => "SSLv23",
25+
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
26+
:ciphers => %w{
27+
ECDHE-ECDSA-AES128-GCM-SHA256
28+
ECDHE-RSA-AES128-GCM-SHA256
29+
ECDHE-ECDSA-AES256-GCM-SHA384
30+
ECDHE-RSA-AES256-GCM-SHA384
31+
DHE-RSA-AES128-GCM-SHA256
32+
DHE-DSS-AES128-GCM-SHA256
33+
DHE-RSA-AES256-GCM-SHA384
34+
DHE-DSS-AES256-GCM-SHA384
35+
ECDHE-ECDSA-AES128-SHA256
36+
ECDHE-RSA-AES128-SHA256
37+
ECDHE-ECDSA-AES128-SHA
38+
ECDHE-RSA-AES128-SHA
39+
ECDHE-ECDSA-AES256-SHA384
40+
ECDHE-RSA-AES256-SHA384
41+
ECDHE-ECDSA-AES256-SHA
42+
ECDHE-RSA-AES256-SHA
43+
DHE-RSA-AES128-SHA256
44+
DHE-RSA-AES256-SHA256
45+
DHE-RSA-AES128-SHA
46+
DHE-RSA-AES256-SHA
47+
DHE-DSS-AES128-SHA256
48+
DHE-DSS-AES256-SHA256
49+
DHE-DSS-AES128-SHA
50+
DHE-DSS-AES256-SHA
51+
AES128-GCM-SHA256
52+
AES256-GCM-SHA384
53+
AES128-SHA256
54+
AES256-SHA256
55+
AES128-SHA
56+
AES256-SHA
57+
ECDHE-ECDSA-RC4-SHA
58+
ECDHE-RSA-RC4-SHA
59+
RC4-SHA
60+
}.join(":"),
61+
:options => -> {
62+
opts = OpenSSL::SSL::OP_ALL
63+
opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
64+
opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
65+
opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
66+
opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
67+
opts
68+
}.call
69+
} unless const_defined? :DEFAULT_PARAMS # JRuby does it in Java
70+
71+
unless const_defined? :DEFAULT_CERT_STORE # JRuby specific
72+
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
73+
DEFAULT_CERT_STORE.set_default_paths
74+
if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
75+
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
76+
end
77+
end
78+
79+
##
80+
# Sets the parameters for this SSL context to the values in +params+.
81+
# The keys in +params+ must be assignment methods on SSLContext.
82+
#
83+
# If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
84+
# cert_store are not set then the system default certificate store is
85+
# used.
86+
87+
def set_params(params={})
88+
params = DEFAULT_PARAMS.merge(params)
89+
params.each{|name, value| self.__send__("#{name}=", value) }
90+
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
91+
unless self.ca_file or self.ca_path or self.cert_store
92+
self.cert_store = DEFAULT_CERT_STORE
93+
end
94+
end
95+
return params
96+
end unless method_defined? :set_params # JRuby: hooked up in "native" Java
97+
end
98+
99+
module SocketForwarder
100+
def addr
101+
to_io.addr
102+
end
103+
104+
def peeraddr
105+
to_io.peeraddr
106+
end
107+
108+
def setsockopt(level, optname, optval)
109+
to_io.setsockopt(level, optname, optval)
110+
end
111+
112+
def getsockopt(level, optname)
113+
to_io.getsockopt(level, optname)
114+
end
115+
116+
def fcntl(*args)
117+
to_io.fcntl(*args)
118+
end
119+
120+
def closed?
121+
to_io.closed?
122+
end
123+
124+
def do_not_reverse_lookup=(flag)
125+
to_io.do_not_reverse_lookup = flag
126+
end
127+
end unless const_defined? :SocketForwarder # JRuby: hooked up in "native" Java
128+
129+
module Nonblock
130+
def initialize(*args)
131+
flag = File::NONBLOCK
132+
flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
133+
@io.fcntl(Fcntl::F_SETFL, flag)
134+
super
135+
end
136+
end unless const_defined? :Nonblock # JRuby: hooked up in "native" Java
22137

23-
# FIXME: Using the old non-ASN1 logic here because our ASN1 appears to
24-
# return the wrong types for some decoded objects.
25-
# @see https://github.com/jruby/jruby/issues/1102
26-
# @private
27138
def verify_certificate_identity(cert, hostname)
28139
should_verify_common_name = true
29140
cert.extensions.each { |ext|
30141
next if ext.oid != "subjectAltName"
31142
ext.value.split(/,\s+/).each { |general_name|
32-
# MRI 1.9.3 (since we parse ASN.1 differently)
33-
# when 2 # dNSName in GeneralName (RFC5280)
143+
#case san.tag
144+
# MRI 2.2.3 (JRuby parses ASN.1 differently)
145+
#when 2 # dNSName in GeneralName (RFC5280)
34146
if /\ADNS:(.*)/ =~ general_name
35147
should_verify_common_name = false
36148
return true if verify_hostname(hostname, $1)
37-
# MRI 1.9.3 (since we parse ASN.1 differently)
38-
# when 7 # iPAddress in GeneralName (RFC5280)
149+
# MRI 2.2.3 (JRuby parses ASN.1 differently)
150+
#when 7 # iPAddress in GeneralName (RFC5280)
39151
elsif /\AIP(?: Address)?:(.*)/ =~ general_name
40152
should_verify_common_name = false
41153
return true if $1 == hostname
42-
# NOTE: bellow logic makes little sense as we read exts differently
43-
#value = $1 # follows GENERAL_NAME_print() in x509v3/v3_alt.c
44-
#if value.size == 4
45-
# return true if value.unpack('C*').join('.') == hostname
46-
#elsif value.size == 16
47-
# return true if value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
154+
# NOTE: bellow logic makes little sense JRuby reads exts differently
155+
# follows GENERAL_NAME_print() in x509v3/v3_alt.c
156+
#if san.value.size == 4
157+
# return true if san.value.unpack('C*').join('.') == hostname
158+
#elsif san.value.size == 16
159+
# return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
48160
#end
49161
end
50162
}
51163
}
52164
if should_verify_common_name
53-
cert.subject.to_a.each { |oid, value|
165+
cert.subject.to_a.each{|oid, value|
54166
if oid == "CN"
55167
return true if verify_hostname(hostname, value)
56168
end
@@ -122,12 +234,33 @@ class SSLSocket
122234
# This method MUST be called after calling #connect to ensure that the
123235
# hostname of a remote peer has been verified.
124236
def post_connection_check(hostname)
237+
if peer_cert.nil?
238+
msg = "Peer verification enabled, but no certificate received."
239+
if using_anon_cipher?
240+
msg += " Anonymous cipher suite #{cipher[0]} was negotiated. Anonymous suites must be disabled to use peer verification."
241+
end
242+
raise SSLError, msg
243+
end
244+
125245
unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
126246
raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
127247
end
128248
return true
129249
end
130250

251+
#def session
252+
# SSL::Session.new(self)
253+
#rescue SSL::Session::SessionError
254+
# nil
255+
#end
256+
257+
private
258+
259+
def using_anon_cipher?
260+
ctx = OpenSSL::SSL::SSLContext.new
261+
ctx.ciphers = "aNULL"
262+
ctx.ciphers.include?(cipher)
263+
end
131264
end
132265

133266
##
@@ -178,8 +311,12 @@ def accept
178311
ssl.sync_close = true
179312
ssl.accept if @start_immediately
180313
ssl
181-
rescue SSLError => ex
182-
sock.close
314+
rescue Exception => ex
315+
if ssl
316+
ssl.close
317+
else
318+
sock.close
319+
end
183320
raise ex
184321
end
185322
end

0 commit comments

Comments
 (0)