Browse Source

Handle case of multiple certificates

new-scoring
aeris 2 years ago
parent
commit
61032231b2
1 changed files with 49 additions and 35 deletions
  1. 49
    35
      lib/cryptcheck/tls/server.rb

+ 49
- 35
lib/cryptcheck/tls/server.rb View File

@@ -35,20 +35,15 @@ module CryptCheck
35 35
 			def initialize(hostname, family, ip, port)
36 36
 				@hostname, @family, @ip, @port = hostname, family, ip, port
37 37
 				@dh                            = []
38
-				Logger.info { name.colorize :perfect }
39
-				extract_cert
40
-				Logger.info { '' }
41
-				Logger.info { "Key : #{Tls.key_to_s self.key}" }
38
+				@chains                        = []
39
+				Logger.info { name.colorize :blue }
42 40
 				fetch_prefered_ciphers
43 41
 				check_supported_cipher
42
+				verify_certs
44 43
 				check_fallback_scsv
45 44
 				uniq_dh
46 45
 			end
47 46
 
48
-			def key
49
-				@cert.public_key
50
-			end
51
-
52 47
 			def cipher_size
53 48
 				supported_ciphers.collect { |c| c.size }.min
54 49
 			end
@@ -73,6 +68,14 @@ module CryptCheck
73 68
 				RUBY_EVAL
74 69
 			end
75 70
 
71
+			def key_status
72
+				Status[@keys]
73
+			end
74
+
75
+			def dh_status
76
+				Status[@dh]
77
+			end
78
+
76 79
 			SIGNATURE_ALGORITHMS = {
77 80
 					'dsaWithSHA'                             => %i(sha1 dss),
78 81
 					'dsaWithSHA1'                            => %i(sha1 dss),
@@ -114,7 +117,9 @@ module CryptCheck
114 117
 			%i(md2 mdc2 md4 md5 ripemd160 sha sha1 sha2 rsa dss ecc ghost).each do |name|
115 118
 				class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
116 119
 					def #{name}_sig?
117
-						SIGNATURE_ALGORITHMS[@cert.signature_algorithm].include? :#{name}
120
+						@chains.any? do |chain|
121
+							SIGNATURE_ALGORITHMS[chain[:cert].signature_algorithm].include? :#{name}
122
+						end
118 123
 					end
119 124
 				RUBY_EVAL
120 125
 			end
@@ -127,10 +132,6 @@ module CryptCheck
127 132
 				RUBY_EVAL
128 133
 			end
129 134
 
130
-			def key_size
131
-				@cert.public_key.size
132
-			end
133
-
134 135
 			def ssl?
135 136
 				sslv2? or sslv3?
136 137
 			end
@@ -253,15 +254,20 @@ module CryptCheck
253 254
 				end
254 255
 			end
255 256
 
256
-			# secp192r1 secp256r1
257
-			SUPPORTED_CURVES = %w(secp160k1 secp160r1 secp160r2 sect163k1
258
-				sect163r1 sect163r2 secp192k1 sect193r1 sect193r2 secp224k1
259
-				secp224r1 sect233k1 sect233r1 sect239k1 secp256k1 sect283k1
260
-				sect283r1 secp384r1 sect409k1 sect409r1 secp521r1 sect571k1
261
-				sect571r1 X25519)
257
+			# SUPPORTED_CURVES = %w(sect163k1 sect163r1 sect163r2 sect193r1
258
+			# 	sect193r2 sect233k1 sect233r1 sect239k1 sect283k1 sect283r1
259
+			# 	sect409k1 sect409r1 sect571k1 sect571r1 secp160k1 secp160r1
260
+			# 	secp160r2 secp192k1 secp192r1 secp224k1 secp224r1 secp256k1
261
+			# 	secp256r1 secp384r1 secp521r1
262
+			# 	prime256v1
263
+			# 	brainpoolP256r1 brainpoolP384r1 brainpoolP512r1)
264
+			SUPPORTED_CURVES = %w(secp256k1 sect283k1 sect283r1 secp384r1
265
+				sect409k1 sect409r1 secp521r1 sect571k1 sect571r1
266
+				prime192v1 prime256v1
267
+				brainpoolP256r1 brainpoolP384r1 brainpoolP512r1)
262 268
 
263 269
 			def ssl_client(method, ciphers = %w(ALL COMPLEMENTOFALL), curves = nil, fallback: false, &block)
264
-				ssl_context = ::OpenSSL::SSL::SSLContext.new method #, fallback_scsv: fallback
270
+				ssl_context = ::OpenSSL::SSL::SSLContext.new method
265 271
 				ssl_context.enable_fallback_scsv if fallback
266 272
 				ssl_context.ciphers     = ciphers.join ':'
267 273
 
@@ -278,20 +284,24 @@ module CryptCheck
278 284
 				end
279 285
 			end
280 286
 
281
-			def extract_cert
282
-				EXISTING_METHODS.each do |method|
283
-					next unless SUPPORTED_METHODS.include? method
284
-					begin
285
-						@cert, @chain = ssl_client(method) { |s| [s.peer_cert, s.peer_cert_chain] }
286
-						Logger.debug { "Certificate #{@cert.subject}" }
287
-						break
288
-					rescue Timeout, TLSTimeout, ConnectionError, ::SystemCallError
289
-						raise
290
-					end
287
+			def verify_certs
288
+				Logger.info { '' }
289
+
290
+				view = {}
291
+				@chains.each do |cert, chain|
292
+					id = cert.subject, cert.serial, cert.issuer
293
+					next if view.include? id
294
+					subject, serial, issuer = id
295
+					key                     = cert.public_key
296
+
297
+					Logger.info { "Certificate #{subject} [#{serial}] issued by #{issuer}" }
298
+					Logger.info { "Key : #{Tls.key_to_s key }" }
299
+					valid    = ::OpenSSL::SSL.verify_certificate_identity cert, (@hostname || @ip)
300
+					trusted  = verify_trust chain, cert
301
+					view[id] = { cert: cert, chain: chain, key: key, valid: valid, trusted: trusted }
291 302
 				end
292
-				raise TLSNotAvailableException unless @cert
293
-				@cert_valid   = ::OpenSSL::SSL.verify_certificate_identity @cert, (@hostname || @ip)
294
-				@cert_trusted = verify_trust @chain, @cert
303
+				@chains = view.values
304
+				@keys   = @chains.collect { |c| c[:key] }
295 305
 			end
296 306
 
297 307
 			def prefered_cipher(method)
@@ -319,8 +329,12 @@ module CryptCheck
319 329
 			end
320 330
 
321 331
 			def supported_cipher?(method, cipher, curves = nil)
322
-				dh = ssl_client(method, [cipher], curves) { |s| s.tmp_key }
332
+				cert, chain, dh = ssl_client(method, [cipher], curves) do |s|
333
+					[s.peer_cert, s.peer_cert_chain, s.tmp_key]
334
+				end
335
+				@chains << [cert, chain]
323 336
 				@dh << dh if dh
337
+				p dh.group.curve_name
324 338
 				cipher = Cipher.new method, cipher, dh
325 339
 				dh     = dh ? " (#{'PFS'.colorize :good} : #{Tls.key_to_s dh})" : ''
326 340
 
@@ -348,7 +362,7 @@ module CryptCheck
348 362
 
349 363
 					available_ciphers = available_ciphers method
350 364
 					available_ciphers.each do |c|
351
-						cipher = Cipher.new method, c
365
+						cipher    = Cipher.new method, c
352 366
 						supported = supported_cipher? method, c.first
353 367
 						if supported
354 368
 							if cipher.ecdhe?

Loading…
Cancel
Save