@@ -11,8 +11,8 @@ if ::File.exist? file | |||
::CryptCheck::Logger.level = :none | |||
::CryptCheck::Tls::Https.analyze_from_file "output/#{name}.yml", "output/#{name}.html" | |||
else | |||
::CryptCheck::Logger.level = :info | |||
server = ::CryptCheck::Tls::Https::Server.new(ARGV[0], ARGV[1] || 443) | |||
::CryptCheck::Logger.level = (ARGV[1] || :info).to_sym | |||
server = ::CryptCheck::Tls::Https::Server.new ARGV[0] | |||
grade = ::CryptCheck::Tls::Https::Grade.new server | |||
::CryptCheck::Logger.info { '' } | |||
grade.display | |||
@@ -7,8 +7,8 @@ require 'cryptcheck' | |||
name = ARGV[0] | |||
if name | |||
::CryptCheck::Logger.level = :info | |||
server = ::CryptCheck::Tls::Smtp::Server.new(ARGV[0], ARGV[1] || 25) | |||
::CryptCheck::Logger.level = (ARGV[1] || :info).to_sym | |||
server = ::CryptCheck::Tls::Smtp::Server.new ARGV[0] | |||
grade = ::CryptCheck::Tls::Smtp::Grade.new server | |||
::CryptCheck::Logger.info { '' } | |||
grade.display | |||
@@ -1,4 +1,5 @@ | |||
require 'colorize' | |||
require 'cryptcheck/tls/fixture' | |||
module CryptCheck | |||
autoload :Logger, 'cryptcheck/logger' | |||
@@ -107,6 +107,25 @@ module CryptCheck | |||
cipher.to_s.colorize colors | |||
end | |||
def self.key_to_s(key) | |||
size = key.rsa_equivalent_size | |||
type_color = case key.type | |||
when :ecc | |||
{ color: :green } | |||
when :dsa | |||
{ color: :yellow } | |||
end | |||
size_color = case size | |||
when 0...1024 | |||
{ color: :white, background: :red } | |||
when 1024...2048 | |||
{ color: :yellow } | |||
when 4096...::Float::INFINITY | |||
{ color: :green } | |||
end | |||
"#{key.type.to_s.upcase.colorize type_color} #{key.size.to_s.colorize size_color} bits" | |||
end | |||
private | |||
SCORES = %w(A+ A A- B C D E F T M X) | |||
@@ -0,0 +1,77 @@ | |||
class ::OpenSSL::PKey::EC | |||
def type | |||
:ecc | |||
end | |||
def size | |||
self.group.degree | |||
end | |||
def rsa_equivalent_size | |||
case self.size | |||
when 160 then 1024 | |||
when 224 then 2048 | |||
when 256 then 3072 | |||
when 384 then 7680 | |||
when 521 then 15360 | |||
end | |||
end | |||
def to_s | |||
"ECC #{self.size} bits" | |||
end | |||
end | |||
class ::OpenSSL::PKey::RSA | |||
def type | |||
:rsa | |||
end | |||
def size | |||
self.n.num_bits | |||
end | |||
def rsa_equivalent_size | |||
self.size | |||
end | |||
def to_s | |||
"RSA #{self.size} bits" | |||
end | |||
end | |||
class ::OpenSSL::PKey::DSA | |||
def type | |||
:dsa | |||
end | |||
def size | |||
self.p.num_bits | |||
end | |||
def rsa_equivalent_size | |||
self.size | |||
end | |||
def to_s | |||
"DSA #{self.size} bits" | |||
end | |||
end | |||
class ::OpenSSL::PKey::DH | |||
def type | |||
:dh | |||
end | |||
def size | |||
self.p.num_bits | |||
end | |||
def rsa_equivalent_size | |||
self.size | |||
end | |||
def to_s | |||
"DH #{self.size} bits" | |||
end | |||
end |
@@ -107,18 +107,20 @@ module CryptCheck | |||
@success << :pfs if @server.pfs_only? | |||
end | |||
ALL_ERROR = %i(md5_sig md5 anonymous dss null export des rc4) | |||
ALL_WARNING = %i(sha1_sig des3) | |||
ALL_SUCCESS = %i(pfs) | |||
ALL_ERROR = %i(md5_sig md5 anonymous dss null export des rc4) | |||
def all_error | |||
ALL_ERROR | |||
end | |||
ALL_WARNING = %i(sha1_sig des3) | |||
def all_warning | |||
ALL_WARNING | |||
end | |||
ALL_SUCCESS = %i(pfs) | |||
def all_success | |||
ALL_SUCCESS | |||
end | |||
@@ -127,28 +129,22 @@ module CryptCheck | |||
@grade = 'A+' if @grade == 'A' and @error.empty? and @warning.empty? and (ALL_SUCCESS & @success) == ALL_SUCCESS | |||
end | |||
METHODS_SCORES = { SSLv2: 0, SSLv3: 80, TLSv1: 90, TLSv1_1: 95, TLSv1_2: 100 } | |||
METHODS_SCORES = { SSLv2: 0, SSLv3: 10, TLSv1: 50, TLSv1_1: 75, TLSv1_2: 100 } | |||
def calculate_protocol_score | |||
methods = @server.supported_methods | |||
worst, best = methods[:worst], methods[:best] | |||
worst, best = methods.last, methods.first | |||
@protocol_score = (METHODS_SCORES[worst] + METHODS_SCORES[best]) / 2 | |||
end | |||
def calculate_key_exchange_score | |||
@key_exchange_score = case @server.key_size | |||
when 0 then | |||
0 | |||
when 0...512 then | |||
20 | |||
when 512...1024 then | |||
40 | |||
when 1024...2048 then | |||
80 | |||
when 2048...4096 then | |||
90 | |||
else | |||
100 | |||
when 0 then 0 | |||
when 0...512 then 20 | |||
when 512...1024 then 40 | |||
when 1024...2048 then 80 | |||
when 2048...4096 then 90 | |||
when 4096...::Float::INFINITY then 100 | |||
end | |||
end | |||
@@ -35,50 +35,18 @@ module CryptCheck | |||
attr_reader :hostname, :port, :prefered_ciphers, :cert, :cert_valid, :cert_trusted | |||
def initialize(hostname, port) | |||
@hostname = hostname | |||
@port = port | |||
@hostname, @port = hostname, port | |||
@dh = [] | |||
Logger.info { "#{hostname}:#{port}".colorize :blue } | |||
extract_cert | |||
#@prefered_ciphers = @supported_ciphers = Hash[SUPPORTED_METHODS.collect { |m| [m, []]}] | |||
Logger.info { '' } | |||
Logger.info { "Key : #{Tls.key_to_s @cert.public_key}" } | |||
fetch_prefered_ciphers | |||
check_supported_cipher | |||
end | |||
def supported_methods | |||
worst = EXISTING_METHODS.find { |method| !@prefered_ciphers[method].nil? } | |||
best = EXISTING_METHODS.reverse.find { |method| !@prefered_ciphers[method].nil? } | |||
{ worst: worst, best: best } | |||
end | |||
def key | |||
key = @cert.public_key | |||
case key | |||
when ::OpenSSL::PKey::RSA then | |||
[:rsa, key.n.num_bits] | |||
when ::OpenSSL::PKey::DSA then | |||
[:dsa, key.p.num_bits] | |||
when ::OpenSSL::PKey::EC then | |||
[:ecc, key.group.degree] | |||
end | |||
end | |||
def key_size | |||
type, size = self.key | |||
if type == :ecc | |||
size = case size | |||
when 160 then | |||
1024 | |||
when 224 then | |||
2048 | |||
when 256 then | |||
3072 | |||
when 384 then | |||
7680 | |||
when 521 then | |||
15360 | |||
end | |||
end | |||
size | |||
EXISTING_METHODS.select { |m| !@prefered_ciphers[m].nil? } | |||
end | |||
def cipher_size | |||
@@ -115,6 +83,10 @@ module CryptCheck | |||
RUBY_EVAL | |||
end | |||
def key_size | |||
@cert.public_key.rsa_equivalent_size | |||
end | |||
def ssl? | |||
sslv2? or sslv3? | |||
end | |||
@@ -139,10 +111,6 @@ module CryptCheck | |||
@supported_ciphers.values.flatten(1).uniq | |||
end | |||
def supported_ciphers_by_method | |||
@supported_ciphers | |||
end | |||
private | |||
def connect(family, host, port, &block) | |||
socket = ::Socket.new family, sock_type | |||
@@ -262,7 +230,6 @@ module CryptCheck | |||
end | |||
def fetch_prefered_ciphers | |||
Logger.info { '' } | |||
@prefered_ciphers = {} | |||
EXISTING_METHODS.each do |method| | |||
next unless SUPPORTED_METHODS.include? method | |||
@@ -278,8 +245,9 @@ module CryptCheck | |||
end | |||
def supported_cipher?(method, cipher) | |||
ssl_client method, [cipher] | |||
Logger.info { "#{Tls.colorize method} / #{Tls.colorize cipher[0]} : Supported" } | |||
dh = ssl_client method, [cipher] { |s| s.tmp_key } | |||
dh = dh ? " (#{'DH'.colorize :green} : #{Tls.key_to_s dh})" : '' | |||
Logger.info { "#{Tls.colorize method} / #{Tls.colorize cipher[0]} : Supported#{dh}" } | |||
true | |||
rescue TLSException => e | |||
Logger.debug { "#{Tls.colorize method} / #{Tls.colorize cipher[0]} : Not supported (#{e})" } | |||