Skip to content

Commit bf64374

Browse files
author
Stephen von Takach
committed
Support setting of min and max protocol versions
Defaults to the highest available as per documentation at https://www.openssl.org/docs/man1.1.0/ssl/TLSv1_2_server_method.html
1 parent a63d67d commit bf64374

File tree

2 files changed

+65
-12
lines changed

2 files changed

+65
-12
lines changed

lib/ruby-tls/ssl.rb

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,6 @@ def self.BIO_pending(bio)
8989
# PutCiphertext
9090
attach_function :BIO_write, [:bio, :buffer_in, :buffer_length], :int
9191

92-
# SelectALPNCallback
93-
# TODO:: SSL_select_next_proto
94-
9592
# Deconstructor
9693
attach_function :SSL_get_shutdown, [:ssl], :int
9794
attach_function :SSL_shutdown, [:ssl], :int
@@ -106,9 +103,6 @@ def self.BIO_pending(bio)
106103
# r, w
107104
attach_function :SSL_set_bio, [:ssl, :bio, :bio], :void
108105

109-
# TODO:: SSL_CTX_set_alpn_select_cb
110-
# Will have to put a try catch around these and support when available
111-
112106
attach_function :SSL_set_ex_data, [:ssl, :int, :string], :int
113107
callback :verify_callback, [:int, :x509], :int
114108
attach_function :SSL_set_verify, [:ssl, :int, :verify_callback], :void
@@ -120,11 +114,33 @@ def self.BIO_pending(bio)
120114
attach_function :X509_STORE_CTX_get_ex_data, [:pointer, :int], :ssl
121115
attach_function :PEM_write_bio_X509, [:bio, :x509], :int
122116

123-
124117
# SSL Context Class
125-
# Constructor
126-
attach_function :SSLv23_server_method, [], :pointer
127-
attach_function :SSLv23_client_method, [], :pointer
118+
# OpenSSL before 1.1.0 do not have these methods
119+
# https://www.openssl.org/docs/man1.1.0/ssl/TLSv1_2_server_method.html
120+
begin
121+
attach_function :TLS_server_method, [], :pointer
122+
attach_function :TLS_client_method, [], :pointer
123+
124+
VERSION_SUPPORTED = true
125+
126+
SSL3_VERSION = 0x0300
127+
TLS1_VERSION = 0x0301
128+
TLS1_1_VERSION = 0x0302
129+
TLS1_2_VERSION = 0x0303
130+
TLS1_3_VERSION = 0x0304
131+
TLS_MAX_VERSION = TLS1_3_VERSION
132+
ANY_VERSION = 0
133+
attach_function :SSL_CTX_set_min_proto_version, [:ssl_ctx, :int], :int
134+
attach_function :SSL_CTX_set_max_proto_version, [:ssl_ctx, :int], :int
135+
rescue FFI::NotFoundError
136+
attach_function :SSLv23_server_method, [], :pointer
137+
attach_function :SSLv23_client_method, [], :pointer
138+
139+
def self.TLS_server_method; self.SSLv23_server_method; end
140+
def self.TLS_client_method; self.SSLv23_client_method; end
141+
142+
VERSION_SUPPORTED = false
143+
end
128144
attach_function :SSL_CTX_new, [:pointer], :ssl_ctx
129145

130146
attach_function :SSL_CTX_ctrl, [:ssl_ctx, :int, :ulong, :pointer], :long
@@ -176,6 +192,7 @@ def self.SSL_CTX_set_tlsext_servername_callback(ctx, callback)
176192
attach_function :SSL_CTX_set_session_id_context, [:ssl_ctx, :string, :buffer_length], :int
177193
attach_function :SSL_load_client_CA_file, [:string], :pointer
178194
attach_function :SSL_CTX_set_client_CA_list, [:ssl_ctx, :pointer], :void
195+
attach_function :SSL_CTX_load_verify_locations, [:ssl_ctx, :pointer], :int, :blocking => true
179196

180197
# OpenSSL before 1.0.2 do not have these methods
181198
begin
@@ -342,12 +359,12 @@ def initialize(server, options = {})
342359
@is_server = server
343360

344361
if @is_server
345-
@ssl_ctx = SSL.SSL_CTX_new(SSL.SSLv23_server_method)
362+
@ssl_ctx = SSL.SSL_CTX_new(SSL.TLS_server_method)
346363
set_private_key(options[:private_key] || SSL::DEFAULT_PRIVATE)
347364
set_certificate(options[:cert_chain] || SSL::DEFAULT_CERT)
348365
set_client_ca(options[:client_ca])
349366
else
350-
@ssl_ctx = SSL.SSL_CTX_new(SSL.SSLv23_client_method)
367+
@ssl_ctx = SSL.SSL_CTX_new(SSL.TLS_client_method)
351368
end
352369

353370
SSL.SSL_CTX_set_options(@ssl_ctx, SSL::SSL_OP_ALL)
@@ -356,6 +373,12 @@ def initialize(server, options = {})
356373
SSL.SSL_CTX_set_cipher_list(@ssl_ctx, options[:ciphers] || CIPHERS)
357374
@alpn_set = false
358375

376+
version = options[:version]
377+
if version
378+
vresult = set_min_proto_version(version)
379+
raise "#{version} is unsupported" unless vresult
380+
end
381+
359382
if @is_server
360383
SSL.SSL_CTX_sess_set_cache_size(@ssl_ctx, 128)
361384
SSL.SSL_CTX_set_session_id_context(@ssl_ctx, SESSION, 8)
@@ -377,6 +400,24 @@ def initialize(server, options = {})
377400
end
378401
end
379402

403+
# Version can be one of:
404+
# :SSL3, :TLS1, :TLS1_1, :TLS1_2, :TLS1_3, :TLS_MAX
405+
def set_min_proto_version(version)
406+
return false unless VERSION_SUPPORTED
407+
num = SSL.const_get("#{version}_VERSION")
408+
SSL.SSL_CTX_set_min_proto_version(@ssl_ctx, num) == 1
409+
rescue NameError
410+
false
411+
end
412+
413+
def set_max_proto_version(version)
414+
return false unless VERSION_SUPPORTED
415+
num = SSL.const_get("#{version}_VERSION")
416+
SSL.SSL_CTX_set_max_proto_version(@ssl_ctx, num) == 1
417+
rescue NameError
418+
false
419+
end
420+
380421
def cleanup
381422
if @ssl_ctx
382423
SSL.SSL_CTX_free(@ssl_ctx)

spec/comms_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44

55
describe RubyTls::SSL::Box do
66

7+
it "fails when passed an unsupported TLS version" do
8+
expect {
9+
RubyTls::SSL::Box.new(false, nil, version: :TLS1_4)
10+
}.to raise_error(/is unsupported/)
11+
end
12+
13+
it "succeeds when passed a supported TLS version" do
14+
expect {
15+
RubyTls::SSL::Box.new(false, nil, version: :TLS1_2)
16+
}.to raise_error(/is unsupported/)
17+
end
18+
719
it "should be able to send and receive encrypted comms" do
820
@server_data = []
921
@client_data = []

0 commit comments

Comments
 (0)