You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
3.9KB

  1. module CryptCheck
  2. module Tls
  3. class Grade
  4. attr_reader :server, :grade, :states
  5. def initialize(server)
  6. @server = server
  7. @checks = checks
  8. @states = calculate_states
  9. @grade = calculate_grade
  10. end
  11. def display
  12. color = case @grade
  13. when 'A', 'A+'
  14. :best
  15. when 'B', 'B+'
  16. :perfect
  17. when 'C', 'C+'
  18. nil
  19. when 'E'
  20. :warning
  21. when 'F'
  22. :error
  23. when 'G'
  24. :critical
  25. when 'M', 'T'
  26. :unknown
  27. end
  28. Logger.info { "Grade : #{self.grade.colorize color }" }
  29. Logger.info { '' }
  30. [
  31. ['Critical', :critical],
  32. ['Error', :error],
  33. ['Warning', :warning],
  34. ['Good', :good],
  35. ['Perfect', :perfect],
  36. ['Best', :best],
  37. ].each do |text, color|
  38. states = @states[color]
  39. Logger.info { "#{text} : #{states.collect { |s| s.to_s.colorize color }.join ' '}" } unless states.empty?
  40. end
  41. end
  42. private
  43. def calculate_grade
  44. case
  45. when !@states[:critical].empty?
  46. return 'G'
  47. when !@states[:error].empty?
  48. return 'F'
  49. when !@states[:warning].empty?
  50. return 'E'
  51. end
  52. goods = @checks.select { |c| c.last == :good }.collect &:first
  53. unless goods.empty?
  54. return 'D' if @states[:good].empty?
  55. return 'C' if @states[:good] != goods
  56. end
  57. perfects = @checks.select { |c| c.last == :perfect }.collect &:first
  58. unless perfects.empty?
  59. return 'C+' if @states[:perfect].empty?
  60. return 'B' if @states[:perfect] != perfects
  61. end
  62. bests = @checks.select { |c| c.last == :best }.collect &:first
  63. unless bests.empty?
  64. return 'B+' if @states[:best].empty?
  65. return 'A' if @states[:best] != bests
  66. end
  67. 'A+'
  68. end
  69. CHECKS = [
  70. # Keys
  71. [:dss_sign, Proc.new { |s| s.dss_sig? }, :critical],
  72. [:weak_key, Proc.new { |s| %i(critical error warning).include? s.key.status } ],
  73. # DH
  74. [:weak_dh, Proc.new { |s| (%i(critical error warning) & s.dh.collect(&:status).uniq).first } ],
  75. # Certificates
  76. [:md2_sign, Proc.new { |s| s.md2_sig? }, :critical],
  77. [:mdc2_sign, Proc.new { |s| s.mdc2_sig? }, :critical],
  78. [:md4_sign, Proc.new { |s| s.md4_sig? }, :critical],
  79. [:md5_sign, Proc.new { |s| s.md5_sig? }, :critical],
  80. [:sha_sign, Proc.new { |s| s.sha_sig? }, :critical],
  81. [:sha1_sign, Proc.new { |s| s.sha1_sig? }, :warning],
  82. # Protocols
  83. [:ssl, Proc.new { |s| s.ssl? }, :critical],
  84. [:tls12, Proc.new { |s| s.tlsv1_2? }, :good],
  85. [:tls12_only, Proc.new { |s| s.tlsv1_2_only? }, :perfect],
  86. # Ciphers
  87. [:dss, Proc.new { |s| s.dss? }, :critical],
  88. [:anonymous, Proc.new { |s| s.anonymous? }, :critical],
  89. [:null, Proc.new { |s| s.null? }, :critical],
  90. [:export, Proc.new { |s| s.export? }, :critical],
  91. [:des, Proc.new { |s| s.des? }, :critical],
  92. [:md5, Proc.new { |s| s.md5? }, :critical],
  93. [:rc4, Proc.new { |s| s.rc4? }, :error],
  94. [:sweet32, Proc.new { |s| s.sweet32? }, :error],
  95. [:no_pfs, Proc.new { |s| not s.pfs_only? }, :warning],
  96. [:pfs, Proc.new { |s| s.pfs? }, :good],
  97. [:pfs_only, Proc.new { |s| s.pfs_only? }, :perfect],
  98. [:ecdhe, Proc.new { |s| s.ecdhe? }, :good],
  99. [:ecdhe_only, Proc.new { |s| s.ecdhe_only? }, :perfect],
  100. [:aead, Proc.new { |s| s.aead_only? }, :good],
  101. #[:aead_only, Proc.new { |s| s.aead_only? }, :best],
  102. ]
  103. def checks
  104. checks = CHECKS
  105. unless @server.fallback_scsv? == nil
  106. checks += [
  107. [:no_fallback_scsv, Proc.new { |s| not s.fallback_scsv? }, :error],
  108. [:fallback_scsv, Proc.new { |s| s.fallback_scsv? }, :good]
  109. ]
  110. end
  111. checks
  112. end
  113. def calculate_states
  114. states = { critical: [], error: [], warning: [], good: [], perfect: [], best: [] }
  115. @checks.each do |name, check, status|
  116. result = check.call @server
  117. if result
  118. state = states[status ? status : result]
  119. state << name if state
  120. end
  121. end
  122. states
  123. end
  124. end
  125. end
  126. end