leap_cli 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/leap +81 -0
- data/lib/core_ext/boolean.rb +14 -0
- data/lib/core_ext/hash.rb +35 -0
- data/lib/core_ext/json.rb +42 -0
- data/lib/core_ext/nil.rb +5 -0
- data/lib/core_ext/string.rb +14 -0
- data/lib/leap/platform.rb +52 -0
- data/lib/leap_cli/commands/ca.rb +430 -0
- data/lib/leap_cli/commands/clean.rb +16 -0
- data/lib/leap_cli/commands/compile.rb +134 -0
- data/lib/leap_cli/commands/deploy.rb +172 -0
- data/lib/leap_cli/commands/facts.rb +93 -0
- data/lib/leap_cli/commands/inspect.rb +140 -0
- data/lib/leap_cli/commands/list.rb +122 -0
- data/lib/leap_cli/commands/new.rb +126 -0
- data/lib/leap_cli/commands/node.rb +272 -0
- data/lib/leap_cli/commands/pre.rb +99 -0
- data/lib/leap_cli/commands/shell.rb +67 -0
- data/lib/leap_cli/commands/test.rb +55 -0
- data/lib/leap_cli/commands/user.rb +140 -0
- data/lib/leap_cli/commands/util.rb +50 -0
- data/lib/leap_cli/commands/vagrant.rb +201 -0
- data/lib/leap_cli/config/macros.rb +369 -0
- data/lib/leap_cli/config/manager.rb +369 -0
- data/lib/leap_cli/config/node.rb +37 -0
- data/lib/leap_cli/config/object.rb +336 -0
- data/lib/leap_cli/config/object_list.rb +174 -0
- data/lib/leap_cli/config/secrets.rb +43 -0
- data/lib/leap_cli/config/tag.rb +18 -0
- data/lib/leap_cli/constants.rb +7 -0
- data/lib/leap_cli/leapfile.rb +97 -0
- data/lib/leap_cli/load_paths.rb +15 -0
- data/lib/leap_cli/log.rb +166 -0
- data/lib/leap_cli/logger.rb +216 -0
- data/lib/leap_cli/markdown_document_listener.rb +134 -0
- data/lib/leap_cli/path.rb +84 -0
- data/lib/leap_cli/remote/leap_plugin.rb +204 -0
- data/lib/leap_cli/remote/puppet_plugin.rb +66 -0
- data/lib/leap_cli/remote/rsync_plugin.rb +35 -0
- data/lib/leap_cli/remote/tasks.rb +36 -0
- data/lib/leap_cli/requirements.rb +19 -0
- data/lib/leap_cli/ssh_key.rb +130 -0
- data/lib/leap_cli/util/remote_command.rb +110 -0
- data/lib/leap_cli/util/secret.rb +54 -0
- data/lib/leap_cli/util/x509.rb +32 -0
- data/lib/leap_cli/util.rb +431 -0
- data/lib/leap_cli/version.rb +9 -0
- data/lib/leap_cli.rb +46 -0
- data/lib/lib_ext/capistrano_connections.rb +16 -0
- data/lib/lib_ext/gli.rb +52 -0
- data/lib/lib_ext/markdown_document_listener.rb +122 -0
- data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +200 -0
- data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +77 -0
- data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +97 -0
- data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +266 -0
- data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +148 -0
- data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +144 -0
- data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +65 -0
- data/vendor/certificate_authority/lib/certificate_authority/revocable.rb +14 -0
- data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +10 -0
- data/vendor/certificate_authority/lib/certificate_authority/signing_entity.rb +16 -0
- data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +56 -0
- data/vendor/certificate_authority/lib/certificate_authority.rb +21 -0
- data/vendor/rsync_command/lib/rsync_command/ssh_options.rb +159 -0
- data/vendor/rsync_command/lib/rsync_command/thread_pool.rb +36 -0
- data/vendor/rsync_command/lib/rsync_command/version.rb +3 -0
- data/vendor/rsync_command/lib/rsync_command.rb +96 -0
- data/vendor/rsync_command/test/rsync_test.rb +74 -0
- data/vendor/rsync_command/test/ssh_options_test.rb +61 -0
- data/vendor/vagrant_ssh_keys/vagrant.key +27 -0
- data/vendor/vagrant_ssh_keys/vagrant.pub +1 -0
- metadata +345 -0
@@ -0,0 +1,200 @@
|
|
1
|
+
module CertificateAuthority
|
2
|
+
class Certificate
|
3
|
+
include ActiveModel::Validations
|
4
|
+
include Revocable
|
5
|
+
|
6
|
+
attr_accessor :distinguished_name
|
7
|
+
attr_accessor :serial_number
|
8
|
+
attr_accessor :key_material
|
9
|
+
attr_accessor :not_before
|
10
|
+
attr_accessor :not_after
|
11
|
+
attr_accessor :extensions
|
12
|
+
attr_accessor :openssl_body
|
13
|
+
|
14
|
+
alias :subject :distinguished_name #Same thing as the DN
|
15
|
+
|
16
|
+
attr_accessor :parent
|
17
|
+
|
18
|
+
validate do |certificate|
|
19
|
+
errors.add :base, "Distinguished name must be valid" unless distinguished_name.valid?
|
20
|
+
errors.add :base, "Key material must be valid" unless key_material.valid?
|
21
|
+
errors.add :base, "Serial number must be valid" unless serial_number.valid?
|
22
|
+
errors.add :base, "Extensions must be valid" unless extensions.each do |item|
|
23
|
+
unless item.respond_to?(:valid?)
|
24
|
+
true
|
25
|
+
else
|
26
|
+
item.valid?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
self.distinguished_name = DistinguishedName.new
|
33
|
+
self.serial_number = SerialNumber.new
|
34
|
+
self.key_material = MemoryKeyMaterial.new
|
35
|
+
self.not_before = Time.now
|
36
|
+
self.not_after = Time.now + 60 * 60 * 24 * 365 #One year
|
37
|
+
self.parent = self
|
38
|
+
self.extensions = load_extensions()
|
39
|
+
|
40
|
+
self.signing_entity = false
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def sign!(signing_profile={})
|
45
|
+
raise "Invalid certificate #{self.errors.full_messages}" unless valid?
|
46
|
+
merge_profile_with_extensions(signing_profile)
|
47
|
+
|
48
|
+
openssl_cert = OpenSSL::X509::Certificate.new
|
49
|
+
openssl_cert.version = 2
|
50
|
+
openssl_cert.not_before = self.not_before
|
51
|
+
openssl_cert.not_after = self.not_after
|
52
|
+
openssl_cert.public_key = self.key_material.public_key
|
53
|
+
|
54
|
+
openssl_cert.serial = self.serial_number.number
|
55
|
+
|
56
|
+
openssl_cert.subject = self.distinguished_name.to_x509_name
|
57
|
+
openssl_cert.issuer = parent.distinguished_name.to_x509_name
|
58
|
+
|
59
|
+
require 'tempfile'
|
60
|
+
t = Tempfile.new("bullshit_conf")
|
61
|
+
# t = File.new("/tmp/openssl.cnf")
|
62
|
+
## The config requires a file even though we won't use it
|
63
|
+
openssl_config = OpenSSL::Config.new(t.path)
|
64
|
+
|
65
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
66
|
+
factory.subject_certificate = openssl_cert
|
67
|
+
|
68
|
+
#NB: If the parent doesn't have an SSL body we're making this a self-signed cert
|
69
|
+
if parent.openssl_body.nil?
|
70
|
+
factory.issuer_certificate = openssl_cert
|
71
|
+
else
|
72
|
+
factory.issuer_certificate = parent.openssl_body
|
73
|
+
end
|
74
|
+
|
75
|
+
self.extensions.keys.each do |k|
|
76
|
+
config_extensions = extensions[k].config_extensions
|
77
|
+
openssl_config = merge_options(openssl_config,config_extensions)
|
78
|
+
end
|
79
|
+
|
80
|
+
# p openssl_config.sections
|
81
|
+
|
82
|
+
factory.config = openssl_config
|
83
|
+
|
84
|
+
# Order matters: e.g. for self-signed, subjectKeyIdentifier must come before authorityKeyIdentifier
|
85
|
+
self.extensions.keys.sort{|a,b| b<=>a}.each do |k|
|
86
|
+
e = extensions[k]
|
87
|
+
next if e.to_s.nil? or e.to_s == "" ## If the extension returns an empty string we won't include it
|
88
|
+
ext = factory.create_ext(e.openssl_identifier, e.to_s)
|
89
|
+
openssl_cert.add_extension(ext)
|
90
|
+
end
|
91
|
+
|
92
|
+
if signing_profile["digest"].nil?
|
93
|
+
digest = OpenSSL::Digest::Digest.new("SHA512")
|
94
|
+
else
|
95
|
+
digest = OpenSSL::Digest::Digest.new(signing_profile["digest"])
|
96
|
+
end
|
97
|
+
self.openssl_body = openssl_cert.sign(parent.key_material.private_key,digest)
|
98
|
+
t.close! if t.is_a?(Tempfile)# We can get rid of the ridiculous temp file
|
99
|
+
self.openssl_body
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_signing_entity?
|
103
|
+
self.extensions["basicConstraints"].ca
|
104
|
+
end
|
105
|
+
|
106
|
+
def signing_entity=(signing)
|
107
|
+
self.extensions["basicConstraints"].ca = signing
|
108
|
+
end
|
109
|
+
|
110
|
+
def revoked?
|
111
|
+
!self.revoked_at.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_pem
|
115
|
+
raise "Certificate has no signed body" if self.openssl_body.nil?
|
116
|
+
self.openssl_body.to_pem
|
117
|
+
end
|
118
|
+
|
119
|
+
def is_root_entity?
|
120
|
+
self.parent == self && is_signing_entity?
|
121
|
+
end
|
122
|
+
|
123
|
+
def is_intermediate_entity?
|
124
|
+
(self.parent != self) && is_signing_entity?
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def merge_profile_with_extensions(signing_profile={})
|
130
|
+
return self.extensions if signing_profile["extensions"].nil?
|
131
|
+
signing_config = signing_profile["extensions"]
|
132
|
+
signing_config.keys.each do |k|
|
133
|
+
extension = self.extensions[k]
|
134
|
+
items = signing_config[k]
|
135
|
+
items.keys.each do |profile_item_key|
|
136
|
+
if extension.respond_to?("#{profile_item_key}=".to_sym)
|
137
|
+
extension.send("#{profile_item_key}=".to_sym, items[profile_item_key] )
|
138
|
+
else
|
139
|
+
p "Tried applying '#{profile_item_key}' to #{extension.class} but it doesn't respond!"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def load_extensions
|
146
|
+
extension_hash = {}
|
147
|
+
|
148
|
+
temp_extensions = []
|
149
|
+
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
|
150
|
+
temp_extensions << basic_constraints
|
151
|
+
crl_distribution_points = CertificateAuthority::Extensions::CrlDistributionPoints.new
|
152
|
+
temp_extensions << crl_distribution_points
|
153
|
+
subject_key_identifier = CertificateAuthority::Extensions::SubjectKeyIdentifier.new
|
154
|
+
temp_extensions << subject_key_identifier
|
155
|
+
authority_key_identifier = CertificateAuthority::Extensions::AuthorityKeyIdentifier.new
|
156
|
+
temp_extensions << authority_key_identifier
|
157
|
+
authority_info_access = CertificateAuthority::Extensions::AuthorityInfoAccess.new
|
158
|
+
temp_extensions << authority_info_access
|
159
|
+
key_usage = CertificateAuthority::Extensions::KeyUsage.new
|
160
|
+
temp_extensions << key_usage
|
161
|
+
extended_key_usage = CertificateAuthority::Extensions::ExtendedKeyUsage.new
|
162
|
+
temp_extensions << extended_key_usage
|
163
|
+
subject_alternative_name = CertificateAuthority::Extensions::SubjectAlternativeName.new
|
164
|
+
temp_extensions << subject_alternative_name
|
165
|
+
certificate_policies = CertificateAuthority::Extensions::CertificatePolicies.new
|
166
|
+
temp_extensions << certificate_policies
|
167
|
+
|
168
|
+
temp_extensions.each do |extension|
|
169
|
+
extension_hash[extension.openssl_identifier] = extension
|
170
|
+
end
|
171
|
+
|
172
|
+
extension_hash
|
173
|
+
end
|
174
|
+
|
175
|
+
def merge_options(config,hash)
|
176
|
+
hash.keys.each do |k|
|
177
|
+
config[k] = hash[k]
|
178
|
+
end
|
179
|
+
config
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.from_openssl openssl_cert
|
183
|
+
unless openssl_cert.is_a? OpenSSL::X509::Certificate
|
184
|
+
raise "Can only construct from an OpenSSL::X509::Certificate"
|
185
|
+
end
|
186
|
+
|
187
|
+
certificate = Certificate.new
|
188
|
+
# Only subject, key_material, and body are used for signing
|
189
|
+
certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
|
190
|
+
certificate.key_material.public_key = openssl_cert.public_key
|
191
|
+
certificate.openssl_body = openssl_cert
|
192
|
+
certificate.serial_number.number = openssl_cert.serial.to_i
|
193
|
+
certificate.not_before = openssl_cert.not_before
|
194
|
+
certificate.not_after = openssl_cert.not_after
|
195
|
+
# TODO extensions
|
196
|
+
certificate
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CertificateAuthority
|
2
|
+
class CertificateRevocationList
|
3
|
+
include ActiveModel::Validations
|
4
|
+
|
5
|
+
attr_accessor :certificates
|
6
|
+
attr_accessor :parent
|
7
|
+
attr_accessor :crl_body
|
8
|
+
attr_accessor :next_update
|
9
|
+
|
10
|
+
validate do |crl|
|
11
|
+
errors.add :next_update, "Next update must be a positive value" if crl.next_update < 0
|
12
|
+
errors.add :parent, "A parent entity must be set" if crl.parent.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
self.certificates = []
|
17
|
+
self.next_update = 60 * 60 * 4 # 4 hour default
|
18
|
+
end
|
19
|
+
|
20
|
+
def <<(revocable)
|
21
|
+
case revocable
|
22
|
+
when Revocable
|
23
|
+
raise "Only revoked entities can be added to a CRL" unless revocable.revoked?
|
24
|
+
self.certificates << revocable
|
25
|
+
when OpenSSL::X509::Certificate
|
26
|
+
raise "Not implemented yet"
|
27
|
+
else
|
28
|
+
raise "#{revocable.class} cannot be included in a CRL"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def sign!(signing_profile={})
|
33
|
+
raise "No parent entity has been set!" if self.parent.nil?
|
34
|
+
raise "Invalid CRL" unless self.valid?
|
35
|
+
|
36
|
+
revocations = self.certificates.collect do |revocable|
|
37
|
+
revocation = OpenSSL::X509::Revoked.new
|
38
|
+
|
39
|
+
## We really just need a serial number, now we have to dig it out
|
40
|
+
case revocable
|
41
|
+
when Certificate
|
42
|
+
x509_cert = OpenSSL::X509::Certificate.new(revocable.to_pem)
|
43
|
+
revocation.serial = x509_cert.serial
|
44
|
+
when SerialNumber
|
45
|
+
revocation.serial = revocable.number
|
46
|
+
end
|
47
|
+
revocation.time = revocable.revoked_at
|
48
|
+
revocation
|
49
|
+
end
|
50
|
+
|
51
|
+
crl = OpenSSL::X509::CRL.new
|
52
|
+
revocations.each do |revocation|
|
53
|
+
crl.add_revoked(revocation)
|
54
|
+
end
|
55
|
+
|
56
|
+
crl.version = 1
|
57
|
+
crl.last_update = Time.now
|
58
|
+
crl.next_update = Time.now + self.next_update
|
59
|
+
|
60
|
+
signing_cert = OpenSSL::X509::Certificate.new(self.parent.to_pem)
|
61
|
+
if signing_profile["digest"].nil?
|
62
|
+
digest = OpenSSL::Digest::Digest.new("SHA512")
|
63
|
+
else
|
64
|
+
digest = OpenSSL::Digest::Digest.new(signing_profile["digest"])
|
65
|
+
end
|
66
|
+
crl.issuer = signing_cert.subject
|
67
|
+
self.crl_body = crl.sign(self.parent.key_material.private_key, digest)
|
68
|
+
|
69
|
+
self.crl_body
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_pem
|
73
|
+
raise "No signed CRL body" if self.crl_body.nil?
|
74
|
+
self.crl_body.to_pem
|
75
|
+
end
|
76
|
+
end#CertificateRevocationList
|
77
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module CertificateAuthority
|
2
|
+
class DistinguishedName
|
3
|
+
include ActiveModel::Validations
|
4
|
+
|
5
|
+
validates_presence_of :common_name
|
6
|
+
|
7
|
+
attr_accessor :common_name
|
8
|
+
alias :cn :common_name
|
9
|
+
alias :cn= :common_name=
|
10
|
+
|
11
|
+
attr_accessor :locality
|
12
|
+
alias :l :locality
|
13
|
+
alias :l= :locality=
|
14
|
+
|
15
|
+
attr_accessor :state
|
16
|
+
alias :s :state
|
17
|
+
alias :st= :state=
|
18
|
+
|
19
|
+
attr_accessor :country
|
20
|
+
alias :c :country
|
21
|
+
alias :c= :country=
|
22
|
+
|
23
|
+
attr_accessor :organization
|
24
|
+
alias :o :organization
|
25
|
+
alias :o= :organization=
|
26
|
+
|
27
|
+
attr_accessor :organizational_unit
|
28
|
+
alias :ou :organizational_unit
|
29
|
+
alias :ou= :organizational_unit=
|
30
|
+
|
31
|
+
attr_accessor :email_address
|
32
|
+
alias :emailAddress :email_address
|
33
|
+
alias :emailAddress= :email_address=
|
34
|
+
|
35
|
+
def to_x509_name
|
36
|
+
raise "Invalid Distinguished Name" unless valid?
|
37
|
+
|
38
|
+
# NB: the capitalization in the strings counts
|
39
|
+
name = OpenSSL::X509::Name.new
|
40
|
+
name.add_entry("C", country) unless country.blank?
|
41
|
+
name.add_entry("ST", state) unless state.blank?
|
42
|
+
name.add_entry("L", locality) unless locality.blank?
|
43
|
+
name.add_entry("O", organization) unless organization.blank?
|
44
|
+
name.add_entry("OU", organizational_unit) unless organizational_unit.blank?
|
45
|
+
name.add_entry("CN", common_name)
|
46
|
+
name.add_entry("emailAddress", email_address) unless email_address.blank?
|
47
|
+
name
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
# Use the established OpenSSL comparison
|
52
|
+
self.to_x509_name() == other.to_x509_name()
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.from_openssl openssl_name
|
56
|
+
unless openssl_name.is_a? OpenSSL::X509::Name
|
57
|
+
raise "Argument must be a OpenSSL::X509::Name"
|
58
|
+
end
|
59
|
+
|
60
|
+
WrappedDistinguishedName.new(openssl_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
## This is a significantly more complicated case. It's possible that
|
65
|
+
## generically handled certificates will include custom OIDs in the
|
66
|
+
## subject.
|
67
|
+
class WrappedDistinguishedName < DistinguishedName
|
68
|
+
attr_accessor :x509_name
|
69
|
+
|
70
|
+
def initialize(x509_name)
|
71
|
+
@x509_name = x509_name
|
72
|
+
|
73
|
+
subject = @x509_name.to_a
|
74
|
+
subject.each do |element|
|
75
|
+
field = element[0].downcase
|
76
|
+
value = element[1]
|
77
|
+
#type = element[2] ## -not used
|
78
|
+
method_sym = "#{field}=".to_sym
|
79
|
+
if self.respond_to?(method_sym)
|
80
|
+
self.send("#{field}=",value)
|
81
|
+
else
|
82
|
+
## Custom OID
|
83
|
+
@custom_oids = true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_x509_name
|
90
|
+
@x509_name
|
91
|
+
end
|
92
|
+
|
93
|
+
def custom_oids?
|
94
|
+
@custom_oids
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module CertificateAuthority
|
2
|
+
module Extensions
|
3
|
+
module ExtensionAPI
|
4
|
+
def to_s
|
5
|
+
raise "Implementation required"
|
6
|
+
end
|
7
|
+
|
8
|
+
def config_extensions
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
|
12
|
+
def openssl_identifier
|
13
|
+
raise "Implementation required"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class BasicConstraints
|
18
|
+
include ExtensionAPI
|
19
|
+
include ActiveModel::Validations
|
20
|
+
attr_accessor :ca
|
21
|
+
attr_accessor :path_len
|
22
|
+
validates :ca, :inclusion => [true,false]
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
self.ca = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def is_ca?
|
29
|
+
self.ca
|
30
|
+
end
|
31
|
+
|
32
|
+
def path_len=(value)
|
33
|
+
raise "path_len must be a non-negative integer" if value < 0 or !value.is_a?(Fixnum)
|
34
|
+
@path_len = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def openssl_identifier
|
38
|
+
"basicConstraints"
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
result = ""
|
43
|
+
result += "CA:#{self.ca}"
|
44
|
+
result += ",pathlen:#{self.path_len}" unless self.path_len.nil?
|
45
|
+
result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class CrlDistributionPoints
|
50
|
+
include ExtensionAPI
|
51
|
+
|
52
|
+
attr_accessor :uri
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
# self.uri = "http://moo.crlendPoint.example.com/something.crl"
|
56
|
+
end
|
57
|
+
|
58
|
+
def openssl_identifier
|
59
|
+
"crlDistributionPoints"
|
60
|
+
end
|
61
|
+
|
62
|
+
## NB: At this time it seems OpenSSL's extension handlers don't support
|
63
|
+
## any of the config options the docs claim to support... everything comes back
|
64
|
+
## "missing value" on GENERAL NAME. Even if copied verbatim
|
65
|
+
def config_extensions
|
66
|
+
{
|
67
|
+
# "custom_crl_fields" => {"fullname" => "URI:#{fullname}"},
|
68
|
+
# "issuer_sect" => {"CN" => "crlissuer.com", "C" => "US", "O" => "shudder"}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
return "" if self.uri.nil?
|
74
|
+
"URI:#{self.uri}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class SubjectKeyIdentifier
|
79
|
+
include ExtensionAPI
|
80
|
+
def openssl_identifier
|
81
|
+
"subjectKeyIdentifier"
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"hash"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class AuthorityKeyIdentifier
|
90
|
+
include ExtensionAPI
|
91
|
+
|
92
|
+
def openssl_identifier
|
93
|
+
"authorityKeyIdentifier"
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_s
|
97
|
+
"keyid,issuer"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class AuthorityInfoAccess
|
102
|
+
include ExtensionAPI
|
103
|
+
|
104
|
+
attr_accessor :ocsp
|
105
|
+
|
106
|
+
def initialize
|
107
|
+
self.ocsp = []
|
108
|
+
end
|
109
|
+
|
110
|
+
def openssl_identifier
|
111
|
+
"authorityInfoAccess"
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_s
|
115
|
+
return "" if self.ocsp.empty?
|
116
|
+
"OCSP;URI:#{self.ocsp}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class KeyUsage
|
121
|
+
include ExtensionAPI
|
122
|
+
|
123
|
+
attr_accessor :usage
|
124
|
+
|
125
|
+
def initialize
|
126
|
+
self.usage = ["digitalSignature", "nonRepudiation"]
|
127
|
+
end
|
128
|
+
|
129
|
+
def openssl_identifier
|
130
|
+
"keyUsage"
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_s
|
134
|
+
"#{self.usage.join(',')}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class ExtendedKeyUsage
|
139
|
+
include ExtensionAPI
|
140
|
+
|
141
|
+
attr_accessor :usage
|
142
|
+
|
143
|
+
def initialize
|
144
|
+
self.usage = ["serverAuth","clientAuth"]
|
145
|
+
end
|
146
|
+
|
147
|
+
def openssl_identifier
|
148
|
+
"extendedKeyUsage"
|
149
|
+
end
|
150
|
+
|
151
|
+
def to_s
|
152
|
+
"#{self.usage.join(',')}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class SubjectAlternativeName
|
157
|
+
include ExtensionAPI
|
158
|
+
|
159
|
+
attr_accessor :uris, :dns_names, :ips
|
160
|
+
|
161
|
+
def initialize
|
162
|
+
self.uris = []
|
163
|
+
self.dns_names = []
|
164
|
+
self.ips = []
|
165
|
+
end
|
166
|
+
|
167
|
+
def uris=(value)
|
168
|
+
raise "URIs must be an array" unless value.is_a?(Array)
|
169
|
+
@uris = value
|
170
|
+
end
|
171
|
+
|
172
|
+
def dns_names=(value)
|
173
|
+
raise "DNS names must be an array" unless value.is_a?(Array)
|
174
|
+
@dns_names = value
|
175
|
+
end
|
176
|
+
|
177
|
+
def ips=(value)
|
178
|
+
raise "IPs must be an array" unless value.is_a?(Array)
|
179
|
+
@ips = value
|
180
|
+
end
|
181
|
+
|
182
|
+
def openssl_identifier
|
183
|
+
"subjectAltName"
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_s
|
187
|
+
res = self.uris.map {|u| "URI:#{u}" }
|
188
|
+
res += self.dns_names.map {|d| "DNS:#{d}" }
|
189
|
+
res += self.ips.map {|i| "IP:#{i}" }
|
190
|
+
|
191
|
+
return res.join(',')
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class CertificatePolicies
|
196
|
+
include ExtensionAPI
|
197
|
+
|
198
|
+
attr_accessor :policy_identifier
|
199
|
+
attr_accessor :cps_uris
|
200
|
+
##User notice
|
201
|
+
attr_accessor :explicit_text
|
202
|
+
attr_accessor :organization
|
203
|
+
attr_accessor :notice_numbers
|
204
|
+
|
205
|
+
def initialize
|
206
|
+
@contains_data = false
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
def openssl_identifier
|
211
|
+
"certificatePolicies"
|
212
|
+
end
|
213
|
+
|
214
|
+
def user_notice=(value={})
|
215
|
+
value.keys.each do |key|
|
216
|
+
self.send("#{key}=".to_sym, value[key])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def config_extensions
|
221
|
+
config_extension = {}
|
222
|
+
custom_policies = {}
|
223
|
+
notice = {}
|
224
|
+
unless self.policy_identifier.nil?
|
225
|
+
custom_policies["policyIdentifier"] = self.policy_identifier
|
226
|
+
end
|
227
|
+
|
228
|
+
if !self.cps_uris.nil? and self.cps_uris.is_a?(Array)
|
229
|
+
self.cps_uris.each_with_index do |cps_uri,i|
|
230
|
+
custom_policies["CPS.#{i}"] = cps_uri
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
unless self.explicit_text.nil?
|
235
|
+
notice["explicitText"] = self.explicit_text
|
236
|
+
end
|
237
|
+
|
238
|
+
unless self.organization.nil?
|
239
|
+
notice["organization"] = self.organization
|
240
|
+
end
|
241
|
+
|
242
|
+
unless self.notice_numbers.nil?
|
243
|
+
notice["noticeNumbers"] = self.notice_numbers
|
244
|
+
end
|
245
|
+
|
246
|
+
if notice.keys.size > 0
|
247
|
+
custom_policies["userNotice.1"] = "@notice"
|
248
|
+
config_extension["notice"] = notice
|
249
|
+
end
|
250
|
+
|
251
|
+
if custom_policies.keys.size > 0
|
252
|
+
config_extension["custom_policies"] = custom_policies
|
253
|
+
@contains_data = true
|
254
|
+
end
|
255
|
+
|
256
|
+
config_extension
|
257
|
+
end
|
258
|
+
|
259
|
+
def to_s
|
260
|
+
return "" unless @contains_data
|
261
|
+
"ia5org,@custom_policies"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
end
|