2019-09-10 17:25:37 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class CreateX509SelfSignedCertificate
|
|
|
|
include Interactor
|
|
|
|
|
2019-09-10 18:16:30 -04:00
|
|
|
before do
|
2019-09-11 05:09:37 -04:00
|
|
|
context.not_before = Time.at(context.not_before).utc
|
|
|
|
context.not_after = Time.at(context.not_after).utc
|
2019-09-10 18:16:30 -04:00
|
|
|
end
|
|
|
|
|
2019-09-10 17:25:37 -04:00
|
|
|
def call
|
2019-09-10 19:06:14 -04:00
|
|
|
context.certificate = X509Certificate.create!(
|
|
|
|
pem: cert.to_pem.freeze,
|
2019-09-11 04:02:25 -04:00
|
|
|
not_before: context.not_before,
|
|
|
|
not_after: context.not_after,
|
2019-09-10 19:06:14 -04:00
|
|
|
)
|
2019-09-10 17:25:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def private_key_pkey
|
|
|
|
@private_key_pkey ||= OpenSSL::PKey::RSA.new context.private_key_pem
|
|
|
|
end
|
|
|
|
|
|
|
|
def public_key_pkey
|
|
|
|
@public_key_pkey ||= OpenSSL::PKey::RSA.new context.public_key.pem
|
|
|
|
end
|
|
|
|
|
|
|
|
def subject
|
|
|
|
@subject ||= OpenSSL::X509::Name.parse context.distinguished_name
|
|
|
|
end
|
|
|
|
|
2019-09-10 18:09:01 -04:00
|
|
|
def cert # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
2019-09-10 17:25:37 -04:00
|
|
|
@cert ||= OpenSSL::X509::Certificate.new.tap do |cert|
|
|
|
|
cert.version = 2
|
2019-09-10 18:13:04 -04:00
|
|
|
cert.serial = SecureRandom.rand 0...(2**16)
|
2019-09-10 17:25:37 -04:00
|
|
|
cert.subject = subject
|
|
|
|
cert.issuer = cert.subject
|
|
|
|
cert.public_key = public_key_pkey
|
|
|
|
cert.not_before = context.not_before
|
|
|
|
cert.not_after = context.not_after
|
|
|
|
|
|
|
|
AddExtensions.call cert
|
|
|
|
|
|
|
|
cert.sign private_key_pkey, OpenSSL::Digest::SHA256.new
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class AddExtensions
|
|
|
|
def self.call(cert)
|
|
|
|
new(cert).call
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(cert)
|
|
|
|
@cert = cert
|
|
|
|
end
|
|
|
|
|
|
|
|
def call
|
|
|
|
cert.add_extension basic_constraints
|
|
|
|
cert.add_extension key_usage
|
|
|
|
cert.add_extension subject_key_ident
|
|
|
|
cert.add_extension authority_key_ident
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
attr_reader :cert
|
|
|
|
|
|
|
|
def ext_factory
|
|
|
|
@ext_factory ||= OpenSSL::X509::ExtensionFactory.new.tap do |ext_factory|
|
|
|
|
ext_factory.subject_certificate = cert
|
|
|
|
ext_factory.issuer_certificate = cert
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def basic_constraints
|
|
|
|
@basic_constraints ||= ext_factory.create_extension(
|
|
|
|
'basicConstraints',
|
|
|
|
'CA:TRUE',
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def key_usage
|
|
|
|
@key_usage ||= ext_factory.create_extension(
|
|
|
|
'keyUsage',
|
|
|
|
'keyCertSign, cRLSign',
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def subject_key_ident
|
|
|
|
@subject_key_ident ||= ext_factory.create_extension(
|
|
|
|
'subjectKeyIdentifier',
|
|
|
|
'hash',
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def authority_key_ident
|
|
|
|
@authority_key_ident ||= ext_factory.create_extension(
|
|
|
|
'authorityKeyIdentifier',
|
|
|
|
'keyid:always,issuer:always',
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|