Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

server.rb 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. require 'socket'
  2. require 'openssl'
  3. require 'httparty'
  4. module CryptCheck
  5. module Tls
  6. class Server
  7. TCP_TIMEOUT = 10
  8. SSL_TIMEOUT = 2*TCP_TIMEOUT
  9. EXISTING_METHODS = %i(TLSv1_2 TLSv1_1 TLSv1 SSLv3 SSLv2)
  10. SUPPORTED_METHODS = ::OpenSSL::SSL::SSLContext::METHODS
  11. class TLSException < ::Exception
  12. end
  13. class TLSNotAvailableException < TLSException
  14. end
  15. class MethodNotAvailable < TLSException
  16. end
  17. class CipherNotAvailable < TLSException
  18. end
  19. class Timeout < Exception
  20. end
  21. class TLSTimeout < Timeout
  22. end
  23. class ConnectionError < Exception
  24. end
  25. attr_reader :family, :ip, :port, :hostname, :prefered_ciphers, :cert, :cert_valid, :cert_trusted, :dh
  26. def initialize(hostname, family, ip, port)
  27. @hostname, @family, @ip, @port = hostname, family, ip, port
  28. @dh = []
  29. Logger.info { name.colorize :blue }
  30. extract_cert
  31. Logger.info { '' }
  32. Logger.info { "Key : #{Tls.key_to_s self.key}" }
  33. fetch_prefered_ciphers
  34. check_supported_cipher
  35. uniq_dh
  36. end
  37. def key
  38. @cert.public_key
  39. end
  40. def cipher_size
  41. supported_ciphers.collect { |c| c.size }.min
  42. end
  43. def supported_protocols
  44. @supported_ciphers.keys
  45. end
  46. def supported_ciphers
  47. @supported_ciphers.values.flatten 1
  48. end
  49. def supported_ciphers_by_protocol(protocol)
  50. @supported_ciphers[protocol]
  51. end
  52. EXISTING_METHODS.each do |method|
  53. class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
  54. def #{method.to_s.downcase}?
  55. !prefered_ciphers[:#{method}].nil?
  56. end
  57. RUBY_EVAL
  58. end
  59. {
  60. md2: %w(md2WithRSAEncryption),
  61. md5: %w(md5WithRSAEncryption md5WithRSA),
  62. sha1: %w(sha1WithRSAEncryption sha1WithRSA dsaWithSHA1 dsaWithSHA1_2 ecdsa_with_SHA1)
  63. }.each do |name, signature|
  64. class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
  65. def #{name}_sig?
  66. #{signature}.include? @cert.signature_algorithm
  67. end
  68. RUBY_EVAL
  69. end
  70. Cipher::TYPES.each do |type, _|
  71. class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
  72. def #{type}?
  73. supported_ciphers.any? { |c| c.#{type}? }
  74. end
  75. RUBY_EVAL
  76. end
  77. def key_size
  78. @cert.public_key.rsa_equivalent_size
  79. end
  80. def ssl?
  81. sslv2? or sslv3?
  82. end
  83. def tls?
  84. tlsv1? or tlsv1_1? or tlsv1_2?
  85. end
  86. def tls_only?
  87. tls? and !ssl?
  88. end
  89. def pfs?
  90. supported_ciphers.any? { |c| c.pfs? }
  91. end
  92. def pfs_only?
  93. supported_ciphers.all? { |c| c.pfs? }
  94. end
  95. private
  96. def name
  97. name = "#{@hostname || @ip}:#@port"
  98. name += " [#@ip]" if @hostname
  99. name
  100. end
  101. def connect(&block)
  102. socket = ::Socket.new @family, sock_type
  103. sockaddr = ::Socket.sockaddr_in @port, @ip
  104. Logger.trace { "Connecting to #{@ip}:#{@port}" }
  105. begin
  106. status = socket.connect_nonblock sockaddr
  107. Logger.trace { "Connecting to #{@ip}:#{@port} status : #{status}" }
  108. raise ConnectionError, status unless status == 0
  109. Logger.trace { "Connected to #{@ip}:#{@port}" }
  110. block_given? ? block.call(socket) : nil
  111. rescue ::IO::WaitReadable
  112. Logger.trace { "Waiting for read to #{@ip}:#{@port}" }
  113. raise Timeout, "Timeout when connect to #{@ip}:#{@port} (max #{TCP_TIMEOUT.humanize})" unless IO.select [socket], nil, nil, TCP_TIMEOUT
  114. retry
  115. rescue ::IO::WaitWritable
  116. Logger.trace { "Waiting for write to #{@ip}:#{@port}" }
  117. raise Timeout, "Timeout when connect to #{@ip}:#{@port} (max #{TCP_TIMEOUT.humanize})" unless IO.select nil, [socket], nil, TCP_TIMEOUT
  118. retry
  119. ensure
  120. socket.close
  121. end
  122. end
  123. def ssl_connect(socket, context, method, &block)
  124. ssl_socket = ::OpenSSL::SSL::SSLSocket.new socket, context
  125. ssl_socket.hostname = @hostname if @hostname and method != :SSLv2
  126. Logger.trace { "SSL connecting to #{name}" }
  127. begin
  128. ssl_socket.connect_nonblock
  129. Logger.trace { "SSL connected to #{name}" }
  130. return block_given? ? block.call(ssl_socket) : nil
  131. rescue ::IO::WaitReadable
  132. Logger.trace { "Waiting for SSL read to #{name}" }
  133. raise TLSTimeout, "Timeout when TLS connect to #{@ip}:#{@port} (max #{SSL_TIMEOUT.humanize})" unless IO.select [ssl_socket], nil, nil, SSL_TIMEOUT
  134. retry
  135. rescue ::IO::WaitWritable
  136. Logger.trace { "Waiting for SSL write to #{name}" }
  137. raise TLSTimeout, "Timeout when TLS connect to #{@ip}:#{@port} (max #{SSL_TIMEOUT.humanize})" unless IO.select nil, [ssl_socket], nil, SSL_TIMEOUT
  138. retry
  139. rescue ::OpenSSL::SSL::SSLError => e
  140. case e
  141. when /state=SSLv2 read server hello A$/,
  142. /state=SSLv3 read server hello A: wrong version number$/
  143. raise MethodNotAvailable, e
  144. when /state=error: no ciphers available$/,
  145. /state=SSLv3 read server hello A: sslv3 alert handshake failure$/
  146. raise CipherNotAvailable, e
  147. end
  148. rescue => e
  149. case e
  150. when /^Connection reset by peer$/
  151. raise MethodNotAvailable, e
  152. end
  153. ensure
  154. ssl_socket.close
  155. end
  156. end
  157. def ssl_client(method, ciphers = nil, &block)
  158. ssl_context = ::OpenSSL::SSL::SSLContext.new method
  159. ssl_context.ciphers = ciphers if ciphers
  160. Logger.trace { "Try #{method} connection with #{ciphers}" }
  161. connect do |socket|
  162. ssl_connect socket, ssl_context, method do |ssl_socket|
  163. return block_given? ? block.call(ssl_socket) : nil
  164. end
  165. end
  166. Logger.debug { "No SSL available on #{name}" }
  167. raise CipherNotAvailable
  168. end
  169. def extract_cert
  170. EXISTING_METHODS.each do |method|
  171. next unless SUPPORTED_METHODS.include? method
  172. begin
  173. @cert, @chain = ssl_client(method) { |s| [s.peer_cert, s.peer_cert_chain] }
  174. Logger.debug { "Certificate #{@cert.subject}" }
  175. break
  176. rescue TLSException
  177. end
  178. end
  179. raise TLSNotAvailableException unless @cert
  180. @cert_valid = ::OpenSSL::SSL.verify_certificate_identity @cert, (@hostname || @ip)
  181. @cert_trusted = verify_trust @chain, @cert
  182. end
  183. def prefered_cipher(method)
  184. cipher = ssl_client(method, 'ALL:COMPLEMENTOFALL') { |s| Cipher.new method, s.cipher, s.tmp_key }
  185. Logger.info { "Prefered cipher for #{Tls.colorize method} : #{cipher.colorize}" }
  186. cipher
  187. rescue TLSException => e
  188. Logger.debug { "Method #{Tls.colorize method} not supported : #{e}" }
  189. nil
  190. end
  191. def fetch_prefered_ciphers
  192. @prefered_ciphers = {}
  193. EXISTING_METHODS.each do |method|
  194. next unless SUPPORTED_METHODS.include? method
  195. @prefered_ciphers[method] = prefered_cipher method
  196. end
  197. raise TLSNotAvailableException unless @prefered_ciphers.any? { |_, c| !c.nil? }
  198. end
  199. def available_ciphers(method)
  200. context = ::OpenSSL::SSL::SSLContext.new method
  201. context.ciphers = 'ALL:COMPLEMENTOFALL'
  202. context.ciphers
  203. end
  204. def supported_cipher?(method, cipher)
  205. dh = ssl_client method, [cipher] { |s| s.tmp_key }
  206. @dh << dh if dh
  207. cipher = Cipher.new method, cipher, dh
  208. dh = dh ? " (#{'DH'.colorize :green} : #{Tls.key_to_s dh})" : ''
  209. Logger.info { "#{Tls.colorize method} / #{cipher.colorize} : Supported#{dh}" }
  210. cipher
  211. rescue TLSException => e
  212. cipher = Cipher.new method, cipher
  213. Logger.debug { "#{Tls.colorize method} / #{cipher.colorize} : Not supported (#{e})" }
  214. nil
  215. end
  216. def check_supported_cipher
  217. Logger.info { '' }
  218. @supported_ciphers = {}
  219. EXISTING_METHODS.each do |method|
  220. next unless SUPPORTED_METHODS.include? method and @prefered_ciphers[method]
  221. supported_ciphers = available_ciphers(method).collect { |c| supported_cipher? method, c }.reject { |c| c.nil? }
  222. Logger.info { '' } unless supported_ciphers.empty?
  223. @supported_ciphers[method] = supported_ciphers
  224. end
  225. end
  226. def verify_trust(chain, cert)
  227. store = ::OpenSSL::X509::Store.new
  228. store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
  229. store.set_default_paths
  230. %w(/etc/ssl/certs).each do |directory|
  231. ::Dir.glob(::File.join directory, '*.pem').each do |file|
  232. cert = ::OpenSSL::X509::Certificate.new ::File.read file
  233. begin
  234. store.add_cert cert
  235. rescue ::OpenSSL::X509::StoreError
  236. end
  237. end
  238. end
  239. chain.each do |cert|
  240. begin
  241. store.add_cert cert
  242. rescue ::OpenSSL::X509::StoreError
  243. end
  244. end
  245. trusted = store.verify cert
  246. p store.error_string unless trusted
  247. trusted
  248. end
  249. def uniq_dh
  250. dh, find = [], []
  251. @dh.each do |k|
  252. f = [k.type, k.size]
  253. unless find.include? f
  254. dh << k
  255. find << f
  256. end
  257. end
  258. @dh = dh
  259. end
  260. end
  261. class TcpServer < Server
  262. private
  263. def sock_type
  264. ::Socket::SOCK_STREAM
  265. end
  266. end
  267. class UdpServer < Server
  268. private
  269. def sock_type
  270. ::Socket::SOCK_DGRAM
  271. end
  272. end
  273. end
  274. end