class Puppet::SSLCertificates::Certificate
SSLCertificates = Puppet::SSLCertificates
attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
attr_accessor :key, :cert, :csr, :cacert
@@params2names = {
:name => "CN",
:state => "ST",
:country => "C",
:email => "emailAddress",
:org => "O",
:city => "L",
:ou => "OU"
}
def certname
OpenSSL::X509::Name.new self.subject
end
def delete
[@certfile,@keyfile].each { |file|
if FileTest.exists?(file)
File.unlink(file)
end
}
if defined? @hash and @hash
if FileTest.symlink?(@hash)
File.unlink(@hash)
end
end
end
def exists?
return FileTest.exists?(@certfile)
end
def getkey
unless FileTest.exists?(@keyfile)
self.mkkey()
end
if @password
@key = OpenSSL::PKey::RSA.new(
File.read(@keyfile),
@password
)
else
@key = OpenSSL::PKey::RSA.new(
File.read(@keyfile)
)
end
end
def initialize(hash)
unless hash.include?(:name)
raise Puppet::Error, "You must specify the common name for the certificate"
end
@name = hash[:name]
# init a few variables
@cert = @key = @csr = nil
if hash.include?(:cert)
@certfile = hash[:cert]
@dir = File.dirname(@certfile)
else
@dir = hash[:dir] || Puppet[:certdir]
@certfile = File.join(@dir, @name)
end
@cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
unless FileTest.directory?(@dir)
Puppet.recmkdir(@dir)
end
unless @certfile =~ /\.pem$/
@certfile += ".pem"
end
@keyfile = hash[:key] || File.join(
Puppet[:privatekeydir], [@name,"pem"].join(".")
)
unless FileTest.directory?(@dir)
Puppet.recmkdir(@dir)
end
[@keyfile].each { |file|
dir = File.dirname(file)
unless FileTest.directory?(dir)
Puppet.recmkdir(dir)
end
}
@ttl = hash[:ttl] || 365 * 24 * 60 * 60
@selfsign = hash[:selfsign] || false
@encrypt = hash[:encrypt] || false
@replace = hash[:replace] || false
@issuer = hash[:issuer] || nil
if hash.include?(:type)
case hash[:type]
when :ca, :client, :server: @type = hash[:type]
else
raise "Invalid Cert type %s" % hash[:type]
end
else
@type = :client
end
@params = {:name => @name}
[:state, :country, :email, :org, :ou].each { |param|
if hash.include?(param)
@params[param] = hash[param]
end
}
if @encrypt
if @encrypt =~ /^\//
File.open(@encrypt) { |f|
@password = f.read.chomp
}
else
raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
end
else
@password = nil
end
if hash.include?(:selfsign)
@selfsign = hash[:selfsign]
else
@selfsign = false
end
end
# this only works for servers, not for users
def mkcsr
unless defined? @key and @key
self.getkey
end
name = OpenSSL::X509::Name.new self.subject
@csr = OpenSSL::X509::Request.new
@csr.version = 0
@csr.subject = name
@csr.public_key = @key.public_key
@csr.sign(@key, OpenSSL::Digest::SHA1.new)
#File.open(@csrfile, "w") { |f|
# f << @csr.to_pem
#}
unless @csr.verify(@key.public_key)
raise Puppet::Error, "CSR sign verification failed"
end
return @csr
end
def mkkey
# @key is the file
@key = OpenSSL::PKey::RSA.new(1024)
# { |p,n|
# case p
# when 0; Puppet.info "key info: ." # BN_generate_prime
# when 1; Puppet.info "key info: +" # BN_generate_prime
# when 2; Puppet.info "key info: *" # searching good prime,
# # n = #of try,
# # but also data from BN_generate_prime
# when 3; Puppet.info "key info: \n" # found good prime, n==0 - p, n==1 - q,
# # but also data from BN_generate_prime
# else; Puppet.info "key info: *" # BN_generate_prime
# end
# }
if @password
#passwdproc = proc { @password }
keytext = @key.export(
OpenSSL::Cipher::DES.new(:EDE3, :CBC),
@password
)
File.open(@keyfile, "w", 0400) { |f|
f << keytext
}
else
File.open(@keyfile, "w", 0400) { |f|
f << @key.to_pem
}
end
#cmd = "#{ossl} genrsa -out #{@key} 1024"
end
def mkselfsigned
unless defined? @key and @key
self.getkey
end
if defined? @cert and @cert
raise Puppet::Error, "Cannot replace existing certificate"
end
args = {
:name => self.certname,
:ttl => @ttl,
:issuer => nil,
:serial => 0x0,
:publickey => @key.public_key
}
if @type
args[:type] = @type
else
args[:type] = :server
end
@cert = SSLCertificates.mkcert(args)
@cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
return @cert
end
def subject(string = false)
subj = @@params2names.collect { |param, name|
if @params.include?(param)
[name, @params[param]]
end
}.reject { |ary| ary.nil? }
if string
return "/" + subj.collect { |ary|
"%s=%s" % ary
}.join("/") + "/"
else
return subj
end
end
# verify that we can track down the cert chain or whatever
def verify
"openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
end
def write
files = {
@certfile => @cert,
@keyfile => @key,
}
if defined? @cacert
files[@cacertfile] = @cacert
end
files.each { |file,thing|
if defined? thing and thing
if FileTest.exists?(file)
next
end
text = nil
if thing.is_a?(OpenSSL::PKey::RSA) and @password
text = thing.export(
OpenSSL::Cipher::DES.new(:EDE3, :CBC),
@password
)
else
text = thing.to_pem
end
File.open(file, "w", 0660) { |f| f.print text }
end
}
if defined? @cacert
SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile)
end
end
end
# $Id: certificate.rb 1581 2006-09-13 16:50:43Z lutter $
syntax highlighted by Code2HTML, v. 0.9.1