File CVE-2011-3872.patch of Package puppet.import5403

Description: fix puppet master impersonation via incorrect certificates
Origin: Patch provided by upstream, but be_within changed to be_close in
 testsuite so it works with version of rspec in Ubuntu, and with the
 first part removed, as it introduced a regression.

Subject: [PATCH 02/32] (#6928) backport Symbol#to_proc for Ruby < 1.8.7
Subject: [PATCH 03/32] (#6928) Don't blow up when the method is undefined...
Subject: [PATCH 04/32] (#2848) Set `certdnsnames` values into the CSR.
Subject: [PATCH 05/32] (#2848) extract the subjectAltName value from the CSR.
Subject: [PATCH 06/32] (#2848) Reject unknown (== all) extensions on the CSR.
Subject: [PATCH 07/32] (#2848) Rewrite SSL Certificate Factory, fixing
Subject: [PATCH 08/32] (#7224) Add a helper to Puppet::SSL::Certificate to
Subject: [PATCH 09/32] (#2848) List subject alt names in output of puppet
Subject: [PATCH 10/32] (#2848) CSR subjectAltNames handling while signing.
Subject: [PATCH 11/32] (#2848) Use `certdnsnames` when bootstrapping a local
Subject: [PATCH 12/32] (#2848) Rename `certdnsnames` to match new behaviour.
Subject: [PATCH 13/32] (#2848) rename subject-alt-name option to
Subject: [PATCH 14/32] Wire up the `setbycli` slot in Puppet settings.
Subject: [PATCH 15/32] (#2848) Migrate `dns-alt-names` back to settings.
Subject: [PATCH 16/32] (#2848) Only mark `subjectAltName` critical if
Subject: [PATCH 17/32] (#2848) Don't enable `emailProtection` for server
Subject: [PATCH 18/32] (#2848) Don't strip the subjectAltName label when
Subject: [PATCH 19/32] (#2848) Consistently use `subject_alt_names` as
Subject: [PATCH 20/32] (#2848) Consistent return values from
Subject: [PATCH 21/32] (#2848) Remove unused xmlrpc code
Subject: [PATCH 22/32] (#2848) Rework the xmlrpc CA handler to use the modern
Subject: [PATCH 23/32] (#2848) Remove the legacy SSLCertificates code
Subject: [PATCH 24/32] (#2848) Eliminate redundant `master_dns_alt_names`.
Subject: [PATCH 25/32] s/not_to/should_not/ for older versions of RSpec 2.
Subject: [PATCH 26/32] Add `lines` alias for `each_line` in Ruby 1.8.5.
Subject: [PATCH 27/32] (#2848) Config options require '_', not '-'.
Subject: [PATCH 28/32] Better 1.8.5 compatible implementation of `lines`.
Subject: [PATCH 29/32] More 1.8.5 compatibility fixes.
Subject: [PATCH 30/32] Backport Enumerable#count to Rubies < 1.8.7
Subject: [PATCH 31/32] Allow a master to bootstrap itself with dns_alt_names
Subject: [PATCH 32/32] Improve the error message when a CSR is rejected

Index: puppet-2.6.4/lib/puppet/application/cert.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/application/cert.rb	2010-12-01 00:42:01.000000000 +0100
+++ puppet-2.6.4/lib/puppet/application/cert.rb	2011-11-01 10:51:35.082524339 +0100
@@ -45,6 +45,10 @@
     Puppet::Util::Log.level = :info
   end
 
+  option("--[no-]allow-dns-alt-names") do |value|
+    options[:allow_dns_alt_names] = value
+  end
+
   def main
     if @all
       hosts = :all
@@ -54,8 +58,8 @@
       hosts = command_line.args.collect { |h| h.downcase }
     end
     begin
-      @ca.apply(:revoke, :to => hosts) if @cert_mode == :destroy
-      @ca.apply(@cert_mode, :to => hosts, :digest => @digest)
+      @ca.apply(:revoke, options.merge(:to => hosts)) if @cert_mode == :destroy
+      @ca.apply(@cert_mode, options.merge(:to => hosts, :digest => @digest))
     rescue => detail
       puts detail.backtrace if Puppet[:trace]
       puts detail.to_s
@@ -74,6 +78,15 @@
       Puppet::SSL::Host.ca_location = :only
     end
 
+    # If we are generating, and the option came from the CLI, it gets added to
+    # the data.  This will do the right thing for non-local certificates, in
+    # that the command line but *NOT* the config file option will apply.
+    if @cert_mode == :generate
+      if Puppet.settings.setting(:dns_alt_names).setbycli
+        options[:dns_alt_names] = Puppet[:dns_alt_names]
+      end
+    end
+
     begin
       @ca = Puppet::SSL::CertificateAuthority.new
     rescue => detail
Index: puppet-2.6.4/lib/puppet/application/kick.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/application/kick.rb	2010-12-01 00:42:01.000000000 +0100
+++ puppet-2.6.4/lib/puppet/application/kick.rb	2011-11-01 10:51:35.082524339 +0100
@@ -48,8 +48,6 @@
   end
 
   def main
-    require 'puppet/network/client'
-
     Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
     require 'puppet/util/ldap/connection'
 
Index: puppet-2.6.4/lib/puppet/defaults.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/defaults.rb	2010-12-01 00:42:43.000000000 +0100
+++ puppet-2.6.4/lib/puppet/defaults.rb	2011-11-01 10:51:35.083524369 +0100
@@ -191,9 +191,58 @@
       to the fully qualified domain name.",
       :call_on_define => true, # Call our hook with the default value, so we're always downcased
       :hook => proc { |value| raise(ArgumentError, "Certificate names must be lower case; see #1168") unless value == value.downcase }},
-    :certdnsnames => ['', "The DNS names on the Server certificate as a colon-separated list.
-      If it's anything other than an empty string, it will be used as an alias in the created
-      certificate.  By default, only the server gets an alias set up, and only for 'puppet'."],
+    :certdnsnames => {
+      :default => '',
+      :hook    => proc do |value|
+        unless value.nil? or value == '' then
+          Puppet.warning <<WARN
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally.  There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+WARN
+        end
+      end,
+      :desc    => <<EOT
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally.  There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+EOT
+    },
+    :dns_alt_names => {
+      :default => '',
+      :desc    => <<EOT,
+The comma-separated list of alternative DNS names to use for the local host.
+
+When the node generates a CSR for itself, these are added to the request
+as the desired `subjectAltName` in the certificate: additional DNS labels
+that the certificate is also valid answering as.
+
+This is generally required if you use a non-hostname `certname`, or if you
+want to use `puppet kick` or `puppet resource -H` and the primary certname
+does not match the DNS name you use to communicate with the host.
+
+This is unnecessary for agents, unless you intend to use them as a server for
+`puppet kick` or remote `puppet resource` management.
+
+It is rarely necessary for servers; it is usually helpful only if you need to
+have a pool of multiple load balanced masters, or for the same master to
+respond on two physically separate networks under different names.
+EOT
+    },
     :certdir => {
       :default => "$ssldir/certs",
       :owner => "service",
Index: puppet-2.6.4/lib/puppet/network/client/ca.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/ca.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,56 +0,0 @@
-require 'puppet/network/client'
-
-# Request a certificate from the remote system.
-class Puppet::Network::Client::CA < Puppet::Network::Client
-  class InvalidCertificate < Puppet::Error; end
-
-  def initialize(options = {})
-    options = symbolize_options(options)
-    unless options.include?(:Server) or options.include?(:CA)
-      options[:Server] = Puppet[:ca_server]
-      options[:Port] = Puppet[:ca_port]
-    end
-    super(options)
-  end
-
-  # This client is really only able to request certificates for the
-  # current host.  It uses the Puppet.settings settings to figure everything out.
-  def request_cert
-    Puppet.settings.use(:main, :ssl)
-
-    if cert = read_cert
-      return cert
-    end
-
-    begin
-      cert, cacert = @driver.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
-
-    begin
-      @cert = OpenSSL::X509::Certificate.new(cert)
-      @cacert = OpenSSL::X509::Certificate.new(cacert)
-    rescue => detail
-      raise InvalidCertificate.new(
-        "Invalid certificate: #{detail}"
-      )
-    end
-
-    unless @cert.check_private_key(key)
-      raise InvalidCertificate, "Certificate does not match private key.  Try 'puppetca --clean #{Puppet[:certname]}' on the server."
-    end
-
-    # Only write the cert out if it passes validating.
-    Puppet.settings.write(:hostcert) do |f| f.print cert end
-    Puppet.settings.write(:localcacert) do |f| f.print cacert end
-
-    @cert
-  end
-end
-
Index: puppet-2.6.4/lib/puppet/network/client/file.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/file.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-class Puppet::Network::Client::File < Puppet::Network::Client::ProxyClient
-  @handler = Puppet::Network::Handler.handler(:fileserver)
-  @drivername = :FileServer
-  self.mkmethods
-end
-
Index: puppet-2.6.4/lib/puppet/network/client/proxy.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/proxy.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-# unlike the other client classes (again, this design sucks) this class
-# is basically just a proxy class -- it calls its methods on the driver
-# and that's about it
-class Puppet::Network::Client::ProxyClient < Puppet::Network::Client
-  def self.mkmethods
-    interface = self.handler.interface
-    namespace = interface.prefix
-
-
-    interface.methods.each { |ary|
-      method = ary[0]
-      Puppet.debug "#{self}: defining #{namespace}.#{method}"
-      define_method(method) { |*args|
-        begin
-          @driver.send(method, *args)
-        rescue XMLRPC::FaultException => detail
-          #Puppet.err "Could not call %s.%s: %s" %
-          #    [namespace, method, detail.faultString]
-          #raise NetworkClientError,
-          #    "XMLRPC Error: #{detail.faultString}"
-          raise NetworkClientError, detail.faultString
-        end
-      }
-    }
-  end
-end
-
Index: puppet-2.6.4/lib/puppet/network/client/report.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/report.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-class Puppet::Network::Client::Report < Puppet::Network::Client
-  @handler = Puppet::Network::Handler.handler(:report)
-
-  def initialize(hash = {})
-    hash[:Report] = self.class.handler.new if hash.include?(:Report)
-
-    super(hash)
-  end
-
-  # Send our report.  We get the transaction report and convert it to YAML
-  # as appropriate.
-  def report(transreport)
-    report = YAML.dump(transreport)
-
-    report = CGI.escape(report) unless self.local
-
-    # Now send the report
-    file = nil
-    benchmark(:info, "Sent transaction report") do
-      file = @driver.report(report)
-    end
-
-    file
-  end
-end
-
Index: puppet-2.6.4/lib/puppet/network/client/runner.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/runner.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-class Puppet::Network::Client::Runner < Puppet::Network::Client::ProxyClient
-  self.mkmethods
-
-  def initialize(hash = {})
-    hash[:Runner] = self.class.handler.new if hash.include?(:Runner)
-
-    super(hash)
-  end
-end
-
Index: puppet-2.6.4/lib/puppet/network/client/status.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client/status.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-class Puppet::Network::Client::Status < Puppet::Network::Client::ProxyClient
-  self.mkmethods
-end
-
Index: puppet-2.6.4/lib/puppet/network/client.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/client.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,179 +0,0 @@
-# the available clients
-
-require 'puppet'
-require 'puppet/network/xmlrpc/client'
-require 'puppet/util/subclass_loader'
-require 'puppet/util/methodhelper'
-require 'puppet/sslcertificates/support'
-
-require 'puppet/network/handler'
-
-require 'net/http'
-
-# Some versions of ruby don't have this method defined, which basically causes
-# us to never use ssl.  Yay.
-class Net::HTTP
-  def use_ssl?
-    if defined?(@use_ssl)
-      @use_ssl
-    else
-      false
-    end
-  end
-
-  # JJM: This is a "backport" of sorts to older ruby versions which
-  # do not have this accessor.  See #896 for more information.
-  attr_accessor :enable_post_connection_check unless Net::HTTP.instance_methods.include? "enable_post_connection_check"
-end
-
-# The base class for all of the clients.  Many clients just directly
-# call methods, but some of them need to do some extra work or
-# provide a different interface.
-class Puppet::Network::Client
-  Client = self
-  include Puppet::Util
-  extend Puppet::Util::SubclassLoader
-  include Puppet::Util::MethodHelper
-
-  # This handles reading in the key and such-like.
-  include Puppet::SSLCertificates::Support
-
-  attr_accessor :schedule, :lastrun, :local, :stopping
-
-  attr_reader :driver
-
-  # Set up subclass loading
-  handle_subclasses :client, "puppet/network/client"
-
-  # Determine what clients look for when being passed an object for local
-  # client/server stuff.  E.g., you could call Client::CA.new(:CA => ca).
-  def self.drivername
-    @drivername ||= self.name
-  end
-
-  # Figure out the handler for our client.
-  def self.handler
-    @handler ||= Puppet::Network::Handler.handler(self.name)
-  end
-
-  # The class that handles xmlrpc interaction for us.
-  def self.xmlrpc_client
-    @xmlrpc_client ||= Puppet::Network::XMLRPCClient.handler_class(self.handler)
-  end
-
-  # Create our client.
-  def initialize(hash)
-    # to whom do we connect?
-    @server = nil
-
-    if hash.include?(:Cache)
-      @cache = hash[:Cache]
-    else
-      @cache = true
-    end
-
-    driverparam = self.class.drivername
-    if hash.include?(:Server)
-      args = {:Server => hash[:Server]}
-      @server = hash[:Server]
-      args[:Port] = hash[:Port] || Puppet[:masterport]
-
-      @driver = self.class.xmlrpc_client.new(args)
-
-      self.read_cert
-
-      # We have to start the HTTP connection manually before we start
-      # sending it requests or keep-alive won't work.  Note that with #1010,
-      # we don't currently actually want keep-alive.
-      @driver.start if @driver.respond_to? :start and Puppet::Network::HttpPool.keep_alive?
-
-      @local = false
-    elsif hash.include?(driverparam)
-      @driver = hash[driverparam]
-      if @driver == true
-        @driver = self.class.handler.new
-      end
-      @local = true
-    else
-      raise Puppet::Network::ClientError, "#{self.class} must be passed a Server or #{driverparam}"
-    end
-  end
-
-  # Are we a local client?
-  def local?
-    if @local
-      true
-    else
-      false
-    end
-  end
-
-  # Make sure we set the driver up when we read the cert in.
-  def recycle_connection
-    @driver.recycle_connection if @driver.respond_to?(:recycle_connection)
-  end
-
-  # A wrapper method to run and then store the last run time
-  def runnow
-    if self.stopping
-      Puppet.notice "In shutdown progress; skipping run"
-      return
-    end
-    begin
-      self.run
-      self.lastrun = Time.now.to_i
-    rescue => detail
-      puts detail.backtrace if Puppet[:trace]
-      Puppet.err "Could not run #{self.class}: #{detail}"
-    end
-  end
-
-  def run
-    raise Puppet::DevError, "Client type #{self.class} did not override run"
-  end
-
-  def scheduled?
-    if sched = self.schedule
-      return sched.match?(self.lastrun)
-    else
-      return true
-    end
-  end
-
-  def shutdown
-    if self.stopping
-      Puppet.notice "Already in shutdown"
-    else
-      self.stopping = true
-      Puppet::Util::Storage.store if self.respond_to? :running? and self.running?
-      rmpidfile
-    end
-  end
-
-  # Start listening for events.  We're pretty much just listening for
-  # timer events here.
-  def start
-    # Create our timer.  Puppet will handle observing it and such.
-
-          timer = Puppet.newtimer(
-                
-      :interval => Puppet[:runinterval],
-      :tolerance => 1,
-        
-      :start? => true
-    ) do
-      begin
-        self.runnow if self.scheduled?
-      rescue => detail
-        puts detail.backtrace if Puppet[:trace]
-        Puppet.err "Could not run client; got otherwise uncaught exception: #{detail}"
-      end
-    end
-
-    # Run once before we start following the timer
-    self.runnow
-  end
-
-  require 'puppet/network/client/proxy'
-end
-
Index: puppet-2.6.4/lib/puppet/network/handler/ca.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/handler/ca.rb	2010-12-01 00:42:01.000000000 +0100
+++ puppet-2.6.4/lib/puppet/network/handler/ca.rb	2011-11-01 10:51:35.084524399 +0100
@@ -1,10 +1,7 @@
 require 'openssl'
 require 'puppet'
-require 'puppet/sslcertificates'
 require 'xmlrpc/server'
-
-# Much of this was taken from QuickCert:
-#   http://segment7.net/projects/ruby/QuickCert/
+require 'puppet/network/handler'
 
 class Puppet::Network::Handler
   class CA < Handler
@@ -18,73 +15,17 @@
       iface.add_method("array getcert(csr)")
     }
 
-    def autosign
-      if defined?(@autosign)
-        @autosign
-      else
-        Puppet[:autosign]
-      end
-    end
-
-    # FIXME autosign? should probably accept both hostnames and IP addresses
-    def autosign?(hostname)
-      # simple values are easy
-      if autosign == true or autosign == false
-        return autosign
-      end
-
-      # we only otherwise know how to handle files
-      unless autosign =~ /^\//
-        raise Puppet::Error, "Invalid autosign value #{autosign.inspect}"
-      end
-
-      unless FileTest.exists?(autosign)
-        unless defined?(@@warnedonautosign)
-          @@warnedonautosign = true
-          Puppet.info "Autosign is enabled but #{autosign} is missing"
-        end
-        return false
-      end
-      auth = Puppet::Network::AuthStore.new
-      File.open(autosign) { |f|
-        f.each { |line|
-          next if line =~ /^\s*#/
-          next if line =~ /^\s*$/
-          auth.allow(line.chomp)
-        }
-      }
-
-      # for now, just cheat and pass a fake IP address to allowed?
-      auth.allowed?(hostname, "127.1.1.1")
-    end
-
     def initialize(hash = {})
       Puppet.settings.use(:main, :ssl, :ca)
-      @autosign = hash[:autosign] if hash.include? :autosign
 
-      @ca = Puppet::SSLCertificates::CA.new(hash)
+      @ca = Puppet::SSL::CertificateAuthority.instance
     end
 
     # our client sends us a csr, and we either store it for later signing,
     # or we sign it right away
     def getcert(csrtext, client = nil, clientip = nil)
-      csr = OpenSSL::X509::Request.new(csrtext)
-
-      # Use the hostname from the CSR, not from the network.
-      subject = csr.subject
-
-      nameary = subject.to_a.find { |ary|
-        ary[0] == "CN"
-      }
-
-      if nameary.nil?
-        Puppet.err(
-          "Invalid certificate request: could not retrieve server name"
-        )
-        return "invalid"
-      end
-
-      hostname = nameary[1]
+      csr = Puppet::SSL::CertificateRequest.from_s(csrtext)
+      hostname = csr.name
 
       unless @ca
         Puppet.notice "Host #{hostname} asked for signing from non-CA master"
@@ -93,57 +34,26 @@
 
       # We used to save the public key, but it's basically unnecessary
       # and it mucks with the permissions requirements.
-      # save_pk(hostname, csr.public_key)
-
-      certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
 
       # first check to see if we already have a signed cert for the host
-      cert, cacert = ca.getclientcert(hostname)
-      if cert and cacert
+      cert = Puppet::SSL::Certificate.find(hostname)
+      cacert = Puppet::SSL::Certificate.find(@ca.host.name)
+
+      if cert
         Puppet.info "Retrieving existing certificate for #{hostname}"
-        unless csr.public_key.to_s == cert.public_key.to_s
+        unless csr.content.public_key.to_s == cert.content.public_key.to_s
           raise Puppet::Error, "Certificate request does not match existing certificate; run 'puppetca --clean #{hostname}'."
         end
-        return [cert.to_pem, cacert.to_pem]
-      elsif @ca
-        if self.autosign?(hostname) or client.nil?
-          Puppet.info "Signing certificate for CA server" if client.nil?
-          # okay, we don't have a signed cert
-          # if we're a CA and autosign is turned on, then go ahead and sign
-          # the csr and return the results
-          Puppet.info "Signing certificate for #{hostname}"
-          cert, cacert = @ca.sign(csr)
-          #Puppet.info "Cert: #{cert.class}; Cacert: #{cacert.class}"
-          return [cert.to_pem, cacert.to_pem]
-        else # just write out the csr for later signing
-          if @ca.getclientcsr(hostname)
-            Puppet.info "Not replacing existing request from #{hostname}"
-          else
-            Puppet.notice "Host #{hostname} has a waiting certificate request"
-            @ca.storeclientcsr(csr)
-          end
-          return ["", ""]
-        end
+        [cert.to_s, cacert.to_s]
       else
-        raise "huh?"
-      end
-    end
-
-    private
+        csr.save
 
-    # Save the public key.
-    def save_pk(hostname, public_key)
-      pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.'))
-
-      if FileTest.exists?(pkeyfile)
-        currentkey = File.open(pkeyfile) { |k| k.read }
-        unless currentkey == public_key.to_s
-          raise Puppet::Error, "public keys for #{hostname} differ"
+        # We determine whether we signed the csr by checking if there's a certificate for it
+        if cert = Puppet::SSL::Certificate.find(hostname)
+          [cert.to_s, cacert.to_s]
+        else
+          nil
         end
-      else
-        File.open(pkeyfile, "w", 0644) { |f|
-          f.print public_key.to_s
-        }
       end
     end
   end
Index: puppet-2.6.4/lib/puppet/network/handler/master.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/handler/master.rb	2010-12-01 00:42:01.000000000 +0100
+++ puppet-2.6.4/lib/puppet/network/handler/master.rb	2011-11-01 10:51:35.084524399 +0100
@@ -1,6 +1,5 @@
 require 'openssl'
 require 'puppet'
-require 'puppet/sslcertificates'
 require 'xmlrpc/server'
 require 'yaml'
 
@@ -33,8 +32,6 @@
 
       args[:Local] = true
 
-      @ca = (hash.include?(:CA) and hash[:CA]) ? Puppet::SSLCertificates::CA.new : nil
-
       # This is only used by the cfengine module, or if --loadclasses was
       # specified in +puppet+.
       args[:Classes] = hash[:Classes] if hash.include?(:Classes)
Index: puppet-2.6.4/lib/puppet/network/handler/runner.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/handler/runner.rb	2010-12-01 00:42:01.000000000 +0100
+++ puppet-2.6.4/lib/puppet/network/handler/runner.rb	2011-11-01 10:51:35.085524429 +0100
@@ -1,4 +1,5 @@
 require 'puppet/run'
+require 'puppet/network/handler'
 
 class Puppet::Network::Handler
   class MissingMasterError < RuntimeError; end # Cannot find the master client
Index: puppet-2.6.4/lib/puppet/network/http_server/webrick.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/http_server/webrick.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,155 +0,0 @@
-require 'puppet'
-require 'webrick'
-require 'webrick/https'
-require 'fcntl'
-
-require 'puppet/sslcertificates/support'
-require 'puppet/network/xmlrpc/webrick_servlet'
-require 'puppet/network/http_server'
-require 'puppet/network/client'
-require 'puppet/network/handler'
-
-module Puppet
-  class ServerError < RuntimeError; end
-  module Network
-    # The old-school, pure ruby webrick server, which is the default serving
-    # mechanism.
-    class HTTPServer::WEBrick < WEBrick::HTTPServer
-      include Puppet::SSLCertificates::Support
-
-      # Read the CA cert and CRL and populate an OpenSSL::X509::Store
-      # with them, with flags appropriate for checking client
-      # certificates for revocation
-      def x509store
-        unless File.exist?(Puppet[:cacrl])
-          # No CRL, no store needed
-          return nil
-        end
-        crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
-        store = OpenSSL::X509::Store.new
-        store.purpose = OpenSSL::X509::PURPOSE_ANY
-        store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
-        raise Puppet::Error, "Could not find CA certificate" unless self.ca_cert
-
-        store.add_file(Puppet[:localcacert])
-        store.add_crl(crl)
-        store
-      end
-
-      # Set up the http log.
-      def httplog
-        args = []
-
-        # yuck; separate http logs
-        file = nil
-        Puppet.settings.use(:main, :ssl, Puppet[:name])
-        if Puppet.run_mode.master?
-          file = Puppet[:masterhttplog]
-        else
-          file = Puppet[:httplog]
-        end
-
-        # open the log manually to prevent file descriptor leak
-        file_io = open(file, "a+")
-        file_io.sync
-        file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
-        args << file_io
-        args << WEBrick::Log::DEBUG if Puppet[:debug]
-
-        log = WEBrick::Log.new(*args)
-
-
-        log
-      end
-
-      # Create our server, yo.
-      def initialize(hash = {})
-        Puppet.info "Starting server for Puppet version #{Puppet.version}"
-
-        if handlers = hash[:Handlers]
-          handler_instances = setup_handlers(handlers)
-        else
-          raise ServerError, "A server must have handlers"
-        end
-
-        unless self.read_cert
-          if ca = handler_instances.find { |handler| handler.is_a?(Puppet::Network::Handler.ca) }
-            request_cert(ca)
-          else
-            raise Puppet::Error, "No certificate and no CA; cannot get cert"
-          end
-        end
-
-        setup_webrick(hash)
-
-        begin
-          super(hash)
-        rescue => detail
-          puts detail.backtrace if Puppet[:trace]
-          raise Puppet::Error, "Could not start WEBrick: #{detail}"
-        end
-
-        # make sure children don't inherit the sockets
-        listeners.each { |sock|
-          sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-        }
-
-        Puppet.info "Listening on port #{hash[:Port]}"
-
-        # this creates a new servlet for every connection,
-        # but all servlets have the same list of handlers
-        # thus, the servlets can have their own state -- passing
-        # around the requests and such -- but the handlers
-        # have a global state
-
-        # mount has to be called after the server is initialized
-        servlet = Puppet::Network::XMLRPC::WEBrickServlet.new( handler_instances)
-        self.mount("/RPC2", servlet)
-      end
-
-      # Create a ca client to set up our cert for us.
-      def request_cert(ca)
-        client = Puppet::Network::Client.ca.new(:CA => ca)
-        raise Puppet::Error, "Could get certificate" unless client.request_cert
-      end
-
-      # Create all of our handler instances.
-      def setup_handlers(handlers)
-        raise ServerError, "Handlers must have arguments" unless handlers.is_a?(Hash)
-
-        handlers.collect { |handler, args|
-          hclass = nil
-          unless hclass = Puppet::Network::Handler.handler(handler)
-            raise ServerError, "Invalid handler #{handler}"
-          end
-          hclass.new(args)
-        }
-      end
-
-      # Handle all of the many webrick arguments.
-      def setup_webrick(hash)
-        hash[:Port] ||= Puppet[:masterport]
-        hash[:Logger] ||= self.httplog
-        hash[:AccessLog] ||= [
-          [ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
-          [ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
-        ]
-
-        hash[:SSLCertificateStore] = x509store
-        hash[:SSLCertificate] = self.cert
-        hash[:SSLPrivateKey] = self.key
-        hash[:SSLStartImmediately] = true
-        hash[:SSLEnable] = true
-        hash[:SSLCACertificateFile] = Puppet[:localcacert]
-        hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
-        hash[:SSLCertName] = nil
-
-        if addr = Puppet[:bindaddress] and addr != ""
-          hash[:BindAddress] = addr
-        end
-      end
-    end
-  end
-end
-
Index: puppet-2.6.4/lib/puppet/network/xmlrpc/client.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/network/xmlrpc/client.rb	2010-12-01 00:42:01.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,211 +0,0 @@
-require 'puppet/sslcertificates'
-require 'puppet/network/http_pool'
-require 'openssl'
-require 'puppet/external/base64'
-
-require 'xmlrpc/client'
-require 'net/https'
-require 'yaml'
-
-module Puppet::Network
-  class ClientError < Puppet::Error; end
-  class XMLRPCClientError < Puppet::Error; end
-  class XMLRPCClient < ::XMLRPC::Client
-
-    attr_accessor :puppet_server, :puppet_port
-    @clients = {}
-
-    class << self
-      include Puppet::Util
-      include Puppet::Util::ClassGen
-    end
-
-    # Create a netclient for each handler
-    def self.mkclient(handler)
-      interface = handler.interface
-      namespace = interface.prefix
-
-      # Create a subclass for every client type.  This is
-      # so that all of the methods are on their own class,
-      # so that their namespaces can define the same methods if
-      # they want.
-      constant = handler.name.to_s.capitalize
-      name = namespace.downcase
-      newclient = genclass(name, :hash => @clients, :constant => constant)
-
-      interface.methods.each { |ary|
-        method = ary[0]
-        newclient.send(:define_method,method) { |*args|
-          make_rpc_call(namespace, method, *args)
-        }
-      }
-
-      newclient
-    end
-
-    def self.handler_class(handler)
-      @clients[handler] || self.mkclient(handler)
-    end
-
-    class ErrorHandler
-      def initialize(&block)
-        singleton_class.define_method(:execute, &block)
-      end
-    end
-
-    # Use a class variable so all subclasses have access to it.
-    @@error_handlers = {}
-
-    def self.error_handler(exception)
-      if handler = @@error_handlers[exception.class]
-        return handler
-      else
-        return @@error_handlers[:default]
-      end
-    end
-
-    def self.handle_error(*exceptions, &block)
-      handler = ErrorHandler.new(&block)
-
-      exceptions.each do |exception|
-        @@error_handlers[exception] = handler
-      end
-    end
-
-    handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
-      if detail.message =~ /bad write retry/
-        Puppet.warning "Transient SSL write error; restarting connection and retrying"
-        client.recycle_connection
-        return :retry
-      end
-      ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
-        Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
-      end
-      raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
-    end
-
-    handle_error(:default) do |client, detail, namespace, method|
-      if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/
-        Puppet.warning "XMLRPC returned wrong size.  Retrying."
-        return :retry
-      end
-      Puppet.err "Could not call #{namespace}.#{method}: #{detail.inspect}"
-      error = XMLRPCClientError.new(detail.to_s)
-      error.set_backtrace detail.backtrace
-      raise error
-    end
-
-    handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
-      if detail.message =~ /bad write retry/
-        Puppet.warning "Transient SSL write error; restarting connection and retrying"
-        client.recycle_connection
-        return :retry
-      end
-      ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
-        Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
-      end
-      raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
-    end
-
-    handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method|
-      raise XMLRPCClientError, detail.faultString
-    end
-
-    handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method|
-      msg = "Could not connect to #{client.host} on port #{client.port}"
-      raise XMLRPCClientError, msg
-    end
-
-    handle_error(SocketError) do |client, detail, namespace, method|
-      Puppet.err "Could not find server #{@host}: #{detail}"
-      error = XMLRPCClientError.new("Could not find server #{client.host}")
-      error.set_backtrace detail.backtrace
-      raise error
-    end
-
-    handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method|
-      Puppet.info "Other end went away; restarting connection and retrying"
-      client.recycle_connection
-      return :retry
-    end
-
-    handle_error(Timeout::Error) do |client, detail, namespace, method|
-      Puppet.err "Connection timeout calling #{namespace}.#{method}: #{detail}"
-      error = XMLRPCClientError.new("Connection Timeout")
-      error.set_backtrace(detail.backtrace)
-      raise error
-    end
-
-    def make_rpc_call(namespace, method, *args)
-      Puppet.debug "Calling #{namespace}.#{method}"
-      begin
-        call("#{namespace}.#{method}",*args)
-      rescue SystemExit,NoMemoryError
-        raise
-      rescue Exception => detail
-        retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry
-      end
-    ensure
-      http.finish if http.started?
-    end
-
-    def http
-      @http ||= Puppet::Network::HttpPool.http_instance(host, port, true)
-    end
-
-    attr_reader :host, :port
-
-    def initialize(hash = {})
-      hash[:Path] ||= "/RPC2"
-      hash[:Server] ||= Puppet[:server]
-      hash[:Port] ||= Puppet[:masterport]
-      hash[:HTTPProxyHost] ||= Puppet[:http_proxy_host]
-      hash[:HTTPProxyPort] ||= Puppet[:http_proxy_port]
-
-      if "none" == hash[:HTTPProxyHost]
-        hash[:HTTPProxyHost] = nil
-        hash[:HTTPProxyPort] = nil
-      end
-
-
-            super(
-                
-        hash[:Server],
-        hash[:Path],
-        hash[:Port],
-        hash[:HTTPProxyHost],
-        hash[:HTTPProxyPort],
-        
-        nil, # user
-        nil, # password
-        true, # use_ssl
-        Puppet[:configtimeout] # use configured timeout (#1176)
-      )
-      @http = Puppet::Network::HttpPool.http_instance(@host, @port)
-    end
-
-    # Get rid of our existing connection, replacing it with a new one.
-    # This should only happen if we lose our connection somehow (e.g., an EPIPE)
-    # or we've just downloaded certs and we need to create new http instances
-    # with the certs added.
-    def recycle_connection
-      http.finish if http.started?
-      @http = nil
-      self.http # force a new one
-    end
-
-    def start
-        @http.start unless @http.started?
-    rescue => detail
-        Puppet.err "Could not connect to server: #{detail}"
-    end
-
-    def local
-      false
-    end
-
-    def local?
-      false
-    end
-  end
-end
Index: puppet-2.6.4/lib/puppet/ssl/certificate_authority/interface.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/certificate_authority/interface.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/certificate_authority/interface.rb	2011-11-01 10:51:35.086524459 +0100
@@ -9,7 +9,7 @@
 
         class InterfaceError < ArgumentError; end
 
-        attr_reader :method, :subjects, :digest
+        attr_reader :method, :subjects, :digest, :options
 
         # Actually perform the work.
         def apply(ca)
@@ -35,49 +35,94 @@
           raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
 
           subjects.each do |host|
-            ca.generate(host)
+            ca.generate(host, options)
           end
         end
 
         def initialize(method, options)
           self.method = method
-          self.subjects = options[:to]
-          @digest = options[:digest] || :MD5
+          self.subjects = options.delete(:to)
+          @digest = options.delete(:digest) || :MD5
+          @options = options
         end
 
         # List the hosts.
         def list(ca)
-          unless subjects
-            puts ca.waiting?.join("\n")
-            return nil
-          end
-
           signed = ca.list
           requests = ca.waiting?
 
-          if subjects == :all
+          case subjects
+          when :all
             hosts = [signed, requests].flatten
-          elsif subjects == :signed
+          when :signed
             hosts = signed.flatten
+          when nil
+            hosts = requests
           else
             hosts = subjects
           end
 
+          certs = {:signed => {}, :invalid => {}, :request => {}}
+
+          return if hosts.empty?
+
           hosts.uniq.sort.each do |host|
-            invalid = false
             begin
               ca.verify(host) unless requests.include?(host)
             rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
-              invalid = details.to_s
+              verify_error = details.to_s
             end
-            if not invalid and signed.include?(host)
-              puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
-            elsif invalid
-              puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
+
+            if verify_error
+              cert = Puppet::SSL::Certificate.indirection.find(host)
+              certs[:invalid][host] = [cert, verify_error]
+            elsif signed.include?(host)
+              cert = Puppet::SSL::Certificate.indirection.find(host)
+              certs[:signed][host] = cert
             else
-              puts "#{host} (#{ca.fingerprint(host, @digest)})"
+              req = Puppet::SSL::CertificateRequest.indirection.find(host)
+              certs[:request][host] = req
             end
           end
+
+          names = certs.values.map(&:keys).flatten
+
+          name_width = names.sort_by(&:length).last.length rescue 0
+
+          output = [:request, :signed, :invalid].map do |type|
+            next if certs[type].empty?
+
+            certs[type].map do |host,info|
+              format_host(ca, host, type, info, name_width)
+            end
+          end.flatten.compact.sort.join("\n")
+
+          puts output
+        end
+
+        def format_host(ca, host, type, info, width)
+          certish, verify_error = info
+          alt_names = case type
+                      when :signed
+                        certish.subject_alt_names
+                      when :request
+                        certish.subject_alt_names
+                      else
+                        []
+                      end
+
+          alt_names.delete(host)
+
+          alt_str = "(alt names: #{alt_names.join(', ')})" unless alt_names.empty?
+
+          glyph = {:signed => '+', :request => ' ', :invalid => '-'}[type]
+
+          name = host.ljust(width)
+          fingerprint = "(#{ca.fingerprint(host, @digest)})"
+
+          explanation = "(#{verify_error})" if verify_error
+
+          [glyph, name, fingerprint, alt_str, explanation].compact.join(' ')
         end
 
         # Set the method to apply.
@@ -113,7 +158,7 @@
           list = subjects == :all ? ca.waiting? : subjects
           raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
           list.each do |host|
-            ca.sign(host)
+            ca.sign(host, options[:allow_dns_alt_names])
           end
         end
 
Index: puppet-2.6.4/lib/puppet/ssl/certificate_authority.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/certificate_authority.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/certificate_authority.rb	2011-11-01 10:51:35.086524459 +0100
@@ -11,6 +11,15 @@
 # it can also be seen as a general interface into all of the
 # SSL stuff.
 class Puppet::SSL::CertificateAuthority
+  # We will only sign extensions on this whitelist, ever.  Any CSR with a
+  # requested extension that we don't recognize is rejected, against the risk
+  # that it will introduce some security issue through our ignorance of it.
+  #
+  # Adding an extension to this whitelist simply means we will consider it
+  # further, not that we will always accept a certificate with an extension
+  # requested on this list.
+  RequestExtensionWhitelist = %w{subjectAltName}
+
   require 'puppet/ssl/certificate_factory'
   require 'puppet/ssl/inventory'
   require 'puppet/ssl/certificate_revocation_list'
@@ -25,6 +34,14 @@
     end
   end
 
+  class CertificateSigningError < RuntimeError
+    attr_accessor :host
+
+    def initialize(host)
+      @host = host
+    end
+  end
+
   class << self
     include Puppet::Util::Cacher
 
@@ -52,7 +69,6 @@
   def apply(method, options)
     raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all" unless options[:to]
     applier = Interface.new(method, options)
-
     applier.apply(self)
   end
 
@@ -108,13 +124,15 @@
   end
 
   # Generate a new certificate.
-  def generate(name)
+  def generate(name, options = {})
     raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.find(name)
-    host = Puppet::SSL::Host.new(name)
 
-    host.generate_certificate_request
+    # Pass on any requested subjectAltName field.
+    san = options[:dns_alt_names]
 
-    sign(name)
+    host = Puppet::SSL::Host.new(name)
+    host.generate_certificate_request(:dns_alt_names => san)
+    sign(name, !!san)
   end
 
   # Generate our CA certificate.
@@ -123,14 +141,16 @@
 
     host.generate_key unless host.key
 
-    # Create a new cert request.  We do this
-    # specially, because we don't want to actually
-    # save the request anywhere.
+    # Create a new cert request.  We do this specially, because we don't want
+    # to actually save the request anywhere.
     request = Puppet::SSL::CertificateRequest.new(host.name)
+
+    # We deliberately do not put any subjectAltName in here: the CA
+    # certificate absolutely does not need them. --daniel 2011-10-13
     request.generate(host.key)
 
     # Create a self-signed certificate.
-    @certificate = sign(host.name, :ca, request)
+    @certificate = sign(host.name, false, request)
 
     # And make sure we initialize our CRL.
     crl
@@ -223,20 +243,34 @@
   end
 
   # Sign a given certificate request.
-  def sign(hostname, cert_type = :server, self_signing_csr = nil)
+  def sign(hostname, allow_dns_alt_names = false, self_signing_csr = nil)
     # This is a self-signed certificate
     if self_signing_csr
+      # # This is a self-signed certificate, which is for the CA.  Since this
+      # # forces the certificate to be self-signed, anyone who manages to trick
+      # # the system into going through this path gets a certificate they could
+      # # generate anyway.  There should be no security risk from that.
       csr = self_signing_csr
+      cert_type = :ca
       issuer = csr.content
     else
+      allow_dns_alt_names = true if hostname == Puppet[:certname].downcase
       unless csr = Puppet::SSL::CertificateRequest.find(hostname)
         raise ArgumentError, "Could not find certificate request for #{hostname}"
       end
+
+      cert_type = :server
       issuer = host.certificate.content
+
+      # Make sure that the CSR conforms to our internal signing policies.
+      # This will raise if the CSR doesn't conform, but just in case...
+      check_internal_signing_policies(hostname, csr, allow_dns_alt_names) or
+        raise CertificateSigningError.new(hostname), "CSR had an unknown failure checking internal signing policies, will not sign!"
     end
 
     cert = Puppet::SSL::Certificate.new(hostname)
-    cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result
+    cert.content = Puppet::SSL::CertificateFactory.
+      build(cert_type, csr, issuer, next_serial)
     cert.content.sign(host.key.content, OpenSSL::Digest::SHA1.new)
 
     Puppet.notice "Signed certificate request for #{hostname}"
@@ -256,6 +290,47 @@
     cert
   end
 
+  def check_internal_signing_policies(hostname, csr, allow_dns_alt_names)
+    # Reject unknown request extensions.
+    unknown_req = csr.request_extensions.
+      reject {|x| RequestExtensionWhitelist.include? x["oid"] }
+
+    if unknown_req and unknown_req.count > 0
+      names = unknown_req.map {|x| x["oid"] }.sort.uniq.join(", ")
+      raise CertificateSigningError.new(hostname), "CSR has request extensions that are not permitted: #{names}"
+    end
+
+    # Wildcards: we don't allow 'em at any point.
+    #
+    # The stringification here makes the content visible, and saves us having
+    # to scrobble through the content of the CSR subject field to make sure it
+    # is what we expect where we expect it.
+    if csr.content.subject.to_s.include? '*'
+      raise CertificateSigningError.new(hostname), "CSR subject contains a wildcard, which is not allowed: #{csr.content.subject.to_s}"
+    end
+
+    unless csr.subject_alt_names.empty?
+      # If you alt names are allowed, they are required. Otherwise they are
+      # disallowed. Self-signed certs are implicitly trusted, however.
+      unless allow_dns_alt_names
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains subject alternative names (#{csr.subject_alt_names.join(', ')}), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{csr.name}` to sign this request."
+      end
+
+      # If subjectAltNames are present, validate that they are only for DNS
+      # labels, not any other kind.
+      unless csr.subject_alt_names.all? {|x| x =~ /^DNS:/ }
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains a subjectAltName outside the DNS label space: #{csr.subject_alt_names.join(', ')}.  To continue, this CSR needs to be cleaned."
+      end
+
+      # Check for wildcards in the subjectAltName fields too.
+      if csr.subject_alt_names.any? {|x| x.include? '*' }
+        raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' subjectAltName contains a wildcard, which is not allowed: #{csr.subject_alt_names.join(', ')}  To continue, this CSR needs to be cleaned."
+      end
+    end
+
+    return true                 # good enough for us!
+  end
+
   # Verify a given host's certificate.
   def verify(name)
     unless cert = Puppet::SSL::Certificate.find(name)
Index: puppet-2.6.4/lib/puppet/ssl/certificate_factory.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/certificate_factory.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/certificate_factory.rb	2011-11-01 10:51:35.087524489 +0100
@@ -2,7 +2,7 @@
 
 # The tedious class that does all the manipulations to the
 # certificate to correctly sign it.  Yay.
-class Puppet::SSL::CertificateFactory
+module Puppet::SSL::CertificateFactory
   # How we convert from various units to the required seconds.
   UNITMAP = {
     "y" => 365 * 24 * 60 * 60,
@@ -11,75 +11,84 @@
     "s" => 1
   }
 
-  attr_reader :name, :cert_type, :csr, :issuer, :serial
+  def self.build(cert_type, csr, issuer, serial)
+    # Work out if we can even build the requested type of certificate.
+    build_extensions = "build_#{cert_type.to_s}_extensions"
+    respond_to?(build_extensions) or
+      raise ArgumentError, "#{cert_type.to_s} is an invalid certificate type!"
+
+    # set up the certificate, and start building the content.
+    cert = OpenSSL::X509::Certificate.new
+
+    cert.version    = 2 # X509v3
+    cert.subject    = csr.content.subject
+    cert.issuer     = issuer.subject
+    cert.public_key = csr.content.public_key
+    cert.serial     = serial
+
+    # Make the certificate valid as of yesterday, because so many people's
+    # clocks are out of sync.  This gives one more day of validity than people
+    # might expect, but is better than making every person who has a messed up
+    # clock fail, and better than having every cert we generate expire a day
+    # before the user expected it to when they asked for "one year".
+    cert.not_before = Time.now - (60*60*24)
+    cert.not_after  = Time.now + ttl
 
-  def initialize(cert_type, csr, issuer, serial)
-    @cert_type, @csr, @issuer, @serial = cert_type, csr, issuer, serial
+    add_extensions_to(cert, csr, issuer, send(build_extensions))
 
-    @name = @csr.subject
-  end
-
-  # Actually generate our certificate.
-  def result
-    @cert = OpenSSL::X509::Certificate.new
-
-    @cert.version = 2 # X509v3
-    @cert.subject = @csr.subject
-    @cert.issuer = @issuer.subject
-    @cert.public_key = @csr.public_key
-    @cert.serial = @serial
-
-    build_extensions
-
-    set_ttl
-
-    @cert
+    return cert
   end
 
   private
 
-  # This is pretty ugly, but I'm not really sure it's even possible to do
-  # it any other way.
-  def build_extensions
-    @ef = OpenSSL::X509::ExtensionFactory.new
-
-    @ef.subject_certificate = @cert
-
-    if @issuer.is_a?(OpenSSL::X509::Request) # It's a self-signed cert
-      @ef.issuer_certificate = @cert
-    else
-      @ef.issuer_certificate = @issuer
+  def self.add_extensions_to(cert, csr, issuer, extensions)
+    ef = OpenSSL::X509::ExtensionFactory.
+      new(cert, issuer.is_a?(OpenSSL::X509::Request) ? cert : issuer)
+
+    # Extract the requested extensions from the CSR.
+    requested_exts = csr.request_extensions.inject({}) do |hash, re|
+      hash[re["oid"]] = [re["value"], re["critical"]]
+      hash
     end
 
-    @subject_alt_name = []
-    @key_usage = nil
-    @ext_key_usage = nil
-    @extensions = []
-
-    method = "add_#{@cert_type.to_s}_extensions"
-
-    begin
-      send(method)
-    rescue NoMethodError
-      raise ArgumentError, "#{@cert_type} is an invalid certificate type"
+    # Produce our final set of extensions.  We deliberately order these to
+    # build the way we want:
+    # 1. "safe" default values, like the comment, that no one cares about.
+    # 2. request extensions, from the CSR
+    # 3. extensions based on the type we are generating
+    # 4. overrides, which we always want to have in their form
+    #
+    # This ordering *is* security-critical, but we want to allow the user
+    # enough rope to shoot themselves in the foot, if they want to ignore our
+    # advice and externally approve a CSR that sets the basicConstraints.
+    #
+    # Swapping the order of 2 and 3 would ensure that you couldn't slip a
+    # certificate through where the CA constraint was true, though, if
+    # something went wrong up there. --daniel 2011-10-11
+    defaults = { "nsComment" => "Puppet Ruby/OpenSSL Internal Certificate" }
+    override = { "subjectKeyIdentifier" => "hash" }
+
+    exts = [defaults, requested_exts, extensions, override].
+      inject({}) {|ret, val| ret.merge(val) }
+
+    cert.extensions = exts.map do |oid, val|
+      val, crit = *val
+      val       = val.join(', ') unless val.is_a? String
+
+      # Enforce the X509v3 rules about subjectAltName being critical:
+      # specifically, it SHOULD NOT be critical if we have a subject, which we
+      # always do. --daniel 2011-10-18
+      crit = false if oid == "subjectAltName"
+
+      # val can be either a string, or [string, critical], and this does the
+      # right thing regardless of what we get passed.
+      ef.create_ext(oid, val, crit)
     end
-
-    @extensions << @ef.create_extension("nsComment", "Puppet Ruby/OpenSSL Generated Certificate")
-    @extensions << @ef.create_extension("basicConstraints", @basic_constraint, true)
-    @extensions << @ef.create_extension("subjectKeyIdentifier", "hash")
-    @extensions << @ef.create_extension("keyUsage", @key_usage.join(",")) if @key_usage
-    @extensions << @ef.create_extension("extendedKeyUsage", @ext_key_usage.join(",")) if @ext_key_usage
-    @extensions << @ef.create_extension("subjectAltName", @subject_alt_name.join(",")) if ! @subject_alt_name.empty?
-
-    @cert.extensions = @extensions
-
-    # for some reason this _must_ be the last extension added
-    @extensions << @ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if @cert_type == :ca
   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
+  def self.ttl
     ttl = Puppet.settings[:ca_ttl]
 
     return ttl unless ttl.is_a?(String)
@@ -89,57 +98,69 @@
     $1.to_i * UNITMAP[$2]
   end
 
-  def set_ttl
-    # Make the certificate valid as of yesterday, because
-    # so many people's clocks are out of sync.
-    from = Time.now - (60*60*24)
-    @cert.not_before = from
-    @cert.not_after = from + ttl
-  end
-
   # Woot! We're a CA.
-  def add_ca_extensions
-    @basic_constraint = "CA:TRUE"
-    @key_usage = %w{cRLSign keyCertSign}
+  def self.build_ca_extensions
+    {
+      # This was accidentally omitted in the previous version of this code: an
+      # effort was made to add it last, but that actually managed to avoid
+      # adding it to the certificate at all.
+      #
+      # We have some sort of bug, which means that when we add it we get a
+      # complaint that the issuer keyid can't be fetched, which breaks all
+      # sorts of things in our test suite and, e.g., bootstrapping the CA.
+      #
+      # http://tools.ietf.org/html/rfc5280#section-4.2.1.1 says that, to be a
+      # conforming CA we MAY omit the field if we are self-signed, which I
+      # think gives us a pass in the specific case.
+      #
+      # It also notes that we MAY derive the ID from the subject and serial
+      # number of the issuer, or from the key ID, and we definitely have the
+      # former data, should we want to restore this...
+      #
+      # Anyway, preserving this bug means we don't risk breaking anything in
+      # the field, even though it would be nice to have. --daniel 2011-10-11
+      #
+      # "authorityKeyIdentifier" => "keyid:always,issuer:always",
+      "keyUsage"               => [%w{cRLSign keyCertSign}, true],
+      "basicConstraints"       => ["CA:TRUE", true],
+    }
   end
 
   # We're a terminal CA, probably not self-signed.
-  def add_terminalsubca_extensions
-    @basic_constraint = "CA:TRUE,pathlen:0"
-    @key_usage = %w{cRLSign keyCertSign}
+  def self.build_terminalsubca_extensions
+    {
+      "keyUsage"         => [%w{cRLSign keyCertSign}, true],
+      "basicConstraints" => ["CA:TRUE,pathlen:0", true],
+    }
   end
 
   # We're a normal server.
-  def add_server_extensions
-    @basic_constraint = "CA:FALSE"
-    dnsnames = Puppet[:certdnsnames]
-    name = @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}
+  def self.build_server_extensions
+    {
+      "keyUsage"         => [%w{digitalSignature keyEncipherment}, true],
+      "extendedKeyUsage" => [%w{serverAuth clientAuth}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+    }
   end
 
   # Um, no idea.
-  def add_ocsp_extensions
-    @basic_constraint = "CA:FALSE"
-    @key_usage = %w{nonRepudiation digitalSignature}
-    @ext_key_usage = %w{serverAuth OCSPSigning}
+  def self.build_ocsp_extensions
+    {
+      "keyUsage"         => [%w{nonRepudiation digitalSignature}, true],
+      "extendedKeyUsage" => [%w{serverAuth OCSPSigning}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+    }
   end
 
   # Normal client.
-  def add_client_extensions
-    @basic_constraint = "CA:FALSE"
-    @key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
-    @ext_key_usage = %w{clientAuth emailProtection}
-
-    @extensions << @ef.create_extension("nsCertType", "client,email")
+  def self.build_client_extensions
+    {
+      "keyUsage"         => [%w{nonRepudiation digitalSignature keyEncipherment}, true],
+      # We don't seem to use this, but that seems much more reasonable here...
+      "extendedKeyUsage" => [%w{clientAuth emailProtection}, true],
+      "basicConstraints" => ["CA:FALSE", true],
+      "nsCertType"       => "client,email",
+    }
   end
 end
 
Index: puppet-2.6.4/lib/puppet/ssl/certificate.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/certificate.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/certificate.rb	2011-11-01 10:51:35.087524489 +0100
@@ -27,6 +27,12 @@
     [:s]
   end
 
+  def subject_alt_names
+    alts = content.extensions.find{|ext| ext.oid == "subjectAltName"}
+    return [] unless alts
+    alts.value.split(/\s*,\s*/)
+  end
+
   def expiration
     return nil unless content
     content.not_after
Index: puppet-2.6.4/lib/puppet/ssl/certificate_request.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/certificate_request.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/certificate_request.rb	2011-11-01 10:51:35.087524489 +0100
@@ -22,8 +22,12 @@
     [:s]
   end
 
+  def extension_factory
+    @ef ||= OpenSSL::X509::ExtensionFactory.new
+  end
+
   # How to create a certificate request with our system defaults.
-  def generate(key)
+  def generate(key, options = {})
     Puppet.info "Creating a new SSL certificate request for #{name}"
 
     # Support either an actual SSL key, or a Puppet key.
@@ -38,6 +42,19 @@
     csr.version = 0
     csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
     csr.public_key = key.public_key
+
+    if options[:dns_alt_names] then
+      names = options[:dns_alt_names].split(/\s*,\s*/).map(&:strip) + [name]
+      names = names.sort.uniq.map {|name| "DNS:#{name}" }.join(", ")
+      names = extension_factory.create_extension("subjectAltName", names, false)
+
+      extReq = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([names])])
+
+      # We only support the standard request extensions.  If you really need
+      # msExtReq support, let us know and we can restore them. --daniel 2011-10-10
+      csr.add_attribute(OpenSSL::X509::Attribute.new("extReq", extReq))
+    end
+
     csr.sign(key, OpenSSL::Digest::MD5.new)
 
     raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
@@ -55,4 +72,74 @@
       ca.autosign
     end
   end
+
+  # Return the set of extensions requested on this CSR, in a form designed to
+  # be useful to Ruby: a hash.  Which, not coincidentally, you can pass
+  # successfully to the OpenSSL constructor later, if you want.
+  def request_extensions
+    raise Puppet::Error, "CSR needs content to extract fields" unless @content
+
+    # Prefer the standard extReq, but accept the Microsoft specific version as
+    # a fallback, if the standard version isn't found.
+    ext = @content.attributes.find {|x| x.oid == "extReq" } or
+      @content.attributes.find {|x| x.oid == "msExtReq" }
+    return [] unless ext
+
+    # Assert the structure and extract the names into an array of arrays.
+    unless ext.value.is_a? OpenSSL::ASN1::Set
+      raise Puppet::Error, "In #{ext.oid}, expected Set but found #{ext.value.class}"
+    end
+
+    unless ext.value.value.is_a? Array
+      raise Puppet::Error, "In #{ext.oid}, expected Set[Array] but found #{ext.value.value.class}"
+    end
+
+    unless ext.value.value.count == 1
+      raise Puppet::Error, "In #{ext.oid}, expected Set[Array[...]], but found #{ext.value.value.count} items in the array"
+    end
+
+    san = ext.value.value.first
+    unless san.is_a? OpenSSL::ASN1::Sequence
+      raise Puppet::Error, "In #{ext.oid}, expected Set[Array[Sequence[...]]], but found #{san.class}"
+    end
+    san = san.value
+
+    # OK, now san should be the array of items, validate that...
+    index = -1
+    san.map do |name|
+      index += 1
+
+      unless name.is_a? OpenSSL::ASN1::Sequence
+        raise Puppet::Error, "In #{ext.oid}, expected request extension record #{index} to be a Sequence, but found #{name.class}"
+      end
+      name = name.value
+
+      # OK, turn that into an extension, to unpack the content.  Lovely that
+      # we have to swap the order of arguments to the underlying method, or
+      # perhaps that the ASN.1 representation chose to pack them in a
+      # strange order where the optional component comes *earlier* than the
+      # fixed component in the sequence.
+      case name.count
+      when 2
+        ev = OpenSSL::X509::Extension.new(name[0].value, name[1].value)
+        { "oid" => ev.oid, "value" => ev.value }
+
+      when 3
+        ev = OpenSSL::X509::Extension.new(name[0].value, name[2].value, name[1].value)
+        { "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
+
+      else
+        raise Puppet::Error, "In #{ext.oid}, expected extension record #{index} to have two or three items, but found #{name.count}"
+      end
+    end.flatten
+  end
+
+  def subject_alt_names
+    @subject_alt_names ||= request_extensions.
+      select {|x| x["oid"] = "subjectAltName" }.
+      map {|x| x["value"].split(/\s*,\s*/) }.
+      flatten.
+      sort.
+      uniq
+  end
 end
Index: puppet-2.6.4/lib/puppet/ssl/host.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/ssl/host.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/ssl/host.rb	2011-11-01 10:51:35.088524519 +0100
@@ -138,11 +138,24 @@
     @certificate_request ||= CertificateRequest.find(name)
   end
 
+  def this_csr_is_for_the_current_host
+    name == Puppet[:certname].downcase
+  end
+
   # Our certificate request requires the key but that's all.
-  def generate_certificate_request
+  def generate_certificate_request(options = {})
     generate_key unless key
+
+    # If this is for the current machine...
+    if this_csr_is_for_the_current_host
+      # ...add our configured dns_alt_names
+      if Puppet[:dns_alt_names] and Puppet[:dns_alt_names] != ''
+        options[:dns_alt_names] ||= Puppet[:dns_alt_names]
+      end
+    end
+
     @certificate_request = CertificateRequest.new(name)
-    @certificate_request.generate(key.content)
+    @certificate_request.generate(key.content, options)
     begin
       @certificate_request.save
     rescue
@@ -185,7 +198,7 @@
     # should use it to sign our request; else, just try to read
     # the cert.
     if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
-      ca.sign(self.name)
+      ca.sign(self.name, true)
     end
   end
 
Index: puppet-2.6.4/lib/puppet/sslcertificates/ca.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates/ca.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,375 +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::SSLCertificates.mkcert(
-      :type => :server,
-      :name => csr.subject,
-      :ttl => ttl,
-      :issuer => @cert,
-      :serial => serial,
-      :publickey => csr.public_key
-    )
-
-    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
-
Index: puppet-2.6.4/lib/puppet/sslcertificates/certificate.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates/certificate.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -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
-
Index: puppet-2.6.4/lib/puppet/sslcertificates/inventory.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates/inventory.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -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
-
Index: puppet-2.6.4/lib/puppet/sslcertificates/monkey_patch.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates/monkey_patch.rb	2010-11-29 08:42:18.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-# This is the file that we use to add indirection to all the SSL Certificate classes.
-
-require 'puppet/indirector'
-
-OpenSSL::PKey::RSA.extend Puppet::Indirector
-OpenSSL::PKey::RSA.indirects :ssl_rsa, :terminus_class => :file
Index: puppet-2.6.4/lib/puppet/sslcertificates/support.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates/support.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -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
Index: puppet-2.6.4/lib/puppet/sslcertificates.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/sslcertificates.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -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
-
Index: puppet-2.6.4/lib/puppet/type/file.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/type/file.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/type/file.rb	2011-11-01 10:51:35.090524581 +0100
@@ -6,7 +6,6 @@
 require 'puppet/network/handler'
 require 'puppet/util/diff'
 require 'puppet/util/checksums'
-require 'puppet/network/client'
 require 'puppet/util/backups'
 
 Puppet::Type.newtype(:file) do
Index: puppet-2.6.4/lib/puppet/util/command_line/puppetca
===================================================================
--- puppet-2.6.4.orig/lib/puppet/util/command_line/puppetca	2010-12-01 20:19:57.000000000 +0100
+++ puppet-2.6.4/lib/puppet/util/command_line/puppetca	2011-11-01 10:51:35.091524612 +0100
@@ -56,6 +56,10 @@
 #   Generate a certificate for a named client.  A certificate/keypair will be
 #   generated for each client named on the command line.
 #
+#   When generate is used the additional `--subject-alt-name` argument can be
+#   used.  The names, separated by `:`, passed will be added as the
+#   subjectAltName of the final certificate.
+#
 # help::
 #   Print this help message
 #
@@ -83,6 +87,19 @@
 #   Sign an outstanding certificate request.  Unless '--all' is specified,
 #   hosts must be listed after all flags.
 #
+#   Puppet will refuse to sign a CSR that requests a `subjectAltName`
+#   extension unless you specify `--allow-subject-alt-name`.  This is required
+#   because of the critical security risks around allowing `subjectAltName`
+#   from client generated certificates.
+#
+#   To further enforce security, if `--allow-subject-alt-name` is given Puppet
+#   will refuse to sign any certificate that does not have request additional
+#   names.
+#
+#   Finally, Puppet will still enforce security policy over the
+#   `subjectAltName` field, and will refuse to allow unknown values, or
+#   wildcards, as part of the certificate.
+#
 # verbose::
 #   Enable verbosity.
 #
@@ -98,6 +115,12 @@
 #   culain.madstop.com
 #   $ puppet cert -s culain.madstop.com
 #
+#   Signing a certificate with `subjectAltName` set, which will be requested
+#   automatically when you bring up a new master in a distributed CA
+#   environment:
+#
+#   $ puppet cert --sign --allow-subject-alt-name master12.local
+#
 # = Author
 #
 # Luke Kanies
@@ -106,5 +129,3 @@
 #
 # Copyright (c) 2005 Puppet Labs, LLC
 # Licensed under the GNU Public License
-
-#Puppet::Application[:cert].run
Index: puppet-2.6.4/lib/puppet/util/monkey_patches.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/util/monkey_patches.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/util/monkey_patches.rb	2011-11-01 10:51:35.091524612 +0100
@@ -48,3 +48,90 @@
   end
 end
 
+class Object
+  # The following code allows callers to make assertions that are only
+  # checked when the environment variable PUPPET_ENABLE_ASSERTIONS is
+  # set to a non-empty string.  For example:
+  #
+  #   assert_that { condition }
+  #   assert_that(message) { condition }
+  if ENV["PUPPET_ENABLE_ASSERTIONS"].to_s != ''
+    def assert_that(message = nil)
+      unless yield
+        raise Exception.new("Assertion failure: #{message}")
+      end
+    end
+  else
+    def assert_that(message = nil)
+    end
+  end
+end
+
+# Workaround for yaml_initialize, which isn't supported before Ruby
+# 1.8.3.
+if RUBY_VERSION == '1.8.1' || RUBY_VERSION == '1.8.2'
+  YAML.add_ruby_type( /^object/ ) { |tag, val|
+    type, obj_class = YAML.read_type_class( tag, Object )
+    r = YAML.object_maker( obj_class, val )
+    if r.respond_to? :yaml_initialize
+      r.instance_eval { instance_variables.each { |name| remove_instance_variable name } }
+      r.yaml_initialize(tag, val)
+    end
+    r
+  }
+end
+
+class Array
+  # Ruby < 1.8.7 doesn't have this method but we use it in tests
+  def combination(num)
+    return [] if num < 0 || num > size
+    return [[]] if num == 0
+    return map{|e| [e] } if num == 1
+    tmp = self.dup
+    self[0, size - (num - 1)].inject([]) do |ret, e|
+      tmp.shift
+      ret += tmp.combination(num - 1).map{|a| a.unshift(e) }
+    end
+  end unless method_defined? :combination
+
+  alias :count :length unless method_defined? :count
+end
+
+
+class Symbol
+  def to_proc
+    Proc.new { |*args| args.shift.__send__(self, *args) }
+  end unless method_defined? :to_proc
+end
+
+module Enumerable
+  # Use *args so we can distinguish no argument from nil.
+  def count(*args)
+    seq = 0
+    if !args.empty?
+      item = args[0]
+      each { |o| seq += 1 if item == o }
+    elsif block_given?
+      each { |o| seq += 1 if yield(o) }
+    else
+      each { seq += 1 }
+    end
+    seq
+  end unless method_defined? :count
+end
+
+class String
+  def lines(separator = $/)
+    lines = split(separator)
+    block_given? and lines.each {|line| yield line }
+    lines
+  end
+end
+
+class IO
+  def lines(separator = $/)
+    lines = split(separator)
+    block_given? and lines.each {|line| yield line }
+    lines
+  end
+end
Index: puppet-2.6.4/lib/puppet/util/settings.rb
===================================================================
--- puppet-2.6.4.orig/lib/puppet/util/settings.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/lib/puppet/util/settings.rb	2011-11-01 10:51:35.091524612 +0100
@@ -495,6 +495,11 @@
     end
     type = legacy_to_mode(type, param)
     @sync.synchronize do # yay, thread-safe
+      # Allow later inspection to determine if the setting was set on the
+      # command line, or through some other code path.  Used for the
+      # `dns_alt_names` option during cert generate. --daniel 2011-10-18
+      setting.setbycli = true if type == :cli
+
       @values[type][param] = value
       @cache.clear
 
Index: puppet-2.6.4/spec/integration/defaults_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/integration/defaults_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/integration/defaults_spec.rb	2011-11-01 10:51:35.092524643 +0100
@@ -22,6 +22,17 @@
     end
   end
 
+  describe "when :certdnsnames is set" do
+    it "should not fail" do
+      expect { Puppet[:certdnsnames] = 'fred:wilma' }.should_not raise_error
+    end
+
+    it "should warn the value is ignored" do
+      Puppet.expects(:warning).with {|msg| msg =~ /CVE-2011-3872/ }
+      Puppet[:certdnsnames] = 'fred:wilma'
+    end
+  end
+
   describe "when configuring the :crl" do
     it "should warn if :cacrl is set to false" do
       Puppet.expects(:warning)
Index: puppet-2.6.4/spec/integration/network/client_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/integration/network/client_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-require 'puppet/network/client'
-
-describe Puppet::Network::Client do
-  %w{ca file report runner status}.each do |name|
-    it "should have a #{name} client" do
-      Puppet::Network::Client.client(name).should be_instance_of(Class)
-    end
-
-    [:name, :handler, :drivername].each do |data|
-      it "should have a #{data} value for the #{name} client" do
-        Puppet::Network::Client.client(name).send(data).should_not be_nil
-      end
-    end
-  end
-end
Index: puppet-2.6.4/spec/integration/network/handler_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/integration/network/handler_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/integration/network/handler_spec.rb	2011-11-01 10:51:35.093524673 +0100
@@ -2,7 +2,7 @@
 
 require File.dirname(__FILE__) + '/../../spec_helper'
 
-require 'puppet/network/client'
+require 'puppet/network/handler'
 
 describe Puppet::Network::Handler do
   %w{ca filebucket fileserver master report runner status}.each do |name|
Index: puppet-2.6.4/spec/unit/network/client_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/network/client_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-#!/usr/bin/env ruby
-#
-#  Created by Luke Kanies on 2008-3-24.
-#  Copyright (c) 2008. All rights reserved.
-
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-require 'puppet/network/client'
-
-describe Puppet::Network::Client do
-  before do
-    Puppet.settings.stubs(:use).returns(true)
-    Puppet::Network::HttpPool.stubs(:cert_setup)
-  end
-
-  describe "when keep-alive is enabled" do
-    before do
-      Puppet::Network::HttpPool.stubs(:keep_alive?).returns true
-    end
-    it "should start the http client up on creation" do
-      http = mock 'http'
-      http.stub_everything
-      http.expects(:start)
-      Net::HTTP.stubs(:new).returns http
-
-      # Pick a random subclass...
-      Puppet::Network::Client.runner.new :Server => Puppet[:server]
-    end
-  end
-
-  describe "when keep-alive is disabled" do
-    before do
-      Puppet::Network::HttpPool.stubs(:keep_alive?).returns false
-    end
-    it "should not start the http client up on creation" do
-      http = mock 'http'
-      http.stub_everything
-      http.expects(:start).never
-      Net::HTTP.stubs(:new).returns http
-
-      # Pick a random subclass...
-      Puppet::Network::Client.runner.new :Server => Puppet[:server]
-    end
-  end
-end
Index: puppet-2.6.4/spec/unit/network/handler/ca_spec.rb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ puppet-2.6.4/spec/unit/network/handler/ca_spec.rb	2011-11-01 10:51:35.093524673 +0100
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+require 'puppet/network/handler/ca'
+
+describe Puppet::Network::Handler::CA do
+  include PuppetSpec::Files
+
+  describe "#getcert" do
+    let(:host)      { "testhost" }
+    let(:x509_name) { OpenSSL::X509::Name.new [['CN', host]] }
+    let(:key)       { Puppet::SSL::Key.new(host).generate }
+
+    let(:csr) do
+      csr = OpenSSL::X509::Request.new
+      csr.subject = x509_name
+      csr.public_key = key.public_key
+      csr
+    end
+
+    let(:ca)     { Puppet::SSL::CertificateAuthority.new }
+    let(:cacert) { ca.instance_variable_get(:@certificate) }
+
+    before :each do
+      Puppet[:confdir] = tmpdir('conf')
+
+      Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true
+      Puppet::SSL::CertificateAuthority.stubs(:singleton_instance).returns ca
+    end
+
+    it "should do nothing if the master is not a CA" do
+      Puppet::SSL::CertificateAuthority.stubs(:ca?).returns false
+
+      csr = OpenSSL::X509::Request.new
+      subject.getcert(csr.to_pem).should == ''
+    end
+
+    describe "when a certificate already exists for the host" do
+      let(:cert)    { ca.generate(host) }
+
+      it "should return the existing cert if it matches the public key of the CSR" do
+        csr.public_key = cert.content.public_key
+
+        subject.getcert(csr.to_pem).should == [cert.to_s, cacert.to_s]
+      end
+
+      it "should fail if the public key of the CSR does not match the existing cert" do
+        cert
+        expect do
+          subject.getcert(csr.to_pem)
+        end.to raise_error(Puppet::Error, /Certificate request does not match existing certificate/)
+      end
+    end
+
+    describe "when autosign is enabled" do
+      before :each do
+        Puppet[:autosign] = true
+      end
+
+      it "should return the new cert and the CA cert" do
+        cert_str, cacert_str = subject.getcert(csr.to_pem)
+
+        returned_cert = Puppet::SSL::Certificate.from_s(cert_str)
+        returned_cacert = Puppet::SSL::Certificate.from_s(cacert_str)
+
+        returned_cert.name.should == host
+        returned_cacert.content.subject.cmp(cacert.content.subject).should == 0
+      end
+    end
+
+    describe "when autosign is disabled" do
+      before :each do
+        Puppet[:autosign] = false
+      end
+
+      it "should save the CSR without signing it" do
+        subject.getcert(csr.to_pem)
+
+        Puppet::SSL::Certificate.find(host).should be_nil
+        Puppet::SSL::CertificateRequest.find(host).should be_a(Puppet::SSL::CertificateRequest)
+      end
+
+      it "should not return a cert" do
+        subject.getcert(csr.to_pem).should be_nil
+      end
+    end
+  end
+end
Index: puppet-2.6.4/spec/unit/ssl/certificate_authority/interface_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/certificate_authority/interface_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/certificate_authority/interface_spec.rb	2011-11-01 10:51:35.094524703 +0100
@@ -32,13 +32,13 @@
   end
   describe "when initializing" do
     it "should set its method using its settor" do
-      @class.any_instance.expects(:method=).with(:generate)
-      @class.new(:generate, :to => :all)
+      instance = @class.new(:generate, :to => :all)
+      instance.method.should == :generate
     end
 
     it "should set its subjects using the settor" do
-      @class.any_instance.expects(:subjects=).with(:all)
-      @class.new(:generate, :to => :all)
+      instance = @class.new(:generate, :to => :all)
+      instance.subjects.should == :all
     end
 
     it "should set the digest if given" do
@@ -54,23 +54,27 @@
 
   describe "when setting the method" do
     it "should set the method" do
-      @class.new(:generate, :to => :all).method.should == :generate
+      instance = @class.new(:generate, :to => :all)
+      instance.method = :list
+
+      instance.method.should == :list
     end
 
     it "should fail if the method isn't a member of the INTERFACE_METHODS array" do
-      Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false
-
-      lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError)
+      lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError, /Invalid method thing to apply/)
     end
   end
 
   describe "when setting the subjects" do
     it "should set the subjects" do
-      @class.new(:generate, :to => :all).subjects.should == :all
+      instance = @class.new(:generate, :to => :all)
+      instance.subjects = :signed
+
+      instance.subjects.should == :signed
     end
 
     it "should fail if the subjects setting isn't :all or an array" do
-      lambda { @class.new(:generate, "other") }.should raise_error(ArgumentError)
+      lambda { @class.new(:generate, :to => "other") }.should raise_error(ArgumentError, /Subjects must be an array or :all; not other/)
     end
   end
 
@@ -118,8 +122,8 @@
       it "should call :generate on the CA for each host specified" do
         @applier = @class.new(:generate, :to => %w{host1 host2})
 
-        @ca.expects(:generate).with("host1")
-        @ca.expects(:generate).with("host2")
+        @ca.expects(:generate).with("host1", {})
+        @ca.expects(:generate).with("host2", {})
 
         @applier.apply(@ca)
       end
@@ -150,15 +154,24 @@
 
     describe ":sign" do
       describe "and an array of names was provided" do
-        before do
-          @applier = @class.new(:sign, :to => %w{host1 host2})
-        end
+        let(:applier) { @class.new(:sign, @options.merge(:to => %w{host1 host2})) }
 
         it "should sign the specified waiting certificate requests" do
-          @ca.expects(:sign).with("host1")
-          @ca.expects(:sign).with("host2")
+          @options = {:allow_dns_alt_names => false}
 
-          @applier.apply(@ca)
+          @ca.expects(:sign).with("host1", false)
+          @ca.expects(:sign).with("host2", false)
+
+          applier.apply(@ca)
+        end
+
+        it "should sign the certificate requests with alt names if specified" do
+          @options = {:allow_dns_alt_names => true}
+
+          @ca.expects(:sign).with("host1", true)
+          @ca.expects(:sign).with("host2", true)
+
+          applier.apply(@ca)
         end
       end
 
@@ -166,8 +179,8 @@
         it "should sign all waiting certificate requests" do
           @ca.stubs(:waiting?).returns(%w{cert1 cert2})
 
-          @ca.expects(:sign).with("cert1")
-          @ca.expects(:sign).with("cert2")
+          @ca.expects(:sign).with("cert1", nil)
+          @ca.expects(:sign).with("cert2", nil)
 
           @applier = @class.new(:sign, :to => :all)
           @applier.apply(@ca)
@@ -183,63 +196,89 @@
     end
 
     describe ":list" do
-      describe "and an empty array was provided" do
-        it "should print a string containing all certificate requests" do
-          @ca.expects(:waiting?).returns %w{host1 host2}
-          @ca.stubs(:verify)
+      before :each do
+        certish = stub('certish', :subject_alt_names => [])
+        Puppet::SSL::Certificate.indirection.stubs(:find).returns certish
+        Puppet::SSL::CertificateRequest.indirection.stubs(:find).returns certish
+
+        @ca.expects(:waiting?).returns %w{host1 host2 host3}
+        @ca.expects(:list).returns %w{host4 host5 host6}
+        @ca.stubs(:fingerprint).returns "fingerprint"
+        @ca.stubs(:verify)
+      end
 
-          @applier = @class.new(:list, :to => [])
+      describe "and an empty array was provided" do
+        it "should print all certificate requests" do
+          applier = @class.new(:list, :to => [])
 
-          @applier.expects(:puts).with "host1\nhost2"
+          applier.expects(:puts).with(<<-OUTPUT.chomp)
+  host1 (fingerprint)
+  host2 (fingerprint)
+  host3 (fingerprint)
+          OUTPUT
 
-          @applier.apply(@ca)
+          applier.apply(@ca)
         end
       end
 
       describe "and :all was provided" do
         it "should print a string containing all certificate requests and certificates" do
-          @ca.expects(:waiting?).returns %w{host1 host2}
-          @ca.expects(:list).returns %w{host3 host4}
-          @ca.stubs(:verify)
-          @ca.stubs(:fingerprint).returns "fingerprint"
-          @ca.expects(:verify).with("host3").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked")
-
-          @applier = @class.new(:list, :to => :all)
-
-          @applier.expects(:puts).with "host1 (fingerprint)"
-          @applier.expects(:puts).with "host2 (fingerprint)"
-          @applier.expects(:puts).with "- host3 (fingerprint) (certificate revoked)"
-          @applier.expects(:puts).with "+ host4 (fingerprint)"
+          @ca.stubs(:verify).with("host4").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked")
 
-          @applier.apply(@ca)
+          applier = @class.new(:list, :to => :all)
+
+          applier.expects(:puts).with(<<-OUTPUT.chomp)
+  host1 (fingerprint)
+  host2 (fingerprint)
+  host3 (fingerprint)
++ host5 (fingerprint)
++ host6 (fingerprint)
+- host4 (fingerprint) (certificate revoked)
+          OUTPUT
+
+          applier.apply(@ca)
         end
       end
 
       describe "and :signed was provided" do
         it "should print a string containing all signed certificate requests and certificates" do
-          @ca.expects(:list).returns %w{host1 host2}
+          applier = @class.new(:list, :to => :signed)
 
-          @applier = @class.new(:list, :to => :signed)
+          applier.expects(:puts).with(<<-OUTPUT.chomp)
++ host4 (fingerprint)
++ host5 (fingerprint)
++ host6 (fingerprint)
+          OUTPUT
 
-          @applier.apply(@ca)
+          applier.apply(@ca)
+        end
+
+        it "should include subject alt names if they are on the certificate request" do
+          request = stub 'request', :subject_alt_names => ["DNS:foo", "DNS:bar"]
+          Puppet::SSL::CertificateRequest.indirection.stubs(:find).returns(request)
+
+          applier = @class.new(:list, :to => ['host1'])
+
+          applier.expects(:puts).with(<<-OUTPUT.chomp)
+  host1 (fingerprint) (alt names: DNS:foo, DNS:bar)
+          OUTPUT
+
+          applier.apply(@ca)
         end
       end
 
       describe "and an array of names was provided" do
-        it "should print a string of all named hosts that have a waiting request" do
-          @ca.expects(:waiting?).returns %w{host1 host2}
-          @ca.expects(:list).returns %w{host3 host4}
-          @ca.stubs(:fingerprint).returns "fingerprint"
-          @ca.stubs(:verify)
-
-          @applier = @class.new(:list, :to => %w{host1 host2 host3 host4})
-
-          @applier.expects(:puts).with "host1 (fingerprint)"
-          @applier.expects(:puts).with "host2 (fingerprint)"
-          @applier.expects(:puts).with "+ host3 (fingerprint)"
-          @applier.expects(:puts).with "+ host4 (fingerprint)"
+        it "should print all named hosts" do
+          applier = @class.new(:list, :to => %w{host1 host2 host4 host5})
 
-          @applier.apply(@ca)
+          applier.expects(:puts).with(<<-OUTPUT.chomp)
+  host1 (fingerprint)
+  host2 (fingerprint)
++ host4 (fingerprint)
++ host5 (fingerprint)
+            OUTPUT
+
+          applier.apply(@ca)
         end
       end
     end
Index: puppet-2.6.4/spec/unit/ssl/certificate_authority_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/certificate_authority_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/certificate_authority_spec.rb	2011-11-01 10:51:35.095524732 +0100
@@ -200,8 +200,9 @@
       request = mock 'request'
       Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request
       request.expects(:generate).with(@ca.host.key)
+      request.stubs(:request_extensions => [])
 
-      @ca.expects(:sign).with(@host.name, :ca, request)
+      @ca.expects(:sign).with(@host.name, false, request)
 
       @ca.stubs :generate_password
 
@@ -243,10 +244,10 @@
       @cert.stubs(:save)
 
       # Stub out the factory
-      @factory = stub 'factory', :result => "my real cert"
-      Puppet::SSL::CertificateFactory.stubs(:new).returns @factory
+      Puppet::SSL::CertificateFactory.stubs(:build).returns "my real cert"
 
-      @request = stub 'request', :content => "myrequest", :name => @name
+      @request_content = stub "request content stub", :subject => @name
+      @request = stub 'request', :name => @name, :request_extensions => [], :subject_alt_names => [], :content => @request_content
 
       # And the inventory
       @inventory = stub 'inventory', :add => nil
@@ -297,37 +298,45 @@
       it "should not look up a certificate request for the host" do
         Puppet::SSL::CertificateRequest.expects(:find).never
 
-        @ca.sign(@name, :ca, @request)
+        @ca.sign(@name, true, @request)
       end
 
       it "should use a certificate type of :ca" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
           args[0] == :ca
-        end.returns @factory
+        end.returns "my real cert"
         @ca.sign(@name, :ca, @request)
       end
 
       it "should pass the provided CSR as the CSR" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
-          args[1] == "myrequest"
-        end.returns @factory
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
+          args[1] == @request
+        end.returns "my real cert"
         @ca.sign(@name, :ca, @request)
       end
 
       it "should use the provided CSR's content as the issuer" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
-          args[2] == "myrequest"
-        end.returns @factory
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
+          args[2].subject == "myhost"
+        end.returns "my real cert"
         @ca.sign(@name, :ca, @request)
       end
 
       it "should pass the next serial as the serial number" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
           args[3] == @serial
-        end.returns @factory
+        end.returns "my real cert"
         @ca.sign(@name, :ca, @request)
       end
 
+      it "should sign the certificate request even if it contains alt names" do
+        @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+        expect do
+          @ca.sign(@name, false, @request)
+        end.should_not raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError)
+      end
+
       it "should save the resulting certificate" do
         @cert.expects(:save)
 
@@ -345,9 +354,9 @@
       end
 
       it "should use a certificate type of :server" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
           args[0] == :server
-        end.returns @factory
+        end.returns "my real cert"
 
         @ca.sign(@name)
       end
@@ -364,17 +373,45 @@
         lambda { @ca.sign(@name) }.should raise_error(ArgumentError)
       end
 
+      it "should fail if an unknown request extension is present" do
+        @request.stubs :request_extensions => [{ "oid"   => "bananas",
+                                                 "value" => "delicious" }]
+        expect { @ca.sign(@name) }.
+          should raise_error(/CSR has request extensions that are not permitted/)
+      end
+
+      it "should fail if the CSR contains alt names and they are not expected" do
+        @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+        expect do
+          @ca.sign(@name, false)
+        end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError, /CSR '#{@name}' contains subject alternative names \(.*?\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{@name}` to sign this request./)
+      end
+
+      it "should not fail if the CSR does not contain alt names and they are expected" do
+        @request.stubs(:subject_alt_names).returns []
+        expect { @ca.sign(@name, true) }.should_not raise_error
+      end
+
+      it "should reject alt names by default" do
+        @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+        expect do
+          @ca.sign(@name)
+        end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError, /CSR '#{@name}' contains subject alternative names \(.*?\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{@name}` to sign this request./)
+      end
+
       it "should use the CA certificate as the issuer" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
           args[2] == @cacert.content
-        end.returns @factory
+        end.returns "my real cert"
         @ca.sign(@name)
       end
 
       it "should pass the next serial as the serial number" do
-        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+        Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
           args[3] == @serial
-        end.returns @factory
+        end.returns "my real cert"
         @ca.sign(@name)
       end
 
@@ -399,6 +436,80 @@
 
         @ca.sign(@name)
       end
+
+      it "should check the internal signing policies" do
+        @ca.expects(:check_internal_signing_policies).returns true
+        @ca.sign(@name)
+      end
+    end
+
+    context "#check_internal_signing_policies" do
+      before do
+        @serial = 10
+        @ca.stubs(:next_serial).returns @serial
+
+        Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request
+        @cert.stubs :save
+      end
+
+      it "should reject a critical extension that isn't on the whitelist" do
+        @request.stubs(:request_extensions).returns [{ "oid" => "banana",
+                                                       "value" => "yumm",
+                                                       "critical" => true }]
+        expect { @ca.sign(@name) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /request extensions that are not permitted/
+        )
+      end
+
+      it "should reject a non-critical extension that isn't on the whitelist" do
+        @request.stubs(:request_extensions).returns [{ "oid" => "peach",
+                                                       "value" => "meh",
+                                                       "critical" => false }]
+        expect { @ca.sign(@name) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /request extensions that are not permitted/
+        )
+      end
+
+      it "should reject non-whitelist extensions even if a valid extension is present" do
+        @request.stubs(:request_extensions).returns [{ "oid" => "peach",
+                                                       "value" => "meh",
+                                                       "critical" => false },
+                                                     { "oid" => "subjectAltName",
+                                                       "value" => "DNS:foo",
+                                                       "critical" => true }]
+        expect { @ca.sign(@name) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /request extensions that are not permitted/
+        )
+      end
+
+      it "should reject a subjectAltName for a non-DNS value" do
+        @request.stubs(:subject_alt_names).returns ['DNS:foo', 'email:bar@example.com']
+        expect { @ca.sign(@name, true) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /subjectAltName outside the DNS label space/
+        )
+      end
+
+      it "should reject a wildcard subject" do
+        @request.content.stubs(:subject).
+          returns(OpenSSL::X509::Name.new([["CN", "*.local"]]))
+
+        expect { @ca.sign(@name) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /subject contains a wildcard/
+        )
+      end
+
+      it "should reject a wildcard subjectAltName" do
+        @request.stubs(:subject_alt_names).returns ['DNS:foo', 'DNS:*.bar']
+        expect { @ca.sign(@name, true) }.to raise_error(
+          Puppet::SSL::CertificateAuthority::CertificateSigningError,
+          /subjectAltName contains a wildcard/
+        )
+      end
     end
 
     it "should create a certificate instance with the content set to the newly signed x509 certificate" do
@@ -763,8 +874,7 @@
       end
 
       it "should sign the generated request" do
-        @ca.expects(:sign).with("him")
-
+        @ca.expects(:sign).with("him", false)
         @ca.generate("him")
       end
     end
Index: puppet-2.6.4/spec/unit/ssl/certificate_factory_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/certificate_factory_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/certificate_factory_spec.rb	2011-11-01 10:51:35.096524761 +0100
@@ -5,103 +5,126 @@
 require 'puppet/ssl/certificate_factory'
 
 describe Puppet::SSL::CertificateFactory do
-  before do
-    @cert_type = mock 'cert_type'
-    @name = mock 'name'
-    @csr = stub 'csr', :subject => @name
-    @issuer = mock 'issuer'
-    @serial = mock 'serial'
-
-    @factory = Puppet::SSL::CertificateFactory.new(@cert_type, @csr, @issuer, @serial)
+  let :serial    do OpenSSL::BN.new('12') end
+  let :name      do "example.local" end
+  let :x509_name do OpenSSL::X509::Name.new([['CN', name]]) end
+  let :key       do Puppet::SSL::Key.new(name).generate end
+  let :csr       do
+    csr = Puppet::SSL::CertificateRequest.new(name)
+    csr.generate(key)
+    csr
   end
-
-  describe "when initializing" do
-    it "should set its :cert_type to its first argument" do
-      @factory.cert_type.should equal(@cert_type)
-    end
-
-    it "should set its :csr to its second argument" do
-      @factory.csr.should equal(@csr)
-    end
-
-    it "should set its :issuer to its third argument" do
-      @factory.issuer.should equal(@issuer)
-    end
-
-    it "should set its :serial to its fourth argument" do
-      @factory.serial.should equal(@serial)
-    end
-
-    it "should set its name to the subject of the csr" do
-      @factory.name.should equal(@name)
-    end
+  let :issuer do
+    cert = OpenSSL::X509::Certificate.new
+    cert.subject = OpenSSL::X509::Name.new([["CN", 'issuer.local']])
+    cert
   end
 
-  describe "when generating the certificate" do
-    before do
-      @cert = mock 'cert'
-
-      @cert.stub_everything
-
-      @factory.stubs :build_extensions
-
-      @factory.stubs :set_ttl
-
-      @issuer_name = mock 'issuer_name'
-      @issuer.stubs(:subject).returns @issuer_name
-
-      @public_key = mock 'public_key'
-      @csr.stubs(:public_key).returns @public_key
-
-      OpenSSL::X509::Certificate.stubs(:new).returns @cert
-    end
+  let(:subject) { Puppet::SSL::CertificateFactory }
 
+  describe "when generating the certificate" do
     it "should return a new X509 certificate" do
-      OpenSSL::X509::Certificate.expects(:new).returns @cert
-      @factory.result.should equal(@cert)
+      subject.build(:server, csr, issuer, serial).should_not ==
+        subject.build(:server, csr, issuer, serial)
     end
 
     it "should set the certificate's version to 2" do
-      @cert.expects(:version=).with 2
-      @factory.result
+      subject.build(:server, csr, issuer, serial).version.should == 2
     end
 
     it "should set the certificate's subject to the CSR's subject" do
-      @cert.expects(:subject=).with @name
-      @factory.result
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.subject.should eql x509_name
     end
 
     it "should set the certificate's issuer to the Issuer's subject" do
-      @cert.expects(:issuer=).with @issuer_name
-      @factory.result
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.issuer.should eql issuer.subject
     end
 
     it "should set the certificate's public key to the CSR's public key" do
-      @cert.expects(:public_key=).with @public_key
-      @factory.result
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.public_key.should be_public
+      cert.public_key.to_s.should == csr.content.public_key.to_s
     end
 
     it "should set the certificate's serial number to the provided serial number" do
-      @cert.expects(:serial=).with @serial
-      @factory.result
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.serial.should == serial
     end
 
-    it "should build extensions for the certificate" do
-      @factory.expects(:build_extensions)
-      @factory.result
+    it "should have 24 hours grace on the start of the cert" do
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.not_before.should be_close(Time.now - 24*60*60,1)
     end
 
-    it "should set the ttl of the certificate" do
-      @factory.expects(:set_ttl)
-      @factory.result
+    it "should set the default TTL of the certificate" do
+      ttl  = Puppet::SSL::CertificateFactory.ttl
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.not_after.should be_close(Time.now + ttl,1)
     end
-  end
 
-  describe "when building extensions" do
-    it "should have tests"
-  end
+    it "should respect a custom TTL for the CA" do
+      Puppet[:ca_ttl] = 12
+      cert = subject.build(:server, csr, issuer, serial)
+      cert.not_after.should be_close(Time.now + 12,1)
+    end
 
-  describe "when setting the ttl" do
-    it "should have tests"
+    it "should build extensions for the certificate" do
+      cert = subject.build(:server, csr, issuer, serial)
+      exts = cert.extensions.map {|x| x.to_h }.group_by {|x| x["oid"] }
+      exts["nsComment"].should ==
+        [{ "oid"      => "nsComment",
+           "value"    => "Puppet Ruby/OpenSSL Internal Certificate",
+           "critical" => false }]
+    end
+
+    # See #2848 for why we are doing this: we need to make sure that
+    # subjectAltName is set if the CSR has it, but *not* if it is set when the
+    # certificate is built!
+    it "should not add subjectAltNames from dns_alt_names" do
+      Puppet[:dns_alt_names] = 'one, two'
+      # Verify the CSR still has no extReq, just in case...
+      csr.request_extensions.should == []
+      cert = subject.build(:server, csr, issuer, serial)
+
+      cert.extensions.find {|x| x.oid == 'subjectAltName' }.should be_nil
+    end
+
+    it "should add subjectAltName when the CSR requests them" do
+      Puppet[:dns_alt_names] = ''
+
+      expect = %w{one two} + [name]
+
+      csr = Puppet::SSL::CertificateRequest.new(name)
+      csr.generate(key, :dns_alt_names => expect.join(', '))
+
+      csr.request_extensions.should_not be_nil
+      csr.subject_alt_names.should =~ expect.map{|x| "DNS:#{x}"}
+
+      cert = subject.build(:server, csr, issuer, serial)
+      san = cert.extensions.find {|x| x.oid == 'subjectAltName' }
+      san.should_not be_nil
+      expect.each do |name|
+        san.value.should =~ /DNS:#{name}\b/i
+      end
+    end
+
+    # Can't check the CA here, since that requires way more infrastructure
+    # that I want to build up at this time.  We can verify the critical
+    # values, though, which are non-CA certs. --daniel 2011-10-11
+    { :ca            => 'CA:TRUE',
+      :terminalsubca => ['CA:TRUE', 'pathlen:0'],
+      :server        => 'CA:FALSE',
+      :ocsp          => 'CA:FALSE',
+      :client        => 'CA:FALSE',
+    }.each do |name, value|
+      it "should set basicConstraints for #{name} #{value.inspect}" do
+        cert = subject.build(name, csr, issuer, serial)
+        bc = cert.extensions.find {|x| x.oid == 'basicConstraints' }
+        bc.should be
+        bc.value.split(/\s*,\s*/).should =~ Array(value)
+      end
+    end
   end
 end
Index: puppet-2.6.4/spec/unit/ssl/certificate_request_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/certificate_request_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/certificate_request_spec.rb	2011-11-01 10:51:35.096524761 +0100
@@ -126,7 +126,7 @@
 
     it "should set the CN to the :ca_name setting when the CSR is for a CA" do
       subject = mock 'subject'
-      Puppet.settings.expects(:value).with(:ca_name).returns "mycertname"
+      Puppet[:ca_name] = "mycertname"
       OpenSSL::X509::Name.expects(:new).with { |subject| subject[0][1] == "mycertname" }.returns(subject)
       @request.expects(:subject=).with(subject)
       Puppet::SSL::CertificateRequest.new(Puppet::SSL::CA_NAME).generate(@key)
@@ -145,6 +145,67 @@
       @instance.generate(@key)
     end
 
+    context "without subjectAltName / dns_alt_names" do
+      before :each do
+        Puppet[:dns_alt_names] = ""
+      end
+
+      ["extreq", "msExtReq"].each do |name|
+        it "should not add any #{name} attribute" do
+          @request.expects(:add_attribute).never
+          @request.expects(:attributes=).never
+          @instance.generate(@key)
+        end
+
+        it "should return no subjectAltNames" do
+          @instance.generate(@key)
+          @instance.subject_alt_names.should be_empty
+        end
+      end
+    end
+
+    context "with dns_alt_names" do
+      before :each do
+        Puppet[:dns_alt_names] = "one, two, three"
+      end
+
+      ["extreq", "msExtReq"].each do |name|
+        it "should not add any #{name} attribute" do
+          @request.expects(:add_attribute).never
+          @request.expects(:attributes=).never
+          @instance.generate(@key)
+        end
+
+        it "should return no subjectAltNames" do
+          @instance.generate(@key)
+          @instance.subject_alt_names.should be_empty
+        end
+      end
+    end
+
+    context "with subjectAltName to generate request" do
+      before :each do
+        Puppet[:dns_alt_names] = ""
+      end
+
+      it "should add an extreq attribute" do
+        @request.expects(:add_attribute).with do |arg|
+          arg.value.value.all? do |x|
+            x.value.all? do |y|
+              y.value[0].value == "subjectAltName"
+            end
+          end
+        end
+
+        @instance.generate(@key, :dns_alt_names => 'one, two')
+      end
+
+      it "should return the subjectAltName values" do
+        @instance.generate(@key, :dns_alt_names => 'one,two')
+        @instance.subject_alt_names.should =~ ["DNS:myname", "DNS:one", "DNS:two"]
+      end
+    end
+
     it "should sign the csr with the provided key and a digest" do
       digest = mock 'digest'
       OpenSSL::Digest::MD5.expects(:new).returns(digest)
Index: puppet-2.6.4/spec/unit/ssl/certificate_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/certificate_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/certificate_spec.rb	2011-11-01 10:51:35.096524761 +0100
@@ -90,6 +90,37 @@
       @certificate.should respond_to(:content)
     end
 
+    describe "#subject_alt_names" do
+      it "should list all alternate names when the extension is present" do
+        key = Puppet::SSL::Key.new('quux')
+        key.generate
+
+        csr = Puppet::SSL::CertificateRequest.new('quux')
+        csr.generate(key, :dns_alt_names => 'foo, bar,baz')
+
+        raw_csr = csr.content
+
+        cert = Puppet::SSL::CertificateFactory.build('server', csr, raw_csr, 14)
+        certificate = @class.from_s(cert.to_pem)
+        certificate.subject_alt_names.
+          should =~ ['DNS:foo', 'DNS:bar', 'DNS:baz', 'DNS:quux']
+      end
+
+      it "should return an empty list of names if the extension is absent" do
+        key = Puppet::SSL::Key.new('quux')
+        key.generate
+
+        csr = Puppet::SSL::CertificateRequest.new('quux')
+        csr.generate(key)
+
+        raw_csr = csr.content
+
+        cert = Puppet::SSL::CertificateFactory.build('client', csr, raw_csr, 14)
+        certificate = @class.from_s(cert.to_pem)
+        certificate.subject_alt_names.should be_empty
+      end
+    end
+
     it "should return a nil expiration if there is no actual certificate" do
       @certificate.stubs(:content).returns nil
 
Index: puppet-2.6.4/spec/unit/ssl/host_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/ssl/host_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ puppet-2.6.4/spec/unit/ssl/host_spec.rb	2011-11-01 10:51:35.097524791 +0100
@@ -5,6 +5,8 @@
 require 'puppet/ssl/host'
 
 describe Puppet::SSL::Host do
+  include PuppetSpec::Files
+
   before do
     @class = Puppet::SSL::Host
     @host = @class.new("myname")
@@ -64,6 +66,46 @@
     Puppet::SSL::Host.localhost.should equal(host)
   end
 
+  it "should create a localhost cert if no cert is available and it is a CA with autosign and it is using DNS alt names" do
+    Puppet[:autosign] = true
+    Puppet[:confdir] = tmpdir('conf')
+    Puppet[:dns_alt_names] = "foo,bar,baz"
+    ca = Puppet::SSL::CertificateAuthority.new
+    Puppet::SSL::CertificateAuthority.stubs(:instance).returns ca
+
+    localhost = Puppet::SSL::Host.localhost
+    cert = localhost.certificate
+
+    cert.should be_a(Puppet::SSL::Certificate)
+    cert.subject_alt_names.should =~ %W[DNS:#{Puppet[:certname]} DNS:foo DNS:bar DNS:baz]
+  end
+
+  context "with dns_alt_names" do
+    before :each do
+      Puppet[:dns_alt_names] = 'one, two'
+
+      @key = stub('key content')
+      key = stub('key', :generate => true, :save => true, :content => @key)
+      Puppet::SSL::Key.stubs(:new).returns key
+
+      @cr = stub('certificate request', :save => true)
+      Puppet::SSL::CertificateRequest.stubs(:new).returns @cr
+    end
+
+    it "should not include subjectAltName if not the local node" do
+      @cr.expects(:generate).with(@key, {})
+
+      Puppet::SSL::Host.new('not-the-' + Puppet[:certname]).generate
+    end
+
+    it "should include subjectAltName if I am a CA" do
+      @cr.expects(:generate).
+        with(@key, { :dns_alt_names => Puppet[:dns_alt_names] })
+
+      Puppet::SSL::Host.localhost
+    end
+  end
+
   it "should always read the key for the localhost instance in from disk" do
     host = stub 'host', :certificate => "eh"
     Puppet::SSL::Host.expects(:new).returns host
@@ -377,7 +419,7 @@
 
       key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
       @host.stubs(:key).returns(key)
-      @request.expects(:generate).with("mycontent")
+      @request.expects(:generate).with("mycontent", {})
       @request.expects(:save)
 
       @host.generate_certificate_request.should be_true
@@ -566,7 +608,7 @@
       it "should use the CA to sign its certificate request if it does not have a certificate" do
         @host.expects(:certificate).returns nil
 
-        @ca.expects(:sign).with(@host.name)
+        @ca.expects(:sign).with(@host.name, true)
 
         @host.generate
       end
Index: puppet-2.6.4/spec/unit/sslcertificates/ca_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/sslcertificates/ca_spec.rb	2010-12-01 00:42:02.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,110 +0,0 @@
-#!/usr/bin/env ruby
-require File.dirname(__FILE__) + '/../../spec_helper'
-
-require 'puppet'
-require 'puppet/sslcertificates'
-require 'puppet/sslcertificates/ca'
-
-describe Puppet::SSLCertificates::CA do
-  before :all do
-    @hosts = %w{host.domain.com Other.Testing.Com}
-  end
-
-  before :each do
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    file = Tempfile.new("ca_testing")
-    @dir = file.path
-    file.delete
-
-    Puppet.settings[:confdir] = @dir
-    Puppet.settings[:vardir]  = @dir
-
-    @ca = Puppet::SSLCertificates::CA.new
-  end
-
-  after :each do
-    system("rm -rf #{@dir}")
-  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
Index: puppet-2.6.4/spec/unit/util/settings_spec.rb
===================================================================
--- puppet-2.6.4.orig/spec/unit/util/settings_spec.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/spec/unit/util/settings_spec.rb	2011-11-01 10:51:35.098524823 +0100
@@ -129,6 +129,16 @@
       @settings[:myval].should == ""
     end
 
+    it "should flag settings from the CLI" do
+      @settings.handlearg("--myval")
+      @settings.setting(:myval).setbycli.should be_true
+    end
+
+    it "should not flag settings memory" do
+      @settings[:myval] = "12"
+      @settings.setting(:myval).setbycli.should be_false
+    end
+
     it "should clear the cache when setting getopt-specific values" do
       @settings.setdefaults :mysection, :one => ["whah", "yay"], :two => ["$one yay", "bah"]
       @settings[:two].should == "whah yay"
Index: puppet-2.6.4/test/certmgr/certmgr.rb
===================================================================
--- puppet-2.6.4.orig/test/certmgr/certmgr.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,308 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppet'
-require 'puppet/sslcertificates.rb'
-require 'puppettest'
-require 'puppettest/certificates'
-require 'mocha'
-
-class TestCertMgr < Test::Unit::TestCase
-  include PuppetTest::Certificates
-  def setup
-    super
-    #@dir = File.join(Puppet[:certdir], "testing")
-    @dir = File.join(@configpath, "certest")
-    system("mkdir -p #{@dir}")
-
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-  end
-
-  def testCreateSelfSignedCertificate
-    cert = nil
-    name = "testing"
-    newcert = proc {
-
-            Puppet::SSLCertificates::Certificate.new(
-                
-        :name => name,
-        
-        :selfsign => true
-      )
-    }
-    assert_nothing_raised {
-      cert = newcert.call
-    }
-    assert_nothing_raised {
-      cert.mkselfsigned
-    }
-
-    assert_raise(Puppet::Error) {
-      cert.mkselfsigned
-    }
-
-    assert_nothing_raised {
-      cert.write
-    }
-
-    assert(FileTest.exists?(cert.certfile))
-
-    assert_nothing_raised {
-      cert.delete
-    }
-
-    assert_nothing_raised {
-      cert = newcert.call
-    }
-    assert_nothing_raised {
-      cert.mkselfsigned
-    }
-
-    assert_nothing_raised {
-      cert.delete
-    }
-
-  end
-
-  def disabled_testCreateEncryptedSelfSignedCertificate
-    cert = nil
-    name = "testing"
-    keyfile = mkPassFile
-    assert_nothing_raised {
-
-            cert = Puppet::SSLCertificates::Certificate.new(
-                
-        :name => name,
-        :selfsign => true,
-        
-        :capass => keyfile
-      )
-    }
-    assert_nothing_raised {
-      cert.mkselfsigned
-    }
-    assert_nothing_raised {
-      cert.mkhash
-    }
-
-    assert_raise(Puppet::Error) {
-      cert.mkselfsigned
-    }
-
-    assert(FileTest.exists?(cert.certfile))
-    assert(FileTest.exists?(cert.hash))
-
-    assert_nothing_raised {
-      cert.delete
-    }
-
-    assert_nothing_raised {
-      cert.mkselfsigned
-    }
-
-    assert_nothing_raised {
-      cert.delete
-    }
-
-  end
-
-  def testCreateCA
-    ca = nil
-    assert_nothing_raised {
-      ca = Puppet::SSLCertificates::CA.new
-    }
-
-    # make the CA again and verify it doesn't fail because everything
-    # still exists
-    assert_nothing_raised {
-      ca = Puppet::SSLCertificates::CA.new
-    }
-
-  end
-
-  def testSignCert
-    ca = mkCA()
-
-    cert = nil
-    assert_nothing_raised {
-
-            cert = Puppet::SSLCertificates::Certificate.new(
-                
-        :name => "signedcertest",
-        :property => "TN",
-        :city => "Nashville",
-        :country => "US",
-        :email => "luke@madstop.com",
-        :org => "Puppet",
-        :ou => "Development",
-        
-        :encrypt => mkPassFile()
-      )
-
-    }
-
-    assert_nothing_raised {
-      cert.mkcsr
-    }
-
-    signedcert = nil
-    cacert = nil
-
-    assert_nothing_raised {
-      signedcert, cacert = ca.sign(cert.csr)
-    }
-
-    assert_instance_of(OpenSSL::X509::Certificate, signedcert)
-    assert_instance_of(OpenSSL::X509::Certificate, cacert)
-
-    assert_nothing_raised {
-      cert.cert = signedcert
-      cert.cacert = cacert
-      cert.write
-    }
-    #system("find #{Puppet[:ssldir]}")
-    #system("cp -R #{Puppet[:ssldir]} /tmp/ssltesting")
-
-    output = nil
-    assert_nothing_raised {
-      output = %x{openssl verify -CAfile #{Puppet[:cacert]} -purpose sslserver #{cert.certfile}}
-      #output = %x{openssl verify -CApath #{Puppet[:certdir]} -purpose sslserver #{cert.certfile}}
-    }
-
-    assert_equal($CHILD_STATUS,0)
-    assert_equal(File.join(Puppet[:certdir], "signedcertest.pem: OK\n"), output)
-  end
-
-
-  def test_interactiveca
-    ca = nil
-
-    assert_nothing_raised {
-      ca = Puppet::SSLCertificates::CA.new
-    }
-
-    # basic initialization
-    hostname = "test.hostname.com"
-    cert = mkcert(hostname)
-
-    # create the csr
-    csr = nil
-    assert_nothing_raised {
-      csr = cert.mkcsr
-    }
-
-    assert_nothing_raised {
-      ca.storeclientcsr(csr)
-    }
-
-    # store it
-    pulledcsr = nil
-    assert_nothing_raised {
-      pulledcsr = ca.getclientcsr(hostname)
-    }
-
-    assert_equal(csr.to_pem, pulledcsr.to_pem)
-
-    signedcert = nil
-    assert_nothing_raised {
-      signedcert, cacert = ca.sign(csr)
-    }
-
-    assert_instance_of(OpenSSL::X509::Certificate, signedcert)
-    newsignedcert = nil
-    assert_nothing_raised {
-      newsignedcert, cacert = ca.getclientcert(hostname)
-    }
-
-    assert(newsignedcert)
-
-    assert_equal(signedcert.to_pem, newsignedcert.to_pem)
-  end
-
-  def test_cafailures
-    ca = mkCA()
-    cert = cacert = nil
-    assert_nothing_raised {
-      cert, cacert = ca.getclientcert("nohost")
-    }
-    assert_nil(cert)
-  end
-
-  def test_crl
-    ca = mkCA()
-    h1 = mksignedcert(ca, "host1.example.com")
-    h2 = mksignedcert(ca, "host2.example.com")
-
-    assert(ca.cert.verify(ca.cert.public_key))
-    assert(h1.verify(ca.cert.public_key))
-    assert(h2.verify(ca.cert.public_key))
-
-    crl = ca.crl
-    assert_not_nil(crl)
-
-    store = mkStore(ca)
-    assert( store.verify(ca.cert))
-    assert( store.verify(h1, [ca.cert]))
-    assert( store.verify(h2, [ca.cert]))
-
-    ca.revoke(h1.serial)
-
-    oldcert = File.read(Puppet.settings[:cacert])
-    oldserial = File.read(Puppet.settings[:serial])
-
-    # Recreate the CA from disk
-    ca = mkCA()
-    newcert = File.read(Puppet.settings[:cacert])
-    newserial = File.read(Puppet.settings[:serial])
-    assert_equal(oldcert, newcert, "The certs are not equal after making a new CA.")
-    assert_equal(oldserial, newserial, "The serials are not equal after making a new CA.")
-    store = mkStore(ca)
-    assert( store.verify(ca.cert), "Could not verify CA certs after reloading certs.")
-    assert(!store.verify(h1, [ca.cert]), "Incorrectly verified revoked cert.")
-    assert( store.verify(h2, [ca.cert]), "Could not verify certs with reloaded CA.")
-
-    ca.revoke(h2.serial)
-    assert_equal(1, ca.crl.extensions.size)
-
-    # Recreate the CA from disk
-    ca = mkCA()
-    store = mkStore(ca)
-    assert( store.verify(ca.cert))
-    assert(!store.verify(h1, [ca.cert]), "first revoked cert passed")
-    assert(!store.verify(h2, [ca.cert]), "second revoked cert passed")
-  end
-
-  def test_ttl
-    cert = mksignedcert
-    assert_equal(5 * 365 * 24 * 60 * 60,  cert.not_after - cert.not_before)
-
-    Puppet[:ca_ttl] = 7 * 24 * 60 * 60
-    cert = mksignedcert
-    assert_equal(7 * 24 * 60 * 60,  cert.not_after - cert.not_before)
-
-    Puppet[:ca_ttl] = "2y"
-    cert = mksignedcert
-    assert_equal(2 * 365 * 24 * 60 * 60,  cert.not_after - cert.not_before)
-
-    Puppet[:ca_ttl] = "2y"
-    cert = mksignedcert
-    assert_equal(2 * 365 * 24 * 60 * 60,  cert.not_after - cert.not_before)
-
-    Puppet[:ca_ttl] = "1h"
-    cert = mksignedcert
-    assert_equal(60 * 60,  cert.not_after - cert.not_before)
-
-    Puppet[:ca_ttl] = "900s"
-    cert = mksignedcert
-    assert_equal(900,  cert.not_after - cert.not_before)
-
-    # This needs to be last, to make sure that setting ca_days
-    # overrides setting ca_ttl
-    Puppet[:ca_days] = 3
-    cert = mksignedcert
-    assert_equal(3 * 24 * 60 * 60,  cert.not_after - cert.not_before)
-
-  end
-end
-
Index: puppet-2.6.4/test/certmgr/inventory.rb
===================================================================
--- puppet-2.6.4.orig/test/certmgr/inventory.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppet'
-require 'puppettest/certificates'
-require 'puppet/sslcertificates/inventory.rb'
-require 'mocha'
-
-class TestCertInventory < Test::Unit::TestCase
-  include PuppetTest::Certificates
-
-  Inventory = Puppet::SSLCertificates::Inventory
-
-  def setup
-    super
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-  end
-
-  def test_format
-    cert = mksignedcert
-
-    format = nil
-    assert_nothing_raised do
-      format = Inventory.format(cert)
-    end
-
-
-      assert(
-        format =~ /^0x0001 \S+ \S+ #{cert.subject}/,
-
-        "Did not create correct format")
-    end
-
-  def test_init
-    # First create a couple of certificates
-    ca = mkCA
-
-    cert1 = mksignedcert(ca, "host1.madstop.com")
-    cert2 = mksignedcert(ca, "host2.madstop.com")
-
-    init = nil
-    assert_nothing_raised do
-      init = Inventory.init
-    end
-
-    [cert1, cert2].each do |cert|
-      assert(init.include?(cert.subject.to_s), "Did not catch #{cert.subject}")
-    end
-  end
-
-  def test_add
-    ca = mkCA
-    cert = mksignedcert(ca, "host.domain.com")
-
-    assert_nothing_raised do
-      file = mock
-      file.expects(:puts).with do |written|
-        written.include? cert.subject.to_s
-      end
-      Puppet::Util::Settings.any_instance.stubs(:write)
-      Puppet::Util::Settings.any_instance.expects(:write).
-        with(:cert_inventory, 'a').yields(file)
-
-      Puppet::SSLCertificates::Inventory.add(cert)
-    end
-  end
-end
-
Index: puppet-2.6.4/test/certmgr/support.rb
===================================================================
--- puppet-2.6.4.orig/test/certmgr/support.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,105 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/sslcertificates/support'
-require 'mocha'
-
-class TestCertSupport < Test::Unit::TestCase
-  include PuppetTest
-  MissingCertificate = Puppet::SSLCertificates::Support::MissingCertificate
-
-  class CertUser
-    include Puppet::SSLCertificates::Support
-  end
-
-  def setup
-    super
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    @user = CertUser.new
-    @ca = Puppet::SSLCertificates::CA.new
-    @client = Puppet::Network::Client.ca.new(:CA => @ca)
-  end
-
-  # Yay, metaprogramming
-  def test_keytype
-    [:key, :csr, :cert, :ca_cert].each do |name|
-      assert(Puppet::SSLCertificates::Support.method_defined?(name), "No retrieval method for #{name}")
-      maker = "mk_#{name}"
-      assert(Puppet::SSLCertificates::Support.method_defined?(maker), "No maker method for #{name}")
-    end
-  end
-
-  def test_keys
-    keys = [:hostprivkey, :hostpubkey].each { |n| Puppet[n] = tempfile }
-
-    key = nil
-    assert_nothing_raised do
-      key = @user.key
-    end
-
-    assert_logged(:info, /Creating a new SSL/, "Did not log about new key")
-    keys.each do |file|
-
-            assert(
-        FileTest.exists?(Puppet[file]),
-        
-        "Did not create #{file} key file")
-    end
-
-    # Make sure it's a valid key
-    assert_nothing_raised("Created key is invalid") do
-      OpenSSL::PKey::RSA.new(File.read(Puppet[:hostprivkey]))
-    end
-
-    # now make sure we can read it in
-    other = CertUser.new
-    assert_nothing_raised("Could not read key in") do
-      other.key
-    end
-
-    assert_equal(@user.key.to_s, other.key.to_s, "Keys are not equal")
-  end
-
-  def test_csr
-    csr = nil
-    assert_nothing_raised("Could not create csr") do
-      csr = @user.csr
-    end
-
-    assert(FileTest.exists?(Puppet[:hostcsr]), "did not create csr file")
-    assert_instance_of(OpenSSL::X509::Request, csr)
-  end
-
-  def test_cacert
-    @user = CertUser.new
-
-    assert_raise(MissingCertificate, "Did not fail when missing cacert") do
-      @user.ca_cert
-    end
-  end
-
-  # Fixing #1382.  This test will always fail on Darwin, because its
-  # FS is case-insensitive.
-  unless Facter.value(:operatingsystem) == "Darwin"
-    def test_uppercase_files_are_renamed_and_read
-      # Write a key out to disk in a file containing upper-case.
-      key = OpenSSL::PKey::RSA.new(32)
-      should_path = Puppet[:hostprivkey]
-
-      dir, file = File.split(should_path)
-      newfile = file.sub(/^([-a-z.0-9]+)\./) { $1.upcase + "."}
-      upper_path = File.join(dir, newfile)
-p upper_path
-      File.open(upper_path, "w") { |f| f.print key.to_s }
-
-      user = CertUser.new
-
-      assert_equal(key.to_s, user.read_key.to_s, "Did not read key in from disk")
-      assert(! FileTest.exist?(upper_path), "Upper case file was not removed")
-      assert(FileTest.exist?(should_path), "File was not renamed to lower-case file")
-      assert_equal(key.to_s, user.read_key.to_s, "Did not read key in from disk")
-    end
-  end
-end
Index: puppet-2.6.4/test/language/functions.rb
===================================================================
--- puppet-2.6.4.orig/test/language/functions.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/language/functions.rb	2011-11-01 10:51:35.099524856 +0100
@@ -4,7 +4,6 @@
 
 require 'puppet'
 require 'puppet/parser/parser'
-require 'puppet/network/client'
 require 'puppettest'
 require 'puppettest/resourcetesting'
 
Index: puppet-2.6.4/test/language/snippets.rb
===================================================================
--- puppet-2.6.4.orig/test/language/snippets.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/language/snippets.rb	2011-11-01 10:51:35.099524856 +0100
@@ -4,8 +4,6 @@
 
 require 'puppet'
 require 'puppet/parser/parser'
-require 'puppet/network/client'
-require 'puppet/network/handler'
 require 'puppettest'
 
 class TestSnippets < Test::Unit::TestCase
@@ -66,13 +64,6 @@
     ast
   end
 
-  def client
-    args = {
-      :Listen => false
-    }
-    Puppet::Network::Client.new(args)
-  end
-
   def ast2scope(ast)
     scope = Puppet::Parser::Scope.new
     ast.evaluate(scope)
Index: puppet-2.6.4/test/lib/puppettest/exetest.rb
===================================================================
--- puppet-2.6.4.orig/test/lib/puppettest/exetest.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/lib/puppettest/exetest.rb	2011-11-01 10:51:35.099524856 +0100
@@ -50,7 +50,7 @@
     args += " --confdir #{Puppet[:confdir]}"
     args += " --rundir #{File.join(Puppet[:vardir], "run")}"
     args += " --vardir #{Puppet[:vardir]}"
-    args += " --certdnsnames #{Puppet[:certdnsnames]}"
+    args += " --dns_alt_names #{Puppet[:master_dns_alt_names]}"
     args += " --masterport #{@@port}"
     args += " --user #{Puppet::Util::SUIDManager.uid}"
     args += " --group #{Puppet::Util::SUIDManager.gid}"
Index: puppet-2.6.4/test/lib/puppettest/servertest.rb
===================================================================
--- puppet-2.6.4.orig/test/lib/puppettest/servertest.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/lib/puppettest/servertest.rb	2011-11-01 10:51:35.100524888 +0100
@@ -1,5 +1,4 @@
 require 'puppettest'
-require 'puppet/network/http_server/webrick'
 
 module PuppetTest::ServerTest
   include PuppetTest
Index: puppet-2.6.4/test/network/client/ca.rb
===================================================================
--- puppet-2.6.4.orig/test/network/client/ca.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'mocha'
-require 'puppettest'
-require 'puppet/network/client/ca'
-require 'puppet/sslcertificates/support'
-
-class TestClientCA < Test::Unit::TestCase
-  include PuppetTest::ServerTest
-
-  def setup
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    super
-    @ca = Puppet::Network::Handler.ca.new
-    @client = Puppet::Network::Client.ca.new :CA => @ca
-  end
-
-  def test_request_cert
-    assert_nothing_raised("Could not request cert") do
-      @client.request_cert
-    end
-
-    [:hostprivkey, :hostcert, :localcacert].each do |name|
-      assert(FileTest.exists?(Puppet.settings[name]), "Did not create cert #{name}")
-    end
-  end
-
-  # Make sure the ca defaults to specific ports and names
-  def test_ca_server
-    Puppet.settings.stubs(:value).returns "eh"
-    Puppet.settings.expects(:value).with(:ca_server).returns("myca")
-    Puppet.settings.expects(:value).with(:ca_port).returns(321)
-    Puppet.settings.stubs(:value).with(:http_proxy_host).returns(nil)
-    Puppet.settings.stubs(:value).with(:http_proxy_port).returns(nil)
-    Puppet.settings.stubs(:value).with(:http_keepalive).returns(false)
-    Puppet.settings.stubs(:value).with(:configtimeout).returns(180)
-
-    # Just throw an error; the important thing is the values, not what happens next.
-    Net::HTTP.stubs(:new).with("myca", 321, nil, nil).raises(ArgumentError)
-    assert_raise(ArgumentError) { Puppet::Network::Client.ca.new }
-  end
-
-  # #578
-  def test_invalid_certs_are_not_written
-    # Run the get once, which should be valid
-
-    assert_nothing_raised("Could not get a certificate") do
-      @client.request_cert
-    end
-
-    # Now remove the cert and keys, so we get a broken cert
-    File.unlink(Puppet[:hostcert])
-    File.unlink(Puppet[:localcacert])
-    File.unlink(Puppet[:hostprivkey])
-
-    @client = Puppet::Network::Client.ca.new :CA => @ca
-    @ca.expects(:getcert).returns("yay") # not a valid cert
-    # Now make sure it fails, since we'll get the old cert but have new keys
-    assert_raise(Puppet::Network::Client::CA::InvalidCertificate, "Did not fail on invalid cert") do
-      @client.request_cert
-    end
-
-    # And then make sure the cert isn't written to disk
-    assert(! FileTest.exists?(Puppet[:hostcert]), "Invalid cert got written to disk")
-  end
-end
-
Index: puppet-2.6.4/test/network/client/dipper.rb
===================================================================
--- puppet-2.6.4.orig/test/network/client/dipper.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/file_bucket/dipper'
-
-class TestDipperClient < Test::Unit::TestCase
-  include PuppetTest::ServerTest
-
-  def setup
-    super
-    @dipper = Puppet::FileBucket::Dipper.new(:Path => tempfile)
-  end
-
-  # Make sure we can create a new file with 'restore'.
-  def test_restore_to_new_file
-    file = tempfile
-    text = "asdf;lkajseofiqwekj"
-    File.open(file, "w") { |f| f.puts text }
-    md5 = nil
-    assert_nothing_raised("Could not send file") do
-      md5 = @dipper.backup(file)
-    end
-
-    newfile = tempfile
-    assert_nothing_raised("could not restore to new path") do
-      @dipper.restore(newfile, md5)
-    end
-
-    assert_equal(File.read(file), File.read(newfile), "did not restore correctly")
-  end
-end
-
Index: puppet-2.6.4/test/network/handler/ca.rb
===================================================================
--- puppet-2.6.4.orig/test/network/handler/ca.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,273 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/network/handler/ca'
-require 'mocha'
-
-$short = (ARGV.length > 0 and ARGV[0] == "short")
-
-class TestCA < Test::Unit::TestCase
-  include PuppetTest::ServerTest
-
-  def setup
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    super
-  end
-
-  # Verify that we're autosigning.  We have to autosign a "different" machine,
-  # since we always autosign the CA server's certificate.
-  def test_autocertgeneration
-    ca = nil
-
-    # create our ca
-    assert_nothing_raised {
-      ca = Puppet::Network::Handler.ca.new(:autosign => true)
-    }
-
-    # create a cert with a fake name
-    key = nil
-    csr = nil
-    cert = nil
-    hostname = "test.domain.com"
-    assert_nothing_raised {
-      cert = Puppet::SSLCertificates::Certificate.new(
-        :name => "test.domain.com"
-      )
-    }
-
-    # make the request
-    assert_nothing_raised {
-      cert.mkcsr
-    }
-
-    # and get it signed
-    certtext = nil
-    cacerttext = nil
-    assert_nothing_raised {
-      certtext, cacerttext = ca.getcert(cert.csr.to_s)
-    }
-
-    # they should both be strings
-    assert_instance_of(String, certtext)
-    assert_instance_of(String, cacerttext)
-
-    # and they should both be valid certs
-    assert_nothing_raised {
-      OpenSSL::X509::Certificate.new(certtext)
-    }
-    assert_nothing_raised {
-      OpenSSL::X509::Certificate.new(cacerttext)
-    }
-
-    # and pull it again, just to make sure we're getting the same thing
-    newtext = nil
-    assert_nothing_raised {
-      newtext, cacerttext = ca.getcert(
-        cert.csr.to_s, "test.reductivelabs.com", "127.0.0.1"
-      )
-    }
-
-    assert_equal(certtext,newtext)
-  end
-
-  # this time don't use autosign
-  def test_storeAndSign
-    ca = nil
-    caserv = nil
-
-    # make our CA server
-    assert_nothing_raised {
-      caserv = Puppet::Network::Handler.ca.new(:autosign => false)
-    }
-
-    # retrieve the actual ca object
-    assert_nothing_raised {
-      ca = caserv.ca
-    }
-
-    # make our test cert again
-    key = nil
-    csr = nil
-    cert = nil
-    hostname = "test.domain.com"
-    assert_nothing_raised {
-      cert = Puppet::SSLCertificates::Certificate.new(
-        :name => "anothertest.domain.com"
-      )
-    }
-    # and the CSR
-    assert_nothing_raised {
-      cert.mkcsr
-    }
-
-    # retrieve them
-    certtext = nil
-    assert_nothing_raised {
-      certtext, cacerttext = caserv.getcert(
-        cert.csr.to_s, "test.reductivelabs.com", "127.0.0.1"
-      )
-    }
-
-    # verify we got nothing back, since autosign is off
-    assert_equal("", certtext)
-
-    # now sign it manually, with the CA object
-    x509 = nil
-    assert_nothing_raised {
-      x509, cacert = ca.sign(cert.csr)
-    }
-
-    # and write it out
-    cert.cert = x509
-    assert_nothing_raised {
-      cert.write
-    }
-
-    assert(File.exists?(cert.certfile))
-
-    # now get them again, and verify that we actually get them
-    newtext = nil
-    assert_nothing_raised {
-      newtext, cacerttext  = caserv.getcert(cert.csr.to_s)
-    }
-
-    assert(newtext)
-    assert_nothing_raised {
-      OpenSSL::X509::Certificate.new(newtext)
-    }
-
-    # Now verify that we can clean a given host's certs
-    assert_nothing_raised {
-      ca.clean("anothertest.domain.com")
-    }
-
-    assert(!File.exists?(cert.certfile), "Cert still exists after clean")
-  end
-
-  # and now test the autosign file
-  def test_autosign
-    autosign = File.join(tmpdir, "autosigntesting")
-    @@tmpfiles << autosign
-    File.open(autosign, "w") { |f|
-      f.puts "hostmatch.domain.com"
-      f.puts "*.other.com"
-    }
-
-    caserv = nil
-    assert_nothing_raised {
-      caserv = Puppet::Network::Handler.ca.new(:autosign => autosign)
-    }
-
-    # make sure we know what's going on
-    assert(caserv.autosign?("hostmatch.domain.com"))
-    assert(caserv.autosign?("fakehost.other.com"))
-    assert(!caserv.autosign?("kirby.reductivelabs.com"))
-    assert(!caserv.autosign?("culain.domain.com"))
-  end
-
-  # verify that things aren't autosigned by default
-  def test_nodefaultautosign
-    caserv = nil
-    assert_nothing_raised {
-      caserv = Puppet::Network::Handler.ca.new
-    }
-
-    # make sure we know what's going on
-    assert(!caserv.autosign?("hostmatch.domain.com"))
-    assert(!caserv.autosign?("fakehost.other.com"))
-    assert(!caserv.autosign?("kirby.reductivelabs.com"))
-    assert(!caserv.autosign?("culain.domain.com"))
-  end
-
-  # We want the CA to autosign its own certificate, because otherwise
-  # the puppetmasterd CA does not autostart.
-  def test_caautosign
-    server = nil
-    Puppet.stubs(:master?).returns true
-    assert_nothing_raised {
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @@port,
-        
-        :Handlers => {
-          :CA => {}, # so that certs autogenerate
-          :Status => nil
-        }
-      )
-    }
-  end
-
-  # Make sure true/false causes the file to be ignored.
-  def test_autosign_true_beats_file
-    caserv = nil
-    assert_nothing_raised {
-      caserv = Puppet::Network::Handler.ca.new
-    }
-
-    host = "hostname.domain.com"
-
-    # Create an autosign file
-    file = tempfile
-    Puppet[:autosign] = file
-
-    File.open(file, "w") { |f|
-      f.puts host
-    }
-
-    # Start with "false"
-    Puppet[:autosign] = false
-
-    assert(! caserv.autosign?(host), "Host was incorrectly autosigned")
-
-    # Then set it to true
-    Puppet[:autosign] = true
-    assert(caserv.autosign?(host), "Host was not autosigned")
-    # And try a different host
-    assert(caserv.autosign?("other.yay.com"), "Host was not autosigned")
-
-    # And lastly the file
-    Puppet[:autosign] = file
-    assert(caserv.autosign?(host), "Host was not autosigned")
-
-    # And try a different host
-    assert(! caserv.autosign?("other.yay.com"), "Host was autosigned")
-  end
-
-  # Make sure that a CSR created with keys that don't match the existing
-  # cert throws an exception on the server.
-  def test_mismatched_public_keys_throws_exception
-    ca = Puppet::Network::Handler.ca.new
-
-    # First initialize the server
-    client = Puppet::Network::Client.ca.new :CA => ca
-    client.request_cert
-    File.unlink(Puppet[:hostcsr])
-
-    # Now use a different cert name
-    Puppet[:certname] = "my.host.com"
-    client = Puppet::Network::Client.ca.new :CA => ca
-    firstcsr = client.csr
-    File.unlink(Puppet[:hostcsr]) if FileTest.exists?(Puppet[:hostcsr])
-
-    assert_nothing_raised("Could not get cert") do
-      ca.getcert(firstcsr.to_s)
-    end
-
-    # Now get rid of the public key, forcing a new csr
-    File.unlink(Puppet[:hostprivkey])
-
-    client = Puppet::Network::Client.ca.new :CA => ca
-
-    second_csr = client.csr
-
-    assert(firstcsr.to_s != second_csr.to_s, "CSR did not change")
-
-    assert_raise(Puppet::Error, "CA allowed mismatched keys") do
-      ca.getcert(second_csr.to_s)
-    end
-  end
-end
-
Index: puppet-2.6.4/test/network/server/mongrel_test.rb
===================================================================
--- puppet-2.6.4.orig/test/network/server/mongrel_test.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,105 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'mocha'
-
-class TestMongrelServer < PuppetTest::TestCase
-  confine "Missing mongrel" => Puppet.features.mongrel?
-
-  include PuppetTest::ServerTest
-
-  def mkserver(handlers = nil)
-    handlers ||= { :Status => nil }
-    mongrel = Puppet::Network::HTTPServer::Mongrel.new(handlers)
-  end
-
-  # Make sure client info is correctly extracted.
-  def test_client_info
-    obj = Object.new
-    obj.singleton_class.send(:attr_accessor, :params)
-    params = {}
-    obj.params = params
-
-    mongrel = mkserver
-
-    ip = Facter.value(:ipaddress)
-    params["REMOTE_ADDR"] = ip
-    params[Puppet[:ssl_client_header]] = ""
-    params[Puppet[:ssl_client_verify_header]] = "failure"
-    info = nil
-    Resolv.expects(:getname).with(ip).returns("host.domain.com").times(4)
-    assert_nothing_raised("Could not call client_info") do
-      info = mongrel.send(:client_info, obj)
-    end
-    assert(! info.authenticated?, "Client info object was marked valid even though headers were missing")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-
-    assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
-    # Now pass the X-Forwarded-For header and check it is preferred over REMOTE_ADDR
-    params["REMOTE_ADDR"] = '127.0.0.1'
-    params["HTTP_X_FORWARDED_FOR"] = ip
-    info = nil
-    assert_nothing_raised("Could not call client_info") do
-      info = mongrel.send(:client_info, obj)
-    end
-    assert(! info.authenticated?, "Client info object was marked valid even though headers were missing")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-
-    assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
-    # Now add a valid auth header.
-    params["REMOTE_ADDR"] = ip
-    params["HTTP_X_FORWARDED_FOR"] = nil
-    params[Puppet[:ssl_client_header]] = "/CN=host.domain.com"
-    assert_nothing_raised("Could not call client_info") do
-      info = mongrel.send(:client_info, obj)
-    end
-    assert(! info.authenticated?, "Client info object was marked valid even though the verify header was fals")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-    assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
-    # Now change the verify header to be true
-    params[Puppet[:ssl_client_verify_header]] = "SUCCESS"
-    assert_nothing_raised("Could not call client_info") do
-      info = mongrel.send(:client_info, obj)
-    end
-
-    assert(info.authenticated?, "Client info object was not marked valid even though all headers were correct")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-    assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
-    # Now try it with a different header name
-    params.delete(Puppet[:ssl_client_header])
-    Puppet[:ssl_client_header] = "header_testing"
-    params["header_testing"] = "/CN=other.domain.com"
-    info = nil
-    assert_nothing_raised("Could not call client_info with other header") do
-      info = mongrel.send(:client_info, obj)
-    end
-
-    assert(info.authenticated?, "Client info object was not marked valid even though the header was present")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-    assert_equal("other.domain.com", info.name, "Did not copy over hostname correctly")
-
-    # Now make sure it's considered invalid without that header
-    params.delete("header_testing")
-    info = nil
-    assert_nothing_raised("Could not call client_info with no header") do
-      info = mongrel.send(:client_info, obj)
-    end
-
-    assert(! info.authenticated?, "Client info object was marked valid without header")
-    assert_equal(ip, info.ip, "Did not copy over ip correctly")
-    assert_equal(Resolv.getname(ip), info.name, "Did not look up hostname correctly")
-  end
-
-  def test_daemonize
-    mongrel = mkserver
-
-    assert(mongrel.respond_to?(:daemonize), "Mongrel server does not respond to daemonize")
-  end
-end
-
Index: puppet-2.6.4/test/network/server/webrick.rb
===================================================================
--- puppet-2.6.4.orig/test/network/server/webrick.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,128 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/network/http_server/webrick'
-require 'mocha'
-
-class TestWebrickServer < Test::Unit::TestCase
-  include PuppetTest::ServerTest
-
-  def setup
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    super
-  end
-
-  def teardown
-    super
-    Puppet::Network::HttpPool.clear_http_instances
-  end
-
-  # Make sure we can create a server, and that it knows how to create its
-  # certs by default.
-  def test_basics
-    server = nil
-    assert_raise(Puppet::Error, "server succeeded with no cert") do
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @@port,
-        
-        :Handlers => {
-          :Status => nil
-        }
-      )
-    end
-
-    assert_nothing_raised("Could not create simple server") do
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @@port,
-        
-        :Handlers => {
-          :CA => {}, # so that certs autogenerate
-          :Status => nil
-        }
-      )
-    end
-
-    assert(server, "did not create server")
-
-    assert(server.cert, "did not retrieve cert")
-  end
-
-  # test that we can connect to the server
-  # we have to use fork here, because we apparently can't use threads
-  # to talk to other threads
-  def test_connect_with_fork
-    Puppet[:autosign] = true
-    serverpid, server = mk_status_server
-
-    # create a status client, and verify it can talk
-    client = mk_status_client
-
-    assert(client.cert, "did not get cert for client")
-
-    retval = nil
-    assert_nothing_raised("Could not connect to server") {
-      retval = client.status
-    }
-    assert_equal(1, retval)
-  end
-
-  def mk_status_client
-    client = nil
-
-    assert_nothing_raised {
-
-            client = Puppet::Network::Client.status.new(
-                
-        :Server => "localhost",
-        
-        :Port => @@port
-      )
-    }
-    client
-  end
-
-  def mk_status_server
-    server = nil
-    Puppet[:certdnsnames] = "localhost"
-    assert_nothing_raised {
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @@port,
-        
-        :Handlers => {
-          :CA => {}, # so that certs autogenerate
-          :Status => nil
-        }
-      )
-
-    }
-
-    pid = fork {
-      Puppet.run_mode.stubs(:master?).returns true
-      assert_nothing_raised {
-        trap(:INT) { server.shutdown }
-        server.start
-      }
-    }
-    @@tmppids << pid
-    [pid, server]
-  end
-
-  def kill_and_wait(pid, file)
-    %x{kill -INT #{pid} 2>/dev/null}
-    count = 0
-    while count < 30 && File::exist?(file)
-      count += 1
-      sleep(1)
-    end
-    assert(count < 30, "Killing server #{pid} failed")
-  end
-end
-
Index: puppet-2.6.4/test/network/xmlrpc/client.rb
===================================================================
--- puppet-2.6.4.orig/test/network/xmlrpc/client.rb	2010-12-01 00:42:03.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/network/xmlrpc/client'
-require 'mocha'
-
-class TestXMLRPCClient < Test::Unit::TestCase
-  include PuppetTest
-
-  def setup
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    super
-  end
-
-  def test_set_backtrace
-    error = Puppet::Network::XMLRPCClientError.new("An error")
-    assert_nothing_raised do
-      error.set_backtrace ["caller"]
-    end
-    assert_equal(["caller"], error.backtrace)
-  end
-
-  # Make sure we correctly generate a netclient
-  def test_handler_class
-    # Create a test handler
-    klass = Puppet::Network::XMLRPCClient
-    yay = Class.new(Puppet::Network::Handler) do
-      @interface = XMLRPC::Service::Interface.new("yay") { |iface|
-        iface.add_method("array getcert(csr)")
-      }
-
-      @name = :Yay
-    end
-    Object.const_set("Yay", yay)
-
-    net = nil
-    assert_nothing_raised("Failed when retrieving client for handler") do
-      net = klass.handler_class(yay)
-    end
-
-    assert(net, "did not get net client")
-  end
-end
Index: puppet-2.6.4/test/rails/rails.rb
===================================================================
--- puppet-2.6.4.orig/test/rails/rails.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/rails/rails.rb	2011-11-01 10:51:35.101524918 +0100
@@ -5,7 +5,6 @@
 require 'puppet'
 require 'puppet/rails'
 require 'puppet/parser/parser'
-require 'puppet/network/client'
 require 'puppettest'
 require 'puppettest/parsertesting'
 require 'puppettest/resourcetesting'
Index: puppet-2.6.4/test/ral/type/filesources.rb
===================================================================
--- puppet-2.6.4.orig/test/ral/type/filesources.rb	2010-12-01 00:42:03.000000000 +0100
+++ puppet-2.6.4/test/ral/type/filesources.rb	2011-11-01 10:51:35.102524947 +0100
@@ -227,66 +227,6 @@
     file
   end
 
-  def test_unmountedNetworkSources
-    server = nil
-    mounts = {
-      "/" => "root",
-      "/noexistokay" => "noexist"
-    }
-
-    fileserverconf = mkfileserverconf(mounts)
-
-    Puppet[:autosign] = true
-    Puppet[:masterport] = @port
-    Puppet[:certdnsnames] = "localhost"
-
-    serverpid = nil
-    assert_nothing_raised("Could not start on port #{@port}") {
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @port,
-        
-        :Handlers => {
-          :CA => {}, # so that certs autogenerate
-          :FileServer => {
-            :Config => fileserverconf
-          }
-        }
-      )
-
-    }
-
-    serverpid = fork {
-      assert_nothing_raised {
-        #trap(:INT) { server.shutdown; Kernel.exit! }
-        trap(:INT) { server.shutdown }
-        server.start
-      }
-    }
-    @@tmppids << serverpid
-
-    sleep(1)
-
-    name = File.join(tmpdir, "nosourcefile")
-
-          file = Puppet::Type.type(:file).new(
-                
-      :source => "puppet://localhost/noexist/file",
-        
-      :name => name
-    )
-
-    assert_raise Puppet::Error do
-      file.retrieve
-    end
-
-    comp = mk_catalog(file)
-    comp.apply
-
-    assert(!FileTest.exists?(name), "File with no source exists anyway")
-  end
-
   def test_sourcepaths
     files = []
     3.times {
openSUSE Build Service is sponsored by