1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
# frozen_string_literal: true
require_relative 'em_test_helper'
# For OpenSSL 1.1.0 and later, cipher_protocol returns single cipher, older
# versions return "TLSv1/SSLv3"
# TLSv1.1 handshake_completed Server/Client callback order is reversed from
# older protocols
class TestSSLProtocols < Test::Unit::TestCase
require_relative 'em_ssl_handlers'
include EMSSLHandlers
# We're checking for whether Context min_version= & max_version= are defined, but
# JRuby has a bug where they're defined, but the private method they call isn't
RUBY_SSL_GE_2_1 = OpenSSL::SSL::SSLContext.private_instance_methods(false).include?(:set_minmax_proto_version)
def test_invalid_ssl_version
assert_raises(RuntimeError, "Unrecognized SSL/TLS Version: badinput") do
client = { ssl_version: %w(tlsv1 badinput) }
server = { ssl_version: %w(tlsv1 badinput) }
client_server client: client, server: server
end
end
def test_any_to_v3
omit("SSLv3 is (correctly) unavailable") if EM::OPENSSL_NO_SSL3
client_server client: TLS_ALL, server: SSL_3
assert Client.handshake_completed?
assert Server.handshake_completed?
end
def test_any_to_tlsv1_2
client_server client: TLS_ALL, server: TLS_1_2
assert Client.handshake_completed?
assert Server.handshake_completed?
if IS_SSL_GE_1_1
assert_equal "TLSv1.2", Client.cipher_protocol
end
end
def test_case_insensitivity
lower_case = SSL_AVAIL.map { |p| p.downcase }
client = { ssl_version: %w(tlsv1_2) }
server = { ssl_version: lower_case }
client_server client: client, server: server
assert Client.handshake_completed?
assert Server.handshake_completed?
end
def test_v3_to_any
omit("SSLv3 is (correctly) unavailable") if EM::OPENSSL_NO_SSL3
client_server client: SSL_3, server: TLS_ALL
assert Client.handshake_completed?
assert Server.handshake_completed?
end
def test_tlsv1_2_to_any
client_server client: TLS_1_2, server: TLS_ALL
assert Client.handshake_completed?
assert Server.handshake_completed?
if IS_SSL_GE_1_1
assert_equal "TLSv1.2", Server.cipher_protocol
end
end
def test_v3_to_v3
omit("SSLv3 is (correctly) unavailable") if EM::OPENSSL_NO_SSL3
client_server client: SSL_3, server: SSL_3
assert Client.handshake_completed?
assert Server.handshake_completed?
end
def test_tlsv1_2_to_tlsv1_2
client_server client: TLS_1_2, server: TLS_1_2
assert Client.handshake_completed?
assert Server.handshake_completed?
if IS_SSL_GE_1_1
assert_equal "TLSv1.2", Client.cipher_protocol
assert_equal "TLSv1.2", Server.cipher_protocol
end
end
def test_tlsv1_3_to_tlsv1_3
omit("TLSv1_3 is unavailable") unless EM.const_defined? :EM_PROTO_TLSv1_3
client_server client: TLS_1_3, server: TLS_1_3
assert Client.handshake_completed?
assert Server.handshake_completed?
assert_equal "TLSv1.3", Client.cipher_protocol
assert_equal "TLSv1.3", Server.cipher_protocol
end
def test_any_to_any
client_server client: TLS_ALL, server: TLS_ALL
assert Client.handshake_completed?
assert Server.handshake_completed?
if IS_SSL_GE_1_1
best_protocol = SSL_AVAIL.last.tr "_", "."
assert_equal best_protocol, Client.cipher_protocol
assert_equal best_protocol, Server.cipher_protocol
end
end
def test_default_to_default
client_server
assert Client.handshake_completed?
assert Server.handshake_completed?
if IS_SSL_GE_1_1
best_protocol = SSL_AVAIL.last.tr "_", "."
assert_equal best_protocol, Client.cipher_protocol
assert_equal best_protocol, Server.cipher_protocol
end
end
def external_client(ext_min, ext_max, ext_ssl, server)
EM.run do
# setup_timeout 2
EM.start_server IP, PORT, Server, server.merge( { stop_after_handshake: true} )
EM.defer do
sock = TCPSocket.new IP, PORT
ctx = OpenSSL::SSL::SSLContext.new
if RUBY_SSL_GE_2_1
ctx.min_version = ext_min if ext_min
ctx.max_version = ext_max if ext_max
else
ctx.ssl_version = ext_ssl
end
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.connect
ssl.close rescue nil
sock.close rescue nil
end
end
assert Server.handshake_completed?
end
def test_v3_with_external_client
omit("SSLv3 is (correctly) unavailable") if EM::OPENSSL_NO_SSL3
external_client nil, nil, :SSLv3_client, SSL_3
end
# Fixed Server
def test_tlsv1_2_with_external_client
external_client nil, nil, :SSLv23_client, TLS_1_2
end
def test_tlsv1_3_with_external_client
omit("TLSv1_3 is unavailable") unless EM.const_defined?(:EM_PROTO_TLSv1_3) &&
OpenSSL::SSL.const_defined?(:TLS1_3_VERSION)
external_client nil, nil, :SSLv23_client, TLS_1_3
end
# Fixed Client
def test_any_with_external_client_tlsv1_2
external_client :TLS1_2, :TLS1_2, :TLSv1_2_client, TLS_ALL
end
def test_any_with_external_client_tlsv1_3
omit("TLSv1_3 is unavailable") unless EM.const_defined? :EM_PROTO_TLSv1_3
external_client :TLS1_3, :TLS1_3, :TLSv1_2_client, TLS_ALL
end
# Refuse a client?
def test_tlsv1_2_required_with_external_client
EM.run do
n = 0
EM.add_periodic_timer(0.5) do
n += 1
(EM.stop rescue nil) if n == 2
end
EM.start_server IP, PORT, Server, TLS_1_2.merge( { stop_after_handshake: true} )
EM.defer do
sock = TCPSocket.new IP, PORT
ctx = OpenSSL::SSL::SSLContext.new
if RUBY_SSL_GE_2_1
ctx.max_version = :TLS1_1
else
ctx.ssl_version = :TLSv1_client
end
ssl = OpenSSL::SSL::SSLSocket.new sock, ctx
assert_raise(OpenSSL::SSL::SSLError) { ssl.connect }
ssl.close rescue nil
sock.close rescue nil
EM.stop rescue nil
end
end
refute Server.handshake_completed?
end
end if EM.ssl?
|