require 'puppet/sslcertificates'
# A module to handle reading of certificates.
module Puppet::SSLCertificates::Support
class MissingCertificate < Puppet::Error; end
class InvalidCertificate < Puppet::Error; end
attr_reader :cacert
# Some metaprogramming to create methods for retrieving and creating keys.
# This probably isn't fewer lines than defining each separately...
def self.keytype(name, options, &block)
var = "@%s" % name
maker = "mk_%s" % name
reader = "read_%s" % name
unless param = options[:param]
raise ArgumentError, "You must specify the parameter for the key"
end
unless klass = options[:class]
raise ArgumentError, "You must specify the class for the key"
end
# Define the method that creates it.
define_method(maker, &block)
# Define the reading method.
define_method(reader) do
return nil unless FileTest.exists?(Puppet[param])
begin
instance_variable_set(var,
klass.new(File.read(Puppet[param])))
rescue => detail
raise InvalidCertificate, "Could not read %s: %s" %
[param, detail]
end
end
# Define the overall method, which just calls the reader and maker
# as appropriate.
define_method(name) do
unless instance_variable_get(var)
unless cert = send(reader)
cert = send(maker)
Puppet.config.write(param) { |f| f.puts cert.to_pem }
end
instance_variable_set(var, cert)
end
instance_variable_get(var)
end
end
# The key pair.
keytype :key, :param => :hostprivkey, :class => OpenSSL::PKey::RSA do
Puppet.info "Creating a new SSL key at %s" % Puppet[:hostprivkey]
key = OpenSSL::PKey::RSA.new(Puppet[:keylength])
# Our key meta programming can only handle one file, so we have
# to separately write out the public key.
Puppet.config.write(:hostpubkey) do |f|
f.print key.public_key.to_pem
end
return key
end
# Our certificate request
keytype :csr, :param => :hostcsr, :class => OpenSSL::X509::Request do
Puppet.info "Creating a new certificate request for %s" %
Puppet[:certname]
csr = OpenSSL::X509::Request.new
csr.version = 0
csr.subject = OpenSSL::X509::Name.new([["CN", Puppet[:certname]]])
csr.public_key = key.public_key
csr.sign(key, OpenSSL::Digest::MD5.new)
return csr
end
keytype :cert, :param => :hostcert, :class => OpenSSL::X509::Certificate do
raise MissingCertificate, "No host certificate"
end
keytype :ca_cert, :param => :localcacert, :class => OpenSSL::X509::Certificate do
raise MissingCertificate, "No CA certificate"
end
# Request a certificate from the remote system. This does all of the work
# of creating the cert request, contacting the remote system, and
# storing the cert locally.
def requestcert
begin
cert, cacert = caclient.getcert(@csr.to_pem)
rescue => detail
if Puppet[:trace]
puts detail.backtrace
end
raise Puppet::Error.new("Certificate retrieval failed: %s" %
detail)
end
if cert.nil? or cert == ""
return nil
end
Puppet.config.write(:hostcert) do |f| f.print cert end
Puppet.config.write(:localcacert) do |f| f.print cacert end
#File.open(@certfile, "w", 0644) { |f| f.print cert }
#File.open(@cacertfile, "w", 0644) { |f| f.print cacert }
begin
@cert = OpenSSL::X509::Certificate.new(cert)
@cacert = OpenSSL::X509::Certificate.new(cacert)
retrieved = true
rescue => detail
raise Puppet::Error.new(
"Invalid certificate: %s" % detail
)
end
unless @cert.check_private_key(@key)
raise Puppet::DevError, "Received invalid certificate"
end
return retrieved
end
end
# $Id: support.rb 2259 2007-03-06 19:03:05Z luke $
syntax highlighted by Code2HTML, v. 0.9.1