Module: Chef::Resource::SslCertificate::Generators

Included in:
CACertificate, Chef::Resource::SslCertificate
Defined in:
libraries/resource_ssl_certificate_generators.rb

Overview

ssl_certificate Chef Resource cert generator helpers.

Constant Summary collapse

FIELDS =
{
  country: {
    field: 'C',
    type: OpenSSL::ASN1::PRINTABLESTRING
  },
  state: {
    field: 'ST',
    type: OpenSSL::ASN1::PRINTABLESTRING
  },
  city: {
    field: 'L',
    type: OpenSSL::ASN1::PRINTABLESTRING
  },
  organization: {
    field: 'O',
    type: OpenSSL::ASN1::UTF8STRING
  },
  department: {
    field: 'OU',
    type: OpenSSL::ASN1::UTF8STRING
  },
  common_name: {
    field: 'CN',
    type: OpenSSL::ASN1::UTF8STRING
  },
  email: {
    field: 'emailAddress',
    type: OpenSSL::ASN1::UTF8STRING
  }
}.freeze
EXTENSIONS =
{
  without_ca: [
    ['basicConstraints', 'CA:TRUE', true],
    ['subjectKeyIdentifier', 'hash', false],
    ['authorityKeyIdentifier', 'keyid:always,issuer:always', false]
  ],
  with_ca: [
    %w(basicConstraints CA:FALSE),
    %w(subjectKeyIdentifier hash),
    %w(keyUsage keyEncipherment,dataEncipherment,digitalSignature)
  ]
}.freeze

Instance Method Summary collapse

Instance Method Details

#cert_add_extensions(cert, ef, extensions) ⇒ Object


131
132
133
134
135
# File 'libraries/resource_ssl_certificate_generators.rb', line 131

def cert_add_extensions(cert, ef, extensions)
  extensions.each do |ext|
    cert.add_extension(ef.create_extension(*ext))
  end
end

#compare_self_signed_cert_with_ca(_key, cert, ca_cert_content) ⇒ Object


250
251
252
253
254
255
256
257
# File 'libraries/resource_ssl_certificate_generators.rb', line 250

def compare_self_signed_cert_with_ca(_key, cert, ca_cert_content)
  cur_subject, new_subject = load_current_subjects(cert)

  log_debug_subjects(cur_subject, new_subject)
  ca_cert = OpenSSL::X509::Certificate.new(ca_cert_content)
  cur_subject.cmp(new_subject) == 0 &&
    cert.issuer.cmp(ca_cert.subject) && cert.verify(ca_cert.public_key)
end

#compare_self_signed_cert_without_ca(key, cert) ⇒ Object


259
260
261
262
263
264
265
266
# File 'libraries/resource_ssl_certificate_generators.rb', line 259

def compare_self_signed_cert_without_ca(key, cert)
  cur_subject, new_subject = load_current_subjects(cert)

  log_debug_subjects(cur_subject, new_subject)
  key.params['n'] == cert.public_key.params['n'] &&
    cur_subject.cmp(new_subject) == 0 &&
    cert.issuer.cmp(cur_subject) == 0
end

#generate_ca_from_content(cert_content, key_content) ⇒ Object


168
169
170
171
172
# File 'libraries/resource_ssl_certificate_generators.rb', line 168

def generate_ca_from_content(cert_content, key_content)
  ca_cert = OpenSSL::X509::Certificate.new(cert_content)
  ca_key = OpenSSL::PKey::RSA.new(key_content, ca_key_passphrase)
  [ca_cert, ca_key]
end

#generate_cert(key, subject, time, ca_cert_content = nil, ca_key_content = nil) ⇒ Object


206
207
208
209
210
211
212
213
214
215
216
217
# File 'libraries/resource_ssl_certificate_generators.rb', line 206

def generate_cert(key, subject, time, ca_cert_content = nil,
                  ca_key_content = nil)

  key, cert = generate_generic_x509_key_cert(key, time)
  if ca_cert_content && ca_key_content
    generate_self_signed_cert_with_ca(
      key, cert, subject, ca_cert_content, ca_key_content
    ).to_pem
  else
    generate_self_signed_cert_without_ca(key, cert, subject).to_pem
  end
end

#generate_cert_subject(s) ⇒ Object


101
102
103
104
105
106
107
108
109
# File 'libraries/resource_ssl_certificate_generators.rb', line 101

def generate_cert_subject(s)
  name =
    if s.is_a?(Hash)
      generate_cert_subject_from_hash(s)
    else
      generate_cert_subject_from_string(s)
    end
  OpenSSL::X509::Name.new(name)
end

#generate_cert_subject_from_hash(s) ⇒ Object


92
93
94
95
96
97
98
99
# File 'libraries/resource_ssl_certificate_generators.rb', line 92

def generate_cert_subject_from_hash(s)
  Generators::FIELDS.each_with_object([]) do |(name, info), mem|
    name = name.to_s
    field = info[:field]
    type = info[:type]
    mem.push([field, s[name].to_s, type]) unless s[name].nil?
  end
end

#generate_cert_subject_from_string(s) ⇒ Object


88
89
90
# File 'libraries/resource_ssl_certificate_generators.rb', line 88

def generate_cert_subject_from_string(s)
  [['CN', s.to_s, OpenSSL::ASN1::UTF8STRING]]
end

#generate_csr(key, subject) ⇒ Object


111
112
113
114
115
116
117
118
# File 'libraries/resource_ssl_certificate_generators.rb', line 111

def generate_csr(key, subject)
  csr = OpenSSL::X509::Request.new
  csr.version = 0
  csr.subject = generate_cert_subject(subject)
  csr.public_key = key.public_key
  csr.sign(key, OpenSSL::Digest::SHA1.new)
  csr
end

#generate_generic_x509_key_cert(key, time, key_pass = nil) ⇒ Object


120
121
122
123
124
125
126
127
128
129
# File 'libraries/resource_ssl_certificate_generators.rb', line 120

def generate_generic_x509_key_cert(key, time, key_pass = nil)
  key = OpenSSL::PKey::RSA.new(key, key_pass)
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = OpenSSL::BN.rand(160)
  cert.not_before = Time.now
  cert.not_after =
    time.is_a?(Time) ? time : cert.not_before + time.to_i
  [key, cert]
end

#generate_key(length = 2048) ⇒ Object


35
36
37
# File 'libraries/resource_ssl_certificate_generators.rb', line 35

def generate_key(length = 2048)
  OpenSSL::PKey::RSA.new(length).to_pem
end

#generate_self_signed_cert_with_ca(key, cert, subject, ca_cert_cont, ca_key_cont) ⇒ Object


187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'libraries/resource_ssl_certificate_generators.rb', line 187

def generate_self_signed_cert_with_ca(key, cert, subject, ca_cert_cont,
                                      ca_key_cont)
  ca_cert, ca_key = generate_ca_from_content(ca_cert_cont, ca_key_cont)

  generate_self_signed_cert_with_ca_csr(cert, key, ca_cert, subject)
  ef = generate_self_signed_cert_with_ca_extensions(cert, ca_cert)

  if subject_alternate_names
    handle_subject_alternative_names(cert, ef, subject_alternate_names)
  end

  if extended_key_usage
    handle_extended_key_usage(cert, ef, extended_key_usage)
  end

  cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
end

#generate_self_signed_cert_with_ca_csr(cert, key, ca_cert, subject) ⇒ Object


180
181
182
183
184
185
# File 'libraries/resource_ssl_certificate_generators.rb', line 180

def generate_self_signed_cert_with_ca_csr(cert, key, ca_cert, subject)
  csr = generate_csr(key, subject)
  cert.subject = csr.subject
  cert.public_key = csr.public_key
  cert.issuer = ca_cert.subject
end

#generate_self_signed_cert_with_ca_extensions(cert, ca_cert) ⇒ Object


174
175
176
177
178
# File 'libraries/resource_ssl_certificate_generators.rb', line 174

def generate_self_signed_cert_with_ca_extensions(cert, ca_cert)
  generate_self_signed_cert_with_extensions(
    cert, ca_cert, Generators::EXTENSIONS[:with_ca]
  )
end

#generate_self_signed_cert_with_extensions(cert, issuer_cert, exts) ⇒ Object


137
138
139
140
141
142
143
# File 'libraries/resource_ssl_certificate_generators.rb', line 137

def generate_self_signed_cert_with_extensions(cert, issuer_cert, exts)
  ef = OpenSSL::X509::ExtensionFactory.new
  ef.subject_certificate = cert
  ef.issuer_certificate = issuer_cert
  cert_add_extensions(cert, ef, exts)
  ef
end

#generate_self_signed_cert_without_ca(key, cert, subject) ⇒ Object


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'libraries/resource_ssl_certificate_generators.rb', line 151

def generate_self_signed_cert_without_ca(key, cert, subject)
  cert.subject = generate_cert_subject(subject)
  cert.issuer = cert.subject # self-signed
  cert.public_key = key.public_key

  ef = generate_self_signed_cert_without_ca_extensions(cert)
  if subject_alternate_names
    handle_subject_alternative_names(cert, ef, subject_alternate_names)
  end

  if extended_key_usage
    handle_extended_key_usage(cert, ef, extended_key_usage)
  end

  cert.sign(key, OpenSSL::Digest::SHA256.new)
end

#generate_self_signed_cert_without_ca_extensions(cert) ⇒ Object


145
146
147
148
149
# File 'libraries/resource_ssl_certificate_generators.rb', line 145

def generate_self_signed_cert_without_ca_extensions(cert)
  generate_self_signed_cert_with_extensions(
    cert, cert, Generators::EXTENSIONS[:without_ca]
  )
end

#handle_extended_key_usage(cert, factory, usage) ⇒ Object


231
232
233
234
235
236
237
# File 'libraries/resource_ssl_certificate_generators.rb', line 231

def handle_extended_key_usage(cert, factory, usage)
  raise 'extended_key_usage must be an Array' unless usage.is_a?(Array)

  usage_list = usage.join(',')
  ext = factory.create_ext('extendedKeyUsage', usage_list, false)
  cert.add_extension(ext)
end

#handle_subject_alternative_names(cert, factory, alt_names) ⇒ Object

Subject Alternative Names support taken and modified from https://github.com/cchandler/certificate_authority/blob/master/lib /certificate_authority/signing_request.rb


222
223
224
225
226
227
228
229
# File 'libraries/resource_ssl_certificate_generators.rb', line 222

def handle_subject_alternative_names(cert, factory, alt_names)
  raise 'alt_names must be an Array' unless alt_names.is_a?(Array)

  name_list =
    alt_names.map { |m| m.include?(':') ? m : "DNS:#{m}" }.join(',')
  ext = factory.create_ext('subjectAltName', name_list, false)
  cert.add_extension(ext)
end

#load_current_subjects(cert) ⇒ Object


239
240
241
242
243
# File 'libraries/resource_ssl_certificate_generators.rb', line 239

def load_current_subjects(cert)
  cur = cert.subject
  new = generate_cert_subject(cert_subject)
  [cur, new]
end

#log_debug_subjects(cur, new) ⇒ Object


245
246
247
248
# File 'libraries/resource_ssl_certificate_generators.rb', line 245

def log_debug_subjects(cur, new)
  Chef::Log.debug("SSL certificate current subject: #{cur}")
  Chef::Log.debug("SSL certificate new subject: #{new}")
end

#verify_self_signed_cert(key, cert, _hostname, ca_cert_content = nil, pass_phrase = nil) ⇒ Object


268
269
270
271
272
273
274
275
276
277
# File 'libraries/resource_ssl_certificate_generators.rb', line 268

def verify_self_signed_cert(key, cert, _hostname,
                            ca_cert_content = nil, pass_phrase = nil)
  key = OpenSSL::PKey::RSA.new(key, pass_phrase)
  cert = OpenSSL::X509::Certificate.new(cert)
  if ca_cert_content
    compare_self_signed_cert_with_ca(key, cert, ca_cert_content)
  else
    compare_self_signed_cert_without_ca(key, cert)
  end
end