kybus-ssl 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2bf5e7b4893134432a12134b41fb41b318b7ef6928e5690a4ec2a978b06cebe
4
- data.tar.gz: 9576e4b32580447fc71678eec7ee7f56e5a7a5c6f34e8d6015aee3d846a00bb1
3
+ metadata.gz: fa8499e77ca6b86352e3e7bcbcd89080419ff5ebf9122b681aecbb189ef3bbd4
4
+ data.tar.gz: 52d7ec328216a409462fbf398c6d99eea73dd0db08e847d9d6a4b30b15affcb8
5
5
  SHA512:
6
- metadata.gz: 726fae80d20e37cc77fe945a33cbee37f093d39e862bb1228c0397c624c476144e91a26ddfefae7e2200c5a05aeaafba483c60c3c3986d31b83dd63afe080a09
7
- data.tar.gz: c7adaeedef2ea71b15c948eb79eb70c8a10082a550aceba4b9a0965b974b6005b26169bc259872d0f7c9342645c25b8ee1d7826158b5999d9d1bd218371423e0
6
+ metadata.gz: a3b5bce4e64ac747d0738b560cf0c0a5a853ca0fe843b8860baf72a1960644bebd397ff61f6fc6710fdf6f336a49e02ca662803277c89e8fc7be52f633dc1f00
7
+ data.tar.gz: 73a58d32976e8b016eec3986c1f0e7a4939a364237769b7fa9e76e88ae8b4e615fe96313b50b2bce1c551c318763678dc2c01432c993d79d891bb1193f55e79a
data/bin/kybssl ADDED
@@ -0,0 +1,90 @@
1
+ require 'optimist'
2
+ require 'yaml'
3
+ require './lib/kybus/ssl/cli'
4
+
5
+ def run_init(opts)
6
+ Kybus::SSL::CLI::Init.new(opts).run
7
+ end
8
+
9
+ def run_add_ca(opts)
10
+ Kybus::SSL::CLI::AddCA.new(opts).run
11
+ end
12
+
13
+ def run_add_certificate(opts)
14
+ Kybus::SSL::CLI::AddCertificate.new(opts).run
15
+ end
16
+
17
+ def run_revoke_certificate(opts); end
18
+
19
+ def run_build(opts); end
20
+
21
+ # Define expected commands and options
22
+ commands = %i[init add_ca add_certificate revoke_certificate build]
23
+ cmd = ARGV.shift&.to_sym || :help
24
+ abort "Invalid command. Valid commands are: #{commands.join(', ')}" unless commands.include?(cmd)
25
+
26
+ def global_params(context, cmd)
27
+ context.instance_eval do
28
+ opt :pki_file, 'PKI File', type: :string, required: true
29
+ opt :team, 'Organization Unit name', type: :string, required: cmd == :init
30
+ opt :country, 'Organization Unit name', type: :string, required: cmd == :init
31
+ opt :state, 'Organization Unit name', type: :string, required: cmd == :init
32
+ opt :city, 'Organization Unit name', type: :string, required: cmd == :init
33
+ opt :organization, 'Organization Unit name', type: :string, required: cmd == :init
34
+ end
35
+ end
36
+
37
+ opts = case cmd
38
+ when :init
39
+ Optimist.options do
40
+ banner 'Usage: kybssl init [options]'
41
+ opt :outputdir, 'Output Directory', type: :string, default: 'pki'
42
+ opt :force, 'Overwrite file if it already exists', type: :bool, default: false
43
+ global_params(self, cmd)
44
+ end
45
+ when :add_ca
46
+ Optimist.options do
47
+ banner 'Usage: kybssl add-ca [options]'
48
+ opt :caname, 'CA Name', type: :string, required: true
49
+ opt :name, 'Common Name', type: :string, required: true
50
+ opt :expiration, 'Validity Years', type: :integer, default: 10
51
+ opt :keysize, 'Key Size', type: :integer, default: 2048
52
+ opt :parent, 'Parent CA', type: :string, default: 'root'
53
+ global_params(self, cmd)
54
+ end
55
+ when :add_certificate
56
+ Optimist.options do
57
+ banner 'Usage: kybssl add-certificate [options]'
58
+ opt :name, 'Common Name', type: :string, required: true
59
+ opt :email, 'User Email', type: :string, require: true
60
+ opt :dns, 'Server DNS', type: :string
61
+ opt :ca, 'CA Name', type: :string, required: true
62
+ opt :expiration, 'Validity Years', type: :integer, default: 5
63
+ opt :type, 'Type of certificate client|server', type: :string, default: 'client'
64
+ global_params(self, cmd)
65
+ end
66
+ when :revoke_certificate
67
+ Optimist.options do
68
+ banner 'Usage: kybssl revoke-certificate [options]'
69
+ opt :serial, 'Certificate Serial', type: :string, required: true
70
+ global_params(self, cmd)
71
+ end
72
+ when :build
73
+ Optimist.options do
74
+ banner 'Usage: kybssl build [options]'
75
+ global_params(self, cmd)
76
+ end
77
+ end
78
+
79
+ case cmd
80
+ when :init
81
+ run_init(opts)
82
+ when :add_ca
83
+ run_add_ca(opts)
84
+ when :add_certificate
85
+ run_add_certificate(opts)
86
+ when :revoke_certificate
87
+ run_revoke_certificate(opts)
88
+ when :build
89
+ run_build(opts)
90
+ end
@@ -39,7 +39,7 @@ module Kybus
39
39
 
40
40
  def sign!
41
41
  @cert.issuer = @ca.cert.subject
42
- @cert.sign(@ca.key, OpenSSL::Digest::SHA256.new)
42
+ @cert.sign(@ca.key, OpenSSL::Digest.new('SHA256'))
43
43
  end
44
44
 
45
45
  def save!
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module SSL
5
+ module CLI
6
+ class AddCA < BaseCommand
7
+ def run
8
+ load_template
9
+ update_yaml_file
10
+ end
11
+
12
+ private
13
+
14
+ def update_yaml_file
15
+ new_ca = {
16
+ caname: @opts[:caname],
17
+ name: @opts[:name],
18
+ expiration: @opts[:expiration],
19
+ key_size: @opts[:key_size],
20
+ parent: @opts[:parent] || 'root',
21
+ serial: next_serial,
22
+ extensions: {
23
+ basicConstraints: {
24
+ details: 'CA:true, pathlen:0',
25
+ critical: true
26
+ }
27
+ }
28
+ }
29
+
30
+ @template['certificate_descriptions']['authorities']['certificates'] << new_ca
31
+
32
+ save_template
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module SSL
5
+ module CLI
6
+ class AddCertificate < BaseCommand
7
+ def run
8
+ load_template
9
+ update_yaml_file
10
+ end
11
+
12
+ private
13
+
14
+ def update_yaml_file
15
+ new_certificate = {
16
+ parent: @opts[:ca],
17
+ name: @opts[:name],
18
+ expiration: @opts[:expiration],
19
+ key_size: @opts[:key_size],
20
+ serial: next_serial,
21
+ organization: @opts[:org],
22
+ team: @opts[:team],
23
+ country: @opts[:country],
24
+ city: @opts[:city],
25
+ state: @opts[:state],
26
+ email: @opts[:email],
27
+ revoked: false
28
+ }.compact
29
+
30
+ @template['certificate_descriptions']['clients']['certificates'] << new_certificate
31
+
32
+ save_template
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kybus
4
+ module SSL
5
+ module CLI
6
+ class BaseCommand
7
+ def initialize(opts)
8
+ @opts = opts
9
+ end
10
+
11
+ def transform_keys_recursively(hash)
12
+ hash.each_with_object({}) do |(key, value), new_hash|
13
+ new_key = key.is_a?(Symbol) ? key.to_s : key
14
+ new_value = if value.is_a?(Hash)
15
+ transform_keys_recursively(value)
16
+ elsif value.is_a?(Array)
17
+ value.map { |v| transform_keys_recursively(v) }
18
+ else
19
+ value
20
+ end
21
+ new_hash[new_key] = new_value
22
+ end
23
+ end
24
+
25
+ def load_template
26
+ @template = YAML.load_file(@opts[:pki_file])
27
+ end
28
+
29
+ def save_template
30
+ @template = transform_keys_recursively(@template)
31
+ File.write(@opts[:pki_file], @template.to_yaml)
32
+ end
33
+
34
+ def next_serial
35
+ @template['serial_counter'] += 1
36
+ end
37
+
38
+ def pki_file_exist?
39
+ File.file?(@opts[:pki_file])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
File without changes
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+
5
+ module Kybus
6
+ module SSL
7
+ module CLI
8
+ class Init < BaseCommand
9
+ def build_default_config
10
+ @template = {
11
+ serial_counter: 3,
12
+ certificate_descriptions: {
13
+ defaults: certificate_defaults,
14
+ authorities: default_authorities,
15
+ clients: default_clients_config,
16
+ servers: default_servers_config
17
+ }
18
+ }
19
+ end
20
+
21
+ def default_certificate_extensions
22
+ {
23
+ subjectKeyIdentifier: {
24
+ details: 'hash',
25
+ critical: false
26
+ },
27
+ authorityKeyIdentifier: {
28
+ details: 'keyid:always',
29
+ critical: false
30
+ },
31
+ basicConstraints: {
32
+ details: 'CA:false',
33
+ critical: false
34
+ }
35
+ }
36
+ end
37
+
38
+ def certificate_defaults
39
+ {
40
+ saving_directory: @opts[:outputdir],
41
+ country: @opts[:country],
42
+ state: @opts[:state],
43
+ city: @opts[:city],
44
+ organization: @opts[:organization],
45
+ team: @opts[:team],
46
+ key_size: @opts[:key_size],
47
+ expiration: 5,
48
+ extensions: default_certificate_extensions
49
+ }
50
+ end
51
+
52
+ def root_ca
53
+ {
54
+ name: "#{@opts[:organization]} Root CA",
55
+ expiration: 20,
56
+ serial: 1,
57
+ key_size: 4096,
58
+ ca: 'root',
59
+ parent: 'root'
60
+ }
61
+ end
62
+
63
+ def servers_ca
64
+ {
65
+ name: "#{@opts[:organization]} Servers CA",
66
+ parent: 'root',
67
+ expiration: 10,
68
+ serial: 2,
69
+ ca: 'servers',
70
+ key_size: 2048,
71
+ extensions: {
72
+ basicConstraints: {
73
+ details: 'CA:true, pathlen:0',
74
+ critical: true
75
+ }
76
+ }
77
+ }
78
+ end
79
+
80
+ def clients_ca
81
+ {
82
+ name: "#{@opts[:organization]} Clients CA",
83
+ parent: 'root',
84
+ expiration: 10,
85
+ serial: 3,
86
+ ca: 'clients',
87
+ key_size: 2048,
88
+ extensions: {
89
+ basicConstraints: {
90
+ details: 'CA:true, pathlen:0',
91
+ critical: true
92
+ }
93
+ }
94
+ }
95
+ end
96
+
97
+ def default_authorities
98
+ {
99
+ defaults: {
100
+ parent: 'root',
101
+ extensions: {
102
+ basicConstraints: {
103
+ details: 'CA:true',
104
+ critical: true
105
+ },
106
+ keyUsage: {
107
+ details: 'Digital Signature, keyCertSign, cRLSign',
108
+ critical: true
109
+ }
110
+ }
111
+ },
112
+ certificates: [root_ca, servers_ca, clients_ca]
113
+ }
114
+ end
115
+
116
+ def default_servers_config
117
+ {
118
+ defaults: {
119
+ parent: 'servers',
120
+ extensions: {
121
+ 'Netscape Cert Type': {
122
+ details: 'SSL Server',
123
+ critical: false
124
+ },
125
+ 'Netscape Comment': {
126
+ details: 'Server certificate',
127
+ critical: false
128
+ },
129
+ keyUsage: {
130
+ details: 'Digital Signature, Key Encipherment',
131
+ critical: true
132
+ },
133
+ extendedKeyUsage: {
134
+ details: 'TLS Web Server Authentication',
135
+ critical: false
136
+ },
137
+ authorityKeyIdentifier: {
138
+ details: 'keyid, issuer:always',
139
+ critical: false
140
+ },
141
+ subjectAltName: {
142
+ details: '$dns',
143
+ critical: false
144
+ }
145
+ }
146
+ },
147
+ certificates: []
148
+ }
149
+ end
150
+
151
+ def default_clients_config
152
+ {
153
+ defaults: {
154
+ parent: 'clients',
155
+ extensions: {
156
+ 'Netscape Cert Type': {
157
+ details: 'SSL Client, S/MIME',
158
+ critical: false
159
+ },
160
+ 'Netscape Comment': {
161
+ details: 'Client certificate',
162
+ critical: false
163
+ },
164
+ keyUsage: {
165
+ details: 'Digital Signature, Non Repudiation, Key Encipherment',
166
+ critical: true
167
+ },
168
+ extendedKeyUsage: {
169
+ details: 'TLS Web Client Authentication, E-mail Protection',
170
+ critical: false
171
+ },
172
+ subjectAltName: {
173
+ details: '$email',
174
+ critical: false
175
+ }
176
+ },
177
+ team: @opts[:team]
178
+ },
179
+ certificates: []
180
+ }
181
+ end
182
+
183
+ def run
184
+ abort 'File already exists. Use --force to overwrite.' if pki_file_exist? && !@opts[:force]
185
+ build_default_config
186
+ save_template
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
File without changes
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'cli/init'
4
+ require_relative 'cli/add_ca'
5
+ require_relative 'cli/add_certificate'
6
+ require_relative 'cli/revoke_certificate'
@@ -26,8 +26,8 @@ module Kybus
26
26
 
27
27
  def subject_string
28
28
  "/C=#{@config['country']}/ST=#{@config['state']}" \
29
- "/L=#{@config['city']}/O=#{@config['organization']}" \
30
- "/OU=#{@config['team']}/CN=#{@config['name']}"
29
+ "/L=#{@config['city']}/O=#{@config['organization']}" \
30
+ "/OU=#{@config['team']}/CN=#{@config['name']}"
31
31
  end
32
32
 
33
33
  def configure_cert_details!(cert)
@@ -35,14 +35,23 @@ module Kybus
35
35
  cert.serial = @config['serial']
36
36
  cert.subject = OpenSSL::X509::Name.parse(subject_string)
37
37
  cert.not_before = Time.now
38
- cert.not_after = cert.not_before + ONE_YEAR * @config['expiration']
38
+ cert.not_after = cert.not_before + (ONE_YEAR * @config['expiration'])
39
+ end
40
+
41
+ def apply_placeholders(description)
42
+ if description.include?('$')
43
+ description.gsub('$email', "email:#{@config['email']}").gsub('$dns', "DNS:#{@config['dns']}")
44
+ else
45
+ description
46
+ end
39
47
  end
40
48
 
41
49
  def configure_extensions!(cert, extension_factory)
42
50
  @config['extensions'].each do |name, details|
51
+ applied_description = apply_placeholders(details['details'])
43
52
  extension = extension_factory.create_extension(
44
53
  name,
45
- details['details'],
54
+ applied_description,
46
55
  details['critical']
47
56
  )
48
57
  cert.add_extension(extension)
@@ -47,6 +47,8 @@ module Kybus
47
47
  # configurations.
48
48
  class SubInventory
49
49
  def initialize(configs, inventory)
50
+ raise 'Nil config' if configs.nil?
51
+
50
52
  defaults = configs['defaults']
51
53
  @parent = inventory
52
54
  @certificates = configs['certificates'].map do |cert|
@@ -64,7 +66,10 @@ module Kybus
64
66
  end
65
67
 
66
68
  def ca(name)
67
- @certificates.find { |cert| cert.ca_name == name }
69
+ ca = @certificates.find { |cert| cert.ca_name == name }
70
+ raise "CA #{name} not found" if ca.nil?
71
+
72
+ ca
68
73
  end
69
74
  end
70
75
  end
@@ -4,7 +4,9 @@ module Kybus
4
4
  module SSL
5
5
  # Generates revocation list after revocating a list of certs
6
6
  # TODO: Implement CRL
7
+ # rubocop: disable Lint/EmptyClass
7
8
  class RevocationList
8
9
  end
10
+ # rubocop: enable Lint/EmptyClass
9
11
  end
10
12
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kybus
4
4
  module SSL
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kybus-ssl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilberto Vargas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-15 00:00:00.000000000 Z
11
+ date: 2024-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: optimist
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -97,12 +111,21 @@ dependencies:
97
111
  description: Package for creating self signed certificates for development purpose
98
112
  email:
99
113
  - tachoguitar@gmail.com
100
- executables: []
114
+ executables:
115
+ - kybssl
101
116
  extensions: []
102
117
  extra_rdoc_files: []
103
118
  files:
119
+ - bin/kybssl
104
120
  - lib/kybus/ssl.rb
105
121
  - lib/kybus/ssl/certificate.rb
122
+ - lib/kybus/ssl/cli.rb
123
+ - lib/kybus/ssl/cli/add_ca.rb
124
+ - lib/kybus/ssl/cli/add_certificate.rb
125
+ - lib/kybus/ssl/cli/base_command.rb
126
+ - lib/kybus/ssl/cli/build.rb
127
+ - lib/kybus/ssl/cli/init.rb
128
+ - lib/kybus/ssl/cli/revoke_certificate.rb
106
129
  - lib/kybus/ssl/configuration.rb
107
130
  - lib/kybus/ssl/inventory.rb
108
131
  - lib/kybus/ssl/revocation_list.rb
@@ -110,7 +133,8 @@ files:
110
133
  homepage: https://github.com/KueskiEngineering/ruby-kybus-server
111
134
  licenses:
112
135
  - MIT
113
- metadata: {}
136
+ metadata:
137
+ rubygems_mfa_required: 'true'
114
138
  post_install_message:
115
139
  rdoc_options: []
116
140
  require_paths:
@@ -126,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
150
  - !ruby/object:Gem::Version
127
151
  version: '0'
128
152
  requirements: []
129
- rubygems_version: 3.1.4
153
+ rubygems_version: 3.5.14
130
154
  signing_key:
131
155
  specification_version: 4
132
156
  summary: Kybus SSL tools