summaryrefslogtreecommitdiffstats
path: root/lib/puppet/sslcertificates.rb
blob: 4e941244ead5a1e9966e886dee6726ad4b8b5f0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# 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