kybus-ssl 0.1.0 → 0.2.0

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.
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