Browse Source

Encapsulate certificate/chain

new-scoring
aeris 2 years ago
parent
commit
5c08e8c44b
2 changed files with 53 additions and 27 deletions
  1. 40
    5
      lib/cryptcheck/tls/cert.rb
  2. 13
    22
      lib/cryptcheck/tls/server.rb

+ 40
- 5
lib/cryptcheck/tls/cert.rb View File

@@ -45,17 +45,24 @@ module CryptCheck

%i(md2 mdc2 md4 md5 ripemd160 sha sha1 sha2 rsa dss ecc ghost).each do |name|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}_sig?
@chains.any? do |chain|
SIGNATURE_ALGORITHMS[chain[:cert].signature_algorithm].include? :#{name}
end
def #{name}?
SIGNATURE_ALGORITHMS[@cert.signature_algorithm].include? :#{name}
end
RUBY_EVAL
end

def initialize(cert, chain=[])
@cert, @chain = case cert
when ::OpenSSL::X509::Certificate
[cert, chain]
when ::OpenSSL::SSL::SSLSocket
[cert.peer_cert, cert.peer_cert_chain]
end
end

def self.trusted?(cert, chain, roots: DEFAULT_CA_DIRECTORIES)
store = ::OpenSSL::X509::Store.new
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
store.purpose = ::OpenSSL::X509::PURPOSE_SSL_CLIENT
store.add_chains roots
chain.each do |cert|
# Never add other self signed certificates than system CA !
@@ -67,6 +74,34 @@ module CryptCheck
return :trusted if trusted
store.error_string
end

def trusted?(roots: DEFAULT_CA_DIRECTORIES)
Cert.trusted? @cert, @chain, roots: roots
end

def valid?(host)
::OpenSSL::SSL.verify_certificate_identity @cert, host
end

def fingerprint
::OpenSSL::Digest::SHA256.hexdigest @cert.to_der
end

def key
@cert.public_key
end

def subject
@cert.subject
end

def serial
@cert.serial
end

def issuer
@cert.issuer
end
end
end
end

+ 13
- 22
lib/cryptcheck/tls/server.rb View File

@@ -447,29 +447,21 @@ module CryptCheck
# Let's begin the fun
# First, collect "standard" connections
# { method => { cipher => connection, ... }, ... }
certs = @supported_ciphers.values.collect(&:values).flatten 1
certs = @supported_ciphers.values.collect(&:values).flatten 1
# Then, collect "ecdsa" connections
# { curve => connection, ... }
certs += @ecdsa_certs.values
# Then, fetch cert and chain
certs = certs.collect { |c| [c.peer_cert, c.peer_cert_chain] }
# Then, filter cert to keep uniq subject + issuer + serial
#certs = certs.uniq { |c, _| [c.subject, c.serial, c.issuer] }
certs += @ecdsa_certs.values
# Then, fetch cert
certs = certs.collect { |c| Cert.new c }
# Then, filter cert to keep uniq fingerprint
certs = certs.uniq { |c, _| OpenSSL::Digest::SHA256.hexdigest c.to_der }

view = {}
certs.each do |cert, chain|
id = cert.subject, cert.serial, cert.issuer
next if view.include? id
subject, serial, issuer = id
key = cert.public_key

identity = ::OpenSSL::SSL.verify_certificate_identity cert, (@hostname || @ip)
trust = Cert.trusted? cert, chain
view[id] = { cert: cert, chain: chain, key: key, identity: identity, trust: trust }
Logger.info { " Certificate #{subject} [#{serial}] issued by #{issuer}" }
Logger.info { ' Key : ' + Tls.key_to_s(key) }
@certs = certs.uniq { |c| c.fingerprint }

@certs.each do |cert|
key = cert.key
identity = cert.valid?(@hostname || @ip)
trust = cert.trusted?
Logger.info { " Certificate #{cert.subject} [#{cert.serial}] issued by #{cert.issuer}" }
Logger.info { ' Key : ' + Tls.key_to_s(key) }
if identity
Logger.info { ' Identity : ' + 'valid'.colorize(:good) }
else
@@ -481,8 +473,7 @@ module CryptCheck
Logger.info { ' Trust : ' + 'untrusted'.colorize(:error) + ' - ' + trust }
end
end
@chains = view.values
@keys = @chains.collect { |c| c[:key] }
@keys = @certs.collect &:key
end

def uniq_dh

Loading…
Cancel
Save