52
56
csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
53
57
csr.public_key = key.public_key
59
if options[:dns_alt_names] then
60
names = options[:dns_alt_names].split(/\s*,\s*/).map(&:strip) + [name]
61
names = names.sort.uniq.map {|name| "DNS:#{name}" }.join(", ")
62
names = extension_factory.create_extension("subjectAltName", names, false)
64
extReq = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([names])])
66
# We only support the standard request extensions. If you really need
67
# msExtReq support, let us know and we can restore them. --daniel 2011-10-10
68
csr.add_attribute(OpenSSL::X509::Attribute.new("extReq", extReq))
54
71
csr.sign(key, OpenSSL::Digest::MD5.new)
56
73
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)
59
76
Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
80
# Return the set of extensions requested on this CSR, in a form designed to
81
# be useful to Ruby: a hash. Which, not coincidentally, you can pass
82
# successfully to the OpenSSL constructor later, if you want.
83
def request_extensions
84
raise Puppet::Error, "CSR needs content to extract fields" unless @content
86
# Prefer the standard extReq, but accept the Microsoft specific version as
87
# a fallback, if the standard version isn't found.
88
ext = @content.attributes.find {|x| x.oid == "extReq" } or
89
@content.attributes.find {|x| x.oid == "msExtReq" }
92
# Assert the structure and extract the names into an array of arrays.
93
unless ext.value.is_a? OpenSSL::ASN1::Set
94
raise Puppet::Error, "In #{ext.oid}, expected Set but found #{ext.value.class}"
97
unless ext.value.value.is_a? Array
98
raise Puppet::Error, "In #{ext.oid}, expected Set[Array] but found #{ext.value.value.class}"
101
unless ext.value.value.length == 1
102
raise Puppet::Error, "In #{ext.oid}, expected Set[Array[...]], but found #{ext.value.value.length} items in the array"
105
san = ext.value.value.first
106
unless san.is_a? OpenSSL::ASN1::Sequence
107
raise Puppet::Error, "In #{ext.oid}, expected Set[Array[Sequence[...]]], but found #{san.class}"
111
# OK, now san should be the array of items, validate that...
116
unless name.is_a? OpenSSL::ASN1::Sequence
117
raise Puppet::Error, "In #{ext.oid}, expected request extension record #{index} to be a Sequence, but found #{name.class}"
121
# OK, turn that into an extension, to unpack the content. Lovely that
122
# we have to swap the order of arguments to the underlying method, or
123
# perhaps that the ASN.1 representation chose to pack them in a
124
# strange order where the optional component comes *earlier* than the
125
# fixed component in the sequence.
128
ev = OpenSSL::X509::Extension.new(name[0].value, name[1].value)
129
{ "oid" => ev.oid, "value" => ev.value }
132
ev = OpenSSL::X509::Extension.new(name[0].value, name[2].value, name[1].value)
133
{ "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
136
raise Puppet::Error, "In #{ext.oid}, expected extension record #{index} to have two or three items, but found #{name.length}"
141
def subject_alt_names
142
@subject_alt_names ||= request_extensions.
143
select {|x| x["oid"] = "subjectAltName" }.
144
map {|x| x["value"].split(/\s*,\s*/) }.