-
Notifications
You must be signed in to change notification settings - Fork 122
/
ca_helpers.rb
163 lines (130 loc) · 4.68 KB
/
ca_helpers.rb
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# frozen_string_literal: true
require 'openssl'
# Utility methods for CA tests
#
module CAHelpers
def generate_root_ca
RootCA.new('CN=Conjur Root CA/DC=Conjur Certificate Authority', 3600)
end
def generate_intermediate_ca(root_ca, password = nil)
int_ca = IntermediateCA.new('CN=Conjur Intermediate CA/DC=Conjur Certificate Authority', password: password)
int_ca.cert = root_ca.sign_ca(int_ca.csr, 3600)
int_ca
end
def create_host(common_name)
Host.new("CN=#{common_name}")
end
def intermediate_ca
@intermediate_ca ||= {}
end
def response_certificate
@response_certificate ||= OpenSSL::X509::Certificate.new certificate_response_body
end
def certificate_response_body
@certificate_response_body ||= (certificate_response_type == 'pem' ? @result : @result['certificate'])
end
def certificate_response_type
@certificate_response_type ||= 'json'
end
# Provides certificate authority capabilities. This is
# namely signing certificates for certificate signing requests (CSRs)
module CertificateAuthority
def sign_ca(csr, ttl)
raise 'CSR cannot be verified' unless csr.verify csr.public_key
csr_cert = OpenSSL::X509::Certificate.new
csr_cert.serial = 0
csr_cert.version = 3
csr_cert.not_before = Time.now
csr_cert.not_after = csr_cert.not_before + ttl
csr_cert.subject = csr.subject
csr_cert.public_key = csr.public_key
csr_cert.issuer = @cert.subject
extension_factory = OpenSSL::X509::ExtensionFactory.new
extension_factory.subject_certificate = csr_cert
extension_factory.issuer_certificate = @cert
csr_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
csr_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
csr_cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true))
# Sign the issued CA certificate with the CA private key
csr_cert.sign @key, OpenSSL::Digest::SHA256.new
csr_cert
end
end
# Provides certificate host capabilities. This includes
# creating a certificate signing request (CSR) to submit
# to an issuer CA
module CertificateHost
def key
@key
end
def key_pem
@password.to_s.empty? ? @key.to_pem : @key.to_pem(OpenSSL::Cipher::AES256.new(:CBC), @password)
end
def cert
@cert
end
def cert=(val)
@cert = val
end
def csr
OpenSSL::X509::Request.new
.tap do |csr|
csr.version = 0
csr.subject = @name
csr.public_key = @key.public_key
csr.sign @key, OpenSSL::Digest::SHA256.new
end
end
end
# Represent a root certificate authority. A root
# CA creates and signs its own certificate
class RootCA
include CertificateAuthority
include CertificateHost
def initialize(name, ttl, key_size: 4096)
@name = OpenSSL::X509::Name.parse name
@key = OpenSSL::PKey::RSA.new key_size
@cert = create_cert(ttl, @key)
end
def create_cert(ttl, key)
cert = OpenSSL::X509::Certificate.new
cert.version = 3
cert.serial = 0
cert.not_before = Time.now
cert.not_after = cert.not_before + ttl
cert.public_key = key.public_key
cert.subject = @name
cert.issuer = @name
extension_factory = OpenSSL::X509::ExtensionFactory.new
extension_factory.subject_certificate = cert
extension_factory.issuer_certificate = cert
cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true))
cert.sign(key, OpenSSL::Digest::SHA256.new)
cert
end
end
# Represents an Intermediate Certificate authority.
# An Intermediate CA cannot sign its own certificate,
# but must submit a CSR to an issuer CA.
class IntermediateCA
include CertificateAuthority
include CertificateHost
def initialize(name, password: nil, key_size: 4096)
@name = OpenSSL::X509::Name.parse name
@key = OpenSSL::PKey::RSA.new key_size
@password = password
end
end
# Represents a host to create a certificate signing request
# for a host certificate
class Host
include CAHelpers::CertificateHost
def initialize(name, key_size: 4096)
@name = OpenSSL::X509::Name.parse name
@key = OpenSSL::PKey::RSA.new key_size
end
end
end
World(CAHelpers)