diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb deleted file mode 100755 index 4e941244e..000000000 --- a/lib/puppet/sslcertificates.rb +++ /dev/null @@ -1,146 +0,0 @@ -# The library for manipulating SSL certs. - -require 'puppet' - -raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl? - -module Puppet::SSLCertificates - #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey) - def self.mkcert(hash) - [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param| - raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param) - } - - cert = OpenSSL::X509::Certificate.new - # Make the certificate valid as of yesterday, because - # so many people's clocks are out of sync. - from = Time.now - (60*60*24) - - cert.subject = hash[:name] - if hash[:issuer] - cert.issuer = hash[:issuer].subject - else - # we're a self-signed cert - cert.issuer = hash[:name] - end - cert.not_before = from - cert.not_after = from + hash[:ttl] - cert.version = 2 # X509v3 - - cert.public_key = hash[:publickey] - cert.serial = hash[:serial] - - basic_constraint = nil - key_usage = nil - ext_key_usage = nil - subject_alt_name = [] - - ef = OpenSSL::X509::ExtensionFactory.new - - ef.subject_certificate = cert - - if hash[:issuer] - ef.issuer_certificate = hash[:issuer] - else - ef.issuer_certificate = cert - end - - ex = [] - case hash[:type] - when :ca - basic_constraint = "CA:TRUE" - key_usage = %w{cRLSign keyCertSign} - when :terminalsubca - basic_constraint = "CA:TRUE,pathlen:0" - key_usage = %w{cRLSign keyCertSign} - when :server - basic_constraint = "CA:FALSE" - dnsnames = Puppet[:certdnsnames] - name = hash[:name].to_s.sub(%r{/CN=},'') - if dnsnames != "" - dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d } - subject_alt_name << 'DNS:' + name # Add the fqdn as an alias - elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server - subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias - subject_alt_name << 'DNS:' + name # Add the fqdn as an alias - subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias - end - key_usage = %w{digitalSignature keyEncipherment} - ext_key_usage = %w{serverAuth clientAuth emailProtection} - 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} - ex << ef.create_extension("nsCertType", "client,email") - else - raise Puppet::Error, "unknown cert type '#{hash[:type]}'" - end - - - ex << ef.create_extension( - "nsComment", - - "Puppet Ruby/OpenSSL Generated Certificate") - ex << ef.create_extension("basicConstraints", basic_constraint, true) - ex << ef.create_extension("subjectKeyIdentifier", "hash") - - ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage - ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage - ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty? - - #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 - - # for some reason this _must_ be the last extension added - ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca - - cert - end - - def self.mkhash(dir, cert, certfile) - # Make sure the hash is zero-padded to 8 chars - hash = "%08x" % cert.issuer.hash - hashpath = nil - 10.times { |i| - path = File.join(dir, "#{hash}.#{i}") - if FileTest.exists?(path) - if FileTest.symlink?(path) - dest = File.readlink(path) - if dest == certfile - # the correct link already exists - hashpath = path - break - else - next - end - else - next - end - end - - File.symlink(certfile, path) - - hashpath = path - break - } - - - hashpath - end - require 'puppet/sslcertificates/certificate' - require 'puppet/sslcertificates/inventory' - require 'puppet/sslcertificates/ca' -end - diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb deleted file mode 100644 index 2541c8113..000000000 --- a/lib/puppet/sslcertificates/ca.rb +++ /dev/null @@ -1,367 +0,0 @@ -require 'sync' - -class Puppet::SSLCertificates::CA - include Puppet::Util::Warnings - - Certificate = Puppet::SSLCertificates::Certificate - attr_accessor :keyfile, :file, :config, :dir, :cert, :crl - - def certfile - @config[:cacert] - end - - # Remove all traces of a given host. This is kind of hackish, but, eh. - def clean(host) - host = host.downcase - [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name| - dir = Puppet[name] - - file = File.join(dir, host + ".pem") - - if FileTest.exists?(file) - begin - if Puppet[:name] == "cert" - puts "Removing #{file}" - else - Puppet.info "Removing #{file}" - end - File.unlink(file) - rescue => detail - raise Puppet::Error, "Could not delete #{file}: #{detail}" - end - end - - end - end - - def host2csrfile(hostname) - File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join(".")) - end - - # this stores signed certs in a directory unrelated to - # normal client certs - def host2certfile(hostname) - File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join(".")) - end - - # Turn our hostname into a Name object - def thing2name(thing) - thing.subject.to_a.find { |ary| - ary[0] == "CN" - }[1] - end - - def initialize(hash = {}) - Puppet.settings.use(:main, :ca, :ssl) - self.setconfig(hash) - - if Puppet[:capass] - if FileTest.exists?(Puppet[:capass]) - #puts "Reading #{Puppet[:capass]}" - #system "ls -al #{Puppet[:capass]}" - #File.read Puppet[:capass] - @config[:password] = self.getpass - else - # Don't create a password if the cert already exists - @config[:password] = self.genpass unless FileTest.exists?(@config[:cacert]) - end - end - - self.getcert - init_crl - unless FileTest.exists?(@config[:serial]) - Puppet.settings.write(:serial) do |f| - f << "%04X" % 1 - end - end - end - - # Generate a new password for the CA. - def genpass - pass = "" - 20.times { pass += (rand(74) + 48).chr } - - begin - Puppet.settings.write(:capass) { |f| f.print pass } - rescue Errno::EACCES => detail - raise Puppet::Error, detail.to_s - end - pass - end - - # Get the CA password. - def getpass - if @config[:capass] and File.readable?(@config[:capass]) - return File.read(@config[:capass]) - else - raise Puppet::Error, "Could not decrypt CA key with password: #{detail}" - end - end - - # Get the CA cert. - def getcert - if FileTest.exists?(@config[:cacert]) - @cert = OpenSSL::X509::Certificate.new( - File.read(@config[:cacert]) - ) - else - self.mkrootcert - end - end - - # Retrieve a client's CSR. - def getclientcsr(host) - csrfile = host2csrfile(host) - return nil unless File.exists?(csrfile) - - OpenSSL::X509::Request.new(File.read(csrfile)) - end - - # Retrieve a client's certificate. - def getclientcert(host) - certfile = host2certfile(host) - return [nil, nil] unless File.exists?(certfile) - - [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert] - end - - # List certificates waiting to be signed. This returns a list of hostnames, not actual - # files -- the names can be converted to full paths with host2csrfile. - def list(dummy_argument=:work_arround_for_ruby_GC_bug) - return Dir.entries(Puppet[:csrdir]).find_all { |file| - file =~ /\.pem$/ - }.collect { |file| - file.sub(/\.pem$/, '') - } - end - - # List signed certificates. This returns a list of hostnames, not actual - # files -- the names can be converted to full paths with host2csrfile. - def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug) - return Dir.entries(Puppet[:signeddir]).find_all { |file| - file =~ /\.pem$/ - }.collect { |file| - file.sub(/\.pem$/, '') - } - end - - # Create the root certificate. - def mkrootcert - # Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA. - name = "Puppet CA: #{Facter["hostname"].value}" - if domain = Facter["domain"].value - name += ".#{domain}" - end - - cert = Certificate.new( - :name => name, - :cert => @config[:cacert], - :encrypt => @config[:capass], - :key => @config[:cakey], - :selfsign => true, - :ttl => ttl, - :type => :ca - ) - - # This creates the cakey file - Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do - @cert = cert.mkselfsigned - end - Puppet.settings.write(:cacert) do |f| - f.puts @cert.to_pem - end - Puppet.settings.write(:capub) do |f| - f.puts @cert.public_key - end - cert - end - - def removeclientcsr(host) - csrfile = host2csrfile(host) - raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile) - - File.unlink(csrfile) - end - - # Revoke the certificate with serial number SERIAL issued by this - # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons - def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) - time = Time.now - revoked = OpenSSL::X509::Revoked.new - revoked.serial = serial - revoked.time = time - enum = OpenSSL::ASN1::Enumerated(reason) - ext = OpenSSL::X509::Extension.new("CRLReason", enum) - revoked.add_extension(ext) - @crl.add_revoked(revoked) - store_crl - end - - # Take the Puppet config and store it locally. - def setconfig(hash) - @config = {} - Puppet.settings.params("ca").each { |param| - param = param.intern if param.is_a? String - if hash.include?(param) - @config[param] = hash[param] - Puppet[param] = hash[param] - hash.delete(param) - else - @config[param] = Puppet[param] - end - } - - if hash.include?(:password) - @config[:password] = hash[:password] - hash.delete(:password) - end - - raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0 - - [:cadir, :csrdir, :signeddir].each { |dir| - raise Puppet::DevError, "#{dir} is undefined" unless @config[dir] - } - end - - # Sign a given certificate request. - def sign(csr) - unless csr.is_a?(OpenSSL::X509::Request) - raise Puppet::Error, - "CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}" - end - - raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key) - - serial = nil - Puppet.settings.readwritelock(:serial) { |f| - serial = File.read(@config[:serial]).chomp.hex - # increment the serial - f << "%04X" % (serial + 1) - } - - newcert = Puppet::SSL::CertificateFactory.build(:server, csr, @cert, serial) - sign_with_key(newcert) - - self.storeclientcert(newcert) - - [newcert, @cert] - end - - # Store the client's CSR for later signing. This is called from - # server/ca.rb, and the CSRs are deleted once the certificate is actually - # signed. - def storeclientcsr(csr) - host = thing2name(csr) - - csrfile = host2csrfile(host) - raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile) - - Puppet.settings.writesub(:csrdir, csrfile) do |f| - f.print csr.to_pem - end - end - - # Store the certificate that we generate. - def storeclientcert(cert) - host = thing2name(cert) - - certfile = host2certfile(host) - Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile) - - Puppet::SSLCertificates::Inventory::add(cert) - Puppet.settings.writesub(:signeddir, certfile) do |f| - f.print cert.to_pem - end - end - - # TTL for new certificates in seconds. If config param :ca_ttl is set, - # use that, otherwise use :ca_days for backwards compatibility - def ttl - days = @config[:ca_days] - if days && days.size > 0 - warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead." - return @config[:ca_days] * 24 * 60 * 60 - else - ttl = @config[:ca_ttl] - if ttl.is_a?(String) - unless ttl =~ /^(\d+)(y|d|h|s)$/ - raise ArgumentError, "Invalid ca_ttl #{ttl}" - end - case $2 - when 'y' - unit = 365 * 24 * 60 * 60 - when 'd' - unit = 24 * 60 * 60 - when 'h' - unit = 60 * 60 - when 's' - unit = 1 - else - raise ArgumentError, "Invalid unit for ca_ttl #{ttl}" - end - return $1.to_i * unit - else - return ttl - end - end - end - - private - def init_crl - if FileTest.exists?(@config[:cacrl]) - @crl = OpenSSL::X509::CRL.new( - File.read(@config[:cacrl]) - ) - else - # Create new CRL - @crl = OpenSSL::X509::CRL.new - @crl.issuer = @cert.subject - @crl.version = 1 - store_crl - @crl - end - end - - def store_crl - # Increment the crlNumber - e = @crl.extensions.find { |e| e.oid == 'crlNumber' } - ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' } - crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0) - ext << OpenSSL::X509::Extension.new("crlNumber", crlNum) - @crl.extensions = ext - - # Set last/next update - now = Time.now - @crl.last_update = now - # Keep CRL valid for 5 years - @crl.next_update = now + 5 * 365*24*60*60 - - sign_with_key(@crl) - Puppet.settings.write(:cacrl) do |f| - f.puts @crl.to_pem - end - end - - def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new) - cakey = nil - if @config[:password] - begin - cakey = OpenSSL::PKey::RSA.new( - File.read(@config[:cakey]), @config[:password] - ) - rescue - raise Puppet::Error, - "Decrypt of CA private key with password stored in @config[:capass] not possible" - end - else - cakey = OpenSSL::PKey::RSA.new( - File.read(@config[:cakey]) - ) - end - - raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey) - - signable.sign(cakey, digest) - end -end - diff --git a/lib/puppet/sslcertificates/certificate.rb b/lib/puppet/sslcertificates/certificate.rb deleted file mode 100644 index 2d30bb09f..000000000 --- a/lib/puppet/sslcertificates/certificate.rb +++ /dev/null @@ -1,255 +0,0 @@ -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| - File.unlink(file) if FileTest.exists?(file) - } - - if @hash - File.unlink(@hash) if FileTest.symlink?(@hash) - end - end - - def exists? - FileTest.exists?(@certfile) - end - - def getkey - self.mkkey unless FileTest.exists?(@keyfile) - 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) - raise Puppet::Error, "You must specify the common name for the certificate" unless hash.include?(:name) - @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") - - Puppet.recmkdir(@dir) unless FileTest.directory?(@dir) - - unless @certfile =~ /\.pem$/ - @certfile += ".pem" - end - @keyfile = hash[:key] || File.join( - Puppet[:privatekeydir], [@name,"pem"].join(".") - ) - Puppet.recmkdir(@dir) unless FileTest.directory?(@dir) - - [@keyfile].each { |file| - dir = File.dirname(file) - - Puppet.recmkdir(dir) unless FileTest.directory?(dir) - } - - @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 #{hash[:type]}" - end - else - @type = :client - end - - @params = {:name => @name} - [:state, :country, :email, :org, :ou].each { |param| - @params[param] = hash[param] if hash.include?(param) - } - - 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 - - @selfsign = hash.include?(:selfsign) && hash[:selfsign] - end - - # this only works for servers, not for users - def mkcsr - self.getkey unless @key - - 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 - #} - - raise Puppet::Error, "CSR sign verification failed" unless @csr.verify(@key.public_key) - - @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 - self.getkey unless @key - - raise Puppet::Error, "Cannot replace existing certificate" if @cert - - 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 - - @cert - end - - def subject(string = false) - subj = @@params2names.collect { |param, name| - [name, @params[param]] if @params.include?(param) - }.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, - } - files[@cacertfile] = @cacert if defined?(@cacert) - - files.each { |file,thing| - if thing - next if FileTest.exists?(file) - - 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 - } - - SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) if defined?(@cacert) - end -end - diff --git a/lib/puppet/sslcertificates/inventory.rb b/lib/puppet/sslcertificates/inventory.rb deleted file mode 100644 index 1075c1377..000000000 --- a/lib/puppet/sslcertificates/inventory.rb +++ /dev/null @@ -1,38 +0,0 @@ -# A module for keeping track of all the certificates issued by the CA, ever -# Maintains the file "$cadir/inventory.txt" -module Puppet::SSLCertificates - module Inventory - - # Add CERT to the inventory of issued certs in '$cadir/inventory.txt' - # If no inventory exists yet, build an inventory and list all the - # certificates that have been signed so far - def self.add(cert) - inited = false - inited = true if FileTest.exists?(Puppet[:cert_inventory]) - - Puppet.settings.write(:cert_inventory, "a") do |f| - f.puts((inited ? nil : self.init).to_s + format(cert)) - end - end - - private - - def self.init - inv = "# Inventory of signed certificates\n" - inv += "# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n" - Dir.glob(File::join(Puppet[:signeddir], "*.pem")) do |f| - inv += format(OpenSSL::X509::Certificate.new(File::read(f))) + "\n" - end - inv - end - - def self.format(cert) - iso = '%Y-%m-%dT%H:%M:%S%Z' - return "0x%04x %s %s %s" % [cert.serial, - cert.not_before.strftime(iso), - cert.not_after.strftime(iso), - cert.subject] - end - end -end - diff --git a/lib/puppet/sslcertificates/support.rb b/lib/puppet/sslcertificates/support.rb deleted file mode 100644 index 7d6708124..000000000 --- a/lib/puppet/sslcertificates/support.rb +++ /dev/null @@ -1,146 +0,0 @@ -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 = "@#{name}" - - maker = "mk_#{name}" - reader = "read_#{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]) or rename_files_with_uppercase(Puppet[param]) - - begin - instance_variable_set(var, klass.new(File.read(Puppet[param]))) - rescue => detail - raise InvalidCertificate, "Could not read #{param}: #{detail}" - end - end - - # Define the overall method, which just calls the reader and maker - # as appropriate. - define_method(name) do - unless cert = instance_variable_get(var) - unless cert = send(reader) - cert = send(maker) - Puppet.settings.write(param) { |f| f.puts cert.to_pem } - end - instance_variable_set(var, cert) - end - cert - end - end - - # The key pair. - keytype :key, :param => :hostprivkey, :class => OpenSSL::PKey::RSA do - Puppet.info "Creating a new SSL key at #{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.settings.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 #{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 - puts detail.backtrace if Puppet[:trace] - raise Puppet::Error.new("Certificate retrieval failed: #{detail}") - end - - if cert.nil? or cert == "" - return nil - end - Puppet.settings.write(:hostcert) do |f| f.print cert end - Puppet.settings.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: #{detail}" - ) - end - - raise Puppet::DevError, "Received invalid certificate" unless @cert.check_private_key(@key) - retrieved - end - - # A hack method to deal with files that exist with a different case. - # Just renames it; doesn't read it in or anything. - def rename_files_with_uppercase(file) - dir = File.dirname(file) - short = File.basename(file) - - # If the dir isn't present, we clearly don't have the file. - #return nil unless FileTest.directory?(dir) - - raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short - - return false unless File.directory?(dir) - - real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other| - other.downcase == short - end - - return nil unless real_file - - full_file = File.join(dir, real_file) - - Puppet.notice "Fixing case in #{full_file}; renaming to #{file}" - File.rename(full_file, file) - - true - end -end diff --git a/spec/unit/sslcertificates/ca_spec.rb b/spec/unit/sslcertificates/ca_spec.rb deleted file mode 100755 index 7a687b825..000000000 --- a/spec/unit/sslcertificates/ca_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env rspec -require 'spec_helper' - -require 'puppet' -require 'puppet/sslcertificates' -require 'puppet/sslcertificates/ca' - -describe Puppet::SSLCertificates::CA, :unless => Puppet.features.microsoft_windows? do - include PuppetSpec::Files - - before :all do - @hosts = %w{host.domain.com Other.Testing.Com} - end - - before :each do - Puppet::Util::SUIDManager.stubs(:asuser).yields - dir = tmpdir("ca_testing") - - Puppet.settings[:confdir] = dir - Puppet.settings[:vardir] = dir - - @ca = Puppet::SSLCertificates::CA.new - end - - describe 'when cleaning' do - it 'should remove associated files' do - dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] - - @hosts.each do |host| - files = [] - dirs.each do |dir| - dir = Puppet[dir] - - # Case insensitivity is handled through downcasing - file = File.join(dir, host.downcase + '.pem') - - File.open(file, "w") do |f| - f.puts "testing" - end - - files << file - end - - lambda { @ca.clean(host) }.should_not raise_error - - files.reject {|f| ! File.exists?(f)}.should be_empty - end - end - end - - describe 'when mapping hosts to files' do - it 'should correctly return the certfile' do - @hosts.each do |host| - value = nil - lambda { value = @ca.host2certfile host }.should_not raise_error - - File.join(Puppet[:signeddir], host.downcase + '.pem').should == value - end - end - - it 'should correctly return the csrfile' do - @hosts.each do |host| - value = nil - lambda { value = @ca.host2csrfile host }.should_not raise_error - - File.join(Puppet[:csrdir], host.downcase + '.pem').should == value - end - end - end - - describe 'when listing' do - it 'should find all csr' do - list = [] - - # Make some fake CSRs - @hosts.each do |host| - file = File.join(Puppet[:csrdir], host.downcase + '.pem') - File.open(file, 'w') { |f| f.puts "yay" } - list << host.downcase - end - - @ca.list.sort.should == list.sort - end - end - - describe 'when creating a root certificate' do - before :each do - lambda { @ca.mkrootcert }.should_not raise_exception - end - - it 'should store the public key' do - File.exists?(Puppet[:capub]).should be_true - end - - it 'should prepend "Puppet CA: " to the fqdn as the ca_name by default' do - host_mock_fact = mock() - host_mock_fact.expects(:value).returns('myhost') - domain_mock_fact = mock() - domain_mock_fact.expects(:value).returns('puppetlabs.lan') - Facter.stubs(:[]).with('hostname').returns(host_mock_fact) - Facter.stubs(:[]).with('domain').returns(domain_mock_fact) - - @ca.mkrootcert.name.should == 'Puppet CA: myhost.puppetlabs.lan' - end - end -end