Przeglądaj źródła

Fetch curves preference

new-scoring
aeris 2 lat temu
rodzic
commit
a97668a5f8

+ 15
- 6
lib/cryptcheck/status.rb Wyświetl plik

@@ -1,9 +1,10 @@
1 1
 module CryptCheck
2
-	module Status
3
-		LEVELS = %i(critical error warning good perfect best).freeze
4
-		PROBLEMS = %i(critical error warning).freeze
2
+	class Status
3
+		LEVELS   = %i(best perfect good warning error critical).freeze
4
+		PROBLEMS = %i(warning error critical).freeze
5 5
 
6 6
 		extend Enumerable
7
+
7 8
 		def self.each(&block)
8 9
 			LEVELS.each &block
9 10
 		end
@@ -22,17 +23,25 @@ module CryptCheck
22 23
 			self.min PROBLEMS, statuses
23 24
 		end
24 25
 
26
+		def self.sort(statuses)
27
+			statuses.sort { |a, b| self.compare a, b }
28
+		end
29
+
30
+		def self.compare(a, b)
31
+			LEVELS.find_index(a.status) <=> LEVELS.find_index(b.status)
32
+		end
33
+
25 34
 		private
26 35
 		def self.convert(statuses)
27
-			statuses = [ statuses ] unless statuses.respond_to? :first
28
-			first = statuses.first
36
+			statuses = [statuses] unless statuses.respond_to? :first
37
+			first    = statuses.first
29 38
 			statuses = statuses.collect &:status if first.respond_to? :status
30 39
 			statuses
31 40
 		end
32 41
 
33 42
 		def self.min(levels, statuses)
34 43
 			return nil if statuses.empty?
35
-			(levels & statuses).first
44
+			(levels & statuses).last
36 45
 		end
37 46
 	end
38 47
 end

+ 16
- 16
lib/cryptcheck/tls/cipher.rb Wyświetl plik

@@ -93,7 +93,7 @@ module CryptCheck
93 93
 			end
94 94
 
95 95
 			def ecc?
96
-				ecdsa? or ecdhe?
96
+				ecdsa? or ecdhe? or ecdh?
97 97
 			end
98 98
 
99 99
 			def sweet32?
@@ -116,14 +116,7 @@ module CryptCheck
116 116
 					[:sweet32, Proc.new { |s| s.sweet32? }, :error],
117 117
 
118 118
 					#[:cbc, Proc.new { |s| s.cbc? }, :warning],
119
-					#[:dhe, Proc.new { |s| s.dhe? }, :warning],
120
-					# [:weak_dh, Proc.new do |s|
121
-					# 	dh = s.dh
122
-					# 	next nil unless dh
123
-					# 	status = dh.status
124
-					# 	next status if %i(critical error warning).include? status
125
-					# 	nil
126
-					# end],
119
+					[:dhe, Proc.new { |s| s.dhe? }, :warning],
127 120
 					[:no_pfs, Proc.new { |s| not s.pfs? }, :warning],
128 121
 
129 122
 					[:pfs, Proc.new { |s| s.pfs? }, :good],
@@ -135,16 +128,16 @@ module CryptCheck
135 128
 				@states = Status.collect { |s| [s, []] }.to_h
136 129
 				CHECKS.each do |name, check, status|
137 130
 					result = check.call self
138
-					states[status ? status : result] << name if result
131
+					@states[status ? status : result] << name if result
139 132
 				end
140
-
141
-				@status = Status[@states.reject { |_, v| v.empty? }.keys]
133
+				statuses = @states.reject { |_, v| v.empty? }.keys
134
+				@status  = Status[statuses]
142 135
 			end
143 136
 
144 137
 			def to_s(type = :long)
145 138
 				case type
146 139
 					when :long
147
-						states = @states.collect { |k, vs| vs.collect { |v| v.to_s.colorize k }}.flatten.join ' '
140
+						states = @states.collect { |k, vs| vs.collect { |v| v.to_s.colorize k } }.flatten.join ' '
148 141
 						"#{@method} #{@name.colorize @status} [#{states}]"
149 142
 					when :short
150 143
 						@name.colorize @status
@@ -152,6 +145,7 @@ module CryptCheck
152 145
 			end
153 146
 
154 147
 			PRIORITY = { good: 1, none: 2, warning: 3, error: 4, critical: 5 }
148
+
155 149
 			def self.sort(ciphers)
156 150
 				ciphers.sort do |a, b|
157 151
 					error_a, error_b = PRIORITY[a.score], PRIORITY[b.score]
@@ -271,12 +265,18 @@ module CryptCheck
271 265
 				end
272 266
 			end
273 267
 
274
-			ALL = 'ALL:COMPLEMENTOFALL'
268
+			def <=>(other)
269
+				status = Status.compare self, other
270
+				return status if status != 0
271
+				@name <=> other.name
272
+			end
273
+
274
+			ALL       = 'ALL:COMPLEMENTOFALL'
275 275
 			SUPPORTED = Method.collect do |m|
276 276
 				context         = ::OpenSSL::SSL::SSLContext.new m.name
277 277
 				context.ciphers = ALL
278
-				[m, context.ciphers.collect { |c| Cipher.new m, c.first }]
279
-			end.to_h
278
+				[m, context.ciphers.collect { |c| Cipher.new m, c.first }.sort ]
279
+			end.to_h.freeze
280 280
 		end
281 281
 	end
282 282
 end

+ 1
- 1
lib/cryptcheck/tls/curve.rb Wyświetl plik

@@ -17,7 +17,7 @@ module CryptCheck
17 17
 			SUPPORTED = %w(secp256k1 sect283k1 sect283r1 secp384r1
18 18
 				sect409k1 sect409r1 secp521r1 sect571k1 sect571r1
19 19
 				prime192v1 prime256v1
20
-				brainpoolP256r1 brainpoolP384r1 brainpoolP512r1).collect { |c| self.new c }
20
+				brainpoolP256r1 brainpoolP384r1 brainpoolP512r1).collect { |c| self.new c }.freeze
21 21
 
22 22
 			extend Enumerable
23 23
 

+ 6
- 2
lib/cryptcheck/tls/method.rb Wyświetl plik

@@ -13,8 +13,8 @@ module CryptCheck
13 13
 				@name = name
14 14
 			end
15 15
 
16
-			EXISTING  = %i(TLSv1_2 TLSv1_1 TLSv1 SSLv3 SSLv2)
17
-			SUPPORTED = (EXISTING & ::OpenSSL::SSL::SSLContext::METHODS).collect { |m| self.new m }
16
+			EXISTING  = %i(TLSv1_2 TLSv1_1 TLSv1 SSLv3 SSLv2).freeze
17
+			SUPPORTED = (EXISTING & ::OpenSSL::SSL::SSLContext::METHODS).collect { |m| self.new m }.freeze
18 18
 
19 19
 			def to_s
20 20
 				colors = case @name
@@ -25,6 +25,10 @@ module CryptCheck
25 25
 						 end
26 26
 				@name.to_s.colorize colors
27 27
 			end
28
+
29
+			def <=>(other)
30
+				EXISTING.find_index(@name) <=> EXISTING.find_index(other.name)
31
+			end
28 32
 		end
29 33
 	end
30 34
 end

+ 64
- 31
lib/cryptcheck/tls/server.rb Wyświetl plik

@@ -40,14 +40,16 @@ module CryptCheck
40 40
 
41 41
 				fetch_supported_methods
42 42
 				fetch_supported_ciphers
43
+				fetch_ciphers_preferences
44
+
43 45
 				fetch_ecdsa_certs
44 46
 				fetch_supported_curves
45
-
46
-				fetch_ciphers_preferences
47
+				fetch_curves_preference
47 48
 
48 49
 				# verify_certs
49 50
 
50 51
 				check_fallback_scsv
52
+				exit
51 53
 			end
52 54
 
53 55
 			def supported_method?(method)
@@ -87,6 +89,37 @@ module CryptCheck
87 89
 				end.to_h
88 90
 			end
89 91
 
92
+			def fetch_ciphers_preferences
93
+				Logger.info { '' }
94
+				Logger.info { 'Cipher suite preferences' }
95
+
96
+				@preferences = @supported_ciphers.collect do |method, ciphers|
97
+					ciphers     = ciphers.keys
98
+					preferences = if ciphers.size < 2
99
+									  Logger.info { method.to_s + ' : ' + 'not applicable'.colorize(:unknown) }
100
+									  nil
101
+								  else
102
+									  a, b, _ = ciphers
103
+									  ab      = ssl_client(method, [a, b]).cipher.first
104
+									  ba      = ssl_client(method, [b, a]).cipher.first
105
+									  if ab != ba
106
+										  Logger.info { method.to_s + ' : ' + 'client preference'.colorize(:warning) }
107
+										  :client
108
+									  else
109
+										  sort        = -> (a, b) do
110
+											  connection = ssl_client method, [a, b]
111
+											  cipher     = connection.cipher.first
112
+											  cipher == a.name ? -1 : 1
113
+										  end
114
+										  preferences = ciphers.sort &sort
115
+										  Logger.info { method.to_s + ' : ' + preferences.collect { |c| c.to_s :short }.join(', ') }
116
+										  preferences
117
+									  end
118
+								  end
119
+					[method, preferences]
120
+				end.to_h
121
+			end
122
+
90 123
 			def fetch_ecdsa_certs
91 124
 				@ecdsa_certs = {}
92 125
 
@@ -152,6 +185,7 @@ module CryptCheck
152 185
 							begin
153 186
 								ssl_client method, ecdh, curves: curve
154 187
 								Logger.info { "ECC curve #{curve} : supported" }
188
+								true
155 189
 							rescue TLSException
156 190
 								Logger.debug { "ECC curve #{curve} : not supported" }
157 191
 								false
@@ -162,34 +196,33 @@ module CryptCheck
162 196
 				end
163 197
 			end
164 198
 
165
-			def fetch_ciphers_preferences
166
-				Logger.info { '' }
167
-				Logger.info { 'Server preferences' }
168
-
169
-				@preferences = @supported_ciphers.collect do |method, ciphers|
170
-					ciphers = ciphers.keys
171
-					if ciphers.size < 2
172
-						Logger.info { "Preference not applicable for #{method}" }
173
-					else
174
-						a, b, _ = ciphers
175
-						ab      = ssl_client(method, [a, b]).cipher.first
176
-						ba      = ssl_client(method, [b, a]).cipher.first
177
-						if ab != ba
178
-							Logger.info { 'Server use client preference for '.colorize(:warning) + method.to_s }
179
-							:client
180
-						else
181
-							sort        = -> (a, b) do
182
-								connection = ssl_client method, [a, b]
183
-								cipher     = connection.cipher.first
184
-								cipher == a.name ? -1 : 1
185
-							end
186
-							preferences = ciphers.sort &sort
187
-							Logger.info { "Cipher preference for #{method} is #{preferences.collect { |c| c.to_s :short }.join ':'}" }
188
-							preferences
189
-						end
190
-					end
191
-					[method, preferences]
192
-				end.to_h
199
+			def fetch_curves_preference
200
+				@curves_preference = if @supported_curves.size < 2
201
+										 Logger.info { 'Curves preference : ' + 'not applicable'.colorize(:unknown) }
202
+										 nil
203
+									 else
204
+										 method, cipher = @supported_ciphers.collect do |method, ciphers|
205
+											 cipher = ciphers.keys.detect { |c| c.ecdh? or c.ecdhe? }
206
+											 [method, cipher]
207
+										 end.detect { |n| !n.nil? }
208
+
209
+										 a, b, _ = @supported_curves
210
+										 ab      = ssl_client(method, cipher, curves: [a, b]).tmp_key.curve
211
+										 ba      = ssl_client(method, cipher, curves: [b, a]).tmp_key.curve
212
+										 if ab != ba
213
+											 Logger.info { 'Curves preference : ' + 'client preference'.colorize(:warning) }
214
+											 :client
215
+										 else
216
+											 sort        = -> (a, b) do
217
+												 connection = ssl_client method, cipher, curves: [a, b]
218
+												 curve      = connection.tmp_key.curve
219
+												 curve == a.name ? -1 : 1
220
+											 end
221
+											 preferences = @supported_curves.sort &sort
222
+											 Logger.info { 'Curves preference : ' + preferences.collect { |c| c.to_s }.join(', ') }
223
+											 preferences
224
+										 end
225
+									 end
193 226
 			end
194 227
 
195 228
 			def check_fallback_scsv
@@ -224,7 +257,7 @@ module CryptCheck
224 257
 				method = method.name
225 258
 				class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
226 259
 					def #{method.to_s.downcase}?
227
-						@supported_methods.detect { |m| m.name == method } 
260
+						@supported_methods.detect { |m| m.name == method }
228 261
 					end
229 262
 				RUBY_EVAL
230 263
 			end

Ładowanie…
Anuluj
Zapisz