diff options
Diffstat (limited to 'lib/puppet')
-rw-r--r-- | lib/puppet/client.rb | 88 | ||||
-rw-r--r-- | lib/puppet/selector.rb | 1 | ||||
-rwxr-xr-x | lib/puppet/sslcertificates.rb | 791 | ||||
-rw-r--r-- | lib/puppet/transportable.rb | 4 | ||||
-rw-r--r-- | lib/puppet/type.rb | 8 | ||||
-rw-r--r-- | lib/puppet/type/package.rb | 1 | ||||
-rw-r--r-- | lib/puppet/type/pfile.rb | 5 |
7 files changed, 431 insertions, 467 deletions
diff --git a/lib/puppet/client.rb b/lib/puppet/client.rb index 288782193..199e59b29 100644 --- a/lib/puppet/client.rb +++ b/lib/puppet/client.rb @@ -5,10 +5,10 @@ # the available clients require 'puppet' -require 'puppet/function' +require 'puppet/sslcertificates' require 'puppet/type' -#require 'puppet/fact' require 'facter' +require 'openssl' require 'puppet/transaction' require 'puppet/transportable' require 'puppet/metric' @@ -54,7 +54,9 @@ module Puppet class Client include Puppet - attr_accessor :local + attr_accessor :local, :secureinit + attr_reader :fqdn + def Client.facts facts = {} Facter.each { |name,fact| @@ -71,7 +73,7 @@ module Puppet if hash.include?(:Server) case hash[:Server] when String: - if $nonetworking + if $noclientnetworking raise NetworkClientError.new("Networking not available: %s" % $nonetworking) end @@ -94,6 +96,72 @@ module Puppet else raise ClientError.new("Must pass :Server to client") end + + if hash.include?(:FQDN) + @fqdn = hash[:FQDN] + else + hostname = Facter["hostname"].value + domain = Facter["domain"].value + @fqdn = [hostname, domain].join(".") + end + + @secureinit = hash[:NoSecureInit] || true + end + + def initcerts + return unless @secureinit + # verify we've got all of the certs set up and such + + # we are not going to encrypt our key, but we need at a minimum + # a keyfile and a certfile + certfile = File.join(Puppet[:certdir], [@fqdn, "pem"].join(".")) + keyfile = File.join(Puppet[:privatekeydir], [@fqdn, "pem"].join(".")) + publickeyfile = File.join(Puppet[:publickeydir], [@fqdn, "pem"].join(".")) + + [Puppet[:certdir], Puppet[:privatekeydir], Puppet[:csrdir], + Puppet[:publickeydir]].each { |dir| + unless FileTest.exists?(dir) + Puppet.recmkdir(dir, 0770) + end + } + if File.exists?(keyfile) + # load the key + @key = OpenSSL::PKey::RSA.new(File.read(keyfile)) + else + # create a new one and store it + Puppet.info "Creating a new SSL key at %s" % keyfile + @key = OpenSSL::PKey::RSA.new(Puppet[:keylength]) + File.open(keyfile, "w", 0660) { |f| f.print @key.to_pem } + File.open(publickeyfile, "w", 0660) { |f| f.print @key.public_key.to_pem } + + end + + unless File.exists?(certfile) + Puppet.info "Creating a new certificate request for %s" % @fqdn + name = OpenSSL::X509::Name.new([["CN", @fqdn]]) + + @csr = OpenSSL::X509::Request.new + @csr.version = 0 + @csr.subject = name + @csr.public_key = @key.public_key + @csr.sign(@key, OpenSSL::Digest::MD5.new) + + Puppet.info "Requesting certificate" + + cert = @driver.getcert(@csr.to_pem) + + if cert.nil? + raise Puppet::Error, "Failed to get certificate" + end + File.open(certfile, "w", 0660) { |f| f.print cert } + begin + @cert = OpenSSL::X509::Certificate.new(cert) + rescue => detail + raise Puppet::Error.new( + "Invalid certificate: %s" % detail + ) + end + end end def getconfig @@ -181,18 +249,6 @@ module Puppet #self.shutdown end - #def callfunc(name,args) - # Puppet.debug("Calling callfunc on %s" % name) - # if function = Puppet::Function[name] - # #debug("calling function %s" % function) - # value = function.call(args) - # #debug("from %s got %s" % [name,value]) - # return value - # else - # raise "Function '%s' not found" % name - # end - #end - private #def on_init diff --git a/lib/puppet/selector.rb b/lib/puppet/selector.rb index 6bfa1e2dd..50e55fb24 100644 --- a/lib/puppet/selector.rb +++ b/lib/puppet/selector.rb @@ -3,7 +3,6 @@ # $Id$ require 'puppet' -require 'puppet/fact' module Puppet #--------------------------------------------------------------- diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index 1f1619a67..13392dedf 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -8,31 +8,9 @@ require 'puppet' require 'openssl' -require 'getoptlong' module Puppet -module OpenSSL - @@config = "/etc/ssl/openssl.cnf" - - def self.config=(config) - @@config = config - end - - def self.config - return @@config - end - - def self.exec(cmd) - output = %x{#{cmd} 2>&1} - - #puts "\n\n%s\n\n" % cmd - unless $? == 0 - puts cmd - raise output - end - return output - end - +module SSLCertificates def self.mkdir(dir) # this is all a bunch of stupid hackery unless FileTest.exists?(dir) @@ -64,367 +42,309 @@ module OpenSSL Puppet::Type.allclear end - - class Config - include Enumerable - attr_accessor :path - - def [](name) - @sectionhash[name] - end - - def clear - @sectionhash.clear - @sectionary.clear + #def self.mkcert(type, name, days, issuercert, issuername, serial, publickey) + def self.mkcert(hash) + [:type, :name, :days, :issuer, :serial, :publickey].each { |param| + unless hash.include?(param) + raise ArgumentError, "mkcert called without %s" % param + end + } + cert = ::OpenSSL::X509::Certificate.new + from = Time.now + + cert.subject = hash[:name] + if hash[:issuer] + cert.issuer = hash[:issuer].subject + else + cert.issuer = cert.subject end - - def each - @sectionary.each { |section| - yield section - } + cert.not_before = from + cert.not_after = from + (hash[:days] * 24 * 60 * 60) + cert.version = 2 # X509v3 + + cert.public_key = hash[:publickey] + cert.serial = hash[:serial] + + basic_constraint = nil + key_usage = [] + ext_key_usage = [] + + case hash[:type] + when :ca: + basic_constraint = "CA:TRUE" + key_usage.push %w{cRLSign keyCertSign} + when :terminalsubca: + basic_constraint = "CA:TRUE,pathlen:0" + key_usage %w{cRLSign keyCertSign} + when :server: + basic_constraint = "CA:FALSE" + key_usage << %w{digitalSignature keyEncipherment} + ext_key_usage << "serverAuth" + when :ocsp: + basic_constraint = "CA:FALSE" + key_usage << %w{nonRepudiation digitalSignature} + ext_key_usage << %w{serverAuth OCSPSigning} + when :client: + basic_constraint = "CA:FALSE" + key_usage << %w{nonRepudiation digitalSignature keyEncipherment} + ext_key_usage << %w{clientAuth emailProtection} + else + raise "unknonwn cert type '%s'" % hash[:type] end - def initialize(path) - @path = path + key_usage.flatten! + ext_key_usage.flatten! - @sectionhash = {} - @sectionary = [] + ef = ::OpenSSL::X509::ExtensionFactory.new - # default to reading the config in - if FileTest.exists?(@path) - self.read - end + if hash[:issuer] + ef.issuer_certificate = hash[:issuer] + else + ef.issuer_certificate = cert end - def newsection(name) - sect = Section.new(name) - @sectionhash[sect.name] = sect - @sectionary.push sect - return sect - end - - def read - self.clear - section = self.newsection(:HEAD) - comments = "" - File.open(@path) { |f| - f.readlines.each { |line| - case line - when /^\s*#/: comments += line - when /^\[ (\w+) \]$/: - name = $1 - section = self.newsection(name) - when /^(\w+)\s*=\s*([^#]+)(#.*)*$/ - section.newparam($1, $2, comments) - comments = "" - when /^(\d+\.\w+)\s*=\s*([^#]+)(#.*)*$/ - section.newparam($1, $2, comments) - comments = "" - when /^\s*$/: # nothing - comments += line - else - puts "Could not match line %s" % line.inspect - end - } - } - end + ef.subject_certificate = cert - def to_s - @sectionary.collect { |section| - section.to_s - }.join("\n") + "\n" + ex = [] + ex << ef.create_extension("basicConstraints", basic_constraint, true) + ex << ef.create_extension("nsComment", + "Ruby/OpenSSL Generated Certificate") + ex << ef.create_extension("subjectKeyIdentifier", "hash") + #ex << ef.create_extension("nsCertType", "client,email") + unless key_usage.empty? then + ex << ef.create_extension("keyUsage", key_usage.join(",")) end - - def write - File.open(@path, "w") { |f| - f.print self.to_s - } + #ex << ef.create_extension("authorityKeyIdentifier", + # "keyid:always,issuer:always") + #ex << ef.create_extension("authorityKeyIdentifier", "keyid:always") + unless ext_key_usage.empty? then + ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) end - class Section - include Enumerable - attr_accessor :name - - def [](name) - @paramhash[name] - end - - def []=(name,value) - if @paramhash.include?(name) - @paramhash[name] = value - else - self.newparam(name, value) - end - end - - def each - @paramary.each { |param| - yield param - } - end - - def include?(name) - @paramhash.include?(name) - end - - def initialize(name) - @name = name - - @paramhash = {} - @paramary = [] - end - def newparam(name, value, comments = nil) - if @paramhash.include?(name) - raise "%s already has a param %s" % [@name, name] - end - obj = Parameter.new(name, value, comments) - @paramhash[name] = obj - @paramary.push obj - end + #if @ca_config[:cdp_location] then + # ex << ef.create_extension("crlDistributionPoints", + # @ca_config[:cdp_location]) + #end - def to_s - str = "" - unless @name == :HEAD - str += "[ #{@name} ]\n" - end - return str + (@paramary.collect { |param| - param.to_s - }.join("\n")) - end - end + #if @ca_config[:ocsp_location] then + # ex << ef.create_extension("authorityInfoAccess", + # "OCSP;" << @ca_config[:ocsp_location]) + #end + cert.extensions = ex - class Parameter - attr_accessor :name, :value, :comments + #cmd = "#{ossl} req -nodes -new -x509 -keyout %s -out %s -config %s" % + # [@key, certfile, Puppet::SSLCertificates.config] - def initialize(name, value, comments) - @name = name - @value = value.sub(/\s+$/,'') - @comments = comments - end + # write the cert out + #File.open(certfile, "w") { |f| f << cert.to_pem } - def to_s - if comments and comments != "" - return "%s%s = %s" % [@comments, @name, @value] - else - return "%s = %s" % [@name, @value] - end - end - end + return cert end + class CA attr_accessor :keyfile, :file, :config, :dir, :cert - @@DEFAULTCONF = %{# -# Default configuration to use when one is not provided on the command line. -# -[ ca ] -default_ca = local_ca - -# -# Default location of directories and files needed to generate -# certificates. -# -[ local_ca ] -certificate = BASEDIR/cacert.pem -database = BASEDIR/index.txt -new_certs_dir = BASEDIR/certs -private_key = BASEDIR/private/cakey.pem -serial = BASEDIR/serial - -# -# Default expiration and encryption policies for certificates. -# -default_crl_days = 365 -default_days = 1825 -default_md = md5 - -policy = local_ca_policy -x509_extensions = local_ca_extensions - -# -# Default policy to use when generating server certificates. The following -# fields must be defined in the server certificate. -# -[ local_ca_policy ] -commonName = supplied -stateOrProvinceName = supplied -countryName = supplied -emailAddress = supplied -organizationName = supplied -organizationalUnitName = supplied - -# -# x509 extensions to use when generating server certificates. -# -[ local_ca_extensions ] -subjectAltName = DNS:altname.somewhere.com -basicConstraints = CA:false -nsCertType = server - -# -# The default policy to use when -# generating the root certificate. -# -[ req ] -default_bits = 2048 -default_keyfile = BASEDIR/private/cakey.pem -default_md = md5 - -prompt = no -distinguished_name = root_ca_distinguished_name -x509_extensions = root_ca_extensions + @@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 => [:ssldir, "autosign"], + :ca_crl_days => 365, + :ca_days => 1825, + :ca_md => "md5", + :req_bits => 2048, + :keylength => 1024, + } -# -# Root Certificate Authority distin- guished name. Change these fields to -# your local environment. -# -[ root_ca_distinguished_name ] -commonName = Reductive Labs Root Certificate Authority -stateOrProvinceName = Some State -countryName = US -emailAddress = root@somename.somewhere.com -organizationName = Root Certificate Authority + @@params.each { |param| + Puppet.setdefault(param,@@defaults[param]) + } -[ root_ca_extensions ] -basicConstraints = CA:true -} - def init - self.mkconfig - self.mkcert + def host2csrfile(hostname) + File.join(Puppet[:csrdir], [hostname, "pem"].join(".")) end - def initialize(hash) - unless hash.include?(:dir) - raise "You must specify the base directory for the CA" - end - @dir = hash[:dir] - - @file = hash[:file] || File.join(@dir, "ca.cnf") - - unless FileTest.exists?(@dir) - Puppet::OpenSSL.mkdir(@dir) - end - - @config = self.getconfig - - @certfile = @config["local_ca"]["certificate"].value.chomp - @keyfile = @config["local_ca"]["private_key"].value.chomp + # this stores signed certs in a directory unrelated to + # normal client certs + def host2certfile(hostname) + File.join(Puppet[:signeddir], [hostname, "pem"].join(".")) + end - certdir = @config["local_ca"]["new_certs_dir"].value.chomp - Puppet::OpenSSL.mkdir(certdir) - - @serial = @config["local_ca"]["serial"].value.chomp - unless FileTest.exists?(@serial) - unless FileTest.exists?(File.dirname(@serial)) - Puppet::OpenSSL.mkdir(File.dirname(@serial)) - end - File.open(@serial, "w", 0600) { |f| f.puts "01" } - end - - database = @config["local_ca"]["database"].value.chomp - unless FileTest.exists?(database) - unless FileTest.exists?(File.dirname(database)) - Puppet::OpenSSL.mkdir(File.dirname(database)) - end - File.open(database, "w", 0600) { |f| f.print "" } - end + def thing2name(thing) + thing.subject.to_a.find { |ary| + ary[0] == "CN" + }[1] + end - @days = @config["local_ca"]["default_crl_days"].value.to_i || 365 - - unless @certfile - raise "could not retrieve cert path" - end + def initialize(hash = {}) + self.setconfig(hash) - unless @keyfile - raise "could not retrieve key file" + self.getcert + unless FileTest.exists?(@config[:serial]) + File.open(@config[:serial], "w") { |f| + f << "%04X" % 0 + } end - if hash.include?(:password) - @password = hash[:password] - else - @passfile = hash[:passfile] || File.join(@dir, "private", "phrase") - @password = self.genpass + if Puppet[:capass] and ! FileTest.exists?(Puppet[:capass]) + self.genpass end - - @cert = self.getcert end def genpass pass = "" 20.times { pass += (rand(74) + 48).chr } - unless @passfile + unless @config[:capass] raise "No passfile" end - Puppet::OpenSSL.mkdir(File.dirname(@passfile)) - File.open(@passfile, "w", 0600) { |f| f.print pass } + 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?(@certfile) - return Puppet::OpenSSL::Certificate.new( - :name => "CAcert", - :cert => @certfile, - :encrypt => @passfile, - :key => @keyfile + if FileTest.exists?(@config[:cacert]) + @cert = OpenSSL::X509::Certificate.new( + File.read(@config[:cacert]) ) else - return self.mkrootcert + self.mkrootcert end end - def getconfig - if FileTest.exists?(@file) - return Puppet::OpenSSL::Config.new(@file) - else - return self.mkconfig + 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 + end + + return OpenSSL::X509::Certificate.new(File.read(certfile)) + 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 => @certfile, - :encrypt => @passfile, - :key => @keyfile, + :cert => @config[:cacert], + :encrypt => @config[:passfile], + :key => @config[:cakey], :selfsign => true, :length => 1825 ) @cert = cert.mkselfsigned + File.open(@config[:cacert], "w", 0660) { |f| + f.puts @cert.to_pem + } @key = cert.key - return cert end - def mkconfig - File.open(@file, "w") { |f| f.print @@DEFAULTCONF } + def removeclientcsr(host) + csrfile = host2csrfile(host) + unless File.exists?(csrfile) + raise Puppet::Error, "No certificate request for %s" % host + end - config = Puppet::OpenSSL::Config.new(@file) + File.unlink(csrfile) + end - config.each { |section| - section.each { |param| - value = param.value.sub(/BASEDIR/, @dir) - param.value = value - } + 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 } - config.write + 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 - return config + [: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(cert) - unless cert.is_a?(Puppet::OpenSSL::Certificate) - raise "CA#sign only accepts Puppet::OpenSSL::Certificate objects" + def sign(csr) + unless csr.is_a?(OpenSSL::X509::Request) + raise "CA#sign only accepts OpenSSL::X509::Request objects, not %s" % + csr.class end - csr = ::OpenSSL::X509::Request.new( - File.read(cert.csrfile) - ) - unless csr.verify(csr.public_key) raise "CSR sign verification failed" end @@ -432,39 +352,66 @@ basicConstraints = CA:true # i should probably check key length... # read the ca cert in - if cert.exists? - raise "Cannot sign existing certificates" - end - cacert = ::OpenSSL::X509::Certificate.new( - File.read(@certfile) + File.read(@config[:cacert]) ) ca_keypair = ::OpenSSL::PKey::RSA.new( - File.read(@keyfile), @password + File.read(@config[:cakey]), @config[:password] ) - serial = File.read(@serial).chomp.hex - newcert = cert.mkcert( - cacert, cacert.subject, serial, ca_keypair.public_key + serial = File.read(@config[:serial]).chomp.hex + newcert = SSLCertificates.mkcert( + :type => :server, + :name => csr.subject, + :days => @config[:ca_days], + :issuer => cacert, + :serial => serial, + :publickey => ca_keypair.public_key ) # increment the serial - File.open(@serial, "w") { |f| + File.open(@config[:serial], "w") { |f| f << "%04X" % (serial + 1) } newcert.sign(ca_keypair, ::OpenSSL::Digest::SHA1.new) - File.open(cert.certfile, "w", 0644) { |f| - f << newcert.to_pem - } + self.storeclientcert(newcert) + return newcert 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 for %s" % host + end + + File.open(certfile, "w", 0660) { |f| + f.print cert.to_pem + } + end + end class Certificate - attr_accessor :certfile, :keyfile, :name, :dir, :hash, :csrfile, :type + attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type attr_accessor :key, :cert, :csr @@params2names = { @@ -482,13 +429,13 @@ basicConstraints = CA:true end def delete - [@certfile,@keyfile,@csrfile].each { |file| + [@certfile,@keyfile].each { |file| if FileTest.exists?(file) File.unlink(file) end } - if @hash + if defined? @hash and @hash if FileTest.symlink?(@hash) File.unlink(@hash) end @@ -496,7 +443,7 @@ basicConstraints = CA:true end def exists? - FileTest.exists?(@certfile) + return FileTest.exists?(@certfile) end def getkey @@ -521,26 +468,39 @@ basicConstraints = CA:true 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] - unless hash.include?(:dir) - raise "You must specify the directory in which to store certs" - end + @dir = hash[:dir] || Puppet[:certdir] @certfile = File.join(@dir, @name) end unless FileTest.directory?(@dir) - Puppet::OpenSSL.mkdir(@dir) + Puppet::SSLCertificates.mkdir(@dir) end unless @certfile =~ /\.pem$/ @certfile += ".pem" end - @keyfile = hash[:key] || File.join(@dir, @name + "_key.pem") - @csrfile = hash[:csr] || File.join(@dir, @name + "_csr.pem") + @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 @@ -583,109 +543,9 @@ basicConstraints = CA:true end end - def mkcert(issuercert, issuername, serial, publickey) - unless issuercert or @selfsign - raise "Certs must either have an issuer or must be self-signed" - end - - if self.exists? - raise "Cannot replace existing certificate" - end - - @cert = ::OpenSSL::X509::Certificate.new - from = Time.now - - @cert.subject = self.certname - @cert.issuer = issuername - @cert.not_before = from - @cert.not_after = from + (@days * 24 * 60 * 60) - @cert.version = 2 # X509v3 - - @cert.public_key = publickey - @cert.serial = serial - - basic_constraint = nil - key_usage = [] - ext_key_usage = [] - - case @type - when :ca: - basic_constraint = "CA:TRUE" - key_usage.push %w{cRLSign keyCertSign} - when :terminalsubca: - basic_constraint = "CA:TRUE,pathlen:0" - key_usage %w{cRLSign keyCertSign} - when :server: - basic_constraint = "CA:FALSE" - key_usage << %w{digitalSignature keyEncipherment} - ext_key_usage << "serverAuth" - when :ocsp: - basic_constraint = "CA:FALSE" - key_usage << %w{nonRepudiation digitalSignature} - ext_key_usage << %w{serverAuth OCSPSigning} - when :client: - basic_constraint = "CA:FALSE" - key_usage << %w{nonRepudiation digitalSignature keyEncipherment} - ext_key_usage << %w{clientAuth emailProtection} - else - raise "unknonwn cert type '%s'" % @type - end - - key_usage.flatten! - ext_key_usage.flatten! - - ef = ::OpenSSL::X509::ExtensionFactory.new - - if issuercert - ef.issuer_certificate = issuercert - else - ef.issuer_certificate = @cert - end - - ef.subject_certificate = @cert - - ex = [] - ex << ef.create_extension("basicConstraints", basic_constraint, true) - ex << ef.create_extension("nsComment", - "Ruby/OpenSSL Generated Certificate") - ex << ef.create_extension("subjectKeyIdentifier", "hash") - #ex << ef.create_extension("nsCertType", "client,email") - unless key_usage.empty? then - ex << ef.create_extension("keyUsage", key_usage.join(",")) - end - #ex << ef.create_extension("authorityKeyIdentifier", - # "keyid:always,issuer:always") - #ex << ef.create_extension("authorityKeyIdentifier", "keyid:always") - unless ext_key_usage.empty? then - ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) - end - - - #if @ca_config[:cdp_location] then - # ex << ef.create_extension("crlDistributionPoints", - # @ca_config[:cdp_location]) - #end - - #if @ca_config[:ocsp_location] then - # ex << ef.create_extension("authorityInfoAccess", - # "OCSP;" << @ca_config[:ocsp_location]) - #end - @cert.extensions = ex - - #cmd = "#{ossl} req -nodes -new -x509 -keyout %s -out %s -config %s" % - # [@key, @certfile, Puppet::OpenSSL.config] - - @cert.sign(@key, ::OpenSSL::Digest::SHA1.new) if @selfsign - - # write the cert out - File.open(@certfile, "w") { |f| f << @cert.to_pem } - - return @cert - end - # this only works for servers, not for users def mkcsr - unless @key + unless defined? @key and @key self.getkey end @@ -697,14 +557,16 @@ basicConstraints = CA:true @csr.public_key = @key.public_key @csr.sign(@key, ::OpenSSL::Digest::MD5.new) - File.open(@csrfile, "w") { |f| - f << @csr.to_pem - } + #File.open(@csrfile, "w") { |f| + # f << @csr.to_pem + #} + return @csr end def mkhash - hash = Puppet::OpenSSL.exec("openssl x509 -noout -hash -in %s" % @certfile).chomp + hash = "%x" % @cert.issuer.hash + path = nil 10.times { |i| path = File.join(@dir, "%s.%s" % [hash, i]) if FileTest.exists?(path) @@ -728,6 +590,8 @@ basicConstraints = CA:true @hash = path break } + + return path end def mkkey @@ -754,12 +618,24 @@ basicConstraints = CA:true end def mkselfsigned - unless @key + unless defined? @key and @key self.getkey end - self.mkcert(nil, self.certname, 0x0, @key.public_key) -# self.mkhash + if defined? @cert and @cert + raise Puppet::Error, "Cannot replace existing certificate" + end + + @cert = SSLCertificates.mkcert( + :type => :server, + :name => self.certname, + :days => @days, + :issuer => nil, + :serial => 0x0, + :publickey => @key.public_key + ) + + @cert.sign(@key, ::OpenSSL::Digest::SHA1.new) if @selfsign end def subject(string = false) @@ -777,6 +653,31 @@ basicConstraints = CA:true return subj end end + + def write + files = { + @certfile => @cert, + @keyfile => @key, + } + #@csrfile => @csr + + files.each { |file,thing| + if defined? thing and thing + if FileTest.exists?(file) + newtext = File.open(file) { |f| f.read } + if newtext != thing.to_pem + raise "Cannot replace existing %s" % thing.class + else + next + end + end + + File.open(file, "w", 0660) { |f| f.print thing.to_pem } + end + } + + self.mkhash + end end end end diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb index eab0e9a53..ebabf3a27 100644 --- a/lib/puppet/transportable.rb +++ b/lib/puppet/transportable.rb @@ -54,7 +54,7 @@ module Puppet if type = Puppet::Type.type(self.type) retobj = type.new(self) else - raise "Could not find object type %s" % self.type + raise Puppet::Error.new("Could not find object type %s" % self.type) end return retobj @@ -143,6 +143,7 @@ module Puppet Puppet.err "Failed to create %s %s: %s" % [child.type,child.name,except.message] if Puppet[:debug] + puts child.inspect puts except.stack end next @@ -150,6 +151,7 @@ module Puppet Puppet.err "Failed to create %s %s: %s" % [child.type,child.name,except.message] if Puppet[:debug] + puts child.inspect puts caller end next diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index c6b9dc5b1..cacc78c28 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -701,7 +701,13 @@ class Type < Puppet::Element order.flatten.each { |name| if hash.include?(name) - self[name] = hash[name] + begin + self[name] = hash[name] + rescue => detail + raise Puppet::DevError.new( + "Could not set %s on %s" % [name, self.class] + ) + end hash.delete name end } diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 77c866c08..4b618d020 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -3,7 +3,6 @@ # $Id$ require 'puppet/type/state' -require 'puppet/fact' module Puppet class PackageError < Puppet::Error; end diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index fd5bc74b0..c0e05f5a8 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -444,7 +444,9 @@ module Puppet if stat = @parent.stat(true) self.is = stat.mode & 007777 unless defined? @fixed - self.dirfix + if defined? @should and @should + self.dirfix + end end else self.is = -1 @@ -503,7 +505,6 @@ module Puppet end def should=(value) - require 'puppet/fact' method = nil gid = nil gname = nil |