ssl_scan 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ssl_scan.rb CHANGED
@@ -4,6 +4,7 @@ require "openssl"
4
4
  require "ssl_scan/version"
5
5
  require "ssl_scan/compat"
6
6
  require "ssl_scan/result"
7
+ require "ssl_scan/util"
7
8
  require "timeout"
8
9
  require "thread"
9
10
  require "ssl_scan/sync/thread_safe"
@@ -1,9 +1,8 @@
1
- require "stringio"
2
-
3
1
  module SSLScan
4
2
  module Commands
5
3
  class Command
6
4
  attr_accessor :results, :options, :stream, :errors
5
+ include FastGettext::Translation
7
6
 
8
7
  def initialize(results=[], stream=nil)
9
8
  @results = results
@@ -17,11 +16,11 @@ module SSLScan
17
16
 
18
17
  # Display Methods
19
18
  def write_header(host, port=443)
20
- stream.printf "\nTesting SSL server #{host} on port #{port}"
19
+ stream.printf _("\nTesting SSL server %{host} on port %{port}\n") % { host: host, port: port }
21
20
  end
22
21
 
23
22
  def write_preferred_ciphers(scanner)
24
- stream.printf("\nServer Preferred Cipher(s)\n")
23
+ stream.printf _("\nServer Preferred Cipher(s)\n")
25
24
  ciphers = scanner.get_preferred_ciphers
26
25
  ciphers.each do |c|
27
26
  if c.length > 1 && !c[1].empty?
@@ -32,7 +31,7 @@ module SSLScan
32
31
  end
33
32
 
34
33
  def write_ciphers(scanner=nil)
35
- stream.printf "\nSupported Server Cipher(s):\n"
34
+ stream.printf _("\nSupported Server Cipher(s):\n")
36
35
 
37
36
  sslv = options.only_ssl2 || options.only_ssl3 || options.only_tls1 || false
38
37
 
@@ -29,9 +29,14 @@ module SSLScan
29
29
  write_header(parts[0])
30
30
  end
31
31
 
32
- write_ciphers(scanner)
33
- write_preferred_ciphers(scanner)
34
- @results << scanner.results
32
+ if options.only_cert
33
+ scanner.get_first_valid_cert
34
+ @results << scanner.results
35
+ else
36
+ write_ciphers(scanner)
37
+ write_preferred_ciphers(scanner)
38
+ @results << scanner.results
39
+ end
35
40
  end
36
41
 
37
42
  end # Host
@@ -56,6 +56,10 @@ def self.is_linux
56
56
  @@is_linux = (RUBY_PLATFORM =~ /linux/) ? true : false
57
57
  end
58
58
 
59
+ def self.is_debian
60
+ return self.is_linux && File.exists?('/etc/debian_version')
61
+ end
62
+
59
63
  def self.is_bsdi
60
64
  return @@is_bsdi if @@is_bsdi
61
65
  @@is_bsdi = (RUBY_PLATFORM =~ /bsdi/i) ? true : false
data/lib/ssl_scan/main.rb CHANGED
@@ -1,11 +1,7 @@
1
- # require "ssl_scan/compat"
2
- # require "ssl_scan/version"
3
- # require "ssl_scan/scanner"
4
- # require "ssl_scan/result"
5
-
6
1
  require "ssl_scan/version"
7
2
  require "ssl_scan/compat"
8
3
  require "ssl_scan/result"
4
+ require "ssl_scan/util"
9
5
  require "timeout"
10
6
  require "thread"
11
7
  require "ssl_scan/sync/thread_safe"
@@ -18,19 +14,42 @@ require "ssl_scan/scanner"
18
14
  require "openssl"
19
15
  require "optparse"
20
16
  require "ostruct"
17
+ require "fast_gettext"
21
18
 
22
19
  require "ssl_scan/commands/command"
23
20
  require "ssl_scan/commands/host"
24
21
 
22
+ #
23
+ # Setup Translations
24
+ #
25
+ FastGettext.add_text_domain('ssl_scan', path: File.join(SSLScan::Util::ROOT, 'locale'))
26
+ FastGettext.text_domain = 'ssl_scan'
27
+ FastGettext.available_locales = ['en', 'de']
28
+ active_locale = "en"
29
+ ['LC_ALL', 'LANG', 'LANGUAGE'].each do |env_lang|
30
+ lang = ENV[env_lang]
31
+ if lang
32
+ lang = lang[0..1]
33
+ if FastGettext.available_locales.include?(lang)
34
+ active_locale = lang
35
+ break
36
+ end
37
+ end
38
+ end
39
+ FastGettext.locale = active_locale
40
+
41
+
25
42
  module SSLScan
26
43
  class Main
27
44
 
45
+ include FastGettext::Translation
46
+
28
47
  EXIT_SUCCESS = 0
29
48
  EXIT_FAILURE = 1
30
49
 
31
- SYNTAX = "ssl_scan [Options] [host:port | host]"
50
+ SYNTAX = _("ssl_scan [Options] [host:port | host]")
32
51
  WEBSITE = "https://www.testcloud.de"
33
- COPYRIGHT = "Copyright (C) John Faucett #{Time.now.year}"
52
+ COPYRIGHT = _("Copyright (C) John Faucett %{year}") % { year: Time.now.year }
34
53
 
35
54
  BANNER =<<EOH
36
55
  _
@@ -47,10 +66,10 @@ EOH
47
66
  def check_host(host, die_on_fail=true)
48
67
  valid = true
49
68
  port = 443
50
- error_msg = "Host invalid"
69
+ error_msg = _("Host invalid")
51
70
  begin
52
71
  if !host
53
- error_msg = "Host not given"
72
+ error_msg = _("Host not given")
54
73
  valid = false
55
74
  else
56
75
  host_parts = host.split(":")
@@ -64,7 +83,7 @@ EOH
64
83
  end
65
84
 
66
85
  unless valid
67
- printf("Error: %s\n", error_msg)
86
+ printf _("Error: %{error}\n") % { error: error_msg }
68
87
  exit(EXIT_FAILURE) unless !die_on_fail
69
88
  end
70
89
  return valid
@@ -106,7 +125,7 @@ EOH
106
125
  alias_method :run, :main
107
126
 
108
127
  def self.version_info
109
- sprintf("ssl_scan version %s\n%s\n%s\n", VERSION::STRING, WEBSITE, COPYRIGHT)
128
+ _("ssl_scan version %{version}\n%{web}\n%{copy}\n") % { version: VERSION::STRING, web: WEBSITE, copy: COPYRIGHT}
110
129
  end
111
130
 
112
131
  def show_results(host, results)
@@ -114,13 +133,18 @@ EOH
114
133
  unless result_set.empty?
115
134
  result_set.each do |result|
116
135
  show_certificate(result.cert)
136
+
137
+ # TODO: Implement certificate verification
138
+ printf _("Verify Certificate:")
139
+ printf _(" NOT IMPLEMENTED")
140
+ printf("\n")
117
141
  end
118
142
  end
119
143
  end
120
144
 
121
145
  def show_certificate(cert)
122
- printf("SSL Certificate:\n")
123
- printf(" Version: %d\n", cert.version)
146
+ printf _("SSL Certificate:\n")
147
+ printf _(" Version: %{version}\n") % { version: cert.version }
124
148
  printf(" Serial Number: %s\n", cert.serial.to_s(16))
125
149
  printf(" Signature Algorithm: %s\n", cert.signature_algorithm)
126
150
  printf(" Issuer: %s\n", cert.issuer.to_s)
@@ -129,7 +153,34 @@ EOH
129
153
  printf(" Subject: %s\n", cert.subject.to_s)
130
154
  printf(" %s", cert.public_key.to_text)
131
155
 
132
- # TODO: Implement extensions (see: cert.extensions)
156
+ unless cert.extensions.empty?
157
+ puts _("X509v3 Extensions:")
158
+ cert.extensions.each do |extension|
159
+ case extension.oid
160
+ when 'keyUsage'
161
+ puts _(" X509v3 Key Usage: critical") if extension.critical?
162
+ when 'certificatePolicies'
163
+ puts _(" X509v3 Certificate Policies:")
164
+ when 'subjectAltName'
165
+ puts _(" X509v3 Subject Alternative Name:")
166
+ when 'basicConstraints'
167
+ puts _(" X509v3 Basic Constraints:")
168
+ when 'extendedKeyUsage'
169
+ puts _(" X509v3 Extended Key Usage:")
170
+ when 'crlDistributionPoints'
171
+ puts _(" X509v3 CRL Distribution Points:")
172
+ when 'authorityInfoAccess'
173
+ puts _(" Authority Information Access:")
174
+ when 'subjectKeyIdentifier'
175
+ puts _(" X509v3 Subject Key Identifier:")
176
+ when 'authorityKeyIdentifier'
177
+ puts _(" X509v3 Authority Key Identifier:")
178
+ else
179
+ puts extension.oid
180
+ end
181
+ puts _(" %{value}") % { value: extension.value }
182
+ end
183
+ end
133
184
  end
134
185
 
135
186
  def show_command_errors(host, errors)
@@ -143,6 +194,7 @@ EOH
143
194
  options.only_ssl2 = false
144
195
  options.only_ssl3 = false
145
196
  options.only_tls1 = false
197
+ options.only_cert = false
146
198
 
147
199
  opts = OptionParser.new do |opts|
148
200
  opts.banner = sprintf("%s%s", BANNER, version_info)
@@ -155,8 +207,8 @@ EOH
155
207
 
156
208
  # File containing list of hosts to check
157
209
  opts.on( "-t",
158
- "--targets FILE",
159
- "A file containing a list of hosts to check with syntax ( host | host:port).") do |filename|
210
+ _("--targets FILE"),
211
+ _("A file containing a list of hosts to check with syntax ( host | host:port).")) do |filename|
160
212
  options.file = filename
161
213
  end
162
214
 
@@ -181,6 +233,12 @@ EOH
181
233
  options.only_tls1 = :TLSv1
182
234
  end
183
235
 
236
+ opts.on( "-c",
237
+ "--cert",
238
+ "Only get the server certificate") do
239
+ options.only_cert = true
240
+ end
241
+
184
242
  opts.on( "-d",
185
243
  "--debug",
186
244
  "Print any SSL errors to stderr.") do
@@ -7,10 +7,12 @@ module SSLScan
7
7
 
8
8
  attr_reader :ciphers
9
9
  attr_reader :supported_versions
10
+ attr_reader :peer_verified
10
11
 
11
12
  def initialize()
12
13
  @cert = nil
13
14
  @ciphers = Set.new
15
+ @peer_verified = false
14
16
  @supported_versions = [:SSLv2, :SSLv3, :TLSv1]
15
17
  end
16
18
 
@@ -88,8 +88,9 @@ class Scanner
88
88
  return scan_result
89
89
  end
90
90
 
91
- sslctx = OpenSSL::SSL::SSLContext.new(ssl_version)
92
- sslctx.ciphers.each do |cipher_name, ssl_ver, key_length, alg_length|
91
+ sslctx = OpenSSL::SSL::SSLContext.new(ssl_version)
92
+ sslctx.ciphers.each do |cipher_name, ssl_ver, key_length, alg_length|
93
+
93
94
  status = test_cipher(ssl_version, cipher_name)
94
95
  scan_result.add_cipher(ssl_version, cipher_name, key_length, status)
95
96
  if status == :accepted and scan_result.cert.nil?
@@ -121,6 +122,10 @@ class Scanner
121
122
  'Timeout' => @timeout
122
123
  )
123
124
  ssl_versions[ssl_version] = scan_client.cipher
125
+
126
+ if scan_client
127
+ scan_client.close
128
+ end
124
129
  rescue => ex
125
130
  ssl_versions.delete(ssl_version)
126
131
  end
@@ -128,6 +133,36 @@ class Scanner
128
133
  ssl_versions
129
134
  end
130
135
 
136
+
137
+ def get_first_valid_cert
138
+ scan_result = SSLScan::Result.new
139
+ scan_result.openssl_sslv2 = sslv2
140
+ @supported_versions.each do |ssl_version|
141
+ begin
142
+ scan_client = SSLScan::Socket::Tcp.create(
143
+ 'Context' => @context,
144
+ 'PeerHost' => @host,
145
+ 'PeerPort' => @port,
146
+ 'SSL' => true,
147
+ 'SSLVersion' => ssl_version,
148
+ 'Timeout' => @timeout
149
+ )
150
+ cipher_name = scan_client.cipher[0]
151
+ key_length = scan_client.cipher[3]
152
+ status = test_cipher(ssl_version, cipher_name)
153
+ scan_result.add_cipher(ssl_version, cipher_name, key_length, status)
154
+ if status == :accepted and scan_result.cert.nil?
155
+ scan_result.cert = get_cert(ssl_version, cipher_name)
156
+ break
157
+ end
158
+ rescue => ex
159
+ # noop
160
+ end
161
+ end
162
+ @results = scan_result
163
+ scan_result
164
+ end
165
+
131
166
  def test_ssl
132
167
  begin
133
168
  scan_client = SSLScan::Socket::Tcp.create(
@@ -0,0 +1,7 @@
1
+ module SSLScan
2
+ module Util
3
+
4
+ ROOT = File.expand_path("../../../", __FILE__)
5
+
6
+ end
7
+ end
@@ -2,7 +2,7 @@ module SSLScan
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- PATCH = 5
5
+ PATCH = 6
6
6
 
7
7
  STRING = [MAJOR,MINOR,PATCH].join('.')
8
8
  end
Binary file
@@ -0,0 +1,46 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) 2014 John Faucett
3
+ # This file is distributed under the same license as the app package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: ssl_scan 0.0.5\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2013-09-29 17:49-0700\n"
12
+ "PO-Revision-Date: 2013-09-29 17:49-0700\n"
13
+ "Last-Translator: John Faucett <jwaterfaucett@gmail.com>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
20
+
21
+ msgid "Host invalid"
22
+ msgstr "Host ungültig"
23
+
24
+ msgid "Error: %{error}\n"
25
+ msgstr "Fehler: %{error}\n"
26
+
27
+ msgid "Host not given"
28
+ msgstr "Host wurde nicht angegeben"
29
+
30
+ msgid "ssl_scan [Options] [host:port | host]"
31
+ msgstr "ssl_scan [Optionen] [host:port | host]"
32
+
33
+ msgid "Copyright (C) John Faucett %{year}"
34
+ msgstr "Copyright (C) John Faucett %{year}"
35
+
36
+ msgid "SSL Certificate:\n"
37
+ msgstr "SSL Zertifikat:\n"
38
+
39
+ msgid " Version: %{version}\n"
40
+ msgstr " Version: %{version}\n"
41
+
42
+ msgid "A file containing a list of hosts to check with syntax ( host | host:port)."
43
+ msgstr "Eine Datei die eine Liste der zu überprüfenden Hosts enthält ( host | host:port)."
44
+
45
+ msgid "--targets FILE"
46
+ msgstr "--targets DATEI"
Binary file
@@ -0,0 +1,34 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) 2014 John Faucett
3
+ # This file is distributed under the same license as the app package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: ssl_scan 0.0.5\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2013-09-29 17:49-0700\n"
12
+ "PO-Revision-Date: 2013-09-29 17:49-0700\n"
13
+ "Last-Translator: John Faucett <jwaterfaucett@gmail.com>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
20
+
21
+ msgid "Host invalid"
22
+ msgstr "Host invalid"
23
+
24
+ msgid "Error: %{error}\n"
25
+ msgstr "Error: %{error}\n"
26
+
27
+ msgid "Host not given"
28
+ msgstr "Host not given"
29
+
30
+ msgid "ssl_scan [Options] [host:port | host]"
31
+ msgstr "ssl_scan [Options] [host:port | host]"
32
+
33
+ msgid "Copyright (C) John Faucett %{year}"
34
+ msgstr "Copyright (C) John Faucett %{year}"
data/sslscan.gemspec CHANGED
@@ -18,7 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_runtime_dependency "fast_gettext", "~> 0.8"
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.5"
22
24
  spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec", "~> 3.0.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "gettext"
24
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ssl_scan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Faucett
@@ -10,6 +10,20 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2014-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fast_gettext
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.8'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +58,28 @@ dependencies:
44
58
  requirements:
45
59
  - - ~>
46
60
  - !ruby/object:Gem::Version
47
- version: 3.0.0
61
+ version: '3.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - ~>
53
67
  - !ruby/object:Gem::Version
54
- version: 3.0.0
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gettext
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description: An SSL Scanner Library and Utility in pure Ruby
56
84
  email:
57
85
  - jwaterfaucett@gmail.com
@@ -67,6 +95,7 @@ files:
67
95
  - README.md
68
96
  - Rakefile
69
97
  - bin/ssl_scan
98
+ - data/cacert.pem
70
99
  - lib/ssl_scan.rb
71
100
  - lib/ssl_scan/commands/command.rb
72
101
  - lib/ssl_scan/commands/host.rb
@@ -95,7 +124,12 @@ files:
95
124
  - lib/ssl_scan/socket/tcp_server.rb
96
125
  - lib/ssl_scan/socket/udp.rb
97
126
  - lib/ssl_scan/sync/thread_safe.rb
127
+ - lib/ssl_scan/util.rb
98
128
  - lib/ssl_scan/version.rb
129
+ - locale/de/LC_MESSAGES/ssl_scan.mo
130
+ - locale/de/ssl_scan.po
131
+ - locale/en/LC_MESSAGES/ssl_scan.mo
132
+ - locale/en/ssl_scan.po
99
133
  - spec/lib/ssl_scan/scanner_spec.rb
100
134
  - spec/spec_helper.rb
101
135
  - sslscan.gemspec