smortex/tls-checker

View on GitHub
lib/tls_checker/tlsa_checker_factory.rb

Summary

Maintainability
A
25 mins
Test Coverage
A
100%
# frozen_string_literal: true

module TLSChecker
  class TLSACheckerFactory
    def initialize
      @resolver = Resolv::DNS.new
    end

    def tlsa_checkers_for(certificate_checker)
      res = []
      return res unless certificate_checker.certificate

      each_tlsa_end_entity_record(certificate_checker) do |record|
        checker = TLSAChecker.new(record, certificate_checker)
        # Since a single domain may have different certificates on different
        # addresses, we are not interested in reporting failures here: a server
        # with 3 certificates on 3 IP addresses is expected to have 3 TLSA
        # records in the DNS, each one being valid for a different certificate.
        #
        # By adding only valid certificates, we can still detect problems when
        # events expire.
        next unless checker.certificate_match_tlsa_record?

        res << checker
      end

      res
    end

    private

    def each_tlsa_end_entity_record(certificate_checker)
      each_tlsa_record(certificate_checker) do |record|
        next unless record.end_entity?

        yield(record)
      end
    end

    def each_tlsa_record(certificate_checker)
      resource = "_#{certificate_checker.port}._tcp.#{certificate_checker.hostname}."

      @resolver.getresources(resource, Resolv::DNS::Resource::IN::ANY).each do |rr|
        # XXX: Should we check the RRSIG here, or can we assume that the resolver
        # should have failed if it could not verify the response?
        next unless rr.instance_of?(Resolv::DNS::Resource::Generic::Type52_Class1)

        record = Resolv::DNS::Resource::IN::TLSA.new(rr.data)
        yield(record)
      end
    end
  end
end