# File lib/puppet/sslcertificates.rb, line 9
  9:   def self.mkcert(hash)
 10:     [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
 11:       raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
 12:     }
 13: 
 14:     cert = OpenSSL::X509::Certificate.new
 15:     # Make the certificate valid as of yesterday, because
 16:     # so many people's clocks are out of sync.
 17:     from = Time.now - (60*60*24)
 18: 
 19:     cert.subject = hash[:name]
 20:     if hash[:issuer]
 21:       cert.issuer = hash[:issuer].subject
 22:     else
 23:       # we're a self-signed cert
 24:       cert.issuer = hash[:name]
 25:     end
 26:     cert.not_before = from
 27:     cert.not_after = from + hash[:ttl]
 28:     cert.version = 2 # X509v3
 29: 
 30:     cert.public_key = hash[:publickey]
 31:     cert.serial = hash[:serial]
 32: 
 33:     basic_constraint = nil
 34:     key_usage = nil
 35:     ext_key_usage = nil
 36:     subject_alt_name = []
 37: 
 38:     ef = OpenSSL::X509::ExtensionFactory.new
 39: 
 40:     ef.subject_certificate = cert
 41: 
 42:     if hash[:issuer]
 43:       ef.issuer_certificate = hash[:issuer]
 44:     else
 45:       ef.issuer_certificate = cert
 46:     end
 47: 
 48:     ex = []
 49:     case hash[:type]
 50:     when :ca
 51:       basic_constraint = "CA:TRUE"
 52:       key_usage = %w{cRLSign keyCertSign}
 53:     when :terminalsubca
 54:       basic_constraint = "CA:TRUE,pathlen:0"
 55:       key_usage = %w{cRLSign keyCertSign}
 56:     when :server
 57:       basic_constraint = "CA:FALSE"
 58:       dnsnames = Puppet[:certdnsnames]
 59:       name = hash[:name].to_s.sub(%r{/CN=},'')
 60:       if dnsnames != ""
 61:         dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
 62:         subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
 63:       elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
 64:         subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
 65:         subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
 66:         subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
 67:       end
 68:       key_usage = %w{digitalSignature keyEncipherment}
 69:       ext_key_usage = %w{serverAuth clientAuth emailProtection}
 70:     when :ocsp
 71:       basic_constraint = "CA:FALSE"
 72:       key_usage = %w{nonRepudiation digitalSignature}
 73:       ext_key_usage = %w{serverAuth OCSPSigning}
 74:     when :client
 75:       basic_constraint = "CA:FALSE"
 76:       key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
 77:       ext_key_usage = %w{clientAuth emailProtection}
 78:       ex << ef.create_extension("nsCertType", "client,email")
 79:     else
 80:       raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
 81:     end
 82: 
 83: 
 84:       ex << ef.create_extension(
 85:         "nsComment",
 86: 
 87:           "Puppet Ruby/OpenSSL Generated Certificate")
 88:     ex << ef.create_extension("basicConstraints", basic_constraint, true)
 89:     ex << ef.create_extension("subjectKeyIdentifier", "hash")
 90: 
 91:     ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
 92:     ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
 93:     ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
 94: 
 95:     #if @ca_config[:cdp_location] then
 96:     #  ex << ef.create_extension("crlDistributionPoints",
 97:     #                            @ca_config[:cdp_location])
 98:     #end
 99: 
100:     #if @ca_config[:ocsp_location] then
101:     #  ex << ef.create_extension("authorityInfoAccess",
102:     #                            "OCSP;" << @ca_config[:ocsp_location])
103:     #end
104:     cert.extensions = ex
105: 
106:     # for some reason this _must_ be the last extension added
107:     ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
108: 
109:     cert
110:   end