From a1d206a126e53434b2ba4ada68d05f5890cc1ce2 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 3 Aug 2005 16:27:38 +0000 Subject: moving git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@490 980ebf18-57e1-0310-9a29-db15c13687c0 --- lib/puppet/certificates.rb | 626 --------------------------------------------- lib/puppet/openssl.rb | 626 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 626 insertions(+), 626 deletions(-) delete mode 100755 lib/puppet/certificates.rb create mode 100755 lib/puppet/openssl.rb diff --git a/lib/puppet/certificates.rb b/lib/puppet/certificates.rb deleted file mode 100755 index 78bec8bd6..000000000 --- a/lib/puppet/certificates.rb +++ /dev/null @@ -1,626 +0,0 @@ -#!/usr/bin/ruby -w - -#-------------------- -# the puppet client -# -# $Id$ - - -require 'puppet' -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 - raise output - end - return output - end - - def self.findopenssl - if defined? @@openssl - return @@openssl - end - @@openssl = %x{which openssl}.chomp - - if @@openssl == "" - $stderr.puts "Could not find openssl in path" - exit(12) - end - - return @@openssl - end - - def self.mkdir(dir) - # this is all a bunch of stupid hackery - unless FileTest.exists?(dir) - comp = Puppet::Type::Component.new( - :name => "certdir creation" - ) - path = [''] - - dir.split(File::SEPARATOR).each { |d| - path << d - if FileTest.exists?(File.join(path)) - unless FileTest.directory?(File.join(path)) - raise "%s exists but is not a directory" % File.join(path) - end - else - obj = Puppet::Type.type(:file).new( - :name => File.join(path), - :mode => "750", - :create => "directory" - ) - - comp.push obj - end - } - trans = comp.evaluate - trans.evaluate - end - - Puppet::Type.allclear - end - - - class Config - include Enumerable - attr_accessor :path - - def [](name) - @sectionhash[name] - end - - def clear - @sectionhash.clear - @sectionary.clear - end - - def each - @sectionary.each { |section| - yield section - } - end - - def initialize(path) - @path = path - - @sectionhash = {} - @sectionary = [] - - # default to reading the config in - if FileTest.exists?(@path) - self.read - end - 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 - - def to_s - @sectionary.collect { |section| - section.to_s - }.join("\n") + "\n" - end - - def write - File.open(@path, "w") { |f| - f.print self.to_s - } - 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 - - def to_s - str = "" - unless @name == :HEAD - str += "[ #{@name} ]\n" - end - return str + (@paramary.collect { |param| - param.to_s - }.join("\n")) - end - end - - class Parameter - attr_accessor :name, :value, :comments - - def initialize(name, value, comments) - @name = name - @value = value.sub(/\s+$/,'') - @comments = comments - end - - def to_s - if comments and comments != "" - return "%s%s = %s" % [@comments, @name, @value] - else - return "%s = %s" % [@name, @value] - end - end - end - 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 - -# -# 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 - -[ root_ca_extensions ] -basicConstraints = CA:true -} - def init - self.mkconfig - self.mkcert - 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 - - 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 - - unless @certfile - raise "could not retrieve cert path" - end - - unless @keyfile - raise "could not retrieve key file" - end - - if hash.include?(:password) - @password = hash[:password] - else - @passfile = hash[:passfile] || File.join(@dir, "private", "phrase") - self.genpass - end - - @cert = self.getcert - end - - def genpass - pass = "" - 20.times { pass += (rand(74) + 48).chr } - - unless @passfile - raise "No passfile" - end - Puppet::OpenSSL.mkdir(File.dirname(@passfile)) - File.open(@passfile, "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 - ) - else - return self.mkcert - end - end - - def getconfig - if FileTest.exists?(@file) - return Puppet::OpenSSL::Config.new(@file) - else - return self.mkconfig - end - end - - def mkcert - #"openssl req -x509 -newkey rsa -out cacert.pem -outform PEM -days 1825" - cert = Certificate.new( - :name => "CAcert", - :cert => @certfile, - :encrypt => @passfile, - :key => @keyfile, - :length => 1825 - ) - - cert.mkselfsigned - return cert - end - - def mkconfig - File.open(@file, "w") { |f| f.print @@DEFAULTCONF } - - config = Puppet::OpenSSL::Config.new(@file) - - config.each { |section| - section.each { |param| - value = param.value.sub(/BASEDIR/, @dir) - param.value = value - } - } - - config.write - - return config - end - - def sign(cert) - unless cert.is_a?(Puppet::OpenSSL::Certificate) - raise "CA#sign only accepts Puppet::OpenSSL::Certificate objects" - end - - ossl = Puppet::OpenSSL.findopenssl - sign = [ossl] - sign << "ca" - sign << "-batch" - sign << ["-config", self.file] - sign << ["-passin", "file:%s" % @passfile] - sign << ["-out", cert.cert] - sign << ["-infiles", cert.csr] - - Puppet::OpenSSL.exec(sign.flatten.join(" ")) - # and then verify it - - #verify = "%s verify -CAfile %s %s" % - # [ossl, @cert, cert.cert] - verify = "%s verify %s" % - [ossl, cert.cert] - - Puppet::OpenSSL.exec(verify) - #openssl ca -config ca.config -out $CERT -infiles $CSR - #echo "CA verifying: $CERT <-> CA cert" - #openssl verify -CAfile ca.crt $CERT - end - end - - class Certificate - attr_accessor :cert, :key, :name, :dir, :hash, :csr - - @@params2names = { - :name => "CN", - :state => "ST", - :country => "C", - :email => "emailAddress", - :org => "O", - :city => "L", - :ou => "OU" - } - - def delete - [@cert,@key,@csr].each { |file| - FileTest.exists?(file) and File.unlink(file) - } - - if @hash - if FileTest.symlink?(@hash) - File.unlink(@hash) - end - end - end - - def exists? - FileTest.exists?(@cert) - end - - def initialize(hash) - unless hash.include?(:name) - raise "You must specify the common name for the certificate" - end - @name = hash[:name] - - if hash.include?(:cert) - @cert = hash[:cert] - @dir = File.dirname(@cert) - else - @dir = hash[:dir] - unless hash.include?(:dir) - raise "You must specify the directory in which to store certs" - end - @cert = File.join(@dir, @name) - end - - unless @cert =~ /\.pem$/ - @cert += ".pem" - end - @key = hash[:key] || File.join(@dir, @name + "_key.pem") - @csr = hash[:csr] || File.join(@dir, @name + "_csr.pem") - @days = hash[:length] || 365 - @selfsign = hash[:selfsign] || false - @encrypt = hash[:encrypt] || false - @replace = hash[:replace] || false - - @params = {:name => @name} - [:state, :country, :email, :org, :ou].each { |param| - if hash.include?(param) - @params[param] = hash[param] - end - } - - if @encrypt - unless @encrypt =~ /^\// - raise ":encrypt must be a path to a pass phrase file" - end - end - - if hash.include?(:selfsign) - @selfsign = hash[:selfsign] - else - @selfsign = false - end - - @ossl = Puppet::OpenSSL.findopenssl - end - - #def mkcert - # cmd = "#{ossl} req -nodes -new -x509 -keyout %s -out %s -config %s" % - # [@key, @cert, Puppet::OpenSSL.config] - #end - - def mkcsr - #cmd = "#{ossl} req -new -key #{@key} -out #{@csr}" - #self.class.exec(exec) - cmd = [@ossl, "req"] - cmd << "-batch" - cmd << "-new" - cmd << ["-newkey", "rsa:1024"] - cmd << ["-subj", self.subject] - cmd << ["-keyout", @key] - cmd << ["-out", @csr] - - if @encrypt - cmd << ["-passout", "file:" + @encrypt] - else - cmd << "-nodes" - end - - Puppet::OpenSSL.exec(cmd.flatten.join(" ")) - end - - def mkhash - hash = Puppet::OpenSSL.exec("openssl x509 -noout -hash -in %s" % @cert).chomp - 10.times { |i| - path = File.join(@dir, "%s.%s" % [hash, i]) - if FileTest.exists?(path) - if FileTest.symlink?(path) - dest = File.readlink(path) - if dest == @cert - # the correct link already exists - puts "hash already exists" - @hash = path - return - else - next - end - else - next - end - end - - File.symlink(@cert, path) - - @hash = path - break - } - end - - #def mkkey - # cmd = "#{ossl} genrsa -out #{@key} 1024" - #end - - def mkselfsigned - if self.exists? - unless @replace - raise "Certificate exists" - end - end - - cmd = [@ossl, "req"] - cmd << "-batch" - cmd << ["-subj", self.subject] - cmd << "-new" - cmd << "-x509" - cmd << ["-keyout", @key] - cmd << ["-out", @cert] - - if @encrypt - cmd << ["-passout", "file:" + @encrypt] - else - cmd << "-nodes" - end - - Puppet::OpenSSL.exec(cmd.flatten.join(" ")) - self.mkhash - end - - def subject - subj = "/" + @@params2names.collect { |param, name| - if @params.include?(param) - "%s=%s" % [name, @params[param]] - end - }.reject { |s| s.nil? }.join("/") + "/" - return subj - end - end -end -end diff --git a/lib/puppet/openssl.rb b/lib/puppet/openssl.rb new file mode 100755 index 000000000..78bec8bd6 --- /dev/null +++ b/lib/puppet/openssl.rb @@ -0,0 +1,626 @@ +#!/usr/bin/ruby -w + +#-------------------- +# the puppet client +# +# $Id$ + + +require 'puppet' +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 + raise output + end + return output + end + + def self.findopenssl + if defined? @@openssl + return @@openssl + end + @@openssl = %x{which openssl}.chomp + + if @@openssl == "" + $stderr.puts "Could not find openssl in path" + exit(12) + end + + return @@openssl + end + + def self.mkdir(dir) + # this is all a bunch of stupid hackery + unless FileTest.exists?(dir) + comp = Puppet::Type::Component.new( + :name => "certdir creation" + ) + path = [''] + + dir.split(File::SEPARATOR).each { |d| + path << d + if FileTest.exists?(File.join(path)) + unless FileTest.directory?(File.join(path)) + raise "%s exists but is not a directory" % File.join(path) + end + else + obj = Puppet::Type.type(:file).new( + :name => File.join(path), + :mode => "750", + :create => "directory" + ) + + comp.push obj + end + } + trans = comp.evaluate + trans.evaluate + end + + Puppet::Type.allclear + end + + + class Config + include Enumerable + attr_accessor :path + + def [](name) + @sectionhash[name] + end + + def clear + @sectionhash.clear + @sectionary.clear + end + + def each + @sectionary.each { |section| + yield section + } + end + + def initialize(path) + @path = path + + @sectionhash = {} + @sectionary = [] + + # default to reading the config in + if FileTest.exists?(@path) + self.read + end + 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 + + def to_s + @sectionary.collect { |section| + section.to_s + }.join("\n") + "\n" + end + + def write + File.open(@path, "w") { |f| + f.print self.to_s + } + 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 + + def to_s + str = "" + unless @name == :HEAD + str += "[ #{@name} ]\n" + end + return str + (@paramary.collect { |param| + param.to_s + }.join("\n")) + end + end + + class Parameter + attr_accessor :name, :value, :comments + + def initialize(name, value, comments) + @name = name + @value = value.sub(/\s+$/,'') + @comments = comments + end + + def to_s + if comments and comments != "" + return "%s%s = %s" % [@comments, @name, @value] + else + return "%s = %s" % [@name, @value] + end + end + end + 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 + +# +# 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 + +[ root_ca_extensions ] +basicConstraints = CA:true +} + def init + self.mkconfig + self.mkcert + 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 + + 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 + + unless @certfile + raise "could not retrieve cert path" + end + + unless @keyfile + raise "could not retrieve key file" + end + + if hash.include?(:password) + @password = hash[:password] + else + @passfile = hash[:passfile] || File.join(@dir, "private", "phrase") + self.genpass + end + + @cert = self.getcert + end + + def genpass + pass = "" + 20.times { pass += (rand(74) + 48).chr } + + unless @passfile + raise "No passfile" + end + Puppet::OpenSSL.mkdir(File.dirname(@passfile)) + File.open(@passfile, "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 + ) + else + return self.mkcert + end + end + + def getconfig + if FileTest.exists?(@file) + return Puppet::OpenSSL::Config.new(@file) + else + return self.mkconfig + end + end + + def mkcert + #"openssl req -x509 -newkey rsa -out cacert.pem -outform PEM -days 1825" + cert = Certificate.new( + :name => "CAcert", + :cert => @certfile, + :encrypt => @passfile, + :key => @keyfile, + :length => 1825 + ) + + cert.mkselfsigned + return cert + end + + def mkconfig + File.open(@file, "w") { |f| f.print @@DEFAULTCONF } + + config = Puppet::OpenSSL::Config.new(@file) + + config.each { |section| + section.each { |param| + value = param.value.sub(/BASEDIR/, @dir) + param.value = value + } + } + + config.write + + return config + end + + def sign(cert) + unless cert.is_a?(Puppet::OpenSSL::Certificate) + raise "CA#sign only accepts Puppet::OpenSSL::Certificate objects" + end + + ossl = Puppet::OpenSSL.findopenssl + sign = [ossl] + sign << "ca" + sign << "-batch" + sign << ["-config", self.file] + sign << ["-passin", "file:%s" % @passfile] + sign << ["-out", cert.cert] + sign << ["-infiles", cert.csr] + + Puppet::OpenSSL.exec(sign.flatten.join(" ")) + # and then verify it + + #verify = "%s verify -CAfile %s %s" % + # [ossl, @cert, cert.cert] + verify = "%s verify %s" % + [ossl, cert.cert] + + Puppet::OpenSSL.exec(verify) + #openssl ca -config ca.config -out $CERT -infiles $CSR + #echo "CA verifying: $CERT <-> CA cert" + #openssl verify -CAfile ca.crt $CERT + end + end + + class Certificate + attr_accessor :cert, :key, :name, :dir, :hash, :csr + + @@params2names = { + :name => "CN", + :state => "ST", + :country => "C", + :email => "emailAddress", + :org => "O", + :city => "L", + :ou => "OU" + } + + def delete + [@cert,@key,@csr].each { |file| + FileTest.exists?(file) and File.unlink(file) + } + + if @hash + if FileTest.symlink?(@hash) + File.unlink(@hash) + end + end + end + + def exists? + FileTest.exists?(@cert) + end + + def initialize(hash) + unless hash.include?(:name) + raise "You must specify the common name for the certificate" + end + @name = hash[:name] + + if hash.include?(:cert) + @cert = hash[:cert] + @dir = File.dirname(@cert) + else + @dir = hash[:dir] + unless hash.include?(:dir) + raise "You must specify the directory in which to store certs" + end + @cert = File.join(@dir, @name) + end + + unless @cert =~ /\.pem$/ + @cert += ".pem" + end + @key = hash[:key] || File.join(@dir, @name + "_key.pem") + @csr = hash[:csr] || File.join(@dir, @name + "_csr.pem") + @days = hash[:length] || 365 + @selfsign = hash[:selfsign] || false + @encrypt = hash[:encrypt] || false + @replace = hash[:replace] || false + + @params = {:name => @name} + [:state, :country, :email, :org, :ou].each { |param| + if hash.include?(param) + @params[param] = hash[param] + end + } + + if @encrypt + unless @encrypt =~ /^\// + raise ":encrypt must be a path to a pass phrase file" + end + end + + if hash.include?(:selfsign) + @selfsign = hash[:selfsign] + else + @selfsign = false + end + + @ossl = Puppet::OpenSSL.findopenssl + end + + #def mkcert + # cmd = "#{ossl} req -nodes -new -x509 -keyout %s -out %s -config %s" % + # [@key, @cert, Puppet::OpenSSL.config] + #end + + def mkcsr + #cmd = "#{ossl} req -new -key #{@key} -out #{@csr}" + #self.class.exec(exec) + cmd = [@ossl, "req"] + cmd << "-batch" + cmd << "-new" + cmd << ["-newkey", "rsa:1024"] + cmd << ["-subj", self.subject] + cmd << ["-keyout", @key] + cmd << ["-out", @csr] + + if @encrypt + cmd << ["-passout", "file:" + @encrypt] + else + cmd << "-nodes" + end + + Puppet::OpenSSL.exec(cmd.flatten.join(" ")) + end + + def mkhash + hash = Puppet::OpenSSL.exec("openssl x509 -noout -hash -in %s" % @cert).chomp + 10.times { |i| + path = File.join(@dir, "%s.%s" % [hash, i]) + if FileTest.exists?(path) + if FileTest.symlink?(path) + dest = File.readlink(path) + if dest == @cert + # the correct link already exists + puts "hash already exists" + @hash = path + return + else + next + end + else + next + end + end + + File.symlink(@cert, path) + + @hash = path + break + } + end + + #def mkkey + # cmd = "#{ossl} genrsa -out #{@key} 1024" + #end + + def mkselfsigned + if self.exists? + unless @replace + raise "Certificate exists" + end + end + + cmd = [@ossl, "req"] + cmd << "-batch" + cmd << ["-subj", self.subject] + cmd << "-new" + cmd << "-x509" + cmd << ["-keyout", @key] + cmd << ["-out", @cert] + + if @encrypt + cmd << ["-passout", "file:" + @encrypt] + else + cmd << "-nodes" + end + + Puppet::OpenSSL.exec(cmd.flatten.join(" ")) + self.mkhash + end + + def subject + subj = "/" + @@params2names.collect { |param, name| + if @params.include?(param) + "%s=%s" % [name, @params[param]] + end + }.reject { |s| s.nil? }.join("/") + "/" + return subj + end + end +end +end -- cgit