Selaa lähdekoodia

Move checks from grade to server/cert/key/dh

new-scoring
aeris 2 vuotta sitten
vanhempi
commit
416737d33c

+ 4
- 1
lib/cryptcheck.rb Näytä tiedosto

@@ -2,7 +2,6 @@ require 'colorize'
2 2
 require 'ipaddr'
3 3
 require 'timeout'
4 4
 require 'yaml'
5
-require 'cryptcheck/tls/fixture'
6 5
 
7 6
 module CryptCheck
8 7
 	MAX_ANALYSIS_DURATION = 120
@@ -96,6 +95,7 @@ module CryptCheck
96 95
 						else
97 96
 							server.new *a, **kargs
98 97
 						end
98
+					ap s.status
99 99
 					exit
100 100
 					if grade
101 101
 						g = grade.new s
@@ -181,3 +181,6 @@ module CryptCheck
181 181
 		SCORES.index a.grade
182 182
 	end
183 183
 end
184
+
185
+require 'cryptcheck/fixture'
186
+require 'cryptcheck/tls/fixture'

+ 52
- 0
lib/cryptcheck/fixture.rb Näytä tiedosto

@@ -0,0 +1,52 @@
1
+class String
2
+	alias :colorize_old :colorize
3
+
4
+	COLORS = {
5
+			critical: { color: :white, background: :red },
6
+			error:    :red,
7
+			warning:  :light_red,
8
+			good:     :green,
9
+			perfect:  :blue,
10
+			best:     :magenta,
11
+			unknown:  { background: :black }
12
+	}
13
+
14
+	def colorize(state)
15
+		color = COLORS[state] || state
16
+		self.colorize_old color
17
+	end
18
+end
19
+
20
+class Exception
21
+	BACKTRACE_REGEXP = /^(.*):(\d+):in `(.*)'$/
22
+
23
+	def colorize
24
+		$stderr.puts self.message.colorize(:red)
25
+		self.backtrace.each do |line|
26
+			line = BACKTRACE_REGEXP.match line
27
+			line = '%s:%s:in `%s\'' % [
28
+					line[1].colorize(:yellow),
29
+					line[2].colorize(:blue),
30
+					line[3].colorize(:magenta)
31
+			]
32
+			$stderr.puts line
33
+		end
34
+	end
35
+end
36
+
37
+class Integer
38
+	def humanize
39
+		secs = self
40
+		[[60, :second],
41
+		 [60, :minute],
42
+		 [24, :hour],
43
+		 [30, :day],
44
+		 [12, :month]].map do |count, name|
45
+			if secs > 0
46
+				secs, n = secs.divmod count
47
+				n       = n.to_i
48
+				n > 0 ? "#{n} #{name}#{n > 1 ? 's' : ''}" : nil
49
+			end
50
+		end.compact.reverse.join ' '
51
+	end
52
+end

+ 10
- 0
lib/cryptcheck/tls/cert.rb Näytä tiedosto

@@ -106,6 +106,16 @@ module CryptCheck
106 106
 			def issuer
107 107
 				@cert.issuer
108 108
 			end
109
+
110
+			include ::CryptCheck::Statused
111
+
112
+			CHECKS = [:weak_sign, -> (s) do
113
+				not (SIGNATURE_ALGORITHMS_X509[s.signature_algorithm] & WEAK_SIGN).empty?
114
+			end, :critical].freeze
115
+
116
+			def children
117
+				[self.key]
118
+			end
109 119
 		end
110 120
 	end
111 121
 end

+ 57
- 87
lib/cryptcheck/tls/fixture.rb Näytä tiedosto

@@ -1,58 +1,5 @@
1 1
 require 'openssl'
2 2
 
3
-class String
4
-	alias :colorize_old :colorize
5
-
6
-	COLORS = {
7
-			critical: { color: :white, background: :red },
8
-			error:    :red,
9
-			warning:  :light_red,
10
-			good:     :green,
11
-			perfect:  :blue,
12
-			best:     :magenta,
13
-			unknown:  { background: :black }
14
-	}
15
-
16
-	def colorize(state)
17
-		color = COLORS[state] || state
18
-		self.colorize_old color
19
-	end
20
-end
21
-
22
-class Exception
23
-	BACKTRACE_REGEXP = /^(.*):(\d+):in `(.*)'$/
24
-
25
-	def colorize
26
-		$stderr.puts self.message.colorize(:red)
27
-		self.backtrace.each do |line|
28
-			line = BACKTRACE_REGEXP.match line
29
-			line = '%s:%s:in `%s\'' % [
30
-					line[1].colorize(:yellow),
31
-					line[2].colorize(:blue),
32
-					line[3].colorize(:magenta)
33
-			]
34
-			$stderr.puts line
35
-		end
36
-	end
37
-end
38
-
39
-class Integer
40
-	def humanize
41
-		secs = self
42
-		[[60, :second],
43
-		 [60, :minute],
44
-		 [24, :hour],
45
-		 [30, :day],
46
-		 [12, :month]].map do |count, name|
47
-			if secs > 0
48
-				secs, n = secs.divmod count
49
-				n       = n.to_i
50
-				n > 0 ? "#{n} #{name}#{n > 1 ? 's' : ''}" : nil
51
-			end
52
-		end.compact.reverse.join ' '
53
-	end
54
-end
55
-
56 3
 class ::OpenSSL::PKey::EC
57 4
 	def type
58 5
 		:ecc
@@ -70,18 +17,23 @@ class ::OpenSSL::PKey::EC
70 17
 		"ECC #{self.size} bits"
71 18
 	end
72 19
 
73
-	def status
74
-		case self.size
75
-			when 0...160
76
-				:critical
77
-			when 160...192
78
-				:error
79
-			when 192...256
80
-				:warning
81
-			when 256...364
82
-			else
83
-				:good
84
-		end
20
+	include ::CryptCheck::Statused
21
+
22
+	CHECKS = [
23
+			[:weak_key, -> (s) do
24
+				case s.size
25
+					when 0...160
26
+						:critical
27
+					when 160...192
28
+						:error
29
+					when 192...256
30
+						:warning
31
+				end
32
+			end]
33
+	].freeze
34
+
35
+	def checks
36
+		CHECKS
85 37
 	end
86 38
 end
87 39
 
@@ -98,16 +50,21 @@ class ::OpenSSL::PKey::RSA
98 50
 		"RSA #{self.size} bits"
99 51
 	end
100 52
 
101
-	def status
102
-		case self.size
103
-			when 0...1024
104
-				:critical
105
-			when 1024...2048
106
-				:error
107
-			when 2048...4096
108
-			else
109
-				:good
110
-		end
53
+	include ::CryptCheck::Statused
54
+
55
+	CHECKS = [
56
+			[:weak_key, -> (s) do
57
+				case s.size
58
+					when 0...1024
59
+						:critical
60
+					when 1024...2048
61
+						:error
62
+				end
63
+			end]
64
+	].freeze
65
+
66
+	def checks
67
+		CHECKS
111 68
 	end
112 69
 end
113 70
 
@@ -124,8 +81,14 @@ class ::OpenSSL::PKey::DSA
124 81
 		"DSA #{self.size} bits"
125 82
 	end
126 83
 
127
-	def status
128
-		return :critical
84
+	include ::CryptCheck::Statused
85
+
86
+	CHECKS = [
87
+			[:weak_key, -> (_) { :critical }]
88
+	].freeze
89
+
90
+	def checks
91
+		CHECKS
129 92
 	end
130 93
 end
131 94
 
@@ -142,16 +105,23 @@ class ::OpenSSL::PKey::DH
142 105
 		"DH #{self.size} bits"
143 106
 	end
144 107
 
145
-	def status
146
-		case self.size
147
-			when 0...1024
148
-				:critical
149
-			when 1024...2048
150
-				:error
151
-			when 2048...4096
152
-			else
153
-				:good
154
-		end
108
+	include ::CryptCheck::Statused
109
+
110
+	CHECKS = [
111
+			[:weak_dh, -> (s) do
112
+				case s.size
113
+					when 0...1024
114
+						:critical
115
+					when 1024...2048
116
+						:error
117
+					else
118
+						:warning
119
+				end
120
+			end]
121
+	].freeze
122
+
123
+	def checks
124
+		CHECKS
155 125
 	end
156 126
 end
157 127
 

+ 0
- 67
lib/cryptcheck/tls/grade.rb Näytä tiedosto

@@ -67,73 +67,6 @@ module CryptCheck
67 67
 
68 68
 				'A+'
69 69
 			end
70
-
71
-			CHECKS = ([
72
-					# Certificates
73
-					[:weak_sign, Proc.new { |s|
74
-						Cert::WEAK_SIGN[:critical]
75
-					}, :critical],
76
-
77
-					# Keys
78
-					[:weak_key, Proc.new { |s| Status.problem s.keys.collect &:status }],
79
-
80
-					# DH
81
-					[:weak_dh, Proc.new { |s| Status.problem s.dh.collect &:status }],
82
-
83
-					# Protocols
84
-					[:ssl, Proc.new { |s| s.ssl? }, :critical],
85
-					[:tls12, Proc.new { |s| s.tlsv1_2? }, :good],
86
-					[:tls12_only, Proc.new { |s| s.tlsv1_2_only? }, :perfect],
87
-
88
-					# Ciphers
89
-					[:dss, Proc.new { |s| s.dss? }, :critical],
90
-					[:anonymous, Proc.new { |s| s.anonymous? }, :critical],
91
-					[:null, Proc.new { |s| s.null? }, :critical],
92
-					[:export, Proc.new { |s| s.export? }, :critical],
93
-					[:des, Proc.new { |s| s.des? }, :critical],
94
-					[:md5, Proc.new { |s| s.md5? }, :critical],
95
-
96
-					[:rc4, Proc.new { |s| s.rc4? }, :error],
97
-					[:sweet32, Proc.new { |s| s.sweet32? }, :error],
98
-
99
-					[:no_pfs, Proc.new { |s| not s.pfs_only? }, :warning],
100
-					[:pfs, Proc.new { |s| s.pfs? }, :good],
101
-					[:pfs_only, Proc.new { |s| s.pfs_only? }, :perfect],
102
-
103
-					[:no_ecdhe, Proc.new { |s| not s.ecdhe? }, :warning],
104
-					[:ecdhe, Proc.new { |s| s.ecdhe? }, :good],
105
-					[:ecdhe_only, Proc.new { |s| s.ecdhe_only? }, :perfect],
106
-
107
-					[:aead, Proc.new { |s| s.aead? }, :good],
108
-					#[:aead_only, Proc.new { |s| s.aead_only? }, :best],
109
-			] + Cert::WEAK_SIGN.collect do |level, hashes|
110
-				hashes.collect do |hash|
111
-					["#{hash}_sig?".to_sym, Proc.new { |s| s.call "#{hash}_sig?".to_sym }, level ]
112
-				end
113
-			end.flatten(1)).freeze
114
-
115
-			def checks
116
-				checks = CHECKS
117
-				unless @server.fallback_scsv? == nil
118
-					checks += [
119
-							[:no_fallback_scsv, Proc.new { |s| not s.fallback_scsv? }, :error],
120
-							[:fallback_scsv, Proc.new { |s| s.fallback_scsv? }, :good]
121
-					]
122
-				end
123
-				checks
124
-			end
125
-
126
-			def calculate_states
127
-				states = Status.empty
128
-				@checks.each do |name, check, status|
129
-					result = check.call @server
130
-					if result
131
-						state = states[status ? status : result]
132
-						state << name if state
133
-					end
134
-				end
135
-				states
136
-			end
137 70
 		end
138 71
 	end
139 72
 end

+ 10
- 1
lib/cryptcheck/tls/https/server.rb Näytä tiedosto

@@ -20,7 +20,7 @@ module CryptCheck
20 20
 														   follow_redirects: false,
21 21
 														   verify:           false,
22 22
 														   timeout:          SSL_TIMEOUT,
23
-														   ssl_version:      @supported_methods.first.name,
23
+														   ssl_version:      @supported_methods.first.to_sym,
24 24
 														   ciphers:          Cipher::ALL
25 25
 												   }
26 26
 						if header = response.headers['strict-transport-security']
@@ -43,9 +43,18 @@ module CryptCheck
43 43
 				end
44 44
 
45 45
 				LONG_HSTS = 6*30*24*60*60
46
+
46 47
 				def hsts_long?
47 48
 					hsts? and @hsts >= LONG_HSTS
48 49
 				end
50
+
51
+				def checks
52
+					super + [
53
+							[:hsts, -> (s) { s.hsts? }, :good],
54
+							[:hsts_long, -> (s) { s.hsts_long? }, :perfect],
55
+							#[:must_staple, -> (s) { s.must_staple? }, :best],
56
+					]
57
+				end
49 58
 			end
50 59
 		end
51 60
 	end

+ 59
- 16
lib/cryptcheck/tls/server.rb Näytä tiedosto

@@ -126,7 +126,7 @@ module CryptCheck
126 126
 
127 127
 			def fetch_dh
128 128
 				@dh = @supported_ciphers.collect do |_, ciphers|
129
-					ciphers.values.collect(&:tmp_key).select { |d| d.is_a? OpenSSL::PKey::DH }.collect &:size
129
+					ciphers.values.collect(&:tmp_key).select { |d| d.is_a? OpenSSL::PKey::DH }
130 130
 				end.flatten
131 131
 			end
132 132
 
@@ -285,7 +285,7 @@ module CryptCheck
285 285
 			Method.each do |method|
286 286
 				class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
287 287
 					def #{method.to_sym.downcase}?
288
-						@supported_methods.detect { |m| m == method }
288
+						@supported_methods.detect { |m| m == :#{method.to_sym} }
289 289
 					end
290 290
 				RUBY_EVAL
291 291
 			end
@@ -293,7 +293,7 @@ module CryptCheck
293 293
 			Cipher::TYPES.each do |type, _|
294 294
 				class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
295 295
 					def #{type}?
296
-						@supported_ciphers.any? { |c| c.#{type}? }
296
+						uniq_supported_ciphers.any? { |c| c.#{type}? }
297 297
 					end
298 298
 				RUBY_EVAL
299 299
 			end
@@ -315,31 +315,31 @@ module CryptCheck
315 315
 			end
316 316
 
317 317
 			def pfs?
318
-				supported_ciphers.any? { |c| c.pfs? }
318
+				uniq_supported_ciphers.any? { |c| c.pfs? }
319 319
 			end
320 320
 
321 321
 			def pfs_only?
322
-				supported_ciphers.all? { |c| c.pfs? }
322
+				uniq_supported_ciphers.all? { |c| c.pfs? }
323 323
 			end
324 324
 
325 325
 			def ecdhe?
326
-				supported_ciphers.any? { |c| c.ecdhe? }
326
+				uniq_supported_ciphers.any? { |c| c.ecdhe? }
327 327
 			end
328 328
 
329 329
 			def ecdhe_only?
330
-				supported_ciphers.all? { |c| c.ecdhe? }
330
+				uniq_supported_ciphers.all? { |c| c.ecdhe? }
331 331
 			end
332 332
 
333 333
 			def aead?
334
-				supported_ciphers.any? { |c| c.aead? }
334
+				uniq_supported_ciphers.any? { |c| c.aead? }
335 335
 			end
336 336
 
337 337
 			def aead_only?
338
-				supported_ciphers.all? { |c| c.aead? }
338
+				uniq_supported_ciphers.all? { |c| c.aead? }
339 339
 			end
340 340
 
341 341
 			def sweet32?
342
-				supported_ciphers.any? { |c| c.sweet32? }
342
+				uniq_supported_ciphers.any? { |c| c.sweet32? }
343 343
 			end
344 344
 
345 345
 			def fallback_scsv?
@@ -350,6 +350,52 @@ module CryptCheck
350 350
 				@cert.extensions.any? { |e| e.oid == '1.3.6.1.5.5.7.1.24' }
351 351
 			end
352 352
 
353
+			include Statused
354
+
355
+			CHECKS = [
356
+					# Protocols
357
+					[:ssl, -> (s) { s.ssl? }, :critical],
358
+					[:tls12, -> (s) { s.tlsv1_2? }, :good],
359
+					[:tls12_only, -> (s) { s.tlsv1_2_only? }, :perfect],
360
+
361
+					# Ciphers
362
+					[:dss, -> (s) { s.dss? }, :critical],
363
+					[:anonymous, -> (s) { s.anonymous? }, :critical],
364
+					[:null, -> (s) { s.null? }, :critical],
365
+					[:export, -> (s) { s.export? }, :critical],
366
+					[:des, -> (s) { s.des? }, :critical],
367
+					[:md5, -> (s) { s.md5? }, :critical],
368
+
369
+					[:rc4, -> (s) { s.rc4? }, :error],
370
+					[:sweet32, -> (s) { s.sweet32? }, :error],
371
+
372
+					[:no_pfs, -> (s) { not s.pfs_only? }, :warning],
373
+					[:pfs, -> (s) { s.pfs? }, :good],
374
+					[:pfs_only, -> (s) { s.pfs_only? }, :perfect],
375
+
376
+					[:no_ecdhe, -> (s) { not s.ecdhe? }, :warning],
377
+					[:ecdhe, -> (s) { s.ecdhe? }, :good],
378
+					[:ecdhe_only, -> (s) { s.ecdhe_only? }, :perfect],
379
+
380
+					[:aead, -> (s) { s.aead? }, :good],
381
+					#[:aead_only, -> (s) { s.aead_only? }, :best],
382
+			].freeze
383
+
384
+			def checks
385
+				checks = CHECKS
386
+				unless self.fallback_scsv? == nil
387
+					checks += [
388
+							[:no_fallback_scsv, -> (s) { not s.fallback_scsv? }, :error],
389
+							[:fallback_scsv, -> (s) { s.fallback_scsv? }, :good]
390
+					]
391
+				end
392
+				checks
393
+			end
394
+
395
+			def children
396
+				@certs + @dh
397
+			end
398
+
353 399
 			private
354 400
 			def connect(&block)
355 401
 				socket   = ::Socket.new @family, sock_type
@@ -497,12 +543,9 @@ module CryptCheck
497 543
 				@dh = dh
498 544
 			end
499 545
 
500
-			Cert::SIGNATURE_ALGORITHMS.each do |s|
501
-				class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
502
-					def #{s}_sign?
503
-						@certs.any? &:#{s}?
504
-					end
505
-				RUBY_EVAL
546
+			private
547
+			def uniq_supported_ciphers
548
+				@supported_ciphers.values.collect(&:keys).flatten.uniq
506 549
 			end
507 550
 		end
508 551
 

Loading…
Peruuta
Tallenna