yawast 0.6.0 → 0.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,11 +30,17 @@ module Yawast
30
30
  code = res.code.to_i
31
31
 
32
32
  # check for error in the response - if we don't, we'll wait forever for nothing
33
- json = JSON.parse body
33
+ begin
34
+ json = JSON.parse body
35
+ rescue => e
36
+ raise StandardError, "Invalid response from SSL Labs: '#{e.message}'"
37
+ end
34
38
  if json.key?('errors')
35
39
  raise InvocationError, "API returned: #{json['errors']}"
36
40
  end
37
41
 
42
+ Yawast::Shared::Output.log_json 'ssl', 'ssl_labs', body
43
+
38
44
  # check the response code, make sure it's 200 - otherwise, we should stop now
39
45
  if code != 200
40
46
  case code
@@ -57,7 +63,11 @@ module Yawast
57
63
  end
58
64
 
59
65
  def self.extract_status(body)
60
- json = JSON.parse body
66
+ begin
67
+ json = JSON.parse body
68
+ rescue => e
69
+ raise StandardError, "Invalid response from SSL Labs: '#{e.message}'"
70
+ end
61
71
 
62
72
  return json['status']
63
73
  end
@@ -17,10 +17,17 @@ module Yawast
17
17
 
18
18
  def self.extract_msg(body)
19
19
  ret = Array.new
20
- json = JSON.parse body
21
20
 
22
- json['messages'].each do |msg|
23
- ret.push msg
21
+ begin
22
+ json = JSON.parse body
23
+ rescue => e
24
+ raise Exception, "Invalid response from SSL Labs: '#{e.message}'"
25
+ end
26
+
27
+ unless json['messages'].nil?
28
+ json['messages'].each do |msg|
29
+ ret.push msg
30
+ end
24
31
  end
25
32
 
26
33
  return ret
@@ -4,15 +4,21 @@ module Yawast
4
4
  module SSL
5
5
  class Sweet32
6
6
  def self.get_tdes_session_msg_count(uri, limit = 10000)
7
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'limit', limit
8
+
7
9
  # this method will send a number of HEAD requests to see
8
10
  # if the connection is eventually killed.
9
11
  unless check_tdes
10
- #if the OpenSSL install doesn't support 3DES, bailout
12
+ # if the OpenSSL install doesn't support 3DES, bailout
11
13
  Yawast::Utilities.puts_error "Your copy of OpenSSL doesn't support 3DES cipher suites - SWEET32 test aborted."
12
14
  puts ' See here for more information: https://github.com/adamcaudill/yawast/wiki/OpenSSL-&-3DES-Compatibility'
15
+
16
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', '3des_supported', false
13
17
  return
14
18
  end
15
19
 
20
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', '3des_supported', true
21
+
16
22
  puts 'TLS Session Request Limit: Checking number of requests accepted using 3DES suites...'
17
23
 
18
24
  count = 0
@@ -22,14 +28,14 @@ module Yawast
22
28
  req.keep_alive_timeout = 600
23
29
  headers = Yawast::Shared::Http.get_headers
24
30
 
25
- #we will use HEAD by default, but allow GET if we have issues with HEAD
31
+ # we will use HEAD by default, but allow GET if we have issues with HEAD
26
32
  use_head = true
27
33
 
28
- #force 3DES - this is to ensure that 3DES specific limits are caught
34
+ # force 3DES - this is to ensure that 3DES specific limits are caught
29
35
  req.ciphers = ['3DES']
30
36
  cipher = nil
31
37
 
32
- #attempt to find a version that supports 3DES
38
+ # attempt to find a version that supports 3DES
33
39
  versions = OpenSSL::SSL::SSLContext::METHODS.find_all { |v| !v.to_s.include?('_client') && !v.to_s.include?('_server')}
34
40
  versions.each do |version|
35
41
  if version.to_s != 'SSLv23'
@@ -48,7 +54,7 @@ module Yawast
48
54
 
49
55
  cipher = http.instance_variable_get(:@socket).io.cipher[0]
50
56
  rescue
51
- #check if we are using HEAD or GET. If we've already switched to GET, no need to do this again.
57
+ # check if we are using HEAD or GET. If we've already switched to GET, no need to do this again.
52
58
  if use_head
53
59
  head = http.request_get(uri.path, headers)
54
60
 
@@ -58,10 +64,10 @@ module Yawast
58
64
  end
59
65
  end
60
66
 
61
- #check to see if this is on Cloudflare - they break Keep-Alive limits, creating a false positive
67
+ # check to see if this is on Cloudflare - they break Keep-Alive limits, creating a false positive
62
68
  head.each do |k, v|
63
69
  if k.downcase == 'server'
64
- if v == 'cloudflare-nginx'
70
+ if v == 'cloudflare'
65
71
  puts 'Cloudflare server found: SWEET32 mitigated: https://support.cloudflare.com/hc/en-us/articles/231510928'
66
72
  end
67
73
  end
@@ -69,14 +75,19 @@ module Yawast
69
75
  end
70
76
 
71
77
  print "Using #{version} (#{cipher})"
78
+
79
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'tls_version', version
80
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'tls_cipher', cipher
81
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'use_head_req', use_head
82
+
72
83
  break
73
84
  rescue
74
- #we don't care
85
+ # we don't care
75
86
  end
76
87
  end
77
88
  end
78
89
 
79
- #reset the req object
90
+ # reset the req object
80
91
  req = Yawast::Shared::Http.get_http(uri)
81
92
  req.use_ssl = uri.scheme == 'https'
82
93
  req.keep_alive_timeout = 600
@@ -84,7 +95,6 @@ module Yawast
84
95
  req.ciphers = [*cipher]
85
96
 
86
97
  req.start do |http|
87
- #cache the number of hits
88
98
  limit.times do |i|
89
99
  if use_head
90
100
  http.head(uri.path, headers)
@@ -92,7 +102,7 @@ module Yawast
92
102
  http.request_get(uri.path, headers)
93
103
  end
94
104
 
95
- # hack to detect transparent disconnects
105
+ # HACK: to detect transparent disconnects
96
106
  if http.instance_variable_get(:@ssl_context).session_cache_stats[:cache_hits] != 0
97
107
  raise 'TLS Reconnected'
98
108
  end
@@ -113,24 +123,34 @@ module Yawast
113
123
  Yawast::Utilities.puts_info "TLS Session Request Limit: Connection terminated after #{count} requests (#{e.message})"
114
124
  end
115
125
 
126
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'vulnerable', false
127
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'requests', count
128
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'exception', e.message
129
+
116
130
  return
117
131
  end
118
132
 
119
133
  puts
120
134
  limit_formatted = limit.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
121
135
  Yawast::Utilities.puts_vuln "TLS Session Request Limit: Connection not terminated after #{limit_formatted} requests; possibly vulnerable to SWEET32"
136
+
137
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'vulnerable', true
138
+ Yawast::Shared::Output.log_value 'ssl', 'sweet32', 'requests', count
122
139
  end
123
140
 
124
141
  def self.check_tdes
142
+ ret = false
125
143
  puts 'Confirming your OpenSSL supports 3DES cipher suites...'
126
144
 
127
- #find all versions that don't include '_server' or '_client'
145
+ # find all versions that don't include '_server' or '_client'
128
146
  versions = OpenSSL::SSL::SSLContext::METHODS.find_all { |v| !v.to_s.include?('_client') && !v.to_s.include?('_server')}
129
147
 
130
148
  versions.each do |version|
131
- #ignore SSLv23, as it's an auto-negotiate, which just adds noise
149
+ # ignore SSLv23, as it's an auto-negotiate, which just adds noise
132
150
  if version.to_s != 'SSLv23' && version.to_s != 'SSLv2'
133
- #try to get the list of ciphers supported for each version
151
+ # try to get the list of ciphers supported for each version
152
+ Yawast::Shared::Output.log_append_value 'openssl', 'tls_versions', version.to_s
153
+
134
154
  ciphers = nil
135
155
 
136
156
  get_ciphers_failed = false
@@ -144,8 +164,10 @@ module Yawast
144
164
  if ciphers != nil
145
165
  ciphers.each do |cipher|
146
166
  if cipher[0].include?('3DES') || cipher[0].include?('CBC3')
147
- return true
167
+ ret = true
148
168
  end
169
+
170
+ Yawast::Shared::Output.log_append_value 'openssl', 'tls_ciphers', version.to_s, cipher[0]
149
171
  end
150
172
  elsif !get_ciphers_failed
151
173
  Yawast::Utilities.puts_info "\t#{version}: No cipher suites available."
@@ -154,7 +176,7 @@ module Yawast
154
176
  end
155
177
 
156
178
  puts ''
157
- return false
179
+ ret
158
180
  end
159
181
  end
160
182
  end
data/lib/scanner/ssl.rb CHANGED
@@ -8,6 +8,11 @@ module Yawast
8
8
  class Ssl
9
9
  def self.info(uri, check_ciphers, tdes_session_count)
10
10
  begin
11
+ puts
12
+ puts 'DEPRECATED: The Internal SSL Scanner (--internalssl) is deprecated and will not be updated.'
13
+ puts 'DEPRECATED: Use a tool such as testssl.sh or sslyze instead.'
14
+ puts
15
+
11
16
  socket = TCPSocket.new(uri.host, uri.port)
12
17
 
13
18
  ctx = OpenSSL::SSL::SSLContext.new
@@ -89,7 +94,7 @@ module Yawast
89
94
  #It looks like a change to Ruby's OpenSSL wrapper is needed to actually fix this right.
90
95
 
91
96
  if cert.issuer == cert.subject
92
- Yawast::Utilities.puts_vuln "\t\tCertificate Is Self-Singed"
97
+ Yawast::Utilities.puts_vuln "\t\tCertificate Is Self-Signed"
93
98
  else
94
99
  Yawast::Utilities.puts_warn "\t\tCertificate Chain Is Incomplete"
95
100
  end
@@ -36,7 +36,14 @@ module Yawast
36
36
  puts "\tSSL Labs: https://www.ssllabs.com/ssltest/analyze.html?d=#{uri.host}&hideResults=on"
37
37
  puts
38
38
 
39
- process_results uri, JSON.parse(data_body), tdes_session_count
39
+ json = nil
40
+ begin
41
+ json = JSON.parse data_body
42
+ rescue => e
43
+ raise Exception, "Invalid response from SSL Labs: '#{e.message}'"
44
+ end
45
+
46
+ process_results uri, json, tdes_session_count
40
47
  rescue => e
41
48
  puts
42
49
  Yawast::Utilities.puts_error "SSL Labs Error: #{e.message}"
@@ -45,24 +52,34 @@ module Yawast
45
52
 
46
53
  def self.process_results(uri, body, tdes_session_count)
47
54
  begin
48
- body['endpoints'].each do |ep|
49
- Yawast::Utilities.puts_info "IP: #{ep['ipAddress']} - Grade: #{ep['grade']}"
50
- puts
51
-
52
- begin
53
- if ep['statusMessage'] == 'Ready'
54
- get_cert_info ep, body
55
- get_config_info ep
56
- get_proto_info ep
57
- else
58
- Yawast::Utilities.puts_error "Error getting information for IP: #{ep['ipAddress']}: #{ep['statusMessage']}"
55
+ if !body['endpoints'].nil?
56
+ body['endpoints'].each do |ep|
57
+ Yawast::Utilities.puts_info "IP: #{ep['ipAddress']} - Grade: #{ep['grade']}"
58
+ puts
59
+
60
+ begin
61
+ if ep['statusMessage'] == 'Ready'
62
+ get_cert_info ep, body
63
+ get_config_info ep
64
+ get_proto_info ep
65
+ else
66
+ Yawast::Utilities.puts_error "Error getting information for IP: #{ep['ipAddress']}: #{ep['statusMessage']}"
67
+ end
68
+ rescue => e
69
+ Yawast::Utilities.puts_error "Error getting information for IP: #{ep['ipAddress']}: #{e.message}"
59
70
  end
60
- rescue => e
61
- Yawast::Utilities.puts_error "Error getting information for IP: #{ep['ipAddress']}: #{e.message}"
62
- end
63
71
 
64
- Yawast::Scanner::Plugins::SSL::Sweet32.get_tdes_session_msg_count(uri) if tdes_session_count
72
+ Yawast::Scanner::Plugins::SSL::Sweet32.get_tdes_session_msg_count(uri) if tdes_session_count
73
+
74
+ puts
75
+ end
76
+ else
77
+ Yawast::Utilities.puts_error 'SSL Labs Error: No Endpoint Data Received.'
65
78
 
79
+ #TODO - Remove this before release
80
+ puts
81
+ puts "DEBUG DATA (send to adam@adamcaudill.com): #{body}"
82
+ puts
66
83
  puts
67
84
  end
68
85
  rescue => e
@@ -259,11 +276,37 @@ module Yawast
259
276
  puts "\t\t Path #{path_count}:"
260
277
  puts "\t\t Root Stores: #{trust_paths[key]}"
261
278
 
279
+ # cert chain issues
280
+ if chain['issues'] & (1<<1) != 0
281
+ Yawast::Utilities.puts_warn "\t\tCertificate Chain Issue: incomplete chain"
282
+ end
283
+
284
+ if chain['issues'] & (1<<2) != 0
285
+ Yawast::Utilities.puts_warn "\t\tCertificate Chain Issue: chain contains unrelated/duplicate certificates"
286
+ end
287
+
288
+ if chain['issues'] & (1<<3) != 0
289
+ Yawast::Utilities.puts_warn "\t\tCertificate Chain Issue: incorrect order"
290
+ end
291
+
292
+ if chain['issues'] & (1<<4) != 0
293
+ Yawast::Utilities.puts_warn "\t\tCertificate Chain Issue: contains anchor"
294
+ end
295
+
296
+ if cert['issues'] & (1<<5) != 0
297
+ Yawast::Utilities.puts_warn "\t\tCertificate Chain Issue: untrusted"
298
+ end
299
+
262
300
  key.each do |path_cert|
263
301
  body['certs'].each do |c|
264
302
  if c['id'] == path_cert
265
303
  Yawast::Utilities.puts_info "\t\t\t#{c['subject']}"
266
304
  Yawast::Utilities.puts_info "\t\t\t Signature: #{c['sigAlg']} Key: #{c['keyAlg']}-#{c['keySize']}"
305
+
306
+ if Yawast::Scanner::Plugins::SSL::SSL.check_symantec_root(c['sha256Hash'])
307
+ Yawast::Utilities.puts_vuln "\t\t\t Untrusted Symantec Root"
308
+ end
309
+
267
310
  Yawast::Utilities.puts_info "\t\t\t https://crt.sh/?q=#{c['sha1Hash']}"
268
311
 
269
312
  if chain['certIds'].find_index(c['sha256Hash']) != nil
@@ -287,7 +330,11 @@ module Yawast
287
330
  protos = Hash.new
288
331
  ep['details']['protocols'].each do |proto|
289
332
  if proto['name'] == 'SSL'
333
+ # show a vuln for SSLvX
290
334
  Yawast::Utilities.puts_vuln "\t\t\t#{proto['name']} #{proto['version']}"
335
+ elsif proto['name'] == 'TLS' && proto['version'] == '1.0'
336
+ # show a warn for TLSv1.0
337
+ Yawast::Utilities.puts_warn "\t\t\t#{proto['name']} #{proto['version']}"
291
338
  else
292
339
  Yawast::Utilities.puts_info "\t\t\t#{proto['name']} #{proto['version']}"
293
340
  end
data/lib/shared/http.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'securerandom'
2
2
  require 'json'
3
+ require 'oj'
3
4
 
4
5
  module Yawast
5
6
  module Shared
@@ -33,7 +34,7 @@ module Yawast
33
34
  end
34
35
  end
35
36
 
36
- def self.get(uri, headers = nil)
37
+ def self.get_with_code(uri, headers = nil)
37
38
  body = ''
38
39
 
39
40
  begin
@@ -41,11 +42,19 @@ module Yawast
41
42
  req.use_ssl = uri.scheme == 'https'
42
43
  res = req.request_get(uri, get_headers(headers))
43
44
  body = res.read_body
45
+ code = res.code
46
+
47
+ Yawast::Shared::Output.log_json 'debug', 'http_get', uri, Oj.dump(res)
44
48
  rescue
45
49
  # do nothing for now
46
50
  end
47
51
 
48
52
  body
53
+ return {:body => body, :code => code}
54
+ end
55
+
56
+ def self.get(uri, headers = nil)
57
+ return get_with_code(uri, headers)[:body]
49
58
  end
50
59
 
51
60
  def self.get_json(uri)
@@ -79,6 +88,9 @@ module Yawast
79
88
  req = get_http(uri)
80
89
  req.use_ssl = uri.scheme == 'https'
81
90
  res = req.head(uri, get_headers)
91
+
92
+ Yawast::Shared::Output.log_json 'debug', 'http_get_status_code', uri, Oj.dump(res)
93
+
82
94
  res.code
83
95
  end
84
96
 
@@ -0,0 +1,151 @@
1
+ require 'json'
2
+ require 'base64'
3
+
4
+ module Yawast
5
+ module Shared
6
+ class Output
7
+ def self.setup(uri, options)
8
+ return if @setup
9
+
10
+ @setup = true
11
+
12
+ time = Time.new.to_i.to_s
13
+ @file = options.output
14
+
15
+ # get the absolute path
16
+ @file = File.absolute_path @file
17
+
18
+ # see if this is a file or directory
19
+ if File.directory? @file
20
+ # in this case, the user just gave us a directory, se we will create a file name
21
+ @file = File.join(@file, uri.hostname + '_' + time + '.json')
22
+ else
23
+ # this means that it's a file, or doesn't exist
24
+ # so, let's see if it exists, if so, warn
25
+ if File.exist? @file
26
+ puts 'WARNING: Output file already exists; it will be replaced.'
27
+ end
28
+ end
29
+
30
+ puts "Saving output to '#{@file}'"
31
+ puts
32
+
33
+ @data = {}
34
+
35
+ # add the initial entries to the output
36
+ log_value 'start_time', time
37
+ log_value 'yawast_version', VERSION
38
+ log_value 'ruby_version', "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
39
+ log_value 'openssl_version', OpenSSL::OPENSSL_VERSION
40
+ log_value 'platform', RUBY_PLATFORM
41
+ log_value 'target_uri', uri
42
+ log_value 'options', options.__hash__
43
+ log_value 'encoding', __ENCODING__
44
+ end
45
+
46
+ def self.log_value(super_parent = nil, parent = nil, key, value)
47
+ return unless @setup
48
+
49
+ target = get_target super_parent, parent
50
+
51
+ target[key] = encode_utf8(value.to_s)
52
+ end
53
+
54
+ def self.log_append_value(super_parent = nil, parent = nil, key, value)
55
+ return unless @setup
56
+
57
+ target = get_target super_parent, parent
58
+
59
+ if target[key].nil?
60
+ target[key] = []
61
+ end
62
+
63
+ # add value, after checking if it's already included
64
+ target[key].push encode_utf8(value.to_s) unless target[key].include? encode_utf8(value.to_s)
65
+ end
66
+
67
+ def self.log_json(super_parent = nil, parent = nil, key, json_block)
68
+ return unless @setup
69
+
70
+ target = get_target super_parent, parent
71
+
72
+ target[key] = JSON.parse(json_block)
73
+ end
74
+
75
+ def self.log_hash(super_parent = nil, parent = nil, key, hash)
76
+ return unless @setup
77
+
78
+ target = get_target super_parent, parent
79
+
80
+ target[key] = hash
81
+ end
82
+
83
+ def self.encode_utf8(str)
84
+ str = str.dup
85
+
86
+ str = str.force_encoding('UTF-8') if [Encoding::ASCII_8BIT, Encoding::US_ASCII].include?(str.encoding)
87
+
88
+ str
89
+ end
90
+
91
+ def self.get_target(super_parent = nil, parent = nil)
92
+ target = @data
93
+
94
+ # fix parent vs super confusion
95
+ if parent.nil? && !super_parent.nil?
96
+ parent = super_parent
97
+ super_parent = nil
98
+ end
99
+
100
+ unless super_parent.nil?
101
+ if target[super_parent].nil?
102
+ target[super_parent] = {}
103
+ end
104
+
105
+ target = target[super_parent]
106
+ end
107
+
108
+ unless parent.nil?
109
+ if target[parent].nil?
110
+ target[parent] = {}
111
+ end
112
+
113
+ target = target[parent]
114
+ end
115
+
116
+ target
117
+ end
118
+
119
+ def self.escape_hash(hash)
120
+ hash.each_pair do |k,v|
121
+ if v.is_a?(Hash)
122
+ escape_hash(v)
123
+ else
124
+ if v.is_a?(String)
125
+ unless v.valid_encoding?
126
+ hash[k] = Base64.encode64 v
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def self.write_file
134
+ return unless @setup
135
+
136
+ # note the ending time
137
+ log_value 'end_time', Time.new.to_i.to_s
138
+
139
+ begin
140
+ json = JSON.pretty_generate @data
141
+ rescue JSON::GeneratorError
142
+ # this means that we don't have valid data to encode - need to perform some cleanup
143
+ @data = escape_hash @data
144
+ json = JSON.pretty_generate @data
145
+ end
146
+
147
+ File.open(@file, 'w') { |file| file.write(json) }
148
+ end
149
+ end
150
+ end
151
+ end
data/lib/util.rb CHANGED
@@ -8,18 +8,22 @@ module Yawast
8
8
 
9
9
  def self.puts_error(msg)
10
10
  puts_msg('[E]'.red, msg)
11
+ Yawast::Shared::Output.log_append_value 'messages', 'error', msg
11
12
  end
12
13
 
13
14
  def self.puts_vuln(msg)
14
15
  puts_msg('[V]'.magenta, msg)
16
+ Yawast::Shared::Output.log_append_value 'messages', 'vulnerability', msg
15
17
  end
16
18
 
17
19
  def self.puts_warn(msg)
18
20
  puts_msg('[W]'.yellow, msg)
21
+ Yawast::Shared::Output.log_append_value 'messages', 'warning', msg
19
22
  end
20
23
 
21
24
  def self.puts_info(msg)
22
25
  puts_msg('[I]'.green, msg)
26
+ Yawast::Shared::Output.log_append_value 'messages', 'info', msg
23
27
  end
24
28
  end
25
29
  end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yawast
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0.beta1'
3
3
  end
data/lib/yawast.rb CHANGED
@@ -36,9 +36,10 @@ module Yawast
36
36
  puts ' \_/\_| |_/\/ \/\_| |_/\____/ \_/ '
37
37
  puts ''
38
38
  puts "YAWAST v#{VERSION} - #{DESCRIPTION}"
39
- puts ' Copyright (c) 2013-2017 Adam Caudill <adam@adamcaudill.com>'
39
+ puts ' Copyright (c) 2013-2019 Adam Caudill <adam@adamcaudill.com>'
40
40
  puts ' Support & Documentation: https://github.com/adamcaudill/yawast'
41
41
  puts " Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; #{OpenSSL::OPENSSL_VERSION} (#{RUBY_PLATFORM})"
42
+ puts " Started at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}"
42
43
 
43
44
  begin
44
45
  version = Yawast::Shared::Http.get_json(URI('https://rubygems.org/api/v1/versions/yawast/latest.json'))['version']
@@ -58,6 +59,10 @@ module Yawast
58
59
  trap 'SIGINT' do
59
60
  puts
60
61
  puts 'Scan cancelled by user.'
62
+
63
+ # attempt to save the output
64
+ Yawast::Shared::Output.write_file
65
+
61
66
  exit 0
62
67
  end
63
68
  end
@@ -10,7 +10,7 @@ class TestInternalSSL < Minitest::Test
10
10
  uri = URI.parse 'https://self-signed.badssl.com/'
11
11
  Yawast::Scanner::Ssl.info uri, false, false
12
12
 
13
- assert stdout_value.include?('Certificate Is Self-Singed'), 'self-signed certificate warning not found'
13
+ assert stdout_value.include?('Certificate Is Self-Signed'), 'self-signed certificate warning not found'
14
14
 
15
15
  restore_stdout
16
16
  end
data/yawast.gemspec CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |s|
22
22
  s.add_runtime_dependency 'public_suffix', '~> 2.0'
23
23
  s.add_runtime_dependency 'sslshake', '~> 1.1'
24
24
  s.add_runtime_dependency 'dnsruby', '~> 1.60'
25
+ s.add_runtime_dependency 'nokogiri', '~> 1.8'
26
+ s.add_runtime_dependency 'oj', '~> 3.6'
25
27
 
26
28
  s.bindir = 'bin'
27
29
  s.files = `git ls-files`.split("\n")