~ubuntu-branches/ubuntu/trusty/puppet/trusty

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-3872.patch/lib/puppet/ssl/host.rb

  • Committer: Package Import Robot
  • Author(s): Stig Sandbeck Mathisen
  • Date: 2011-10-22 14:08:22 UTC
  • mfrom: (1.1.25) (3.1.32 sid)
  • Revision ID: package-import@ubuntu.com-20111022140822-odxde5lohc45yhuz
Tags: 2.7.6-1
* New upstream release (CVE-2011-3872)
* Remove cherry-picked "groupadd_aix_warning" patch
* Install all new manpages

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
require 'puppet/indirector'
2
 
require 'puppet/ssl'
3
 
require 'puppet/ssl/key'
4
 
require 'puppet/ssl/certificate'
5
 
require 'puppet/ssl/certificate_request'
6
 
require 'puppet/ssl/certificate_revocation_list'
7
 
require 'puppet/util/cacher'
8
 
 
9
 
# The class that manages all aspects of our SSL certificates --
10
 
# private keys, public keys, requests, etc.
11
 
class Puppet::SSL::Host
12
 
  # Yay, ruby's strange constant lookups.
13
 
  Key = Puppet::SSL::Key
14
 
  CA_NAME = Puppet::SSL::CA_NAME
15
 
  Certificate = Puppet::SSL::Certificate
16
 
  CertificateRequest = Puppet::SSL::CertificateRequest
17
 
  CertificateRevocationList = Puppet::SSL::CertificateRevocationList
18
 
 
19
 
  extend Puppet::Indirector
20
 
  indirects :certificate_status, :terminus_class => :file
21
 
 
22
 
  attr_reader :name
23
 
  attr_accessor :ca
24
 
 
25
 
  attr_writer :key, :certificate, :certificate_request
26
 
 
27
 
  # This accessor is used in instances for indirector requests to hold desired state
28
 
  attr_accessor :desired_state
29
 
 
30
 
  class << self
31
 
    include Puppet::Util::Cacher
32
 
 
33
 
    cached_attr(:localhost) do
34
 
      result = new
35
 
      result.generate unless result.certificate
36
 
      result.key # Make sure it's read in
37
 
      result
38
 
    end
39
 
  end
40
 
 
41
 
  # This is the constant that people will use to mark that a given host is
42
 
  # a certificate authority.
43
 
  def self.ca_name
44
 
    CA_NAME
45
 
  end
46
 
 
47
 
  class << self
48
 
    attr_reader :ca_location
49
 
  end
50
 
 
51
 
  # Configure how our various classes interact with their various terminuses.
52
 
  def self.configure_indirection(terminus, cache = nil)
53
 
    Certificate.indirection.terminus_class = terminus
54
 
    CertificateRequest.indirection.terminus_class = terminus
55
 
    CertificateRevocationList.indirection.terminus_class = terminus
56
 
 
57
 
    host_map = {:ca => :file, :file => nil, :rest => :rest}
58
 
    if term = host_map[terminus]
59
 
      self.indirection.terminus_class = term
60
 
    else
61
 
      self.indirection.reset_terminus_class
62
 
    end
63
 
 
64
 
    if cache
65
 
      # This is weird; we don't actually cache our keys, we
66
 
      # use what would otherwise be the cache as our normal
67
 
      # terminus.
68
 
      Key.indirection.terminus_class = cache
69
 
    else
70
 
      Key.indirection.terminus_class = terminus
71
 
    end
72
 
 
73
 
    if cache
74
 
      Certificate.indirection.cache_class = cache
75
 
      CertificateRequest.indirection.cache_class = cache
76
 
      CertificateRevocationList.indirection.cache_class = cache
77
 
    else
78
 
      # Make sure we have no cache configured.  puppet master
79
 
      # switches the configurations around a bit, so it's important
80
 
      # that we specify the configs for absolutely everything, every
81
 
      # time.
82
 
      Certificate.indirection.cache_class = nil
83
 
      CertificateRequest.indirection.cache_class = nil
84
 
      CertificateRevocationList.indirection.cache_class = nil
85
 
    end
86
 
  end
87
 
 
88
 
  CA_MODES = {
89
 
    # Our ca is local, so we use it as the ultimate source of information
90
 
    # And we cache files locally.
91
 
    :local => [:ca, :file],
92
 
    # We're a remote CA client.
93
 
    :remote => [:rest, :file],
94
 
    # We are the CA, so we don't have read/write access to the normal certificates.
95
 
    :only => [:ca],
96
 
    # We have no CA, so we just look in the local file store.
97
 
    :none => [:file]
98
 
  }
99
 
 
100
 
  # Specify how we expect to interact with our certificate authority.
101
 
  def self.ca_location=(mode)
102
 
    modes = CA_MODES.collect { |m, vals| m.to_s }.join(", ")
103
 
    raise ArgumentError, "CA Mode can only be one of: #{modes}" unless CA_MODES.include?(mode)
104
 
 
105
 
    @ca_location = mode
106
 
 
107
 
    configure_indirection(*CA_MODES[@ca_location])
108
 
  end
109
 
 
110
 
  # Puppet::SSL::Host is actually indirected now so the original implementation
111
 
  # has been moved into the certificate_status indirector.  This method is in-use
112
 
  # in `puppet cert -c <certname>`.
113
 
  def self.destroy(name)
114
 
    indirection.destroy(name)
115
 
  end
116
 
 
117
 
  def self.from_pson(pson)
118
 
    instance = new(pson["name"])
119
 
    if pson["desired_state"]
120
 
      instance.desired_state = pson["desired_state"]
121
 
    end
122
 
    instance
123
 
  end
124
 
 
125
 
  # Puppet::SSL::Host is actually indirected now so the original implementation
126
 
  # has been moved into the certificate_status indirector.  This method does not
127
 
  # appear to be in use in `puppet cert -l`.
128
 
  def self.search(options = {})
129
 
    indirection.search("*", options)
130
 
  end
131
 
 
132
 
  # Is this a ca host, meaning that all of its files go in the CA location?
133
 
  def ca?
134
 
    ca
135
 
  end
136
 
 
137
 
  def key
138
 
    @key ||= Key.indirection.find(name)
139
 
  end
140
 
 
141
 
  # This is the private key; we can create it from scratch
142
 
  # with no inputs.
143
 
  def generate_key
144
 
    @key = Key.new(name)
145
 
    @key.generate
146
 
    begin
147
 
      Key.indirection.save(@key)
148
 
    rescue
149
 
      @key = nil
150
 
      raise
151
 
    end
152
 
    true
153
 
  end
154
 
 
155
 
  def certificate_request
156
 
    @certificate_request ||= CertificateRequest.indirection.find(name)
157
 
  end
158
 
 
159
 
  # Our certificate request requires the key but that's all.
160
 
  def generate_certificate_request
161
 
    generate_key unless key
162
 
    @certificate_request = CertificateRequest.new(name)
163
 
    @certificate_request.generate(key.content)
164
 
    begin
165
 
      CertificateRequest.indirection.save(@certificate_request)
166
 
    rescue
167
 
      @certificate_request = nil
168
 
      raise
169
 
    end
170
 
 
171
 
    true
172
 
  end
173
 
 
174
 
  def certificate
175
 
    unless @certificate
176
 
      generate_key unless key
177
 
 
178
 
      # get the CA cert first, since it's required for the normal cert
179
 
      # to be of any use.
180
 
      return nil unless Certificate.indirection.find("ca") unless ca?
181
 
      return nil unless @certificate = Certificate.indirection.find(name)
182
 
 
183
 
      unless certificate_matches_key?
184
 
        raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key"
185
 
      end
186
 
    end
187
 
    @certificate
188
 
  end
189
 
 
190
 
  def certificate_matches_key?
191
 
    return false unless key
192
 
    return false unless certificate
193
 
 
194
 
    certificate.content.check_private_key(key.content)
195
 
  end
196
 
 
197
 
  # Generate all necessary parts of our ssl host.
198
 
  def generate
199
 
    generate_key unless key
200
 
    generate_certificate_request unless certificate_request
201
 
 
202
 
    # If we can get a CA instance, then we're a valid CA, and we
203
 
    # should use it to sign our request; else, just try to read
204
 
    # the cert.
205
 
    if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
206
 
      ca.sign(self.name)
207
 
    end
208
 
  end
209
 
 
210
 
  def initialize(name = nil)
211
 
    @name = (name || Puppet[:certname]).downcase
212
 
    @key = @certificate = @certificate_request = nil
213
 
    @ca = (name == self.class.ca_name)
214
 
  end
215
 
 
216
 
  # Extract the public key from the private key.
217
 
  def public_key
218
 
    key.content.public_key
219
 
  end
220
 
 
221
 
  # Create/return a store that uses our SSL info to validate
222
 
  # connections.
223
 
  def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
224
 
    unless @ssl_store
225
 
      @ssl_store = OpenSSL::X509::Store.new
226
 
      @ssl_store.purpose = purpose
227
 
 
228
 
      # Use the file path here, because we don't want to cause
229
 
      # a lookup in the middle of setting our ssl connection.
230
 
      @ssl_store.add_file(Puppet[:localcacert])
231
 
 
232
 
      # If there's a CRL, add it to our store.
233
 
      if crl = Puppet::SSL::CertificateRevocationList.indirection.find(CA_NAME)
234
 
        @ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
235
 
        @ssl_store.add_crl(crl.content)
236
 
      end
237
 
      return @ssl_store
238
 
    end
239
 
    @ssl_store
240
 
  end
241
 
 
242
 
  def to_pson(*args)
243
 
    my_cert = Puppet::SSL::Certificate.indirection.find(name)
244
 
    pson_hash = { :name  => name }
245
 
 
246
 
    my_state = state
247
 
 
248
 
    pson_hash[:state] = my_state
249
 
    pson_hash[:desired_state] = desired_state if desired_state
250
 
 
251
 
    if my_state == 'requested'
252
 
      pson_hash[:fingerprint] = certificate_request.fingerprint
253
 
    else
254
 
      pson_hash[:fingerprint] = my_cert.fingerprint
255
 
    end
256
 
 
257
 
    pson_hash.to_pson(*args)
258
 
  end
259
 
 
260
 
  # Attempt to retrieve a cert, if we don't already have one.
261
 
  def wait_for_cert(time)
262
 
    begin
263
 
      return if certificate
264
 
      generate
265
 
      return if certificate
266
 
    rescue SystemExit,NoMemoryError
267
 
      raise
268
 
    rescue Exception => detail
269
 
      puts detail.backtrace if Puppet[:trace]
270
 
      Puppet.err "Could not request certificate: #{detail}"
271
 
      if time < 1
272
 
        puts "Exiting; failed to retrieve certificate and waitforcert is disabled"
273
 
        exit(1)
274
 
      else
275
 
        sleep(time)
276
 
      end
277
 
      retry
278
 
    end
279
 
 
280
 
    if time < 1
281
 
      puts "Exiting; no certificate found and waitforcert is disabled"
282
 
      exit(1)
283
 
    end
284
 
 
285
 
    while true
286
 
      sleep time
287
 
      begin
288
 
        break if certificate
289
 
        Puppet.notice "Did not receive certificate"
290
 
      rescue StandardError => detail
291
 
        puts detail.backtrace if Puppet[:trace]
292
 
        Puppet.err "Could not request certificate: #{detail}"
293
 
      end
294
 
    end
295
 
  end
296
 
 
297
 
  def state
298
 
    my_cert = Puppet::SSL::Certificate.indirection.find(name)
299
 
    if certificate_request
300
 
      return 'requested'
301
 
    end
302
 
 
303
 
    begin
304
 
      Puppet::SSL::CertificateAuthority.new.verify(my_cert)
305
 
      return 'signed'
306
 
    rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError
307
 
      return 'revoked'
308
 
    end
309
 
  end
310
 
end
311
 
 
312
 
require 'puppet/ssl/certificate_authority'