yawast 0.6.0 → 0.7.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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")