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
|
# File 'lib/puppet/functions/complyadm/generate_cert_chain.rb', line 4
Puppet::Functions.create_function(:'complyadm::generate_cert_chain') do
dispatch :generate do
param 'String', :hostname
end
def generate(hostname)
ca_key = create_private_key
ca_cert = create_self_signed_ca(ca_key, "/CN=Comply CA: #{hostname}")
ca_crl = create_crl_for(ca_cert, ca_key)
host_key = create_private_key
host_csr = create_csr(host_key, "/CN=#{hostname}")
host_cert = sign(hostname, ca_key, ca_cert, host_csr)
{
'crl' => ca_crl.to_s,
'private_key' => host_key.to_s,
'cert_chain' => "#{host_cert}#{ca_cert}"
}
end
PRIVATE_KEY_LENGTH = 4096
FIFTEEN_YEARS_SECONDS = 15 * 365 * 24 * 60 * 60
SSL_SERVER_CERT_OID = '1.3.6.1.5.5.7.3.1'.freeze
CA_EXTENSIONS = [
['basicConstraints', 'CA:TRUE', true],
['keyUsage', 'keyCertSign, cRLSign', true],
['subjectKeyIdentifier', 'hash', false],
['authorityKeyIdentifier', 'keyid:always', false],
].freeze
SERVER_EXTENSIONS = [
['keyUsage', 'digitalSignature,keyEncipherment', true],
['subjectKeyIdentifier', 'hash', false],
['extendedKeyUsage', SSL_SERVER_CERT_OID.to_s, true],
].freeze
DEFAULT_SIGNING_DIGEST = OpenSSL::Digest::SHA256.new
def create_private_key
OpenSSL::PKey::RSA.new(PRIVATE_KEY_LENGTH)
end
def create_self_signed_ca(key, name)
cert = OpenSSL::X509::Certificate.new
cert.public_key = key.public_key
cert.subject = OpenSSL::X509::Name.parse(name)
cert.issuer = cert.subject
cert.version = 2
cert.serial = rand(2**128)
not_before = just_now
cert.not_before = not_before
cert.not_after = not_before + FIFTEEN_YEARS_SECONDS
ext_factory = extension_factory_for(cert, cert)
CA_EXTENSIONS.each do |ext|
extension = ext_factory.create_extension(*ext)
cert.add_extension(extension)
end
cert.sign(key, DEFAULT_SIGNING_DIGEST)
cert
end
def create_csr(key, name)
csr = OpenSSL::X509::Request.new
csr.public_key = key.public_key
csr.subject = OpenSSL::X509::Name.parse(name)
csr.version = 2
csr.sign(key, DEFAULT_SIGNING_DIGEST)
csr
end
def sign(hostname, ca_key, ca_cert, csr)
cert = OpenSSL::X509::Certificate.new
cert.public_key = csr.public_key
cert.subject = csr.subject
cert.issuer = ca_cert.subject
cert.version = 2
cert.serial = rand(2**128)
not_before = just_now
cert.not_before = not_before
cert.not_after = not_before + FIFTEEN_YEARS_SECONDS
ext_factory = extension_factory_for(ca_cert, cert)
SERVER_EXTENSIONS.each do |ext|
extension = ext_factory.create_extension(*ext)
cert.add_extension(extension)
end
type_string = if (hostname =~ Resolv::IPv4::Regex) || (hostname =~ Resolv::IPv6::Regex)
'IP'
else
'DNS'
end
alt_names_ext = ext_factory.create_extension('subjectAltName', "#{type_string}:#{hostname}", false)
cert.add_extension(alt_names_ext)
cert.sign(ca_key, DEFAULT_SIGNING_DIGEST)
cert
end
def just_now
Time.now - 60
end
def create_crl_for(cert, key)
crl = OpenSSL::X509::CRL.new
crl.version = 1
crl.issuer = cert.subject
ef = extension_factory_for(cert)
crl.add_extension(ef.create_extension(['authorityKeyIdentifier', 'keyid:always', false]))
crl.add_extension(OpenSSL::X509::Extension.new('crlNumber', OpenSSL::ASN1::Integer(0)))
crl.last_update = just_now
crl.next_update = just_now + FIFTEEN_YEARS_SECONDS
crl.sign(key, DEFAULT_SIGNING_DIGEST)
crl
end
def extension_factory_for(ca, cert = nil)
ef = OpenSSL::X509::ExtensionFactory.new
ef.issuer_certificate = ca
ef.subject_certificate = cert if cert
ef
end
end
|