icsp 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5f813acb3d0e89f89f936b73e81f414916ce2c18e7cd88b5e64ee1f87c6d3da1
4
+ data.tar.gz: fd0068b0ac9eaaa50effa685dd1b838fc9fc2e3ab82abb6ec5ba3931b95d0b69
5
+ SHA512:
6
+ metadata.gz: a2f2b36acc25f7eca2ff29831aa8f6488c8678624cdfa82301945fa0156e391a72e34d2b3d2bd6d4da9e3a1f22c414618acf15a2096f68cc813fa99a50d10e0f
7
+ data.tar.gz: 9ea0e971e15a6d53137f2b028decedc1dabffe9acab64b91237f36fc89cd049050cbc24f887efd0532b7080e9a57987e86ee11239f7061e0abe40037b580ea9e
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .idea
14
+ .env
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ Style/Documentation:
2
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.6
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'rake', '~> 12.0'
8
+ gem 'rspec', '~> 3.0'
9
+
10
+ group :development, :test do
11
+ gem 'rubocop', '~> 1.18', require: false
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,73 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ icsp (0.1.0)
5
+ os (~> 1.1)
6
+ tty-prompt (~> 0.23.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ diff-lcs (1.5.0)
13
+ os (1.1.1)
14
+ parallel (1.20.1)
15
+ parser (3.0.2.0)
16
+ ast (~> 2.4.1)
17
+ pastel (0.8.0)
18
+ tty-color (~> 0.5)
19
+ rainbow (3.0.0)
20
+ rake (12.3.3)
21
+ regexp_parser (2.1.1)
22
+ rexml (3.2.5)
23
+ rspec (3.12.0)
24
+ rspec-core (~> 3.12.0)
25
+ rspec-expectations (~> 3.12.0)
26
+ rspec-mocks (~> 3.12.0)
27
+ rspec-core (3.12.0)
28
+ rspec-support (~> 3.12.0)
29
+ rspec-expectations (3.12.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.12.0)
32
+ rspec-mocks (3.12.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.12.0)
35
+ rspec-support (3.12.0)
36
+ rubocop (1.18.3)
37
+ parallel (~> 1.10)
38
+ parser (>= 3.0.0.0)
39
+ rainbow (>= 2.2.2, < 4.0)
40
+ regexp_parser (>= 1.8, < 3.0)
41
+ rexml
42
+ rubocop-ast (>= 1.7.0, < 2.0)
43
+ ruby-progressbar (~> 1.7)
44
+ unicode-display_width (>= 1.4.0, < 3.0)
45
+ rubocop-ast (1.8.0)
46
+ parser (>= 3.0.1.1)
47
+ ruby-progressbar (1.11.0)
48
+ tty-color (0.6.0)
49
+ tty-cursor (0.7.1)
50
+ tty-prompt (0.23.1)
51
+ pastel (~> 0.8)
52
+ tty-reader (~> 0.8)
53
+ tty-reader (0.9.0)
54
+ tty-cursor (~> 0.7)
55
+ tty-screen (~> 0.8)
56
+ wisper (~> 2.0)
57
+ tty-screen (0.8.1)
58
+ unicode-display_width (2.0.0)
59
+ wisper (2.0.1)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ icsp!
66
+ os (~> 1.1)
67
+ rake (~> 12.0)
68
+ rspec (~> 3.0)
69
+ rubocop (~> 1.18)
70
+ tty-prompt (~> 0.23.1)
71
+
72
+ BUNDLED WITH
73
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Denis Semenenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # iCSP
2
+
3
+ An interactive CryptoPro CSP shell that tries to imitate its GUI counterpart on the Windows platform.
4
+ Built for macOS and Linux daily use by wrapping a set of CryptoPro CLI tools: cryptcp, certmgr, csptest, cpconfig, etc.
5
+
6
+ The project goal is only to simplify my daily life with CryptoPro CSP on *nix systems.
7
+ Not everything is polished. Feel free to submit a PR if you need to add extra commands/options or fix bugs.
8
+
9
+ See:
10
+ * https://www.cryptopro.ru/products/other/cryptcp
11
+ * https://www.cryptopro.ru/sites/default/files/products/cryptcp/cryptcp_5.0.x.pdf
12
+ * https://www.cryptopro.ru/sites/default/files/docs/certmgr.pdf
13
+
14
+ ## Usage
15
+
16
+ Management commands:
17
+
18
+ * certificate — Manage certificates
19
+ * list
20
+ * view
21
+ * install
22
+ * delete
23
+
24
+ * container — Manage containers
25
+ * list
26
+ * check
27
+
28
+ * hardware — Manage hardware
29
+ * list — Review of the installed readers, generators of random numbers and media
30
+
31
+ * license — Manage licenses
32
+ * view — View license
33
+ * set — Set license
34
+
35
+ CSP commands:
36
+
37
+ * create_signature
38
+ * verify_signature
39
+ * create_hash
40
+ * verify_hash
41
+ * encrypt_file
42
+ * decrypt_file
43
+
44
+
45
+ ## Examples
46
+
47
+ List all key containers
48
+
49
+ ```bash
50
+ icsp container list
51
+ ```
52
+
53
+ Create a signature for the file
54
+
55
+ ```bash
56
+ icsp create_signature document.txt
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ ICSP is configured by ENV variables
62
+
63
+ * `CSP_PATH` allows to override default CryptoPro CSP path. Default is `/opt/cprocsp`.
64
+ * `LOG_LEVEL` to debug your operations. Default is `warn`.
65
+
66
+ ## License
67
+
68
+ [MIT](./LICENSE)
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'csp'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/config/config.rb ADDED
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Config
4
+ def initialize
5
+ @bin = %i[certmgr cryptcp csptest].freeze
6
+ @sbin = [:cpconfig].freeze
7
+ end
8
+
9
+ def csp_path
10
+ @csp_path ||= ENV.fetch('CSP_PATH', '/opt/cprocsp')
11
+ end
12
+
13
+ def build_path(binary_name)
14
+ File.join(csp_path, category_path(binary_name), arch_path, binary_name.to_s)
15
+ end
16
+
17
+ def category_path(binary_name)
18
+ @sbin.include?(binary_name) ? 'sbin' : 'bin'
19
+ end
20
+
21
+ def arch_path
22
+ return '' if OS.mac?
23
+
24
+ OS.bits == 64 ? 'amd64' : 'ia32'
25
+ end
26
+
27
+ def log_level
28
+ @log_level ||= ENV.fetch('LOG_LEVEL', 'warn').upcase
29
+ end
30
+
31
+ private
32
+
33
+ def method_missing(symbol, *args)
34
+ if @bin.include?(symbol) || @sbin.include?(symbol)
35
+ build_path(symbol)
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def respond_to_missing?(symbol, *args)
42
+ if @bin.include?(symbol) || @sbin.include?(symbol)
43
+ true
44
+ else
45
+ super
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ def self.config
5
+ @config ||= Config.new
6
+ end
7
+
8
+ def self.logger
9
+ @logger ||= Logger.new($stdout, level: Object.const_get("Logger::Severity::#{config.log_level}"))
10
+ end
11
+ end
data/exe/icsp ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'csp'
data/icsp.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/csp/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'icsp'
7
+ spec.version = ICSP::VERSION
8
+ spec.authors = ['Denis Semenenko']
9
+ spec.email = ['hypercoderx@gmail.com']
10
+
11
+ spec.summary = 'An interactive CryptoPro CSP shell'
12
+ spec.description = 'An interactive CryptoPro CSP shell that tries to imitate its GUI counterpart on the Windows platform.
13
+ Built for macOS and Linux daily use by wrapping a set of CryptoPro CLI tools: cryptcp, certmgr, csptest, cpconfig, etc.'
14
+ spec.homepage = 'https://github.com/denblackstache/icsp'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
17
+
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/denblackstache/icsp'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_dependency 'os', '~> 1.1'
33
+ spec.add_dependency 'tty-prompt', '~> 0.23.1'
34
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class BaseCommand
6
+ def initialize(config:, options:, arguments:)
7
+ @config = config
8
+ @options = options
9
+ @arguments = arguments
10
+ @prompt = TTY::Prompt.new
11
+ ::ICSP.logger.debug('Command initialized with:')
12
+ ::ICSP.logger.debug("arguments: #{@arguments.inspect}")
13
+ ::ICSP.logger.debug("options: #{@options.inspect}")
14
+ end
15
+
16
+ attr_reader :config, :options, :arguments, :prompt
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Certificate
6
+ class Delete < ::ICSP::Commands::BaseCommand
7
+ def certmgr
8
+ @certmgr ||= @config.certmgr
9
+ end
10
+
11
+ def execute
12
+ store = prompt.select('Select store:', available_stores)
13
+ result = ::ICSP::Shell.new("#{certmgr} -delete -store #{store}", fork: false).execute
14
+ exit(result.exit_code) unless result.ok
15
+
16
+ puts result
17
+ end
18
+
19
+ def available_stores
20
+ %w[uMy root ca]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Certificate
6
+ class Install < ::ICSP::Commands::BaseCommand
7
+ def certmgr
8
+ @certmgr ||= @config.certmgr
9
+ end
10
+
11
+ def execute
12
+ unless options[:file]
13
+ install_from_container
14
+ return
15
+ end
16
+
17
+ install_from_file
18
+ end
19
+
20
+ def install_from_container
21
+ result = ::ICSP::Shell.new("#{certmgr} -inst -cont '#{selected_container}'", convert_to_utf8: false).execute
22
+ exit(result.exit_code) unless result.ok
23
+
24
+ puts result
25
+ end
26
+
27
+ def install_from_file
28
+ store = prompt.select('Select store:', available_stores)
29
+ not_crl = prompt.no?('Is it CRL?')
30
+ result = ::ICSP::Shell.new(
31
+ "#{certmgr} -inst -file '#{options[:file]}' -store #{store} #{not_crl ? '' : '-crl'}", convert_to_utf8: false
32
+ ).execute
33
+ exit(result.exit_code) unless result.ok
34
+
35
+ puts result
36
+ end
37
+
38
+ def selected_container
39
+ ::ICSP::Commands::Container::List.new(config: config, options: options, arguments: arguments).select
40
+ end
41
+
42
+ def available_stores
43
+ %w[uMy root ca]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Certificate
6
+ class List < ::ICSP::Commands::BaseCommand
7
+ def certmgr
8
+ @certmgr ||= @config.certmgr
9
+ end
10
+
11
+ def execute
12
+ store = prompt.select('Select store:', available_stores)
13
+ result = ::ICSP::Shell.new("#{certmgr} -list -store #{store}", convert_to_utf8: false).execute
14
+ exit(result.exit_code) unless result.ok
15
+
16
+ result
17
+ end
18
+
19
+ def select
20
+ list_divider = '============================================================================='
21
+ i = 1
22
+ certificate_hash = {}
23
+ certificates = []
24
+ divider_count = 0
25
+ execute.output_lines.each do |line|
26
+ index_line = "#{i}-------"
27
+ next_index_line = "#{i + 1}-------"
28
+ if line == index_line || next_index_line || line == list_divider
29
+ if line == "#{i}-------"
30
+ certificate_hash = {}
31
+ certificate_hash['index'] = i
32
+ next
33
+ end
34
+
35
+ if line == "#{i + 1}-------"
36
+ certificates << OpenStruct.new(certificate_hash.dup)
37
+ i += 1
38
+ certificate_hash = {}
39
+ certificate_hash['index'] = i
40
+ end
41
+
42
+ if line == list_divider
43
+ divider_count += 1
44
+ break if divider_count == 2
45
+ end
46
+ end
47
+
48
+ next unless certificate_hash['index']
49
+
50
+ attribute = line.split(' : ').map(&:strip)
51
+ key = attribute.first
52
+ value = attribute[1..].join(' : ')
53
+
54
+ certificate_hash[key] = value if key
55
+ end
56
+
57
+ choices = certificates.map { |certificate| [certificate['Subject'], certificate['SHA1 Hash']] }.to_h
58
+ @prompt.select('Choose certificate:', choices)
59
+ end
60
+
61
+ def print
62
+ puts execute
63
+ end
64
+
65
+ def available_stores
66
+ %w[uMy root ca]
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Certificate
6
+ class View < ::ICSP::Commands::BaseCommand
7
+ def execute
8
+ result = ::ICSP::Shell.new("openssl x509 -in #{arguments.first} -text -noout -nameopt multiline,-esc_msb,utf8").execute
9
+ exit(result.exit_code) unless result.ok
10
+
11
+ puts result
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class ChangePinCode < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ raise 'Not implemented'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class Check < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ result = ::ICSP::Shell.new("#{csptest} -keyset -check -cont '#{selected_container}'").execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ puts result
16
+ end
17
+
18
+ def selected_container
19
+ ::ICSP::Commands::Container::List.new(config: config, options: options, arguments: arguments).select
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class Copy < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ raise 'Not implemented'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class Delete < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ raise 'Not implemented'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class ForgetAllPinCodes < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ raise 'Not implemented'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class List < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ result = ::ICSP::Shell.new("#{csptest} -keyset -enum_containers -verifycontext -fqcn").execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ result.output_lines.filter { |l| l.start_with?('\\') }
16
+ end
17
+
18
+ def print
19
+ puts execute
20
+ end
21
+
22
+ def select
23
+ @prompt.select('Choose container:', execute)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Container
6
+ class View < ::ICSP::Commands::BaseCommand
7
+ def csptest
8
+ @csptest ||= @config.csptest
9
+ end
10
+
11
+ def execute
12
+ raise 'Not implemented'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end