|
- module CryptCheck
- module Tls
- class Cert
- DEFAULT_CA_DIRECTORIES = [
- '/usr/share/ca-certificates/mozilla'
- ]
-
- SIGNATURE_ALGORITHMS = %i(md2 mdc2 md4 md5 ripemd160 sha sha1 sha2 rsa dss ecc ghost).freeze
- SIGNATURE_ALGORITHMS_X509 = {
- 'dsaWithSHA' => %i(sha1 dss),
- 'dsaWithSHA1' => %i(sha1 dss),
- 'dsaWithSHA1_2' => %i(sha1 dss),
- 'dsa_with_SHA224' => %i(sha2 dss),
- 'dsa_with_SHA256' => %i(sha2 dss),
-
- 'mdc2WithRSA' => %i(mdc2 rsa),
-
- 'md2WithRSAEncryption' => %i(md2 rsa),
-
- 'md4WithRSAEncryption' => %i(md4, rsa),
-
- 'md5WithRSA' => %i(md5 rsa),
- 'md5WithRSAEncryption' => %i(md5 rsa),
-
- 'shaWithRSAEncryption' => %i(sha rsa),
- 'sha1WithRSA' => %i(sha1 rsa),
- 'sha1WithRSAEncryption' => %i(sha1 rsa),
- 'sha224WithRSAEncryption' => %i(sha2 rsa),
- 'sha256WithRSAEncryption' => %i(sha2 rsa),
- 'sha384WithRSAEncryption' => %i(sha2 rsa),
- 'sha512WithRSAEncryption' => %i(sha2 rsa),
-
- 'ripemd160WithRSA' => %i(ripemd160 rsa),
-
- 'ecdsa-with-SHA1' => %i(sha1 ecc),
- 'ecdsa-with-SHA224' => %i(sha2 ecc),
- 'ecdsa-with-SHA256' => %i(sha2 ecc),
- 'ecdsa-with-SHA384' => %i(sha2 ecc),
- 'ecdsa-with-SHA512' => %i(sha2 ecc),
-
- 'id_GostR3411_94_with_GostR3410_2001' => %i(ghost),
- 'id_GostR3411_94_with_GostR3410_94' => %i(ghost),
- 'id_GostR3411_94_with_GostR3410_94_cc' => %i(ghost),
- 'id_GostR3411_94_with_GostR3410_2001_cc' => %i(ghost)
- }.freeze
- WEAK_SIGN = {
- critical: %i(mdc2 md2 md4 md5 sha sha1)
- }.freeze
-
- SIGNATURE_ALGORITHMS.each do |name|
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}?
- SIGNATURE_ALGORITHMS_X509[@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_SERVER
- store.add_chains roots
- chain.each do |cert|
- # Never add other self signed certificates than system CA !
- next if cert.subject == cert.issuer
- store.add_cert cert rescue nil
- end if chain
-
- trusted = store.verify cert
- 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
- @cert.fingerprint
- end
-
- def key
- @cert.public_key
- end
-
- def subject
- @cert.subject
- end
-
- def serial
- @cert.serial
- end
-
- def issuer
- @cert.issuer
- end
-
- def lifetime
- { not_before: @cert.not_before, not_after: @cert.not_after }
- end
-
- def to_h
- {
- subject: self.subject.to_s,
- serial: self.serial.to_s,
- issuer: self.issuer.to_s,
- lifetime: self.lifetime,
- fingerprint: self.fingerprint,
- chain: @chain.collect do |cert|
- {
- subject: cert.subject.to_s,
- serial: cert.serial.to_s,
- issuer: cert.issuer.to_s,
- fingerprint: cert.fingerprint,
- lifetime: { not_before: cert.not_before, not_after: cert.not_after }
- }
- end,
- key: self.key.to_h,
- states: self.states
- }
- end
-
- protected
- include State
-
- CHECKS = WEAK_SIGN.collect do |level, hashes|
- hashes.collect do |hash|
- ["#{hash}_sign".to_sym, level, -> (s) { s.send "#{hash}?" }]
- end
- end.flatten(1).freeze
-
- def available_checks
- CHECKS
- end
-
- def children
- [self.key]
- end
- end
- end
- end
|