thales-pse 0.1.1
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 +7 -0
- data/.rspec +3 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +70 -0
- data/README.md +29 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/thales/pse/cli.rb +69 -0
- data/lib/thales/pse/config.rb +313 -0
- data/lib/thales/pse/hsm.rb +75 -0
- data/lib/thales/pse/slot.rb +23 -0
- data/lib/thales/pse/token.rb +313 -0
- data/lib/thales/pse/version.rb +7 -0
- data/lib/thales/pse.rb +21 -0
- data/pty_test.rb +23 -0
- data/thales-pse.gemspec +43 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9822d9ede725eb7e93e61f5da6edd57880e9085263fac58f4e0d28ac72949747
|
4
|
+
data.tar.gz: c3c6041f5dbde1e17a4709092be0a425f752f11535fb2db9074cb39d2a19abbb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8bfc6a8cd47b76425c40c9d00959997583d07c5a62394a7e6f928ff367d89905c5dbcc189c0aebbc780a1e33753501c980b2bd74dc09f5403732e327e78d3f3b
|
7
|
+
data.tar.gz: 51661eade08e5edfd65a7d61a2e3d4e32978e5c07aebb0552067ef92623e091b44f9e8e1d7b39eda3ea916f9d45315ef99819ae2ff8b7fca49e55d2aa644b0e7
|
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in thales-pse.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "rspec", "~> 3.0"
|
11
|
+
|
12
|
+
#gem 'toolrack', path: '/mnt/Vault/08.Dev/01.Workspaces/WIP/toolrack'
|
13
|
+
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
thales-pse (0.1.0)
|
5
|
+
tlogger
|
6
|
+
toolrack
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
base58 (0.2.3)
|
12
|
+
devops_helper (0.5.0)
|
13
|
+
git_cli
|
14
|
+
gvcs
|
15
|
+
tlogger
|
16
|
+
toolrack
|
17
|
+
tty-prompt (= 0.22.0)
|
18
|
+
diff-lcs (1.4.4)
|
19
|
+
git_cli (0.8.0)
|
20
|
+
gvcs (>= 0.1.0)
|
21
|
+
ptools (~> 1.4.0)
|
22
|
+
tlogger (>= 0.21)
|
23
|
+
toolrack (>= 0.4.0)
|
24
|
+
gvcs (0.1.0)
|
25
|
+
pastel (0.8.0)
|
26
|
+
tty-color (~> 0.5)
|
27
|
+
ptools (1.4.2)
|
28
|
+
rake (13.0.6)
|
29
|
+
rspec (3.10.0)
|
30
|
+
rspec-core (~> 3.10.0)
|
31
|
+
rspec-expectations (~> 3.10.0)
|
32
|
+
rspec-mocks (~> 3.10.0)
|
33
|
+
rspec-core (3.10.1)
|
34
|
+
rspec-support (~> 3.10.0)
|
35
|
+
rspec-expectations (3.10.1)
|
36
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
+
rspec-support (~> 3.10.0)
|
38
|
+
rspec-mocks (3.10.2)
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
+
rspec-support (~> 3.10.0)
|
41
|
+
rspec-support (3.10.2)
|
42
|
+
tlogger (0.26.1)
|
43
|
+
toolrack (0.15.0)
|
44
|
+
base58
|
45
|
+
tlogger
|
46
|
+
tty-color (0.6.0)
|
47
|
+
tty-cursor (0.7.1)
|
48
|
+
tty-prompt (0.22.0)
|
49
|
+
pastel (~> 0.8)
|
50
|
+
tty-reader (~> 0.8)
|
51
|
+
tty-reader (0.9.0)
|
52
|
+
tty-cursor (~> 0.7)
|
53
|
+
tty-screen (~> 0.8)
|
54
|
+
wisper (~> 2.0)
|
55
|
+
tty-screen (0.8.1)
|
56
|
+
wisper (2.0.1)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
java
|
60
|
+
universal-java-1.8
|
61
|
+
x86_64-linux
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
devops_helper
|
65
|
+
rake (~> 13.0)
|
66
|
+
rspec (~> 3.0)
|
67
|
+
thales-pse!
|
68
|
+
|
69
|
+
BUNDLED WITH
|
70
|
+
2.2.28
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Thales::Pse
|
2
|
+
|
3
|
+
Collection of utilities to integrates with the Thales (Previously SafeNet) ProtectServer External (PSE) HSM.
|
4
|
+
|
5
|
+
It is tested to ease the usage for local development with the simulator. Not for production use.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'thales-pse'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install thales-pse
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Check the usage inside the spec/thales/hsm\_spec.rb
|
26
|
+
|
27
|
+
Currently it is just API to assist in setting up the HSM for usage.
|
28
|
+
|
29
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "thales/pse"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
require 'pty'
|
3
|
+
require 'expect'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Thales
|
7
|
+
module Pse
|
8
|
+
module Cli
|
9
|
+
include TR::CondUtils
|
10
|
+
include TR::CliUtils
|
11
|
+
|
12
|
+
class ExecutableNotFoundError < StandardError; end
|
13
|
+
|
14
|
+
def cli_exec(exec, &block)
|
15
|
+
|
16
|
+
exePath = which(exec)
|
17
|
+
raise ExecutableNotFoundError, "#{exec} cannot be found" if is_empty?(exePath)
|
18
|
+
raise Error, "Block is required" if not block
|
19
|
+
|
20
|
+
params = block.call(:params) || []
|
21
|
+
expect_list = block.call(:expect_list)
|
22
|
+
|
23
|
+
output = block.call(:output) || TR::NullOut.new
|
24
|
+
|
25
|
+
cmd = "#{exePath} #{params.join(" ")}"
|
26
|
+
|
27
|
+
logger.tdebug :cmd, "cli_exec command : #{cmd}"
|
28
|
+
|
29
|
+
PTY.spawn(exePath, *params) do |read, write, pid|
|
30
|
+
|
31
|
+
begin
|
32
|
+
|
33
|
+
if not is_empty?(expect_list)
|
34
|
+
expect_list.each do |ex|
|
35
|
+
to = ex[:timeout] || 1
|
36
|
+
cont = read.expect(/#{ex[:matcher]}/, to)
|
37
|
+
output.puts cont
|
38
|
+
write.puts block.call(ex[:block_key], cont)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Timeout.timeout(1) do
|
43
|
+
read.each do |l|
|
44
|
+
output.puts l if not_empty?(l)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
rescue Timeout::Error => e
|
49
|
+
read.close
|
50
|
+
write.close
|
51
|
+
Process.kill('TERM',pid)
|
52
|
+
output.puts "Process #{cmd} ('#{pid}') killed due to timeout"
|
53
|
+
rescue Errno::EIO
|
54
|
+
output.puts "[Done] #{cmd}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def logger
|
61
|
+
if @logger.nil?
|
62
|
+
@logger = Tlogger.new
|
63
|
+
end
|
64
|
+
@logger
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
|
2
|
+
require 'pty'
|
3
|
+
require 'expect'
|
4
|
+
require 'toolrack'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
require_relative 'cli'
|
8
|
+
|
9
|
+
module Thales
|
10
|
+
module Pse
|
11
|
+
module Config
|
12
|
+
include TR::CondUtils
|
13
|
+
include TR::CliUtils
|
14
|
+
include Cli
|
15
|
+
|
16
|
+
def init(&block)
|
17
|
+
|
18
|
+
expect = [
|
19
|
+
{ key: "enter new Admin SO pin:", block_key: :admin_so_pin, timeout: 1 },
|
20
|
+
{ key: "confirm new Admin SO pin:", block_key: :admin_so_pin_confirm, timeout: 1 },
|
21
|
+
{ key: "enter new Administrator\'s pin:", block_key: :admin_pin, timeout: 1 },
|
22
|
+
{ key: "confirm new Administrator\'s pin:", block_key: :admin_pin_confirm, timeout: 1 }
|
23
|
+
]
|
24
|
+
|
25
|
+
begin
|
26
|
+
|
27
|
+
cli_exec("ctconf") do |ops|
|
28
|
+
case ops
|
29
|
+
when :expect_list
|
30
|
+
expect
|
31
|
+
else
|
32
|
+
block.call(ops)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue ExecutableNotFoundError
|
37
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def init_token(&block)
|
43
|
+
|
44
|
+
raise Error, "Block is required" if not block
|
45
|
+
|
46
|
+
expect = [
|
47
|
+
{ key: "new token label:", block_key: :token_label, timeout: 1 },
|
48
|
+
{ key: "enter Security Officer\'s pin:", block_key: :token_so_pin, timeout: 1 },
|
49
|
+
{ key: "confirm Security Officer\'s pin:", block_key: :token_so_pin_confirm, timeout: 1 }
|
50
|
+
]
|
51
|
+
|
52
|
+
slot = block.call(:slot) || 0
|
53
|
+
|
54
|
+
begin
|
55
|
+
|
56
|
+
cli_exec("ctconf") do |ops|
|
57
|
+
case ops
|
58
|
+
when :params
|
59
|
+
["-n#{slot}"]
|
60
|
+
when :expect_list
|
61
|
+
expect
|
62
|
+
else
|
63
|
+
block.call(ops)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
rescue ExecutableNotFoundError
|
68
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def init_user_pin(&block)
|
74
|
+
|
75
|
+
raise Error, "Block is required" if not block
|
76
|
+
|
77
|
+
expect = [
|
78
|
+
# this key is handled locally not passed to external
|
79
|
+
{ key: "Security Officer PIN.+:|current user PIN.+:", block_key: :auth_pin, timeout: 3 },
|
80
|
+
{ key: "enter the new user PIN.+:", block_key: :token_user_pin, timeout: 1 },
|
81
|
+
{ key: "confirm the new user PIN.+:", block_key: :token_user_pin_confirm, timeout: 1 }
|
82
|
+
]
|
83
|
+
|
84
|
+
slot = block.call(:slot) || 0
|
85
|
+
|
86
|
+
begin
|
87
|
+
|
88
|
+
cli_exec("ctkmu") do |ops, val|
|
89
|
+
case ops
|
90
|
+
when :params
|
91
|
+
["p","-s#{slot}"]
|
92
|
+
when :expect_list
|
93
|
+
expect
|
94
|
+
when :auth_pin
|
95
|
+
if not_empty?(val)
|
96
|
+
if val.join =~ /Security Officer/
|
97
|
+
block.call(:token_so_pin)
|
98
|
+
else
|
99
|
+
block.call(:token_user_pin)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
else
|
103
|
+
block.call(ops)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
rescue ExecutableNotFoundError
|
108
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def genkey(type, &block)
|
115
|
+
|
116
|
+
raise Error, "Block is required" if not block
|
117
|
+
|
118
|
+
expect = [
|
119
|
+
{ key: "Enter user PIN.+:", block_key: :slot_user_pin, timeout: 1 }
|
120
|
+
]
|
121
|
+
|
122
|
+
case type
|
123
|
+
when :rsa
|
124
|
+
else
|
125
|
+
raise Error, "Unsupported key type #{type}"
|
126
|
+
end
|
127
|
+
|
128
|
+
slot = block.call(:slot) || 0
|
129
|
+
|
130
|
+
name = block.call(:name)
|
131
|
+
raise Error, "Name is required " if is_empty?(name)
|
132
|
+
name.gsub!(" ","_")
|
133
|
+
|
134
|
+
attr = block.call(:attr)
|
135
|
+
raise Error, "Attributes (attr) is required " if is_empty?(attr)
|
136
|
+
attr = [attr] if not attr.is_a?(Array)
|
137
|
+
atRes = []
|
138
|
+
attr.each do |at|
|
139
|
+
case at
|
140
|
+
when :private
|
141
|
+
atRes << "P"
|
142
|
+
when :modifiable
|
143
|
+
atRes << "M"
|
144
|
+
when :sensitive
|
145
|
+
atRes << "T"
|
146
|
+
when :wrap
|
147
|
+
atRes << "W"
|
148
|
+
when :export
|
149
|
+
atRes << "w"
|
150
|
+
when :import
|
151
|
+
atRes << "I"
|
152
|
+
when :unwrap
|
153
|
+
atRes << "U"
|
154
|
+
when :extractable
|
155
|
+
atRes << "X"
|
156
|
+
when :exportable
|
157
|
+
atRes << "x"
|
158
|
+
when :derive
|
159
|
+
atRes << "R"
|
160
|
+
when :encrypt
|
161
|
+
atRes << "E"
|
162
|
+
when :decrypt
|
163
|
+
atRes << "D"
|
164
|
+
when :sign
|
165
|
+
atRes << "S"
|
166
|
+
when :verify
|
167
|
+
atRes << "V"
|
168
|
+
when :sign_local_cert
|
169
|
+
atRes << "L"
|
170
|
+
when :usage_count
|
171
|
+
atRes << "C"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
keysize = block.call(:keysize) || 2048
|
176
|
+
|
177
|
+
begin
|
178
|
+
|
179
|
+
cli_exec("ctkmu") do |ops, val|
|
180
|
+
case ops
|
181
|
+
when :params
|
182
|
+
["c","-t#{type}","-s#{slot}","-n#{name}","-a#{atRes.join}"]
|
183
|
+
when :expect_list
|
184
|
+
expect
|
185
|
+
else
|
186
|
+
block.call(ops)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
rescue ExecutableNotFoundError
|
191
|
+
raise Error, "Executable 'ctkmu' not found from PATH. Please install the driver or add the executable to PATH"
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
def gencert(&block)
|
198
|
+
|
199
|
+
raise Error, "Block is required" if not block
|
200
|
+
|
201
|
+
expect = [
|
202
|
+
{ key: "Enter user PIN.+:", block_key: :slot_user_pin, timeout: 1 },
|
203
|
+
]
|
204
|
+
|
205
|
+
keylabel = block.call(:keylabel)
|
206
|
+
raise Error, "Keylabel should not be empty" if is_empty?(keylabel)
|
207
|
+
keylabel.gsub!(" ","_")
|
208
|
+
|
209
|
+
slot = block.call(:slot)
|
210
|
+
validFrom = block.call(:valid_from)
|
211
|
+
#if is_empty?(validFrom) or not validFrom.is_a?(Time)
|
212
|
+
# today = Time.now
|
213
|
+
# validFrom = Time.new(today.year, today.month, today.day)
|
214
|
+
#end
|
215
|
+
validity = block.call(:validity)
|
216
|
+
if not (validity =~ /h|d|m|y/)
|
217
|
+
raise Error, "Validity requires unit in hour (h), day (d), month (m) or year (y)"
|
218
|
+
end
|
219
|
+
validTo = block.call(:valid_to)
|
220
|
+
raise Error, "Valid_to requires a time object" if (not_empty?(validTo) and not validTo.is_a?(Time))
|
221
|
+
|
222
|
+
slot = block.call(:slot) || 0
|
223
|
+
certFile = block.call(:cert_file)
|
224
|
+
|
225
|
+
cn = block.call(:common_name)
|
226
|
+
raise Error, "Common name is mandatory" if is_empty?(cn)
|
227
|
+
expect << { key: "Common Name:", block_key: :cn, timeout: 1 }
|
228
|
+
org = block.call(:org)
|
229
|
+
expect << { key: "Organization:", block_key: :org, timeout: 1 }
|
230
|
+
ou = block.call(:ou)
|
231
|
+
expect << { key: "Organizational Unit:", block_key: :ou, timeout: 1 }
|
232
|
+
loc = block.call(:locality)
|
233
|
+
expect << { key: "Locality:", block_key: :loc, timeout: 1 }
|
234
|
+
st = block.call(:state)
|
235
|
+
expect << { key: "State:", block_key: :st, timeout: 1 }
|
236
|
+
ctry = block.call(:country)
|
237
|
+
expect << { key: "Country:", block_key: :ctry, timeout: 1 }
|
238
|
+
sn = block.call(:serial_no) || SecureRandom.uuid.gsub("-","")
|
239
|
+
expect << { key: "certificate\'s serial number.+:", block_key: :sn, timeout: 1 }
|
240
|
+
|
241
|
+
params = ["c","-l#{keylabel}", "-s#{slot}"]
|
242
|
+
if not_empty?(validFrom)
|
243
|
+
params << "-b#{validFrom.strftime("%Y%m%d%H%M%S")}"
|
244
|
+
end
|
245
|
+
if not_empty?(validity)
|
246
|
+
params << "-d#{validity}"
|
247
|
+
end
|
248
|
+
if not_empty?(validTo)
|
249
|
+
params << "-e#{validTo.strftime("%Y%m%d%H%M%S")}"
|
250
|
+
end
|
251
|
+
|
252
|
+
begin
|
253
|
+
|
254
|
+
cli_exec("ctcert") do |ops, val|
|
255
|
+
case ops
|
256
|
+
when :params
|
257
|
+
params
|
258
|
+
when :expect_list
|
259
|
+
expect
|
260
|
+
when :cn
|
261
|
+
cn
|
262
|
+
when :org
|
263
|
+
org
|
264
|
+
when :ou
|
265
|
+
ou
|
266
|
+
when :loc
|
267
|
+
loc
|
268
|
+
when :st
|
269
|
+
st
|
270
|
+
when :ctry
|
271
|
+
ctry
|
272
|
+
when :sn
|
273
|
+
sn
|
274
|
+
else
|
275
|
+
block.call(ops)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
rescue ExecutableNotFoundError
|
280
|
+
raise Error, "Executable 'ctkmu' not found from PATH. Please install the driver or add the executable to PATH"
|
281
|
+
end
|
282
|
+
|
283
|
+
if not_empty?(certFile)
|
284
|
+
export_cert(keylabel, certFile, slot)
|
285
|
+
end
|
286
|
+
|
287
|
+
end # gencert
|
288
|
+
|
289
|
+
def export_cert(label, outFile, slot = 0, &block)
|
290
|
+
|
291
|
+
raise Error, "Key label cannot be empty" if is_empty?(label)
|
292
|
+
raise Error, "Output file cannot be empty" if is_empty?(outFile)
|
293
|
+
|
294
|
+
label.gsub!(" ","_")
|
295
|
+
|
296
|
+
begin
|
297
|
+
|
298
|
+
cli_exec("ctcert") do |ops|
|
299
|
+
case ops
|
300
|
+
when :params
|
301
|
+
["x","-l#{label}","-s#{slot}","-f#{outFile}"]
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
rescue ExecutableNotFoundError
|
306
|
+
raise Error, "Executable 'ctcert' not found from PATH. Please install the driver or add the executable to PATH"
|
307
|
+
end
|
308
|
+
|
309
|
+
end # export_cert
|
310
|
+
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
require_relative 'cli'
|
3
|
+
require_relative 'slot'
|
4
|
+
|
5
|
+
module Thales
|
6
|
+
module Pse
|
7
|
+
|
8
|
+
class HSM
|
9
|
+
|
10
|
+
def self.instance(eng = :cli)
|
11
|
+
case eng
|
12
|
+
when :cli
|
13
|
+
h = HSM.new
|
14
|
+
h.extend(Cli::HSM)
|
15
|
+
h
|
16
|
+
else
|
17
|
+
h = HSM.new
|
18
|
+
h.extend(Cli::HSM)
|
19
|
+
h
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
module Cli
|
26
|
+
module HSM
|
27
|
+
include TR::CondUtils
|
28
|
+
include TR::CliUtils
|
29
|
+
include Cli
|
30
|
+
|
31
|
+
def init_hsm(*args,&block)
|
32
|
+
|
33
|
+
expect = [
|
34
|
+
{ matcher: "enter new Admin SO pin:", block_key: :admin_so_pin, timeout: 5 },
|
35
|
+
{ matcher: "confirm new Admin SO pin:", block_key: :admin_so_pin_confirm, timeout: 5 },
|
36
|
+
{ matcher: "enter new Administrator\'s pin:", block_key: :admin_pin, timeout: 5 },
|
37
|
+
{ matcher: "confirm new Administrator\'s pin:", block_key: :admin_pin_confirm, timeout: 5 }
|
38
|
+
]
|
39
|
+
|
40
|
+
begin
|
41
|
+
|
42
|
+
cli_exec("ctconf") do |ops|
|
43
|
+
case ops
|
44
|
+
when :expect_list
|
45
|
+
expect
|
46
|
+
else
|
47
|
+
block.call(ops)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
rescue ExecutableNotFoundError
|
52
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_user_slot
|
59
|
+
if @defUserSlot.nil?
|
60
|
+
@defUserSlot = Slot.new(0)
|
61
|
+
end
|
62
|
+
@defUserSlot
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_admin_slot
|
66
|
+
if @defAdminSlot.nil?
|
67
|
+
@defAdminSlot = Slot.new(1)
|
68
|
+
end
|
69
|
+
@defAdminSlot
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require_relative 'token'
|
3
|
+
|
4
|
+
module Thales
|
5
|
+
module Pse
|
6
|
+
class Slot
|
7
|
+
|
8
|
+
attr_reader :id, :token
|
9
|
+
def initialize(id)
|
10
|
+
@id = id
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_token
|
14
|
+
if @token.nil?
|
15
|
+
@token = Token.new(self)
|
16
|
+
end
|
17
|
+
@token
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require_relative 'cli'
|
4
|
+
|
5
|
+
module Thales
|
6
|
+
module Pse
|
7
|
+
module Cli
|
8
|
+
module Token
|
9
|
+
include TR::CondUtils
|
10
|
+
include TR::CliUtils
|
11
|
+
include Cli
|
12
|
+
|
13
|
+
def init_token(*args, &block)
|
14
|
+
|
15
|
+
init_token_so(&block)
|
16
|
+
init_token_user(&block)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def init_token_so(*args, &block)
|
21
|
+
|
22
|
+
raise TokenError, "Block is required" if not block
|
23
|
+
raise TokenError, "Slot is not available!" if is_empty?(@slot)
|
24
|
+
|
25
|
+
expect = [
|
26
|
+
{ matcher: "new token label:", block_key: :token_label, timeout: 1 },
|
27
|
+
{ matcher: "enter Security Officer\'s pin:", block_key: :token_so_pin, timeout: 1 },
|
28
|
+
{ matcher: "confirm Security Officer\'s pin:", block_key: :token_so_pin_confirm, timeout: 1 }
|
29
|
+
]
|
30
|
+
|
31
|
+
#slot = block.call(:slot) || 0
|
32
|
+
slot = @slot.id
|
33
|
+
|
34
|
+
begin
|
35
|
+
|
36
|
+
cli_exec("ctconf") do |ops|
|
37
|
+
case ops
|
38
|
+
when :params
|
39
|
+
["-n#{slot}"]
|
40
|
+
when :expect_list
|
41
|
+
expect
|
42
|
+
else
|
43
|
+
block.call(ops)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
rescue ExecutableNotFoundError
|
48
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def init_token_user(*args, &block)
|
54
|
+
|
55
|
+
raise TokenError, "Block is required" if not block
|
56
|
+
raise TokenError, "Slot is not available!" if is_empty?(@slot)
|
57
|
+
|
58
|
+
expect = [
|
59
|
+
# this key is handled locally not passed to external
|
60
|
+
{ matcher: "Security Officer PIN.+:|current user PIN.+:", block_key: :auth_pin, timeout: 3 },
|
61
|
+
{ matcher: "enter the new user PIN.+:", block_key: :token_user_pin, timeout: 1 },
|
62
|
+
{ matcher: "confirm the new user PIN.+:", block_key: :token_user_pin_confirm, timeout: 1 }
|
63
|
+
]
|
64
|
+
|
65
|
+
#slot = block.call(:slot) || 0
|
66
|
+
slot = @slot.id
|
67
|
+
|
68
|
+
begin
|
69
|
+
|
70
|
+
cli_exec("ctkmu") do |ops, val|
|
71
|
+
case ops
|
72
|
+
when :params
|
73
|
+
["p","-s#{slot}"]
|
74
|
+
when :expect_list
|
75
|
+
expect
|
76
|
+
when :auth_pin
|
77
|
+
if not_empty?(val)
|
78
|
+
if val.join =~ /Security Officer/
|
79
|
+
block.call(:token_so_pin)
|
80
|
+
else
|
81
|
+
block.call(:token_user_pin)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
block.call(ops)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
rescue ExecutableNotFoundError
|
90
|
+
raise Error, "Executable 'ctconf' not found from PATH. Please install the driver or add the executable to PATH"
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def genkey(*args, &block)
|
96
|
+
|
97
|
+
raise TokenError, "Block is required" if not block
|
98
|
+
raise TokenError, "Slot is not available!" if is_empty?(@slot)
|
99
|
+
|
100
|
+
expect = [
|
101
|
+
{ matcher: "Enter user PIN.+:", block_key: :token_user_pin, timeout: 1 }
|
102
|
+
]
|
103
|
+
|
104
|
+
type = args.first
|
105
|
+
case type
|
106
|
+
when :rsa
|
107
|
+
else
|
108
|
+
raise Error, "Unsupported key type #{type}"
|
109
|
+
end
|
110
|
+
|
111
|
+
#slot = block.call(:slot) || 0
|
112
|
+
slot = @slot.id
|
113
|
+
|
114
|
+
keylabel = block.call(:keylabel)
|
115
|
+
raise Error, "Keylabel is required " if is_empty?(keylabel)
|
116
|
+
keylabel.gsub!(" ","_")
|
117
|
+
|
118
|
+
attr = block.call(:attr)
|
119
|
+
raise Error, "Attributes (attr) is required " if is_empty?(attr)
|
120
|
+
attr = [attr] if not attr.is_a?(Array)
|
121
|
+
atRes = []
|
122
|
+
attr.each do |at|
|
123
|
+
case at
|
124
|
+
when :private
|
125
|
+
atRes << "P"
|
126
|
+
when :modifiable
|
127
|
+
atRes << "M"
|
128
|
+
when :sensitive
|
129
|
+
atRes << "T"
|
130
|
+
when :wrap
|
131
|
+
atRes << "W"
|
132
|
+
when :export
|
133
|
+
atRes << "w"
|
134
|
+
when :import
|
135
|
+
atRes << "I"
|
136
|
+
when :unwrap
|
137
|
+
atRes << "U"
|
138
|
+
when :extractable
|
139
|
+
atRes << "X"
|
140
|
+
when :exportable
|
141
|
+
atRes << "x"
|
142
|
+
when :derive
|
143
|
+
atRes << "R"
|
144
|
+
when :encrypt
|
145
|
+
atRes << "E"
|
146
|
+
when :decrypt
|
147
|
+
atRes << "D"
|
148
|
+
when :sign
|
149
|
+
atRes << "S"
|
150
|
+
when :verify
|
151
|
+
atRes << "V"
|
152
|
+
when :sign_local_cert
|
153
|
+
atRes << "L"
|
154
|
+
when :usage_count
|
155
|
+
atRes << "C"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
keysize = block.call(:keysize) || 2048
|
160
|
+
|
161
|
+
begin
|
162
|
+
|
163
|
+
cli_exec("ctkmu") do |ops, val|
|
164
|
+
case ops
|
165
|
+
when :params
|
166
|
+
["c","-t#{type}","-s#{slot}","-n#{keylabel}","-a#{atRes.join}"]
|
167
|
+
when :expect_list
|
168
|
+
expect
|
169
|
+
else
|
170
|
+
block.call(ops)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
rescue ExecutableNotFoundError
|
175
|
+
raise Error, "Executable 'ctkmu' not found from PATH. Please install the driver or add the executable to PATH"
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
def gencert(*args, &block)
|
181
|
+
|
182
|
+
raise TokenError, "Block is required" if not block
|
183
|
+
raise TokenError, "Slot is not available!" if is_empty?(@slot)
|
184
|
+
|
185
|
+
expect = [
|
186
|
+
{ matcher: "Enter user PIN.+:", block_key: :token_user_pin, timeout: 1 },
|
187
|
+
]
|
188
|
+
|
189
|
+
keylabel = block.call(:keylabel)
|
190
|
+
raise Error, "Keylabel should not be empty" if is_empty?(keylabel)
|
191
|
+
keylabel.gsub!(" ","_")
|
192
|
+
|
193
|
+
validFrom = block.call(:valid_from)
|
194
|
+
#if is_empty?(validFrom) or not validFrom.is_a?(Time)
|
195
|
+
# today = Time.now
|
196
|
+
# validFrom = Time.new(today.year, today.month, today.day)
|
197
|
+
#end
|
198
|
+
validity = block.call(:validity)
|
199
|
+
if not (validity =~ /h|d|m|y/)
|
200
|
+
raise Error, "Validity requires unit in hour (h), day (d), month (m) or year (y)"
|
201
|
+
end
|
202
|
+
validTo = block.call(:valid_to)
|
203
|
+
raise Error, "Valid_to requires a time object" if (not_empty?(validTo) and not validTo.is_a?(Time))
|
204
|
+
|
205
|
+
#slot = block.call(:slot) || 0
|
206
|
+
slot = @slot.id
|
207
|
+
certFile = block.call(:cert_file)
|
208
|
+
|
209
|
+
cn = block.call(:common_name)
|
210
|
+
raise Error, "Common name is mandatory" if is_empty?(cn)
|
211
|
+
expect << { matcher: "Common Name:", block_key: :cn, timeout: 1 }
|
212
|
+
org = block.call(:org)
|
213
|
+
expect << { matcher: "Organization:", block_key: :org, timeout: 1 }
|
214
|
+
ou = block.call(:ou)
|
215
|
+
expect << { matcher: "Organizational Unit:", block_key: :ou, timeout: 1 }
|
216
|
+
loc = block.call(:locality)
|
217
|
+
expect << { matcher: "Locality:", block_key: :loc, timeout: 1 }
|
218
|
+
st = block.call(:state)
|
219
|
+
expect << { matcher: "State:", block_key: :st, timeout: 1 }
|
220
|
+
ctry = block.call(:country)
|
221
|
+
expect << { matcher: "Country:", block_key: :ctry, timeout: 1 }
|
222
|
+
sn = block.call(:serial_no) || SecureRandom.uuid.gsub("-","")
|
223
|
+
expect << { matcher: "certificate\'s serial number.+:", block_key: :sn, timeout: 1 }
|
224
|
+
|
225
|
+
params = ["c","-l#{keylabel}", "-s#{slot}"]
|
226
|
+
if not_empty?(validFrom)
|
227
|
+
params << "-b#{validFrom.strftime("%Y%m%d%H%M%S")}"
|
228
|
+
end
|
229
|
+
if not_empty?(validity)
|
230
|
+
params << "-d#{validity}"
|
231
|
+
end
|
232
|
+
if not_empty?(validTo)
|
233
|
+
params << "-e#{validTo.strftime("%Y%m%d%H%M%S")}"
|
234
|
+
end
|
235
|
+
|
236
|
+
begin
|
237
|
+
|
238
|
+
cli_exec("ctcert") do |ops, val|
|
239
|
+
case ops
|
240
|
+
when :params
|
241
|
+
params
|
242
|
+
when :expect_list
|
243
|
+
expect
|
244
|
+
when :cn
|
245
|
+
cn
|
246
|
+
when :org
|
247
|
+
org
|
248
|
+
when :ou
|
249
|
+
ou
|
250
|
+
when :loc
|
251
|
+
loc
|
252
|
+
when :st
|
253
|
+
st
|
254
|
+
when :ctry
|
255
|
+
ctry
|
256
|
+
when :sn
|
257
|
+
sn
|
258
|
+
else
|
259
|
+
block.call(ops)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
rescue ExecutableNotFoundError
|
264
|
+
raise Error, "Executable 'ctkmu' not found from PATH. Please install the driver or add the executable to PATH"
|
265
|
+
end
|
266
|
+
|
267
|
+
if not_empty?(certFile)
|
268
|
+
export_cert(keylabel, certFile)
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
def export_cert(label, outFile, &block)
|
274
|
+
|
275
|
+
raise TokenError, "Key label cannot be empty" if is_empty?(label)
|
276
|
+
raise TokenError, "Output file cannot be empty" if is_empty?(outFile)
|
277
|
+
raise TokenError, "Slot is not available!" if is_empty?(@slot)
|
278
|
+
|
279
|
+
slot = @slot.id
|
280
|
+
label.gsub!(" ","_")
|
281
|
+
|
282
|
+
begin
|
283
|
+
|
284
|
+
cli_exec("ctcert") do |ops|
|
285
|
+
case ops
|
286
|
+
when :params
|
287
|
+
["x","-l#{label}","-s#{slot}","-f#{outFile}"]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
rescue ExecutableNotFoundError
|
292
|
+
raise Error, "Executable 'ctcert' not found from PATH. Please install the driver or add the executable to PATH"
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
end # Cli
|
300
|
+
|
301
|
+
class Token
|
302
|
+
include Cli::Token
|
303
|
+
|
304
|
+
attr_accessor :slot
|
305
|
+
def initialize(slot)
|
306
|
+
@slot = slot
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
data/lib/thales/pse.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tlogger'
|
4
|
+
require 'toolrack'
|
5
|
+
|
6
|
+
require_relative "pse/version"
|
7
|
+
require_relative "pse/hsm"
|
8
|
+
|
9
|
+
module Thales
|
10
|
+
module Pse
|
11
|
+
class Error < StandardError; end
|
12
|
+
|
13
|
+
class HSMError < StandardError; end
|
14
|
+
class SlotError < StandardError; end
|
15
|
+
class TokenError < StandardError; end
|
16
|
+
|
17
|
+
# Your code goes here...
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/pty_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require 'pty'
|
3
|
+
|
4
|
+
prs, pws = PTY.open
|
5
|
+
r, w = IO.pipe
|
6
|
+
|
7
|
+
pid = spawn("/opt/safenet/protecttoolkit5/cpsdk/bin/linux-x86_64/ctconf 2>&1", in: r, out: pws)
|
8
|
+
|
9
|
+
r.close
|
10
|
+
pws.close
|
11
|
+
|
12
|
+
loop do
|
13
|
+
begin
|
14
|
+
line = prs.gets
|
15
|
+
rescue Errno::EIO => ex
|
16
|
+
p ex
|
17
|
+
Process.kill('TERM', pid)
|
18
|
+
break
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "done"
|
23
|
+
|
data/thales-pse.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/thales/pse/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "thales-pse"
|
7
|
+
spec.version = Thales::Pse::VERSION
|
8
|
+
spec.authors = ["Ian"]
|
9
|
+
spec.email = ["cameronian0@protonmail.com"]
|
10
|
+
|
11
|
+
spec.summary = ""
|
12
|
+
spec.description = ""
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.required_ruby_version = ">= 2.4.0"
|
15
|
+
|
16
|
+
#spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
17
|
+
|
18
|
+
#spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
#spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
20
|
+
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_dependency 'tlogger'
|
34
|
+
spec.add_dependency 'toolrack'
|
35
|
+
|
36
|
+
spec.add_development_dependency "devops_helper"
|
37
|
+
|
38
|
+
# Uncomment to register a new dependency of your gem
|
39
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
40
|
+
|
41
|
+
# For more information and examples about making a new gem, checkout our
|
42
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thales-pse
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tlogger
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: toolrack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: devops_helper
|
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: ''
|
56
|
+
email:
|
57
|
+
- cameronian0@protonmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".rspec"
|
63
|
+
- Gemfile
|
64
|
+
- Gemfile.lock
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- bin/console
|
68
|
+
- bin/setup
|
69
|
+
- lib/thales/pse.rb
|
70
|
+
- lib/thales/pse/cli.rb
|
71
|
+
- lib/thales/pse/config.rb
|
72
|
+
- lib/thales/pse/hsm.rb
|
73
|
+
- lib/thales/pse/slot.rb
|
74
|
+
- lib/thales/pse/token.rb
|
75
|
+
- lib/thales/pse/version.rb
|
76
|
+
- pty_test.rb
|
77
|
+
- thales-pse.gemspec
|
78
|
+
homepage: ''
|
79
|
+
licenses: []
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.4.0
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubygems_version: 3.2.22
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: ''
|
100
|
+
test_files: []
|