tls-cookbook-cli 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f229793f288565888b208f802076074a4f17c3de
4
+ data.tar.gz: 222c9728bc5b935a0d4c737596a5f91b70d99c41
5
+ SHA512:
6
+ metadata.gz: b534f591efd00f47c6e3ba21be967f59747bf9da57a4e0f42cfc0c979395ab8473057987c8ebbfa35477e16301a840574c1ae6de5dfb1f20006b4fc1894ceb42
7
+ data.tar.gz: dee4a11547884ca1f1450589529f2db457388240c03e17e55b0e4e377463273c4795503d38a9806e8a3e89bb28ada83d6da021bdc9848a1a1065e7a53458b569
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'tls/cli'
3
+ ::ChefCookbook::TLS::CLI::Main.start(ARGV)
data/lib/tls/cli.rb ADDED
@@ -0,0 +1 @@
1
+ require 'tls/cli/main'
@@ -0,0 +1,195 @@
1
+ require 'thor'
2
+ require 'openssl'
3
+ require 'date'
4
+ require 'digest'
5
+ require 'base64'
6
+
7
+ module ChefCookbook
8
+ module TLS
9
+ module CLI
10
+ module Helpers
11
+ def self.valid_key_file?(key_file)
12
+ key = nil
13
+ if ::File.exist?(key_file)
14
+ begin
15
+ key = ::OpenSSL::PKey.read(::IO.read(key_file))
16
+ rescue ::OpenSSL::PKey::PKeyError
17
+ key = nil
18
+ end
19
+ end
20
+
21
+ !key.nil?
22
+ end
23
+
24
+ def self.valid_certificate_file?(cert_file)
25
+ cert = nil
26
+ if ::File.exist?(cert_file)
27
+ cert = ::OpenSSL::X509::Certificate.new(::IO.read(cert_file))
28
+ end
29
+
30
+ !cert.nil?
31
+ end
32
+
33
+ def self.valid_certificate_directory?(path)
34
+ valid_key_file?(::File.join(path, 'server.key')) &&
35
+ valid_certificate_file?(::File.join(path, 'server.crt')) &&
36
+ ::File.exist?(::File.join(path, 'server.chain.crt')) &&
37
+ ::File.exist?(::File.join(path, 'server.fullchain.crt'))
38
+ end
39
+
40
+ def self.valid_next_directory?(path)
41
+ valid_key_file?(::File.join(path, 'server.key'))
42
+ end
43
+
44
+ def self.valid_directory?(path)
45
+ certificate_dir_regexp = /^\d{4}-\d{2}-\d{2}$/
46
+ has_next_dir = false
47
+ has_certificate_dir = false
48
+ dir = ::Dir.new(path)
49
+ dir.each do |x|
50
+ subdir_path = ::File.join(path, x)
51
+ if ::File.directory?(subdir_path)
52
+ if x == 'next'
53
+ has_next_dir = valid_next_directory?(subdir_path)
54
+ end
55
+
56
+ if !has_certificate_dir && !certificate_dir_regexp.match(x).nil?
57
+ has_certificate_dir = valid_certificate_directory?(subdir_path)
58
+ end
59
+ end
60
+ end
61
+
62
+ has_next_dir && has_certificate_dir
63
+ end
64
+
65
+ def self.list_entries(pwd)
66
+ dir = ::Dir.new(pwd)
67
+ stop_list = %w(
68
+ .
69
+ ..
70
+ .emergency
71
+ )
72
+ dir.select do |x|
73
+ path = ::File.join(pwd, x)
74
+ !stop_list.include?(x) && ::File.directory?(path) && valid_directory?(path)
75
+ end
76
+ end
77
+
78
+ def self.get_possible_items(path)
79
+ dir = ::Dir.new(path)
80
+ certificate_dir_regexp = /^\d{4}-\d{2}-\d{2}$/
81
+ dir.select do |x|
82
+ subdir_path = ::File.join(path, x)
83
+ ::File.directory?(subdir_path) && !certificate_dir_regexp.match(x).nil? && valid_certificate_directory?(subdir_path)
84
+ end
85
+ end
86
+
87
+ def self.find_valid_item(path)
88
+ get_possible_items(path).max_by do |x|
89
+ ::Date.parse(x)
90
+ end
91
+ end
92
+
93
+ def self.get_private_key(pwd, entry_name, item_name)
94
+ path = ::File.join(pwd, entry_name, item_name, 'server.key')
95
+ return ::IO.read(path).strip
96
+ end
97
+
98
+ def self.get_certificates(path)
99
+ certificates = []
100
+ ::IO.readlines(path).each do |ln|
101
+ if ln == "-----BEGIN CERTIFICATE-----\n"
102
+ certificates << ln
103
+ else
104
+ certificates[-1] += ln
105
+ end
106
+ end
107
+
108
+ certificates.map { |x| x.strip }
109
+ end
110
+
111
+ def self.get_fullchain(pwd, entry_name, item_name)
112
+ fullchain_file = ::File.join(pwd, entry_name, item_name, 'server.fullchain.crt')
113
+ get_certificates(fullchain_file)
114
+ end
115
+
116
+ def self.get_domain_list(pwd, entry_name, item_name)
117
+ cert_file = ::File.join(pwd, entry_name, item_name, 'server.crt')
118
+ cert = ::OpenSSL::X509::Certificate.new(::IO.read(cert_file))
119
+ domains = []
120
+
121
+ cert.extensions.each do |x|
122
+ if x.oid == 'subjectAltName'
123
+ domains += x.value.split(',').map { |x| x.split(':')[1] }
124
+ end
125
+ end
126
+
127
+ domains
128
+ end
129
+
130
+ def self.get_hpkp_pin(key_file)
131
+ key = ::OpenSSL::PKey.read(::IO.read(key_file))
132
+ public_key = nil
133
+ if key.class == ::OpenSSL::PKey::RSA
134
+ public_key = key.public_key
135
+ elsif key.class == ::OpenSSL::PKey::EC
136
+ public_key = ::OpenSSL::PKey::EC.new(key.group.curve_name)
137
+ public_key.public_key = key.public_key
138
+ end
139
+
140
+ ::Digest::SHA256.base64digest(public_key.to_der)
141
+ end
142
+
143
+ def self.get_hpkp_pin_list(pwd, entry_name, item_name)
144
+ pin_list = []
145
+ main_key_file = ::File.join(pwd, entry_name, item_name, 'server.key')
146
+ pin_list << get_hpkp_pin(main_key_file)
147
+
148
+ emergency_key_file = nil
149
+ key = ::OpenSSL::PKey.read(::IO.read(main_key_file))
150
+ if key.class == ::OpenSSL::PKey::RSA
151
+ emergency_key_file = ::File.join(pwd, '.emergency', 'rsa', 'server.key')
152
+ elsif key.class == ::OpenSSL::PKey::EC
153
+ emergency_key_file = ::File.join(pwd, '.emergency', 'ec', 'server.key')
154
+ end
155
+ if !emergency_key_file.nil? && ::File.file?(emergency_key_file)
156
+ pin_list.unshift(get_hpkp_pin(emergency_key_file))
157
+ end
158
+
159
+ next_key_file = ::File.join(pwd, entry_name, 'next', 'server.key')
160
+ pin_list << get_hpkp_pin(next_key_file)
161
+
162
+ pin_list
163
+ end
164
+
165
+ def self.get_scts(pwd, entry_name, item_name)
166
+ scts_dir = ::File.join(pwd, entry_name, item_name, 'scts')
167
+ h = {}
168
+ if ::File.directory?(scts_dir)
169
+ ::Dir.new(scts_dir).each do |x|
170
+ path = ::File.join(scts_dir, x)
171
+ if ::File.file?(path) && ::File.extname(path) == '.sct'
172
+ log_name = ::File.basename(path, '.sct')
173
+ h[log_name] = ::Base64.strict_encode64(::IO.read(path))
174
+ end
175
+ end
176
+ end
177
+
178
+ h
179
+ end
180
+
181
+ def self.jsonify_entry(pwd, entry_name)
182
+ item_name = find_valid_item(::File.join(pwd, entry_name))
183
+ {
184
+ name: entry_name,
185
+ domains: get_domain_list(pwd, entry_name, item_name),
186
+ chain: get_fullchain(pwd, entry_name, item_name),
187
+ private_key: get_private_key(pwd, entry_name, item_name),
188
+ hpkp_pins: get_hpkp_pin_list(pwd, entry_name, item_name),
189
+ scts: get_scts(pwd, entry_name, item_name)
190
+ }
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,30 @@
1
+ require 'thor'
2
+ require 'json'
3
+ require 'tls/cli/helpers'
4
+
5
+ module ChefCookbook
6
+ module TLS
7
+ module CLI
8
+ class Main < ::Thor
9
+ desc 'list', 'List directory'
10
+ option :pwd
11
+ def list
12
+ pwd = options[:pwd] || ::Dir.pwd
13
+ puts ::ChefCookbook::TLS::CLI::Helpers.list_entries(pwd)
14
+ end
15
+
16
+ desc 'jsonify ENTRY_NAME', 'Present ENTRY_NAME in JSON format'
17
+ option :pwd
18
+ def jsonify(entry_name)
19
+ pwd = options[:pwd] || ::Dir.pwd
20
+ puts ::JSON.pretty_generate(
21
+ ::ChefCookbook::TLS::CLI::Helpers.jsonify_entry(
22
+ pwd,
23
+ entry_name
24
+ )
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tls-cookbook-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Pyatkin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.19.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.19.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: TLS Cookbook CLI
56
+ email: aspyatkin@gmail.com
57
+ executables:
58
+ - tls-cookbook-cli
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/tls-cookbook-cli
63
+ - lib/tls/cli.rb
64
+ - lib/tls/cli/helpers.rb
65
+ - lib/tls/cli/main.rb
66
+ homepage: https://github.com/aspyatkin/tls-cookbook-cli
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '2.3'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.6.11
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: TLS Cookbook CLI
90
+ test_files: []