sslshake 1.0.12 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 73fea6614c1a8dac99abcc7e97607e4e33a2f4e1
4
- data.tar.gz: 8ffbb4598f29d65b3b03c574641404f76f9ed85c
2
+ SHA256:
3
+ metadata.gz: 641256e779df0499064eb598aebf58897dc4b9be47c61ec5dc15990a801f3358
4
+ data.tar.gz: 1f92a00e7c0711d9d7329439f3c59081727631c95e5a5166df044990cdb08046
5
5
  SHA512:
6
- metadata.gz: c6ee7096edd757778e9b13a8a4090ce4f3982762373132213cc8b605bf7129032a63c44351ccebcaf11a2f5f9f32766269e7c2713703f8fcc0164a77f3be9ca7
7
- data.tar.gz: 278ea0a3d288c0d636fe4bb12c34f36bf5be30859e09636932bc45ded810cf8aefd38b8c04a5a3d62b5aad46184a739f3fbaf480aed3c57f227c79ec8f7405ea
6
+ metadata.gz: fdca401dc68dd60345f32bcb091bf3df052552cc217d13d537acb3af41d53317146ea30385dc3d93a32dfb6216abdb638f32da5534604d511db0a30acc0da981
7
+ data.tar.gz: 1894127ce300872c215cf2b7c659c1033273fcebef6556fccba8f0496c506ebad06828d71d4d35f519e41ced377b52d2c2df36ec2b90d5a10ca9a83ea4e71dfa
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
1
  performance
2
2
  .ssldummies
3
3
  .testssl
4
+ *.gem
5
+ *.json
6
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ source 'https://rubygems.org'
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'pry'
7
+ gem 'rb-readline'
8
+ end
9
+
10
+ group :test do
11
+ gem 'messages'
12
+ end
data/README.md CHANGED
@@ -13,6 +13,13 @@ require 'sslshake'
13
13
  SSLShake.hello('my.host', port: 4443, protocol: 'tls1.2')
14
14
  ```
15
15
 
16
+ ## Test (requires Docker)
17
+
18
+ ```bash
19
+ bundle install
20
+ bundle exec test/accuracy/test.rb
21
+ ```
22
+
16
23
  ## License
17
24
 
18
25
  MPLv2, see [https://www.mozilla.org/en-US/MPL/2.0/](https://www.mozilla.org/en-US/MPL/2.0/)
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rake
2
+ # encoding: utf-8
3
+
4
+ require 'bundler'
5
+ require 'bundler/gem_tasks'
6
+ require 'rake/testtask'
7
+ require 'rubocop/rake_task'
8
+
9
+ # Rubocop
10
+ desc 'Run Rubocop lint checks'
11
+ task :rubocop do
12
+ RuboCop::RakeTask.new
13
+ end
14
+
15
+ # lint the project
16
+ desc 'Run robocop linter'
17
+ task lint: [:rubocop]
18
+
19
+ # run tests
20
+ task default: [:lint]
21
+
@@ -61,7 +61,15 @@ module SSLShake
61
61
  cur_socket.send(ssl.hello(opts[:ciphers]), 0)
62
62
  else
63
63
  ssl = SSLShake::TLS.new
64
- cur_socket.send(ssl.hello(protocol, opts[:ciphers]), 0)
64
+
65
+ sni = nil
66
+ if opts[:servername] != nil && opts[:protocol] != 'ssl3'
67
+ sni = '0000' + sprintf('%04x', opts[:servername].length + 5) +
68
+ sprintf('%04x', opts[:servername].length + 3) + '00' +
69
+ sprintf('%04x', opts[:servername].length) +
70
+ opts[:servername].unpack('H*')[0]
71
+ end
72
+ cur_socket.send(ssl.hello(protocol, opts[:ciphers], sni), 0)
65
73
  end
66
74
 
67
75
  res = ssl.parse_hello(cur_socket, opts)
@@ -166,7 +166,12 @@ module SSLShake # rubocop:disable Metrics/ModuleLength
166
166
  '00C4' => 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256',
167
167
  '00C5' => 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256',
168
168
  '00FF' => 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV',
169
- '5600' => 'TLS_FALLBACK_SCSV',
169
+ # See https://tools.ietf.org/html/rfc8446#appendix-B.4
170
+ "1301" => "TLS_AES_128_GCM_SHA256",
171
+ "1302" => "TLS_AES_256_GCM_SHA384",
172
+ "1303" => "TLS_CHACHA20_POLY1305_SHA256",
173
+ "1304" => "TLS_AES_128_CCM_SHA256",
174
+ "1305" => "TLS_AES_128_CCM_8_SHA256",
170
175
  'C001' => 'TLS_ECDH_ECDSA_WITH_NULL_SHA',
171
176
  'C002' => 'TLS_ECDH_ECDSA_WITH_RC4_128_SHA',
172
177
  'C003' => 'TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA',
@@ -355,6 +360,6 @@ module SSLShake # rubocop:disable Metrics/ModuleLength
355
360
  'FEFE' => 'SSL_RSA_FIPS_WITH_DES_CBC_SHA',
356
361
  'FEFF' => 'SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA',
357
362
  'FFE0' => 'SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA',
358
- 'FFE1' => 'SSL_RSA_FIPS_WITH_DES_CBC_SHA',
363
+ 'FFE1' => 'SSL_RSA_FIPS_WITH_DES_CBC_SHA'
359
364
  }.invert.freeze
360
365
  end
@@ -53,7 +53,8 @@ module SSLShake
53
53
  end
54
54
 
55
55
  len = head & 0x7fff
56
- res['raw'] = response = socket.read(len).unpack('H*')[0].upcase
56
+ res['raw'] = response = socket_read(socket, len, opts[:timeout], opts[:retries])
57
+ .unpack('H*')[0].upcase
57
58
  raw = response.scan(/../)
58
59
 
59
60
  res['message_type'] = MESSAGE_TYPES.key(raw.shift)
@@ -14,6 +14,16 @@ module SSLShake
14
14
  'tls1.0' => '0301',
15
15
  'tls1.1' => '0302',
16
16
  'tls1.2' => '0303',
17
+ # NOTE(ssd) 2020-03-21: RFC 8446 4.1.2:
18
+ #
19
+ # In TLS 1.3, the client indicates its version preferences in the
20
+ # "supported_versions" extension (Section 4.2.1) and the
21
+ # legacy_version field MUST be set to 0x0303, which is the version
22
+ # number for TLS 1.2. TLS 1.3 ClientHellos are identified as having
23
+ # a legacy_version of 0x0303 and a supported_versions extension
24
+ # present with 0x0304 as the highest version indicated therein.
25
+ #
26
+ 'tls1.3' => '0303',
17
27
  }.freeze
18
28
 
19
29
  CONTENT_TYPES = {
@@ -38,10 +48,54 @@ module SSLShake
38
48
  'Finished' => '20',
39
49
  }.freeze
40
50
 
51
+ ALERT_SEVERITY = {
52
+ "WARNING" => "01",
53
+ "FATAL" => "02"
54
+ }.freeze
55
+
56
+ # https://tools.ietf.org/html/rfc5246#appendix-A.3
57
+ # https://tools.ietf.org/html/rfc8446#appendix-B.2
58
+ ALERT_DESCRIPTIONS = {
59
+ "CLOSE_NOTIFY" => "00",
60
+ "UNEXPECTED_MESSAGE" => "0A",
61
+ "BAD_RECORD_MAC" => "14",
62
+ "DECRYPTION_FAILED_RESERVED" => "15",
63
+ "RECORD_OVERFLOW" => "16",
64
+ "DECOMPRESSION_FAILURE" => "1E",
65
+ "HANDSHAKE_FAILURE" => "28",
66
+ "NO_CERTIFICATE_RESERVED" => "29",
67
+ "BAD_CERTIFICATE" => "2A",
68
+ "UNSUPPORTED_CERTIFICATE" => "2B",
69
+ "CERTIFICATE_REVOKED" => "2C",
70
+ "CERTIFICATE_EXPIRED" => "2D",
71
+ "CERTIFICATE_UNKNOWN" => "2D",
72
+ "ILLEGAL_PARAMETER" => "2E",
73
+ "UNKNOWN_CA" => "2F",
74
+ "ACCESS_DENIED" => "30",
75
+ "DECODE_ERROR" => "31",
76
+ "DECRYPT_ERROR" => "32",
77
+ "EXPORT_RESTRICTION_RESERVED" => "3C",
78
+ "PROTOCOL_VERSION" => "46",
79
+ "INSUFFICIENT_SECURITY" => "47",
80
+ "INTERNAL_ERROR" => "50",
81
+ "USER_CANCELED" => "5A",
82
+ "NO_RENEGOTIATION" => "64",
83
+ "MISSING_EXTENSION" => "6D",
84
+ "UNSUPPORTED_EXTENSION" => "6E",
85
+ "CERTIFICATE_UNOBTAINABLE_RESERVED" => "6F",
86
+ "UNRECOGNIZED_NAME" => "70",
87
+ "BAD_CERTIFICATE_STATUS_RESPONSE" => "71",
88
+ "BAD_CERTIFICATE_HASH_VALUE_RESERVED" => "72",
89
+ "UNKNOWN_PSK_IDENTITY" => "73",
90
+ "CERTIFICATE_REQUIRED" => "74",
91
+ "NO_APPLICATION_PROTOCOL" => "78",
92
+ }.freeze
93
+
41
94
  # https://tools.ietf.org/html/rfc6101#appendix-A.6
42
- SSL3_CIPHERS = ::SSLShake::CIPHERS.select { |_, v| v < '001F' && v.length == 4 }
95
+ SSL3_CIPHERS = ::SSLShake::CIPHERS.select { |_, v| v.length == 4 }
43
96
  TLS_CIPHERS = ::SSLShake::CIPHERS.select { |k, _| k.start_with? 'TLS_' }
44
97
  TLS10_CIPHERS = TLS_CIPHERS.select { |_, v| v[0] == '0' && v[1] == '0' }
98
+ TLS13_CIPHERS = TLS_CIPHERS.select { |_, v| v[0] == '1' && v[1] == '3' }
45
99
 
46
100
  # Additional collection of ciphers used by different apps and versions
47
101
  OPENSSL_1_0_2_TLS10_CIPHERS = 'c014c00ac022c021c02000390038003700360088008700860085c00fc00500350084c013c009c01fc01ec01d00330032008000810082008300310030009a0099009800970045004400430042c00ec004002f009600410007c011c0070066c00cc00200050004c012c008c01cc01bc01a001600130010000dc00dc003000a006300150012000f000c006200090065006400140011000e000b00080006000300ff'.freeze
@@ -66,9 +120,37 @@ module SSLShake
66
120
  when 'ssl3'
67
121
  ciphers = cipher_string(SSL3_CIPHERS, cipher_search)
68
122
  when 'tls1.0', 'tls1.1'
69
- ciphers = cipher_string(TLS10_CIPHERS, cipher_search)
123
+ ciphers = cipher_string(TLS_CIPHERS, cipher_search)
124
+ (extensions ||= '') << '000f000101' # add Heartbeat
125
+ extensions << '000d00140012040308040401050308050501080606010201' # add signature_algorithms
126
+ extensions << '000b00020100' # add ec_points_format
127
+ extensions << '000a000a0008fafa001d00170018' # add elliptic_curve
70
128
  when 'tls1.2'
71
129
  ciphers = cipher_string(TLS_CIPHERS, cipher_search)
130
+ (extensions ||= '') << '000f000101' # add Heartbeat
131
+ extensions << '000d00140012040308040401050308050501080606010201' # add signature_algorithms
132
+ extensions << '000b00020100' # add ec_points_format
133
+ extensions << '000a000a0008fafa001d00170018' # add elliptic_curve
134
+ when 'tls1.3'
135
+ ciphers = cipher_string(TLS13_CIPHERS, cipher_search)
136
+ (extensions ||= '') << '002b0003020304' # TLSv1.3 Supported Versions extension
137
+ extensions << '000d00140012040308040401050308050501080606010201' # add signature_algorithms
138
+ extensions << '000a00080006001d00170018' # Supported Groups extension
139
+ # This is a pre-generated public/private key pair using the x25519 curve:
140
+ # It was generated from the command line with:
141
+ #
142
+ # > openssl-1.1.1e/apps/openssl genpkey -algorithm x25519 > pkey
143
+ # > openssl-1.1.1e/apps/openssl pkey -noout -text < pkey
144
+ # priv:
145
+ # 30:90:f3:89:f4:9e:52:59:3c:ba:e9:f4:78:84:a0:
146
+ # 23:86:73:5e:f5:c9:46:6c:3a:c3:4e:ec:56:57:81:
147
+ # 5d:62
148
+ # pub:
149
+ # e7:08:71:36:d0:81:e0:16:19:3a:cb:67:ca:b8:28:
150
+ # d9:45:92:16:ff:36:63:0d:0d:5a:3d:9d:47:ce:3e:
151
+ # cd:7e
152
+ public_key= 'e7087136d081e016193acb67cab828d9459216ff36630d0d5a3d9d47ce3ecd7e'
153
+ extensions << '003300260024001d0020' + public_key
72
154
  else
73
155
  fail UserError, "This version is not supported: #{version.inspect}"
74
156
  end
@@ -77,10 +159,17 @@ module SSLShake
77
159
 
78
160
  def parse_hello(socket, opts) # rubocop:disable Meterics/AbcSize
79
161
  raw = socket_read(socket, 5, opts[:timeout], opts[:retries])
80
- .unpack('H*')[0].upcase.scan(/../)
162
+ .unpack('H*')[0].upcase.scan(/../)
81
163
  type = raw.shift
82
164
  if type == CONTENT_TYPES['Alert']
83
- return { 'error' => 'SSL Alert.' }
165
+ raw.shift(2) # Shift off version
166
+ len = raw.shift(2).join.to_i(16)
167
+ raw_alert = socket_read(socket, len, opts[:timeout], opts[:retries])
168
+ .unpack('H*')[0].upcase.scan(/../)
169
+ severity = ALERT_SEVERITY.key(raw_alert.shift)
170
+ desc_raw = raw_alert.shift
171
+ description = ALERT_DESCRIPTIONS.key(desc_raw)
172
+ return { 'error' => "SSL Alert: #{severity} #{description || desc_raw}" }
84
173
  end
85
174
  unless type == CONTENT_TYPES['Handshake']
86
175
  return { 'error' => 'Failed to parse response. It is not an SSL handshake.' }
@@ -90,7 +179,8 @@ module SSLShake
90
179
  res['version'] = VERSIONS.key(raw.shift(2).join(''))
91
180
  len = raw.shift(2).join.to_i(16)
92
181
 
93
- res['raw'] = response = socket.read(len).unpack('H*')[0].upcase
182
+ res['raw'] = response = socket_read(socket, len, opts[:timeout], opts[:retries])
183
+ .unpack('H*')[0].upcase
94
184
  raw = response.scan(/../)
95
185
 
96
186
  res['handshake_type'] = HANDSHAKE_TYPES.key(raw.shift)
@@ -110,9 +200,24 @@ module SSLShake
110
200
  end
111
201
  res['cipher_suite'] = ciphers.key(raw.shift(2).join(''))
112
202
  res['compression_method'] = raw.shift
203
+
204
+ #
205
+ # TLS 1.3 pretends to be TLS 1.2 in the preceeding headers for
206
+ # compatibility. To correctly identify it, we have to look at
207
+ # any Supported Versions extensions that the server sent us.
208
+ #
209
+ all_ext_len = raw.shift(2).join.to_i(16)
210
+ all_ext_data = raw.shift(all_ext_len)
211
+ while all_ext_data.length > 0
212
+ ext_type = all_ext_data.shift(2).join
213
+ ext_len = all_ext_data.shift(2).join.to_i(16)
214
+ ext_data = all_ext_data.shift(ext_len)
215
+ if ext_type == '002B' && ext_data.join == '0304' # Supported Versions
216
+ res['version'] = 'tls1.3'
217
+ end
218
+ end
113
219
  res['success'] = true
114
220
  res['success'] = (res['version'] == opts[:protocol]) unless opts[:protocol].nil?
115
-
116
221
  res
117
222
  rescue SystemCallError, Alert => _
118
223
  return { 'error' => 'Failed to parse response. The connection was terminated.' }
@@ -3,5 +3,5 @@
3
3
  # license: MPLv2
4
4
 
5
5
  module SSLShake
6
- VERSION = '1.0.12'.freeze
6
+ VERSION = '1.3.1'.freeze
7
7
  end
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.summary = 'Ruby library for pure SSL/TLS handshake testing.'
12
12
  spec.description = 'This is a library to simulate SSL and TLS handshake from SSLv2, SSLv3, to TLS 1.0-1.2. It does not rely on OpenSSL and is not designed as a replacement either. It targets full support for even older handshakes, which are not available in current releases of OpenSSL anymore. It also aims to be executable on all systems with a sufficiently modern version of Ruby without any additional requirements or pre-compiled binaries.'
13
13
  spec.homepage = 'https://github.com/arlimus/sslshake'
14
- spec.license = 'MPLv2'
14
+ spec.license = 'MPL-2.0'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.require_paths = ['lib']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sslshake
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.12
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-15 00:00:00.000000000 Z
11
+ date: 2020-06-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a library to simulate SSL and TLS handshake from SSLv2, SSLv3,
14
14
  to TLS 1.0-1.2. It does not rely on OpenSSL and is not designed as a replacement
@@ -23,7 +23,9 @@ extensions: []
23
23
  extra_rdoc_files: []
24
24
  files:
25
25
  - ".gitignore"
26
+ - Gemfile
26
27
  - README.md
28
+ - Rakefile
27
29
  - lib/sslshake.rb
28
30
  - lib/sslshake/ciphers.rb
29
31
  - lib/sslshake/common.rb
@@ -33,9 +35,9 @@ files:
33
35
  - sslshake.gemspec
34
36
  homepage: https://github.com/arlimus/sslshake
35
37
  licenses:
36
- - MPLv2
38
+ - MPL-2.0
37
39
  metadata: {}
38
- post_install_message:
40
+ post_install_message:
39
41
  rdoc_options: []
40
42
  require_paths:
41
43
  - lib
@@ -50,9 +52,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
52
  - !ruby/object:Gem::Version
51
53
  version: '0'
52
54
  requirements: []
53
- rubyforge_project:
54
- rubygems_version: 2.5.1
55
- signing_key:
55
+ rubygems_version: 3.1.3
56
+ signing_key:
56
57
  specification_version: 4
57
58
  summary: Ruby library for pure SSL/TLS handshake testing.
58
59
  test_files: []