~lynxman/ubuntu/precise/puppet/puppetlabsfixbug12844

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-3872.patch/lib/puppet/sslcertificates/certificate.rb

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-10-24 15:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20111024150512-yxqwfdp6hcs6of5l
Tags: 2.7.1-1ubuntu3.2
* SECURITY UPDATE: puppet master impersonation via incorrect certificates
  - debian/patches/CVE-2011-3872.patch: refactor certificate handling.
  - Thanks to upstream for providing the patch.
  - CVE-2011-3872

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
class Puppet::SSLCertificates::Certificate
 
2
  SSLCertificates = Puppet::SSLCertificates
 
3
 
 
4
  attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
 
5
  attr_accessor :key, :cert, :csr, :cacert
 
6
 
 
7
  @@params2names = {
 
8
    :name       => "CN",
 
9
    :state      => "ST",
 
10
    :country    => "C",
 
11
    :email      => "emailAddress",
 
12
    :org        => "O",
 
13
    :city       => "L",
 
14
    :ou         => "OU"
 
15
  }
 
16
 
 
17
  def certname
 
18
    OpenSSL::X509::Name.new self.subject
 
19
  end
 
20
 
 
21
  def delete
 
22
    [@certfile,@keyfile].each { |file|
 
23
      File.unlink(file) if FileTest.exists?(file)
 
24
    }
 
25
 
 
26
    if @hash
 
27
      File.unlink(@hash) if FileTest.symlink?(@hash)
 
28
    end
 
29
  end
 
30
 
 
31
  def exists?
 
32
    FileTest.exists?(@certfile)
 
33
  end
 
34
 
 
35
  def getkey
 
36
    self.mkkey unless FileTest.exists?(@keyfile)
 
37
    if @password
 
38
 
 
39
      @key = OpenSSL::PKey::RSA.new(
 
40
 
 
41
        File.read(@keyfile),
 
42
 
 
43
        @password
 
44
      )
 
45
    else
 
46
      @key = OpenSSL::PKey::RSA.new(
 
47
        File.read(@keyfile)
 
48
      )
 
49
    end
 
50
  end
 
51
 
 
52
  def initialize(hash)
 
53
    raise Puppet::Error, "You must specify the common name for the certificate" unless hash.include?(:name)
 
54
    @name = hash[:name]
 
55
 
 
56
    # init a few variables
 
57
    @cert = @key = @csr = nil
 
58
 
 
59
    if hash.include?(:cert)
 
60
      @certfile = hash[:cert]
 
61
      @dir = File.dirname(@certfile)
 
62
    else
 
63
      @dir = hash[:dir] || Puppet[:certdir]
 
64
      @certfile = File.join(@dir, @name)
 
65
    end
 
66
 
 
67
    @cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
 
68
 
 
69
    Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
 
70
 
 
71
    unless @certfile =~ /\.pem$/
 
72
      @certfile += ".pem"
 
73
    end
 
74
    @keyfile = hash[:key] || File.join(
 
75
      Puppet[:privatekeydir], [@name,"pem"].join(".")
 
76
    )
 
77
    Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
 
78
 
 
79
    [@keyfile].each { |file|
 
80
      dir = File.dirname(file)
 
81
 
 
82
      Puppet.recmkdir(dir) unless FileTest.directory?(dir)
 
83
    }
 
84
 
 
85
    @ttl = hash[:ttl] || 365 * 24 * 60 * 60
 
86
    @selfsign = hash[:selfsign] || false
 
87
    @encrypt = hash[:encrypt] || false
 
88
    @replace = hash[:replace] || false
 
89
    @issuer = hash[:issuer] || nil
 
90
 
 
91
    if hash.include?(:type)
 
92
      case hash[:type]
 
93
      when :ca, :client, :server; @type = hash[:type]
 
94
      else
 
95
        raise "Invalid Cert type #{hash[:type]}"
 
96
      end
 
97
    else
 
98
      @type = :client
 
99
    end
 
100
 
 
101
    @params = {:name => @name}
 
102
    [:state, :country, :email, :org, :ou].each { |param|
 
103
      @params[param] = hash[param] if hash.include?(param)
 
104
    }
 
105
 
 
106
    if @encrypt
 
107
      if @encrypt =~ /^\//
 
108
        File.open(@encrypt) { |f|
 
109
          @password = f.read.chomp
 
110
        }
 
111
      else
 
112
        raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
 
113
      end
 
114
    else
 
115
      @password = nil
 
116
    end
 
117
 
 
118
    @selfsign = hash.include?(:selfsign) && hash[:selfsign]
 
119
  end
 
120
 
 
121
  # this only works for servers, not for users
 
122
  def mkcsr
 
123
    self.getkey unless @key
 
124
 
 
125
    name = OpenSSL::X509::Name.new self.subject
 
126
 
 
127
    @csr = OpenSSL::X509::Request.new
 
128
    @csr.version = 0
 
129
    @csr.subject = name
 
130
    @csr.public_key = @key.public_key
 
131
    @csr.sign(@key, OpenSSL::Digest::SHA1.new)
 
132
 
 
133
    #File.open(@csrfile, "w") { |f|
 
134
    #    f << @csr.to_pem
 
135
    #}
 
136
 
 
137
    raise Puppet::Error, "CSR sign verification failed" unless @csr.verify(@key.public_key)
 
138
 
 
139
    @csr
 
140
  end
 
141
 
 
142
  def mkkey
 
143
    # @key is the file
 
144
 
 
145
    @key = OpenSSL::PKey::RSA.new(1024)
 
146
#            { |p,n|
 
147
#                case p
 
148
#                when 0; Puppet.info "key info: ."  # BN_generate_prime
 
149
#                when 1; Puppet.info "key info: +"  # BN_generate_prime
 
150
#                when 2; Puppet.info "key info: *"  # searching good prime,
 
151
#                                          # n = #of try,
 
152
#                                          # but also data from BN_generate_prime
 
153
#                when 3; Puppet.info "key info: \n" # found good prime, n==0 - p, n==1 - q,
 
154
#                                          # but also data from BN_generate_prime
 
155
#                else;   Puppet.info "key info: *"  # BN_generate_prime
 
156
#                end
 
157
#            }
 
158
 
 
159
  if @password
 
160
  #        passwdproc = proc { @password }
 
161
 
 
162
    keytext = @key.export(
 
163
 
 
164
      OpenSSL::Cipher::DES.new(:EDE3, :CBC),
 
165
 
 
166
      @password
 
167
      )
 
168
      File.open(@keyfile, "w", 0400) { |f|
 
169
        f << keytext
 
170
      }
 
171
    else
 
172
      File.open(@keyfile, "w", 0400) { |f|
 
173
        f << @key.to_pem
 
174
      }
 
175
    end
 
176
 
 
177
    #cmd = "#{ossl} genrsa -out #{@key} 1024"
 
178
  end
 
179
 
 
180
  def mkselfsigned
 
181
    self.getkey unless @key
 
182
 
 
183
    raise Puppet::Error, "Cannot replace existing certificate" if @cert
 
184
 
 
185
    args = {
 
186
      :name => self.certname,
 
187
      :ttl => @ttl,
 
188
      :issuer => nil,
 
189
      :serial => 0x0,
 
190
      :publickey => @key.public_key
 
191
    }
 
192
    if @type
 
193
      args[:type] = @type
 
194
    else
 
195
      args[:type] = :server
 
196
    end
 
197
    @cert = SSLCertificates.mkcert(args)
 
198
 
 
199
    @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
 
200
 
 
201
    @cert
 
202
  end
 
203
 
 
204
  def subject(string = false)
 
205
    subj = @@params2names.collect { |param, name|
 
206
      [name, @params[param]] if @params.include?(param)
 
207
    }.reject { |ary| ary.nil? }
 
208
 
 
209
    if string
 
210
      return "/" + subj.collect { |ary|
 
211
        "%s=%s" % ary
 
212
      }.join("/") + "/"
 
213
    else
 
214
      return subj
 
215
    end
 
216
  end
 
217
 
 
218
  # verify that we can track down the cert chain or whatever
 
219
  def verify
 
220
    "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
 
221
  end
 
222
 
 
223
  def write
 
224
    files = {
 
225
      @certfile => @cert,
 
226
      @keyfile => @key,
 
227
    }
 
228
    files[@cacertfile] = @cacert if defined?(@cacert)
 
229
 
 
230
    files.each { |file,thing|
 
231
      if thing
 
232
        next if FileTest.exists?(file)
 
233
 
 
234
        text = nil
 
235
 
 
236
        if thing.is_a?(OpenSSL::PKey::RSA) and @password
 
237
 
 
238
          text = thing.export(
 
239
 
 
240
            OpenSSL::Cipher::DES.new(:EDE3, :CBC),
 
241
 
 
242
            @password
 
243
          )
 
244
        else
 
245
          text = thing.to_pem
 
246
        end
 
247
 
 
248
        File.open(file, "w", 0660) { |f| f.print text }
 
249
      end
 
250
    }
 
251
 
 
252
    SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) if defined?(@cacert)
 
253
  end
 
254
end
 
255