Class: SSLTool::CertificateStore

Inherits:
Object
  • Object
show all
Defined in:
lib/ssltool/adapters/base.rb,
lib/ssltool/adapters/sequel.rb,
lib/ssltool/certificate_store.rb,
lib/ssltool/adapters/filesystem.rb

Defined Under Namespace

Classes: Adapter, FilesystemAdapter, SequelAdapter

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store_url) ⇒ CertificateStore

Returns a new instance of CertificateStore.



14
15
16
17
18
19
20
# 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).select(&:acceptable?)
  @intermediate_pool = @adapter.load_pool(:intermediate).select(&:acceptable?)
  @excluded_pool     = @adapter.load_pool(:excluded)
end

Class Method Details

.instantiate_adapter(store_url) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
# 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

Instance Method Details

#combined_trusted_pool_setObject

trust



36
37
38
# 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) ⇒ Object

intermediate detection



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 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) ⇒ Object



64
65
66
67
68
69
70
71
# 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) ⇒ Object

Raises:

  • (ArgumentError)


73
74
75
76
# 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) ⇒ Object

chains



80
81
82
83
84
# 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) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
# 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