1class Gem::Security::TrustDir
2
3  DEFAULT_PERMISSIONS = {
4    :trust_dir    => 0700,
5    :trusted_cert => 0600,
6  }
7
8  def initialize dir, permissions = DEFAULT_PERMISSIONS
9    @dir = dir
10    @permissions = permissions
11
12    @digester = Gem::Security::DIGEST_ALGORITHM
13  end
14
15  attr_reader :dir
16
17  ##
18  # Returns the path to the trusted +certificate+
19
20  def cert_path certificate
21    name_path certificate.subject
22  end
23
24  ##
25  # Enumerates trusted certificates.
26
27  def each_certificate
28    return enum_for __method__ unless block_given?
29
30    glob = File.join @dir, '*.pem'
31
32    Dir[glob].each do |certificate_file|
33      begin
34        certificate = load_certificate certificate_file
35
36        yield certificate, certificate_file
37      rescue OpenSSL::X509::CertificateError
38        next # HACK warn
39      end
40    end
41  end
42
43  ##
44  # Returns the issuer certificate of the given +certificate+ if it exists in
45  # the trust directory.
46
47  def issuer_of certificate
48    path = name_path certificate.issuer
49
50    return unless File.exist? path
51
52    load_certificate path
53  end
54
55  ##
56  # Returns the path to the trusted certificate with the given ASN.1 +name+
57
58  def name_path name
59    digest = @digester.hexdigest name.to_s
60
61    File.join @dir, "cert-#{digest}.pem"
62  end
63
64  ##
65  # Loads the given +certificate_file+
66
67  def load_certificate certificate_file
68    pem = File.read certificate_file
69
70    OpenSSL::X509::Certificate.new pem
71  end
72
73  ##
74  # Add a certificate to trusted certificate list.
75
76  def trust_cert certificate
77    verify
78
79    destination = cert_path certificate
80
81    open destination, 'wb', @permissions[:trusted_cert] do |io|
82      io.write certificate.to_pem
83    end
84  end
85
86  ##
87  # Make sure the trust directory exists.  If it does exist, make sure it's
88  # actually a directory.  If not, then create it with the appropriate
89  # permissions.
90
91  def verify
92    if File.exist? @dir then
93      raise Gem::Security::Exception,
94        "trust directory #{@dir} is not a directory" unless
95          File.directory? @dir
96
97      FileUtils.chmod 0700, @dir
98    else
99      FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
100    end
101  end
102
103end
104
105