summaryrefslogtreecommitdiffstats
path: root/lib/puppet/sslcertificates.rb
blob: 357959d0b7a7465017b2947dbb6cdcc86dab08e2 (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
# The library for manipulating SSL certs.

require 'puppet'

begin
    require 'openssl'
rescue LoadError
    raise Puppet::Error, "You must have the Ruby openssl library installed"
end

module Puppet::SSLCertificates
    #def self.mkcert(type, name, ttl, issuercert, issuername, serial, publickey)
    def self.mkcert(hash)
        [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
            unless hash.include?(param)
                raise ArgumentError, "mkcert called without %s" % param
            end
        }

        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

        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"
            key_usage = %w{digitalSignature keyEncipherment}
        ext_key_usage = %w{serverAuth clientAuth}
        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 '%s'" % 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")

        if key_usage
          ex << ef.create_extension("keyUsage", key_usage.join(","))
        end
        if ext_key_usage
          ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(","))
        end

        #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
        if hash[:type] == :ca
            ex << ef.create_extension("authorityKeyIdentifier",
                                      "keyid:always,issuer:always")
        end

        return 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, "%s.%s" % [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
        }


        return hashpath
    end
    require 'puppet/sslcertificates/certificate'
    require 'puppet/sslcertificates/inventory'
    require 'puppet/sslcertificates/ca'
end

# $Id$