summaryrefslogtreecommitdiffstats
path: root/lib/puppet/sslcertificates.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/sslcertificates.rb')
-rwxr-xr-xlib/puppet/sslcertificates.rb574
1 files changed, 3 insertions, 571 deletions
diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb
index 6c21f7c49..0c6322bcf 100755
--- a/lib/puppet/sslcertificates.rb
+++ b/lib/puppet/sslcertificates.rb
@@ -8,8 +8,7 @@ rescue LoadError
raise Puppet::Error, "You must have the Ruby openssl library installed"
end
-module Puppet
-module SSLCertificates
+module Puppet::SSLCertificates
def self.mkdir(dir)
# this is all a bunch of stupid hackery
unless FileTest.exists?(dir)
@@ -165,575 +164,8 @@ module SSLCertificates
return hashpath
end
-
-
-
- class CA
- attr_accessor :keyfile, :file, :config, :dir, :cert
-
- @@params = [
- :certdir,
- :publickeydir,
- :privatekeydir,
- :cadir,
- :cakey,
- :cacert,
- :capass,
- :capub,
- :csrdir,
- :signeddir,
- :serial,
- :privatedir,
- :ca_crl_days,
- :ca_days,
- :ca_md,
- :req_bits,
- :keylength,
- :autosign
- ]
-
- @@defaults = {
- :certdir => [:ssldir, "certs"],
- :publickeydir => [:ssldir, "public_keys"],
- :privatekeydir => [:ssldir, "private_keys"],
- :cadir => [:ssldir, "ca"],
- :cacert => [:cadir, "ca_crt.pem"],
- :cakey => [:cadir, "ca_key.pem"],
- :capub => [:cadir, "ca_pub.pem"],
- :csrdir => [:cadir, "requests"],
- :signeddir => [:cadir, "signed"],
- :capass => [:cadir, "ca.pass"],
- :serial => [:cadir, "serial"],
- :privatedir => [:ssldir, "private"],
- :passfile => [:privatedir, "password"],
- :autosign => [:puppetconf, "autosign.conf"],
- :ca_crl_days => 365,
- :ca_days => 1825,
- :ca_md => "md5",
- :req_bits => 2048,
- :keylength => 1024,
- }
-
- @@params.each { |param|
- Puppet.setdefault(param,@@defaults[param])
- }
-
- def certfile
- @config[:cacert]
- end
-
- def host2csrfile(hostname)
- File.join(Puppet[:csrdir], [hostname, "pem"].join("."))
- end
-
- # this stores signed certs in a directory unrelated to
- # normal client certs
- def host2certfile(hostname)
- File.join(Puppet[:signeddir], [hostname, "pem"].join("."))
- end
-
- def thing2name(thing)
- thing.subject.to_a.find { |ary|
- ary[0] == "CN"
- }[1]
- end
-
- def initialize(hash = {})
- self.setconfig(hash)
-
- self.getcert
- unless FileTest.exists?(@config[:serial])
- File.open(@config[:serial], "w") { |f|
- f << "%04X" % 1
- }
- end
-
- if Puppet[:capass] and ! FileTest.exists?(Puppet[:capass])
- self.genpass
- end
- end
-
- def genpass
- pass = ""
- 20.times { pass += (rand(74) + 48).chr }
-
- unless @config[:capass]
- raise "No passfile"
- end
- Puppet::SSLCertificates.mkdir(File.dirname(@config[:capass]))
- File.open(@config[:capass], "w", 0600) { |f| f.print pass }
- return pass
- end
-
- def getcert
- if FileTest.exists?(@config[:cacert])
- @cert = OpenSSL::X509::Certificate.new(
- File.read(@config[:cacert])
- )
- else
- self.mkrootcert
- end
- end
-
- def getclientcsr(host)
- csrfile = host2csrfile(host)
- unless File.exists?(csrfile)
- return nil
- end
-
- return OpenSSL::X509::Request.new(File.read(csrfile))
- end
-
- def getclientcert(host)
- certfile = host2certfile(host)
- unless File.exists?(certfile)
- return [nil, nil]
- end
-
- return [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
- end
-
- def list
- return Dir.entries(Puppet[:csrdir]).reject { |file|
- file =~ /^\.+$/
- }.collect { |file|
- file.sub(/\.pem$/, '')
- }
- end
-
- def mkrootcert
- cert = Certificate.new(
- :name => "CAcert",
- :cert => @config[:cacert],
- :encrypt => @config[:passfile],
- :key => @config[:cakey],
- :selfsign => true,
- :length => 1825,
- :type => :ca
- )
- @cert = cert.mkselfsigned
- File.open(@config[:cacert], "w", 0660) { |f|
- f.puts @cert.to_pem
- }
- @key = cert.key
- return cert
- end
-
- def removeclientcsr(host)
- csrfile = host2csrfile(host)
- unless File.exists?(csrfile)
- raise Puppet::Error, "No certificate request for %s" % host
- end
-
- File.unlink(csrfile)
- end
-
- def setconfig(hash)
- @config = {}
- @@params.each { |param|
- if hash.include?(param)
- begin
- @config[param] = hash[param]
- Puppet[param] = hash[param]
- hash.delete(param)
- rescue => detail
- puts detail
- exit
- end
- else
- begin
- @config[param] = Puppet[param]
- rescue => detail
- puts detail
- exit
- end
- end
- }
-
- if hash.include?(:password)
- @config[:password] = hash[:password]
- hash.delete(:password)
- end
-
- if hash.length > 0
- raise ArgumentError, "Unknown parameters %s" % hash.keys.join(",")
- end
-
- [:cadir, :csrdir, :signeddir].each { |dir|
- unless @config[dir]
- raise "%s is undefined" % dir
- end
- unless FileTest.exists?(@config[dir])
- Puppet::SSLCertificates.mkdir(@config[dir])
- end
- }
- end
-
- def sign(csr)
- unless csr.is_a?(OpenSSL::X509::Request)
- raise Puppet::Error,
- "CA#sign only accepts OpenSSL::X509::Request objects, not %s" %
- csr.class
- end
-
- unless csr.verify(csr.public_key)
- raise Puppet::Error, "CSR sign verification failed"
- end
-
- # i should probably check key length...
-
- # read the ca cert in
- cacert = OpenSSL::X509::Certificate.new(
- File.read(@config[:cacert])
- )
-
- cakey = nil
- if @config[:password]
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey]), @config[:password]
- )
- else
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey])
- )
- end
-
- unless cacert.check_private_key(cakey)
- raise Puppet::Error, "CA Certificate is invalid"
- end
-
- serial = File.read(@config[:serial]).chomp.hex
- newcert = SSLCertificates.mkcert(
- :type => :server,
- :name => csr.subject,
- :days => @config[:ca_days],
- :issuer => cacert,
- :serial => serial,
- :publickey => csr.public_key
- )
-
- # increment the serial
- File.open(@config[:serial], "w") { |f|
- f << "%04X" % (serial + 1)
- }
-
- newcert.sign(cakey, OpenSSL::Digest::SHA1.new)
-
- self.storeclientcert(newcert)
-
- return [newcert, cacert]
- end
-
- def storeclientcsr(csr)
- host = thing2name(csr)
-
- csrfile = host2csrfile(host)
- if File.exists?(csrfile)
- raise Puppet::Error, "Certificate request for %s already exists" % host
- end
-
- File.open(csrfile, "w", 0660) { |f|
- f.print csr.to_pem
- }
- end
-
- def storeclientcert(cert)
- host = thing2name(cert)
-
- certfile = host2certfile(host)
- if File.exists?(certfile)
- Puppet.notice "Overwriting signed certificate %s for %s" %
- [certfile, host]
- end
-
- File.open(certfile, "w", 0660) { |f|
- f.print cert.to_pem
- }
- end
-
- end
-
- class Certificate
- 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 "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::SSLCertificates.mkdir(@dir)
- end
-
- unless @certfile =~ /\.pem$/
- @certfile += ".pem"
- end
- @keyfile = hash[:key] || File.join(
- Puppet[:privatekeydir], [@name,"pem"].join(".")
- )
- unless FileTest.directory?(@dir)
- Puppet::SSLCertificates.mkdir(@dir)
- end
-
- [@keyfile].each { |file|
- dir = File.dirname(file)
-
- unless FileTest.directory?(dir)
- Puppet::SSLCertificates.mkdir(dir)
- end
- }
-
- @days = hash[:length] || 365
- @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 ":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,
- :days => @days,
- :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
-end
+ require 'puppet/sslcertificates/certificate'
+ require 'puppet/sslcertificates/ca'
end
-#
# $Id$