Browse Source

Refactoring

new-scoring
aeris 1 year ago
parent
commit
3d176613c6

+ 1
- 1
lib/cryptcheck/state.rb View File

@@ -96,7 +96,7 @@ module CryptCheck
96 96
 		def self.compare(a, b)
97 97
 			a = LEVELS.find_index(a.status) || (LEVELS.size - 1) / 2.0
98 98
 			b = LEVELS.find_index(b.status) || (LEVELS.size - 1) / 2.0
99
-			a <=> b
99
+			b <=> a
100 100
 		end
101 101
 
102 102
 		protected

+ 11
- 10
lib/cryptcheck/tls.rb View File

@@ -3,20 +3,21 @@ require 'parallel'
3 3
 
4 4
 module CryptCheck
5 5
 	module Tls
6
-		def self.analyze(host, port)
7
-			::CryptCheck.analyze host, port, TcpServer
6
+		def self.aggregate(hosts)
7
+			hosts = [hosts] unless hosts.respond_to? :collect
8
+			hosts.inject([]) { |l, h| l + h.to_h }
8 9
 		end
9 10
 
10 11
 		def self.key_to_s(key)
11 12
 			size, color = case key.type
12
-							  when :ecc
13
-								  ["#{key.group.curve_name} #{key.size}", :good]
14
-							  when :rsa
15
-								  [key.size, nil]
16
-							  when :dsa
17
-								  [key.size, :critical]
18
-							  when :dh
19
-								  [key.size, :warning]
13
+						  when :ecc
14
+							  ["#{key.group.curve_name} #{key.size}", :good]
15
+						  when :rsa
16
+							  [key.size, nil]
17
+						  when :dsa
18
+							  [key.size, :critical]
19
+						  when :dh
20
+							  [key.size, :warning]
20 21
 						  end
21 22
 			"#{key.type.to_s.upcase.colorize color} #{size.to_s.colorize key.status} bits"
22 23
 		end

+ 35
- 28
lib/cryptcheck/tls/cipher.rb View File

@@ -26,15 +26,17 @@ module CryptCheck
26 26
 					des:       %w(DES-CBC),
27 27
 					des3:      %w(3DES DES-CBC3),
28 28
 					aes:       %w(AES(128|256) AES-(128|256)),
29
+					aes128:    %w(AES128 AES-128),
30
+					aes256:    %w(AES256 AES-256),
29 31
 					camellia:  %w(CAMELLIA(128|256)),
30 32
 					seed:      %w(SEED),
31 33
 					idea:      %w(IDEA),
32 34
 					chacha20:  %w(CHACHA20),
33 35
 
34
-					#cbc:       %w(CBC),
36
+					# cbc:      %w(CBC),
35 37
 					gcm:       %w(GCM),
36 38
 					ccm:       %w(CCM)
37
-			}
39
+			}.freeze
38 40
 
39 41
 			attr_reader :method, :name
40 42
 
@@ -49,6 +51,7 @@ module CryptCheck
49 51
 			end
50 52
 
51 53
 			def self.[](method)
54
+				method = Method[method] if method.is_a? Symbol
52 55
 				SUPPORTED[method]
53 56
 			end
54 57
 
@@ -63,6 +66,15 @@ module CryptCheck
63 66
 				RUBY_EVAL
64 67
 			end
65 68
 
69
+			def self.aes?(cipher)
70
+				aes?(cipher) or aes?(cipher)
71
+			end
72
+
73
+			def aes?
74
+				aes128? or aes256?
75
+			end
76
+
77
+
66 78
 			def self.cbc?(cipher)
67 79
 				!aead? cipher
68 80
 			end
@@ -76,7 +88,7 @@ module CryptCheck
76 88
 			end
77 89
 
78 90
 			def aead?
79
-				gcm? or ccm?
91
+				gcm? or ccm? or chacha20?
80 92
 			end
81 93
 
82 94
 			def ssl?
@@ -96,7 +108,7 @@ module CryptCheck
96 108
 			end
97 109
 
98 110
 			def sweet32?
99
-				size = self.block_size
111
+				size = self.encryption[1]
100 112
 				return false unless size # Not block encryption
101 113
 				size <= 64
102 114
 			end
@@ -115,7 +127,7 @@ module CryptCheck
115 127
 				hmac = self.hmac
116 128
 				{
117 129
 						protocol:   @method, name: self.name, key_exchange: self.kex, authentication: self.auth,
118
-						encryption: { name: self.encryption, mode: self.mode, block_size: self.block_size },
130
+						encryption: self.encryption,
119 131
 						hmac:       { name: hmac.first, size: hmac.last }, states: self.states
120 132
 				}
121 133
 			end
@@ -177,23 +189,27 @@ module CryptCheck
177 189
 			def encryption
178 190
 				case
179 191
 					when chacha20?
180
-						:chacha20
181
-					when aes?
182
-						:aes
192
+						[:chacha20, nil, 128, self.mode]
193
+					when aes128?
194
+						[:aes, 128, 128, self.mode]
195
+					when aes256?
196
+						[:aes, 128, 128, self.mode]
183 197
 					when camellia?
184
-						:camellia
198
+						[:camellia, 128, 128, self.mode]
185 199
 					when seed?
186
-						:seed
200
+						[:seed, 128, 128, self.mode]
187 201
 					when idea?
188
-						:idea
202
+						[:idea, 64, 128, self.mode]
189 203
 					when des3?
190
-						:'3des'
204
+						[:'3des', 64, 112, self.mode]
191 205
 					when des?
192
-						:des
206
+						[:des, 64, 56, self.mode]
193 207
 					when rc4?
194
-						:rc4
208
+						[:rc4, nil, nil, self.mode]
195 209
 					when rc2?
196
-						:rc2
210
+						[:rc2, 64, 64, self.mode]
211
+					when null?
212
+						[nil, nil, nil, nil]
197 213
 				end
198 214
 			end
199 215
 
@@ -203,24 +219,15 @@ module CryptCheck
203 219
 						:gcm
204 220
 					when ccm?
205 221
 						:ccm
206
-					when rc4? || chacha20?
222
+					when chacha20?
223
+						:aead
224
+					when rc4?
207 225
 						nil
208 226
 					else
209 227
 						:cbc
210 228
 				end
211 229
 			end
212 230
 
213
-			def block_size
214
-				case self.encryption
215
-					when :'3des', :idea, :rc2
216
-						64
217
-					when :aes, :camellia, :seed
218
-						128
219
-					else
220
-						nil
221
-				end
222
-			end
223
-
224 231
 			def hmac
225 232
 				case
226 233
 					when poly1305?
@@ -265,7 +272,7 @@ module CryptCheck
265 272
 				@name <=> other.name
266 273
 			end
267 274
 
268
-			ALL       = 'ALL:COMPLEMENTOFALL'
275
+			ALL       = 'ALL:COMPLEMENTOFALL'.freeze
269 276
 			SUPPORTED = Method.collect do |m|
270 277
 				context         = ::OpenSSL::SSL::SSLContext.new m.to_sym
271 278
 				context.ciphers = ALL

+ 40
- 33
lib/cryptcheck/tls/engine.rb View File

@@ -4,6 +4,7 @@ require 'openssl'
4 4
 module CryptCheck
5 5
 	module Tls
6 6
 		module Engine
7
+			SLOW_DOWN   = ENV.fetch('SLOW_DOWN', '0').to_i
7 8
 			TCP_TIMEOUT = 10
8 9
 			TLS_TIMEOUT = 2*TCP_TIMEOUT
9 10
 
@@ -176,11 +177,15 @@ module CryptCheck
176 177
 						ecdsa = ciphers.keys.detect &:ecdsa?
177 178
 						next unless ecdsa
178 179
 						@supported_curves = Curve.select do |curve|
179
-							next true if curve == ecdsa_curve # ECDSA curve is always supported
180
+							if curve == ecdsa_curve
181
+								# ECDSA curve is always supported
182
+								Logger.info { "  ECC curve #{curve.name}" }
183
+								next true
184
+							end
180 185
 							begin
181
-								connection       = ssl_client method, ecdsa, curves: [curve, ecdsa_curve]
186
+								connection = ssl_client method, ecdsa, curves: [curve, ecdsa_curve]
182 187
 								# Not too fast !!!
183
-								# Handshake will **always** succeed, because ECDSA
188
+								# Handshake will **always** succeed, because ECDSA
184 189
 								# curve is always supported.
185 190
 								# So, we need to test for the real curve!
186 191
 								# Treaky case : if server preference is enforced,
@@ -248,7 +253,7 @@ module CryptCheck
248 253
 											 Logger.info { 'Curves preference : ' + 'client preference'.colorize(:warning) }
249 254
 											 :client
250 255
 										 else
251
-											 sort        = -> (a, b) do
256
+											 sort        = lambda do |a, b|
252 257
 												 curves = [a, b]
253 258
 												 if cipher.ecdsa?
254 259
 													 # In case of ECDSA, add the cert key at the end
@@ -273,10 +278,10 @@ module CryptCheck
273 278
 				if @supported_methods.size > 1
274 279
 					# We will try to connect to the not better supported method
275 280
 					method = @supported_methods[1]
276
-
277 281
 					begin
278 282
 						ssl_client method, fallback: true
279
-					rescue InappropriateFallback
283
+					rescue InappropriateFallback,
284
+							CipherNotAvailable # Seems some servers reply with "sslv3 alert handshake failure"...
280 285
 						@fallback_scsv = true
281 286
 					end
282 287
 				else
@@ -284,12 +289,12 @@ module CryptCheck
284 289
 				end
285 290
 
286 291
 				text, color = case @fallback_scsv
287
-								  when true
288
-									  ['supported', :good]
289
-								  when false
290
-									  ['not supported', :error]
291
-								  when nil
292
-									  ['not applicable', :unknown]
292
+							  when true
293
+								  ['supported', :good]
294
+							  when false
295
+								  ['not supported', :error]
296
+							  when nil
297
+								  ['not applicable', :unknown]
293 298
 							  end
294 299
 				Logger.info { 'Fallback SCSV : ' + text.colorize(color) }
295 300
 			end
@@ -311,6 +316,7 @@ module CryptCheck
311 316
 			end
312 317
 
313 318
 			private
319
+
314 320
 			def connect(&block)
315 321
 				socket   = ::Socket.new @family, sock_type
316 322
 				sockaddr = ::Socket.sockaddr_in @port, @ip
@@ -354,26 +360,26 @@ module CryptCheck
354 360
 					retry
355 361
 				rescue ::OpenSSL::SSL::SSLError => e
356 362
 					case e.message
357
-						when /state=SSLv2 read server hello A$/,
358
-								/state=SSLv3 read server hello A$/,
359
-								/state=SSLv3 read server hello A: wrong version number$/,
360
-								/state=SSLv3 read server hello A: tlsv1 alert protocol version$/,
361
-								/state=SSLv3 read server key exchange A: sslv3 alert handshake failure$/
362
-							raise MethodNotAvailable, e
363
-						when /state=SSLv2 read server hello A: peer error no cipher$/,
364
-								/state=error: no ciphers available$/,
365
-								/state=SSLv3 read server hello A: sslv3 alert handshake failure$/,
366
-								/state=error: missing export tmp dh key$/,
367
-								/state=error: wrong curve$/
368
-							raise CipherNotAvailable, e
369
-						when /state=SSLv3 read server hello A: tlsv1 alert inappropriate fallback$/
370
-							raise InappropriateFallback, e
363
+					when /state=SSLv2 read server hello A$/,
364
+							/state=SSLv3 read server hello A$/,
365
+							/state=SSLv3 read server hello A: wrong version number$/,
366
+							/state=SSLv3 read server hello A: tlsv1 alert protocol version$/,
367
+							/state=SSLv3 read server key exchange A: sslv3 alert handshake failure$/
368
+						raise MethodNotAvailable, e
369
+					when /state=SSLv2 read server hello A: peer error no cipher$/,
370
+							/state=error: no ciphers available$/,
371
+							/state=SSLv3 read server hello A: sslv3 alert handshake failure$/,
372
+							/state=error: missing export tmp dh key$/,
373
+							/state=error: wrong curve$/
374
+						raise CipherNotAvailable, e
375
+					when /state=SSLv3 read server hello A: tlsv1 alert inappropriate fallback$/
376
+						raise InappropriateFallback, e
371 377
 					end
372 378
 					raise
373 379
 				rescue ::SystemCallError => e
374 380
 					case e.message
375
-						when /^Connection reset by peer - SSL_connect$/
376
-							raise TLSNotAvailableException, e
381
+					when /^Connection reset by peer - SSL_connect$/
382
+						raise TLSNotAvailableException, e
377 383
 					end
378 384
 					raise
379 385
 				ensure
@@ -382,6 +388,7 @@ module CryptCheck
382 388
 			end
383 389
 
384 390
 			def ssl_client(method, ciphers = nil, curves: nil, fallback: false, &block)
391
+				sleep SLOW_DOWN if SLOW_DOWN > 0
385 392
 				ssl_context = ::OpenSSL::SSL::SSLContext.new method.to_sym
386 393
 				ssl_context.enable_fallback_scsv if fallback
387 394
 
@@ -394,7 +401,7 @@ module CryptCheck
394 401
 				ssl_context.ciphers = ciphers
395 402
 
396 403
 				if curves
397
-					curves                  = [curves] unless curves.is_a? Enumerable
404
+					curves = [curves] unless curves.is_a? Enumerable
398 405
 					# OpenSSL fails if the same curve is selected multiple times
399 406
 					# So because Array#uniq preserves order, remove the less prefered ones
400 407
 					curves                  = curves.collect(&:name).uniq.join ':'
@@ -421,14 +428,14 @@ module CryptCheck
421 428
 				# Let's begin the fun
422 429
 				# First, collect "standard" connections
423 430
 				# { method => { cipher => connection, ... }, ... }
424
-				certs  = @supported_ciphers.values.collect(&:values).flatten 1
431
+				certs = @supported_ciphers.values.collect(&:values).flatten 1
425 432
 				# Then, collect "ecdsa" connections
426 433
 				# { curve => connection, ... }
427
-				certs  += @ecdsa_certs.values
434
+				certs += @ecdsa_certs.values
428 435
 				# For anonymous cipher, there is no certificate at all
429
-				certs  = certs.reject { |c| c.peer_cert.nil? }
436
+				certs = certs.reject { |c| c.peer_cert.nil? }
430 437
 				# Then, fetch cert
431
-				certs  = certs.collect { |c| Cert.new c }
438
+				certs = certs.collect { |c| Cert.new c }
432 439
 				# Then, filter cert to keep uniq fingerprint
433 440
 				@certs = certs.uniq { |c| c.fingerprint }
434 441
 

+ 31
- 25
lib/cryptcheck/tls/fixture.rb View File

@@ -33,12 +33,14 @@ class ::OpenSSL::PKey::EC
33 33
 	CHECKS = [
34 34
 			[:ecc, %i(critical error warning), -> (s) do
35 35
 				case s.size
36
-					when 0...160
37
-						:critical
38
-					when 160...192
39
-						:error
40
-					when 192...256
41
-						:warning
36
+				when 0...160
37
+					:critical
38
+				when 160...192
39
+					:error
40
+				when 192...256
41
+					:warning
42
+				else
43
+					false
42 44
 				end
43 45
 			end]
44 46
 	].freeze
@@ -69,12 +71,14 @@ class ::OpenSSL::PKey::RSA
69 71
 	include ::CryptCheck::State
70 72
 
71 73
 	CHECKS = [
72
-			[:rsa, %i(critical error), -> (s) do
74
+			[:rsa, %i(critical error), ->(s) do
73 75
 				case s.size
74
-					when 0...1024
75
-						:critical
76
-					when 1024...2048
77
-						:error
76
+				when 0...1024
77
+					:critical
78
+				when 1024...2048
79
+					:error
80
+				else
81
+					false
78 82
 				end
79 83
 			end]
80 84
 	].freeze
@@ -136,10 +140,12 @@ class ::OpenSSL::PKey::DH
136 140
 	CHECKS = [
137 141
 			[:dh, %i(critical error), -> (s) do
138 142
 				case s.size
139
-					when 0...1024
140
-						:critical
141
-					when 1024...2048
142
-						:error
143
+				when 0...1024
144
+					:critical
145
+				when 1024...2048
146
+					:error
147
+				else
148
+					false
143 149
 				end
144 150
 			end]
145 151
 	].freeze
@@ -161,17 +167,17 @@ class ::OpenSSL::X509::Store
161 167
 		chains = [chains] unless chains.is_a? Enumerable
162 168
 		chains.each do |chain|
163 169
 			case chain
164
-				when ::OpenSSL::X509::Certificate
165
-					self.add_cert chain
170
+			when ::OpenSSL::X509::Certificate
171
+				self.add_cert chain
172
+			else
173
+				if File.directory?(chain)
174
+					Dir.entries(chain)
175
+							.collect { |e| File.join chain, e }
176
+							.select { |e| File.file? e }
177
+							.each { |f| self.add_file f }
166 178
 				else
167
-					if File.directory?(chain)
168
-						Dir.entries(chain)
169
-								.collect { |e| File.join chain, e }
170
-								.select { |e| File.file? e }
171
-								.each { |f| self.add_file f }
172
-					else
173
-						self.add_file chain
174
-					end
179
+					self.add_file chain
180
+				end
175 181
 			end
176 182
 		end
177 183
 	end

+ 17
- 8
lib/cryptcheck/tls/host.rb View File

@@ -1,4 +1,5 @@
1 1
 require 'awesome_print'
2
+AwesomePrint.force_colors = true
2 3
 require 'timeout'
3 4
 
4 5
 module CryptCheck
@@ -31,7 +32,7 @@ module CryptCheck
31 32
 
32 33
 				first    = true
33 34
 				@servers = resolve.collect do |args|
34
-					_, ip, _, _ = args
35
+					_, ip = args
35 36
 					first ? (first = false) : Logger.info { '' }
36 37
 					result = begin
37 38
 						server = ::Timeout.timeout MAX_ANALYSIS_DURATION do
@@ -42,24 +43,31 @@ module CryptCheck
42 43
 						Logger.info { server.states.ai }
43 44
 						server
44 45
 					rescue Engine::TLSException, Engine::ConnectionError, Engine::Timeout => e
46
+						# Logger.error { e.backtrace }
47
+						Logger.error { e }
45 48
 						AnalysisFailure.new e
46 49
 					rescue ::Timeout::Error
50
+						# Logger.error { e.backtrace }
51
+						Logger.error { e }
47 52
 						TooLongAnalysis.new
48 53
 					end
49 54
 					[[@hostname, ip, @port], result]
50 55
 				end.to_h
51 56
 			rescue => e
57
+				# Logger.error { e.backtrace }
58
+				Logger.error { e }
52 59
 				@error = e
53 60
 			end
54 61
 
62
+			def key
63
+				{ hostname: @hostname, port: @port }
64
+			end
65
+
55 66
 			def to_h
56
-				target = {
57
-						target: { hostname: @hostname, port: @port },
58
-				}
59 67
 				if @error
60
-					target[:error] = @error
68
+					target = { error: @error }
61 69
 				else
62
-					target[:hosts] = @servers.collect do |host, server|
70
+					target = @servers.collect do |host, server|
63 71
 						hostname, ip, port = host
64 72
 						host               = {
65 73
 								hostname: hostname,
@@ -72,7 +80,7 @@ module CryptCheck
72 80
 								host[:states]     = server.states
73 81
 								host[:grade]     = server.grade
74 82
 							else
75
-								host[:error] = server.message
83
+								host[:error] = server.to_s
76 84
 						end
77 85
 						host
78 86
 					end
@@ -81,10 +89,11 @@ module CryptCheck
81 89
 			end
82 90
 
83 91
 			private
92
+
84 93
 			def resolve
85 94
 				begin
86 95
 					ip = IPAddr.new @hostname
87
-					return [[nil, ip.to_s, ip.family]]
96
+					return [[nil, ip.to_s, ip.family, @port]]
88 97
 				rescue IPAddr::InvalidAddressError
89 98
 				end
90 99
 				::Addrinfo.getaddrinfo(@hostname, nil, nil, :STREAM)

+ 5
- 6
lib/cryptcheck/tls/https.rb View File

@@ -1,12 +1,11 @@
1
+require 'resolv'
2
+
1 3
 module CryptCheck
2 4
 	module Tls
3 5
 		module Https
4
-			def self.analyze(host, port=443)
5
-				::CryptCheck.analyze host, port, Server
6
-			end
7
-
8
-			def self.analyze_file(input, output)
9
-				::CryptCheck.analyze_file(input, 'output/https.erb', output) { |host| self.analyze host }
6
+			def self.analyze(hostname, port = 443)
7
+				host = Host.new hostname, port
8
+				Tls.aggregate host
10 9
 			end
11 10
 		end
12 11
 	end

+ 1
- 0
lib/cryptcheck/tls/https/host.rb View File

@@ -3,6 +3,7 @@ module CryptCheck
3 3
 		module Https
4 4
 			class Host < Tls::Host
5 5
 				private
6
+
6 7
 				def server(*args)
7 8
 					Https::Server.new *args
8 9
 				end

+ 7
- 5
lib/cryptcheck/tls/https/server.rb View File

@@ -6,7 +6,7 @@ module CryptCheck
6 6
 			class Server < Tls::TcpServer
7 7
 				attr_reader :hsts
8 8
 
9
-				def initialize(hostname, ip, family, port=443)
9
+				def initialize(hostname, ip, family, port = 443)
10 10
 					super
11 11
 					fetch_hsts
12 12
 				end
@@ -19,7 +19,7 @@ module CryptCheck
19 19
 												   {
20 20
 														   follow_redirects: false,
21 21
 														   verify:           false,
22
-														   timeout: TLS_TIMEOUT,
22
+														   timeout:          TLS_TIMEOUT,
23 23
 														   ssl_version:      @supported_methods.first.to_sym,
24 24
 														   ciphers:          Cipher::ALL
25 25
 												   }
@@ -31,7 +31,8 @@ module CryptCheck
31 31
 								return
32 32
 							end
33 33
 						end
34
-					rescue
34
+					rescue Exception => e
35
+						Logger.debug { e }
35 36
 					end
36 37
 
37 38
 					Logger.info { 'No HSTS'.colorize :warning }
@@ -42,7 +43,7 @@ module CryptCheck
42 43
 					!@hsts.nil?
43 44
 				end
44 45
 
45
-				LONG_HSTS = 6*30*24*60*60
46
+				LONG_HSTS = 6 * 30 * 24 * 60 * 60
46 47
 
47 48
 				def hsts_long?
48 49
 					hsts? and @hsts >= LONG_HSTS
@@ -53,10 +54,11 @@ module CryptCheck
53 54
 				end
54 55
 
55 56
 				protected
57
+
56 58
 				def available_checks
57 59
 					super + [
58 60
 							[:hsts, %i(warning good great), -> (s) { s.hsts_long? ? :great : s.hsts? ? :good : :warning }],
59
-							#[:must_staple, :best, -> (s) { s.must_staple? }],
61
+					#[:must_staple, :best, -> (s) { s.must_staple? }],
60 62
 					]
61 63
 				end
62 64
 			end

+ 2
- 2
lib/cryptcheck/tls/method.rb View File

@@ -31,7 +31,7 @@ module CryptCheck
31 31
 				{ protocol: self.to_sym, states: self.states }
32 32
 			end
33 33
 
34
-			alias :to_sym :__getobj__
34
+			alias to_sym __getobj__
35 35
 
36 36
 			def <=>(other)
37 37
 				EXISTING.find_index(self) <=> EXISTING.find_index(other)
@@ -44,7 +44,7 @@ module CryptCheck
44 44
 					[:sslv3, :critical, -> (s) { s == :SSLv3 }],
45 45
 					[:tlsv1_0, :error, -> (s) { s == :TLSv1 }],
46 46
 					[:tlsv1_1, :warning, -> (s) { s == :TLSv1_1 }]
47
-			]
47
+			].freeze
48 48
 
49 49
 			protected
50 50
 			def available_checks

+ 27
- 10
lib/cryptcheck/tls/server.rb View File

@@ -62,15 +62,32 @@ module CryptCheck
62 62
 			end
63 63
 
64 64
 			def to_h
65
+				ciphers_preference = @preferences.collect do |p, cs|
66
+					case cs
67
+					when :client
68
+						{ protocol: p, client: true }
69
+					when nil
70
+						{ protocol: p, na: true }
71
+					else
72
+						{ protocol: p, cipher_suite: cs.collect(&:to_h) }
73
+					end
74
+				end
75
+
76
+				curves_preferences = case @curves_preference
77
+									 when :client
78
+										 :client
79
+									 else
80
+										 @curves_preference&.collect(&:name)
81
+									 end
65 82
 				{
66
-						certs:            @certs.collect(&:to_h),
67
-						dh:               @dh.collect(&:to_h),
68
-						protocols:        @supported_methods.collect(&:to_h),
69
-						ciphers:          uniq_supported_ciphers.collect(&:to_h),
70
-						cipher_suites:    @preferences.collect { |p, cs| { protocol: p, cipher_suite: cs.collect(&:name) } },
71
-						curves:           @supported_curves.collect(&:to_h),
72
-						curve_preference: @curves_preference.collect(&:name),
73
-						fallback_scsv:    @fallback_scsv
83
+						certs:              @certs.collect(&:to_h),
84
+						dh:                 @dh.collect(&:to_h),
85
+						protocols:          @supported_methods.collect(&:to_h),
86
+						ciphers:            uniq_supported_ciphers.collect(&:to_h),
87
+						ciphers_preference: ciphers_preference,
88
+						curves:             @supported_curves.collect(&:to_h),
89
+						curves_preference:  curves_preferences,
90
+						fallback_scsv:      @fallback_scsv
74 91
 				}
75 92
 			end
76 93
 
@@ -78,11 +95,11 @@ module CryptCheck
78 95
 			include State
79 96
 
80 97
 			CHECKS = [
81
-					[:fallback_scsv, :good, -> (s) { s.fallback_scsv? }]
98
+					[:fallback_scsv, :good, -> (s) { s.fallback_scsv? }],
82 99
 			# [:tlsv1_2_only, -> (s) { s.tlsv1_2_only? }, :great],
83 100
 			# [:pfs_only, -> (s) { s.pfs_only? }, :great],
84 101
 			# [:ecdhe_only, -> (s) { s.ecdhe_only? }, :great],
85
-			#[:aead_only, -> (s) { s.aead_only? }, :best],
102
+			# [:aead_only, -> (s) { s.aead_only? }, :best],
86 103
 			].freeze
87 104
 
88 105
 			def available_checks

+ 11
- 13
lib/cryptcheck/tls/smtp.rb View File

@@ -1,20 +1,18 @@
1
+require 'resolv'
2
+
1 3
 module CryptCheck
2 4
 	module Tls
3 5
 		module Smtp
4
-			def self.analyze(host, port=25, domain: nil)
5
-				::CryptCheck.analyze host, port, Server, Grade, domain: domain
6
-			end
7
-
8
-			def self.analyze_domain(domain)
9
-				srv = Resolv::DNS.new.getresources(domain, Resolv::DNS::Resource::IN::MX).sort_by &:preference
10
-				hosts = srv.empty? ? [domain] : srv.collect { |s| s.exchange.to_s }
11
-				results = {}
12
-				hosts.each { |h| results.merge! self.analyze(h, domain: domain) }
13
-				results
14
-			end
6
+			def self.analyze(hostname, port = 25)
7
+				srv   = ::Resolv::DNS.new.getresources(hostname, ::Resolv::DNS::Resource::IN::MX)
8
+								.sort_by &:preference
9
+				hosts = if srv.empty?
10
+							[hostname]
11
+						else
12
+							srv.collect { |s| s.exchange.to_s }
13
+						end
15 14
 
16
-			def self.analyze_file(input, output)
17
-				::CryptCheck.analyze_file(input, 'output/smtp.erb', output) { |host| self.analyze_domain host }
15
+				Tls.aggregate hosts.collect { |h| Host.new h, port }
18 16
 			end
19 17
 		end
20 18
 	end

+ 13
- 0
lib/cryptcheck/tls/smtp/host.rb View File

@@ -0,0 +1,13 @@
1
+module CryptCheck
2
+	module Tls
3
+		module Smtp
4
+			class Host < Tls::Host
5
+				private
6
+
7
+				def server(*args)
8
+					Smtp::Server.new *args
9
+				end
10
+			end
11
+		end
12
+	end
13
+end

+ 0
- 8
lib/cryptcheck/tls/smtp/server.rb View File

@@ -2,18 +2,10 @@ module CryptCheck
2 2
 	module Tls
3 3
 		module Smtp
4 4
 			class Server < Tls::TcpServer
5
-				attr_reader :domain
6
-
7
-				def initialize(hostname, family, ip, port, domain:)
8
-					@domain = domain
9
-					super hostname, family, ip, port
10
-				end
11
-
12 5
 				def ssl_connect(socket, context, method, &block)
13 6
 					socket.recv 1024
14 7
 					socket.write "EHLO #{Socket.gethostbyname(Socket.gethostname).first}\r\n"
15 8
 					features = socket.recv(1024).split "\r\n"
16
-					features
17 9
 					starttls = features.find { |f| /250[- ]STARTTLS/ =~ f }
18 10
 					raise TLSNotAvailableException unless starttls
19 11
 					socket.write "STARTTLS\r\n"

+ 15
- 18
lib/cryptcheck/tls/xmpp.rb View File

@@ -1,27 +1,24 @@
1 1
 module CryptCheck
2 2
 	module Tls
3 3
 		module Xmpp
4
-			def self.analyze(host, port=nil, domain: nil, type: :s2s)
5
-				domain ||= host
6
-				::CryptCheck.analyze host, port, Server, Grade, domain: domain, type: type
7
-			end
8
-
9
-			def self.analyze_domain(domain, type: :s2s)
4
+			def self.analyze(hostname, type = :s2s)
10 5
 				service, port = case type
11
-									when :s2s
12
-										['_xmpp-server', 5269]
13
-									when :c2s
14
-										['_xmpp-client', 5222]
6
+								when :s2s
7
+									['_xmpp-server', 5269]
8
+								when :c2s
9
+									['_xmpp-client', 5222]
10
+								end
11
+				srv           = Resolv::DNS.new.getresources("#{service}._tcp.#{hostname}",
12
+															 Resolv::DNS::Resource::IN::SRV)
13
+										.sort_by &:priority
14
+				hosts         = if srv.empty?
15
+									[[hostname, port]]
16
+								else
17
+									srv.collect { |s| [s.target.to_s, s.port] }
15 18
 								end
16
-				srv = Resolv::DNS.new.getresources("#{service}._tcp.#{domain}", Resolv::DNS::Resource::IN::SRV).sort_by &:priority
17
-				hosts = srv.empty? ? [[domain, port]] : srv.collect { |s| [s.target.to_s, s.port] }
18
-				results = {}
19
-				hosts.each { |host, port| results.merge! self.analyze(host, port, domain: domain, type: type) }
20
-				results
21
-			end
22 19
 
23
-			def self.analyze_file(input, output)
24
-				::CryptCheck.analyze_file(input, 'output/xmpp.erb', output) { |host| self.analyze_domain host }
20
+				hosts.collect { |args| Host.new *args, domain: hostname }
21
+				p hosts
25 22
 			end
26 23
 		end
27 24
 	end

+ 22
- 0
lib/cryptcheck/tls/xmpp/host.rb View File

@@ -0,0 +1,22 @@
1
+module CryptCheck
2
+	module Tls
3
+		module Xmpp
4
+			class Host < Tls::Host
5
+				attr_reader :domain
6
+
7
+				def initialize(*args, domain: nil, type: :s2s)
8
+					@domain, @type = domain, type
9
+					super *args
10
+					Logger.info { '' }
11
+					Logger.info { self.required? ? 'Required'.colorize(:good) : 'Not required'.colorize(:warning) }
12
+				end
13
+
14
+				private
15
+
16
+				def server(*args)
17
+					Xmpp::Server.new *args, domain: @domain, type: @type
18
+				end
19
+			end
20
+		end
21
+	end
22
+end

+ 13
- 13
lib/cryptcheck/tls/xmpp/server.rb View File

@@ -3,31 +3,31 @@ require 'nokogiri'
3 3
 module CryptCheck
4 4
 	module Tls
5 5
 		module Xmpp
6
-			TLS_NAMESPACE = 'urn:ietf:params:xml:ns:xmpp-tls'
7
-
8 6
 			class Server < Tls::TcpServer
9 7
 				attr_reader :domain
10 8
 
11
-				def initialize(hostname, family, ip, port=nil, domain: nil, type: :s2s)
9
+				def initialize(hostname, ip, family, port = nil, domain: nil, type: :s2s)
12 10
 					domain         ||= hostname
13
-					@type, @domain = type, domain
11
+					@domain, @type = domain, type
14 12
 					port           = case type
15
-										 when :s2s
16
-											 5269
17
-										 when :c2s
18
-											 5222
13
+									 when :s2s
14
+										 5269
15
+									 when :c2s
16
+										 5222
19 17
 									 end unless port
20
-					super hostname, family, ip, port
18
+					super hostname, ip, family, port
21 19
 					Logger.info { '' }
22 20
 					Logger.info { self.required? ? 'Required'.colorize(:good) : 'Not required'.colorize(:warning) }
23 21
 				end
24 22
 
23
+				TLS_NAMESPACE = 'urn:ietf:params:xml:ns:xmpp-tls'.freeze
24
+
25 25
 				def ssl_connect(socket, context, method, &block)
26 26
 					type = case @type
27
-							   when :s2s then
28
-								   'jabber:server'
29
-							   when :c2s then
30
-								   'jabber:client'
27
+						   when :s2s then
28
+							   'jabber:server'
29
+						   when :c2s then
30
+							   'jabber:client'
31 31
 						   end
32 32
 					socket.puts "<?xml version='1.0' ?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='#{type}' to='#{@domain}' version='1.0'>"
33 33
 					response = ''

Loading…
Cancel
Save