File: test_ssl_protocols.rb

package info (click to toggle)
ruby-eventmachine 1.3~pre20201020-b50c135-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,768 kB
  • sloc: ruby: 10,597; cpp: 6,032; java: 1,136; makefile: 12
file content (190 lines) | stat: -rw-r--r-- 5,996 bytes parent folder | download | duplicates (3)
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?