class SSLTool::CertificateStore

Public Class Methods

instantiate_adapter(store_url) click to toggle source
# File lib/ssltool/certificate_store.rb, line 22
def self.instantiate_adapter(store_url)
  scheme = URI.parse(store_url).scheme
  if scheme == 'file' then
    require_relative 'adapters/filesystem'
    FilesystemAdapter.new(store_url.sub(%r[^file://], ''))
  else
    require_relative 'adapters/sequel'
    raise ArgumentError unless Sequel::Database::ADAPTERS.include?(scheme.to_sym)
    SequelAdapter.new(store_url)
  end
end
new(store_url) click to toggle source
# File lib/ssltool/certificate_store.rb, line 14
def initialize(store_url)
  @circular_chain_notification_callbacks = []
  @adapter           = self.class.instantiate_adapter(store_url)
  @trusted_pool      = @adapter.load_pool(:trusted).keep_if(&:acceptable?)
  @intermediate_pool = @adapter.load_pool(:intermediate).keep_if(&:acceptable?)
  @excluded_pool     = @adapter.load_pool(:excluded)
end

Public Instance Methods

combined_trusted_pool_set() click to toggle source

trust

# File lib/ssltool/certificate_store.rb, line 36
def combined_trusted_pool_set
  (@trusted_pool + @intermediate_pool).to_set.freeze
end
detect_and_merge_intermediates!(unfiltered_pool, strict = true) click to toggle source

intermediate detection

# File lib/ssltool/certificate_store.rb, line 46
def detect_and_merge_intermediates!(unfiltered_pool, strict = true)
  return if combined_trusted_pool_set.superset?(unfiltered_pool.to_set)
  viable_pool = unfiltered_pool
                .select { |c| !strict || c.version < 2 ? !c.for_domain_name? : c.certificate_authority? && c.certificate_sign? }
                .select(&:acceptable?)
                .to_set
  return if combined_trusted_pool_set.superset?(viable_pool)
  working_pool   = intermediate_pool + viable_pool - excluded_pool
  all_chains     = working_pool.map { |cert| cert.chain_from(working_pool) }
  unique_chains  = all_chains.sort_by(&:length).reverse.inject([]) { |chains, chain|
                     chains << chain unless chains.any? { |longer_chain| (chain - longer_chain).empty? }; chains }
  trusted_certs  = unique_chains.select { |chain| trust?(chain) }.flatten
  trusted_certs -= detect_circular_chains(unique_chains).flatten
  return if trusted_certs.to_set == @intermediate_pool
  @intermediate_pool.replace(trusted_certs)
  @adapter.store_pool(:intermediate, intermediate_pool)
end
detect_circular_chains(chains) click to toggle source
# File lib/ssltool/certificate_store.rb, line 64
def detect_circular_chains(chains)
  circular_chains = chains.map(&:dup)
    .each   { |chain| chain.shift until chain[1..-1].to_a.any? { |other_cert| chain.first.signs?(other_cert) } || chain.empty? }
    .reject { |chain| chain.length <= 1 }
    .map(&:to_set).uniq.map(&:to_a)
  @circular_chain_notification_callbacks.each { |proc| proc.call(circular_chains) } unless circular_chains.empty?
  circular_chains
end
on_circular_chain_detection(&block) click to toggle source
# File lib/ssltool/certificate_store.rb, line 73
def on_circular_chain_detection(&block)
  raise ArgumentError, "Missing block" unless block_given?
  @circular_chain_notification_callbacks << block
end
resolve_chain(certs) click to toggle source

chains

# File lib/ssltool/certificate_store.rb, line 80
def resolve_chain(certs)
  certs = Certificate.scan(certs) if certs.is_a?(String)
  detect_and_merge_intermediates!(certs)
  ChainResolution.new(certs, self)
end
trust?(*chain) click to toggle source
# File lib/ssltool/certificate_store.rb, line 40
def trust?(*chain)
  chain.flatten.reverse.any? { |cert| trusted_pool.any? { |trusted_cert| trusted_cert.signs? cert } }
end