1
3
class Puppet::SSLCertificates::CA
2
4
include Puppet::Util::Warnings
4
6
Certificate = Puppet::SSLCertificates::Certificate
5
7
attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
7
Puppet.setdefaults(:ca,
8
:cadir => { :default => "$ssldir/ca",
12
:desc => "The root directory for the certificate authority."
14
:cacert => { :default => "$cadir/ca_crt.pem",
18
:desc => "The CA certificate."
20
:cakey => { :default => "$cadir/ca_key.pem",
24
:desc => "The CA private key."
26
:capub => { :default => "$cadir/ca_pub.pem",
29
:desc => "The CA public key."
31
:cacrl => { :default => "$cadir/ca_crl.pem",
35
:desc => "The certificate revocation list (CRL) for the CA. Set this to 'none' if you do not want to use a CRL."
37
:caprivatedir => { :default => "$cadir/private",
41
:desc => "Where the CA stores private certificate information."
43
:csrdir => { :default => "$cadir/requests",
46
:desc => "Where the CA stores certificate requests"
48
:signeddir => { :default => "$cadir/signed",
52
:desc => "Where the CA stores signed certificates."
54
:capass => { :default => "$caprivatedir/ca.pass",
58
:desc => "Where the CA stores the password for the private key"
60
:serial => { :default => "$cadir/serial",
63
:desc => "Where the serial number for certificates is stored."
65
:autosign => { :default => "$confdir/autosign.conf",
67
:desc => "Whether to enable autosign. Valid values are true (which
68
autosigns any key request, and is a very bad idea), false (which
69
never autosigns any key request), and the path to a file, which
70
uses that configuration file to determine which keys to sign."},
71
:ca_days => ["", "How long a certificate should be valid.
72
This parameter is deprecated, use ca_ttl instead"],
73
:ca_ttl => ["5y", "The default TTL for new certificates; valid values
74
must be an integer, optionally followed by one of the units
75
'y' (years of 365 days), 'd' (days), 'h' (hours), or
76
's' (seconds). The unit defaults to seconds. If this parameter
77
is set, ca_days is ignored. Examples are '3600' (one hour)
78
and '1825d', which is the same as '5y' (5 years) "],
79
:ca_md => ["md5", "The type of hash used in certificates."],
80
:req_bits => [2048, "The bit length of the certificates."],
81
:keylength => [1024, "The bit length of keys."]
88
# TTL for new certificates in seconds. If config param :ca_ttl is set,
89
# use that, otherwise use :ca_days for backwards compatibility
91
days = @config[:ca_days]
92
if days && days.size > 0
93
warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
94
return @config[:ca_days] * 24 * 60 * 60
96
ttl = @config[:ca_ttl]
98
unless ttl =~ /^(\d+)(y|d|h|s)$/
99
raise ArgumentError, "Invalid ca_ttl #{ttl}"
103
unit = 365 * 24 * 60 * 60
111
raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
113
return $1.to_i * unit
120
13
# Remove all traces of a given host. This is kind of hackish, but, eh.
122
16
[:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
123
17
dir = Puppet[name]
144
38
def host2csrfile(hostname)
145
File.join(Puppet[:csrdir], [hostname, "pem"].join("."))
39
File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
148
42
# this stores signed certs in a directory unrelated to
149
43
# normal client certs
150
44
def host2certfile(hostname)
151
File.join(Puppet[:signeddir], [hostname, "pem"].join("."))
45
File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
154
48
# Turn our hostname into a Name object
283
191
File.unlink(csrfile)
194
# Revoke the certificate with serial number SERIAL issued by this
195
# CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
196
def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
197
if @config[:cacrl] == 'false'
198
raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'false'"
201
revoked = OpenSSL::X509::Revoked.new
202
revoked.serial = serial
204
enum = OpenSSL::ASN1::Enumerated(reason)
205
ext = OpenSSL::X509::Extension.new("CRLReason", enum)
206
revoked.add_extension(ext)
207
@crl.add_revoked(revoked)
286
211
# Take the Puppet config and store it locally.
287
212
def setconfig(hash)
289
Puppet.config.params("ca").each { |param|
214
Puppet.settings.params("ca").each { |param|
290
215
param = param.intern if param.is_a? String
291
216
if hash.include?(param)
292
217
@config[param] = hash[param]
358
285
raise Puppet::Error, "Certificate request for %s already exists" % host
361
Puppet.config.writesub(:csrdir, csrfile) do |f|
288
Puppet.settings.writesub(:csrdir, csrfile) do |f|
362
289
f.print csr.to_pem
366
# Revoke the certificate with serial number SERIAL issued by this
367
# CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
368
def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
369
if @config[:cacrl] == 'none'
370
raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'none'"
373
revoked = OpenSSL::X509::Revoked.new
374
revoked.serial = serial
376
enum = OpenSSL::ASN1::Enumerated(reason)
377
ext = OpenSSL::X509::Extension.new("CRLReason", enum)
378
revoked.add_extension(ext)
379
@crl.add_revoked(revoked)
383
293
# Store the certificate that we generate.
384
294
def storeclientcert(cert)
385
295
host = thing2name(cert)
393
303
Puppet::SSLCertificates::Inventory::add(cert)
394
Puppet.config.writesub(:signeddir, certfile) do |f|
304
Puppet.settings.writesub(:signeddir, certfile) do |f|
395
305
f.print cert.to_pem
309
# TTL for new certificates in seconds. If config param :ca_ttl is set,
310
# use that, otherwise use :ca_days for backwards compatibility
312
days = @config[:ca_days]
313
if days && days.size > 0
314
warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
315
return @config[:ca_days] * 24 * 60 * 60
317
ttl = @config[:ca_ttl]
319
unless ttl =~ /^(\d+)(y|d|h|s)$/
320
raise ArgumentError, "Invalid ca_ttl #{ttl}"
324
unit = 365 * 24 * 60 * 60
332
raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
334
return $1.to_i * unit
401
343
if FileTest.exists?(@config[:cacrl])
402
344
@crl = OpenSSL::X509::CRL.new(
403
345
File.read(@config[:cacrl])
405
elsif @config[:cacrl] == 'none'
347
elsif @config[:cacrl] == 'false'