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.
118 lines
2.7 KiB
118 lines
2.7 KiB
module CryptCheck
|
|
module Tls
|
|
class Cipher
|
|
TYPES = {
|
|
md5: %w(MD5),
|
|
sha1: %w(SHA),
|
|
|
|
psk: %w(PSK),
|
|
srp: %w(SRP),
|
|
anonymous: %w(ADH AECDH),
|
|
|
|
dss: %w(DSS),
|
|
|
|
null: %w(NULL),
|
|
export: %w(EXP),
|
|
des: %w(DES-CBC),
|
|
rc2: %w(RC2),
|
|
rc4: %w(RC4),
|
|
des3: %w(3DES DES-CBC3),
|
|
|
|
pfs: %w(DHE EDH ECDHE)
|
|
}
|
|
|
|
attr_reader :protocol, :name, :size, :dh
|
|
|
|
def initialize(protocol, cipher, dh=nil)
|
|
@protocol, @dh = protocol, dh
|
|
@name, _, @size = cipher
|
|
end
|
|
|
|
TYPES.each do |name, ciphers|
|
|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
|
def self.#{name}?(cipher)
|
|
#{ciphers}.any? { |c| /(^|-)#\{c\}(-|$)/ =~ cipher }
|
|
end
|
|
def #{name}?
|
|
#{ciphers}.any? { |c| /(^|-)#\{c\}(-|$)/ =~ @name }
|
|
end
|
|
RUBY_EVAL
|
|
end
|
|
|
|
def ssl?
|
|
sslv2? or sslv3?
|
|
end
|
|
|
|
def tls?
|
|
tlsv1? or tlsv1_1? or tlsv1_2?
|
|
end
|
|
|
|
def colorize
|
|
colors = case
|
|
when dss?,
|
|
anonymous?,
|
|
null?,
|
|
export?,
|
|
md5?,
|
|
des?,
|
|
rc4?
|
|
{ color: :white, background: :red }
|
|
when des3?
|
|
{ color: :yellow }
|
|
when pfs?
|
|
{ color: :green }
|
|
end
|
|
@name.colorize colors
|
|
end
|
|
|
|
def state
|
|
ok = Proc.new { |n| self.send "#{n}?" }
|
|
{
|
|
success: %i(pfs).select { |n| ok.call n },
|
|
warning: %i().select { |n| ok.call n },
|
|
danger: %i(des3).select { |n| ok.call n },
|
|
error: %i(dss md5 psk srp anonymous null export des rc2 rc4).select { |n| ok.call n }
|
|
}
|
|
end
|
|
|
|
def score
|
|
state = self.state
|
|
return :error unless state[:error].empty?
|
|
return :danger unless state[:danger].empty?
|
|
return :warning unless state[:warning].empty?
|
|
return :success unless state[:success].empty?
|
|
:none
|
|
end
|
|
|
|
PRIORITY = { success: 1, none: 2, warning: 3, danger: 4, error: 5 }
|
|
def self.sort(ciphers)
|
|
ciphers.sort do |a, b|
|
|
error_a, error_b = PRIORITY[a.score], PRIORITY[b.score]
|
|
compare = error_a <=> error_b
|
|
next compare unless compare == 0
|
|
|
|
size_a, size_b = a.size, b.size
|
|
compare = size_b <=> size_a
|
|
next compare unless compare == 0
|
|
|
|
dh_a, dh_b = a.dh, b.dh
|
|
next -1 if not dh_a and dh_b
|
|
next 1 if dh_a and not dh_b
|
|
next a.name <=> b.name if not dh_a and not dh_b
|
|
|
|
compare = b.dh.size <=> a.dh.size
|
|
next compare unless compare == 0
|
|
|
|
a.name <=> b.name
|
|
end
|
|
end
|
|
|
|
def self.list(cipher_suite = 'ALL:COMPLEMENTOFALL', protocol: :TLSv1_2)
|
|
context = OpenSSL::SSL::SSLContext.new protocol
|
|
context.ciphers = cipher_suite
|
|
ciphers = context.ciphers.collect { |c| self.new protocol, c }
|
|
self.sort ciphers
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|