easy_code_sign 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 +7 -0
- data/CHANGELOG.md +95 -0
- data/LICENSE +21 -0
- data/README.md +331 -0
- data/Rakefile +16 -0
- data/exe/easysign +7 -0
- data/lib/easy_code_sign/cli.rb +428 -0
- data/lib/easy_code_sign/configuration.rb +102 -0
- data/lib/easy_code_sign/deferred_signing_request.rb +104 -0
- data/lib/easy_code_sign/errors.rb +113 -0
- data/lib/easy_code_sign/pdf/appearance_builder.rb +104 -0
- data/lib/easy_code_sign/pdf/timestamp_handler.rb +31 -0
- data/lib/easy_code_sign/providers/base.rb +126 -0
- data/lib/easy_code_sign/providers/pkcs11_base.rb +197 -0
- data/lib/easy_code_sign/providers/safenet.rb +109 -0
- data/lib/easy_code_sign/signable/base.rb +98 -0
- data/lib/easy_code_sign/signable/gem_file.rb +224 -0
- data/lib/easy_code_sign/signable/pdf_file.rb +486 -0
- data/lib/easy_code_sign/signable/zip_file.rb +226 -0
- data/lib/easy_code_sign/signer.rb +254 -0
- data/lib/easy_code_sign/timestamp/client.rb +184 -0
- data/lib/easy_code_sign/timestamp/request.rb +114 -0
- data/lib/easy_code_sign/timestamp/response.rb +246 -0
- data/lib/easy_code_sign/timestamp/verifier.rb +227 -0
- data/lib/easy_code_sign/verification/certificate_chain.rb +298 -0
- data/lib/easy_code_sign/verification/result.rb +222 -0
- data/lib/easy_code_sign/verification/signature_checker.rb +196 -0
- data/lib/easy_code_sign/verification/trust_store.rb +140 -0
- data/lib/easy_code_sign/verifier.rb +426 -0
- data/lib/easy_code_sign/version.rb +5 -0
- data/lib/easy_code_sign.rb +183 -0
- data/plugin/.gitignore +21 -0
- data/plugin/Gemfile +24 -0
- data/plugin/Gemfile.lock +134 -0
- data/plugin/README.md +248 -0
- data/plugin/Rakefile +121 -0
- data/plugin/docs/API_REFERENCE.md +366 -0
- data/plugin/docs/DEVELOPMENT.md +522 -0
- data/plugin/docs/INSTALLATION.md +204 -0
- data/plugin/native_host/build/Rakefile +90 -0
- data/plugin/native_host/install/com.easysign.host.json +9 -0
- data/plugin/native_host/install/install_chrome.sh +81 -0
- data/plugin/native_host/install/install_firefox.sh +81 -0
- data/plugin/native_host/src/easy_sign_host.rb +158 -0
- data/plugin/native_host/src/protocol.rb +101 -0
- data/plugin/native_host/src/signing_service.rb +167 -0
- data/plugin/native_host/test/native_host_test.rb +113 -0
- data/plugin/src/easy_sign/background.rb +323 -0
- data/plugin/src/easy_sign/content.rb +74 -0
- data/plugin/src/easy_sign/inject.rb +239 -0
- data/plugin/src/easy_sign/messaging.rb +109 -0
- data/plugin/src/easy_sign/popup.rb +200 -0
- data/plugin/templates/manifest.json +58 -0
- data/plugin/templates/popup.css +223 -0
- data/plugin/templates/popup.html +59 -0
- data/sig/easy_code_sign.rbs +4 -0
- data/test/easy_code_sign_test.rb +122 -0
- data/test/pdf_signable_test.rb +569 -0
- data/test/signable_test.rb +334 -0
- data/test/test_helper.rb +18 -0
- data/test/timestamp_test.rb +163 -0
- data/test/verification_test.rb +350 -0
- metadata +219 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 795cefa5ad0f01177caeb61d8aaa3c910e6796a5d0f7caad13653a762ada80c1
|
|
4
|
+
data.tar.gz: 4a65763e2aa2e0396c285c5bf3d75e3dc36697cf4e5f50b4489403a4e0789489
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0ceaf7fcd326449fd314d493828ed33ca12b4c004f86e08cef72ab1f22212ce92525a4d9ee1aeed5f421dc8636c0504e7b78e75bb5530ef6da1e8aeda929002e
|
|
7
|
+
data.tar.gz: 0e59683b775e2809b102022b0f16dd3ed142e1fdb1296c83162e1f2fc0747b75440189ea43372f07518f99d7e95e2040af19713ea79fecaf47f03bd011c0fbf3
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **PDF Document Signing**
|
|
13
|
+
- Sign PDF documents (.pdf) with PKCS#7 digital signatures
|
|
14
|
+
- Visible signature annotations with customizable position (top-left, top-right, bottom-left, bottom-right)
|
|
15
|
+
- Signature metadata (reason, location, contact info)
|
|
16
|
+
- Page selection for signature placement
|
|
17
|
+
- RFC 3161 timestamp embedding in PDF signatures
|
|
18
|
+
- ByteRange-based signing for PDF incremental updates
|
|
19
|
+
|
|
20
|
+
- **PDF Verification**
|
|
21
|
+
- Verify signed PDF documents
|
|
22
|
+
- ByteRange integrity checking
|
|
23
|
+
- Extract and display PDF signature metadata
|
|
24
|
+
|
|
25
|
+
- **CLI Enhancements for PDF**
|
|
26
|
+
- `--visible-signature` - Add visible signature annotation
|
|
27
|
+
- `--signature-page` - Select page for signature
|
|
28
|
+
- `--signature-position` - Position preset (top_left, top_right, bottom_left, bottom_right)
|
|
29
|
+
- `--signature-reason` - Reason for signing
|
|
30
|
+
- `--signature-location` - Signing location
|
|
31
|
+
|
|
32
|
+
### Dependencies
|
|
33
|
+
|
|
34
|
+
- Added HexaPDF (~> 1.0) for PDF manipulation and signing
|
|
35
|
+
|
|
36
|
+
## [0.1.0] - 2025-01-06
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **Core Signing Functionality**
|
|
41
|
+
- Sign Ruby gems (.gem) with PKCS#7 detached signatures compatible with `gem cert`
|
|
42
|
+
- Sign ZIP archives (.zip, .jar, .apk, .war, .ear) using JAR-style signing with META-INF manifest
|
|
43
|
+
- Batch signing support for multiple files in a single token session
|
|
44
|
+
|
|
45
|
+
- **Hardware Token Support**
|
|
46
|
+
- SafeNet eToken integration via PKCS#11
|
|
47
|
+
- Extensible provider architecture for future HSM support
|
|
48
|
+
- Automatic PKCS#11 library detection on macOS, Linux, and Windows
|
|
49
|
+
- Secure PIN entry via interactive prompt (never passed as CLI argument)
|
|
50
|
+
- Token slot listing and management
|
|
51
|
+
|
|
52
|
+
- **RFC 3161 Timestamping**
|
|
53
|
+
- Full RFC 3161 timestamp protocol support
|
|
54
|
+
- Compatible with common TSAs (DigiCert, GlobalSign, Sectigo, SSL.com)
|
|
55
|
+
- Timestamp verification with certificate chain validation
|
|
56
|
+
- Configurable hash algorithms (SHA-256, SHA-384, SHA-512)
|
|
57
|
+
|
|
58
|
+
- **Signature Verification**
|
|
59
|
+
- Cryptographic signature validation
|
|
60
|
+
- File integrity checking (tamper detection)
|
|
61
|
+
- Certificate validity and expiration checking
|
|
62
|
+
- Certificate chain validation
|
|
63
|
+
- Trust anchor verification using system CA store or custom trust stores
|
|
64
|
+
- Timestamp validation for point-in-time verification
|
|
65
|
+
- Certificate revocation checking (OCSP with CRL fallback)
|
|
66
|
+
|
|
67
|
+
- **Command-Line Interface**
|
|
68
|
+
- `easysign sign` - Sign files with hardware token
|
|
69
|
+
- `easysign verify` - Verify signed files with detailed output
|
|
70
|
+
- `easysign list-slots` - List available token slots
|
|
71
|
+
- `easysign info` - Display signature information
|
|
72
|
+
- JSON output option for scripting and automation
|
|
73
|
+
- Verbose and quiet modes
|
|
74
|
+
|
|
75
|
+
- **Ruby API**
|
|
76
|
+
- Simple high-level API (`EasyCodeSign.sign`, `EasyCodeSign.verify`)
|
|
77
|
+
- Comprehensive configuration system
|
|
78
|
+
- Custom trust store support
|
|
79
|
+
- PIN callback for programmatic secure PIN entry
|
|
80
|
+
- Detailed result objects with structured error reporting
|
|
81
|
+
|
|
82
|
+
- **Error Handling**
|
|
83
|
+
- 18 specific error types for clear diagnostics
|
|
84
|
+
- Hierarchical error classes for flexible rescue
|
|
85
|
+
- PIN retry tracking with lockout warnings
|
|
86
|
+
- Network timeout handling for TSA requests
|
|
87
|
+
|
|
88
|
+
### Security
|
|
89
|
+
|
|
90
|
+
- PINs are never logged, stored, or passed as command-line arguments
|
|
91
|
+
- Secure interactive PIN prompt using `noecho` to prevent display
|
|
92
|
+
- Private keys never leave the hardware token
|
|
93
|
+
- Certificate revocation checking enabled by default
|
|
94
|
+
|
|
95
|
+
[0.1.0]: https://github.com/mpantel/easy_code_sign/releases/tag/v0.1.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 michail
|
|
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,331 @@
|
|
|
1
|
+
# EasyCodeSign
|
|
2
|
+
|
|
3
|
+
A Ruby gem for signing and verifying Ruby gems, ZIP files, and PDF documents using hardware security tokens (HSM/smart cards). Currently supports SafeNet eToken with plans for additional providers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Sign Ruby gems** (.gem) - Creates PKCS#7 signatures compatible with `gem cert`
|
|
8
|
+
- **Sign ZIP archives** (.zip, .jar, .apk, .war, .ear) - JAR-style signing with META-INF manifest
|
|
9
|
+
- **Sign PDF documents** (.pdf) - Digital signatures with optional visible annotations
|
|
10
|
+
- **Hardware token support** - SafeNet eToken via PKCS#11 (extensible for other HSMs)
|
|
11
|
+
- **RFC 3161 timestamping** - Proves signature existed at a specific time
|
|
12
|
+
- **Full verification** - Signature, certificate chain, trust, and timestamp validation
|
|
13
|
+
- **Certificate revocation checking** - OCSP and CRL support
|
|
14
|
+
- **Command-line interface** - Easy-to-use CLI for signing and verification
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Add to your Gemfile:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
gem 'easy_code_sign'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install directly:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
gem install easy_code_sign
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Prerequisites
|
|
31
|
+
|
|
32
|
+
- Ruby 3.2+
|
|
33
|
+
- SafeNet eToken drivers and PKCS#11 library installed
|
|
34
|
+
- Hardware token with code signing certificate
|
|
35
|
+
|
|
36
|
+
## Command-Line Usage
|
|
37
|
+
|
|
38
|
+
### Sign a file
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Basic signing (will prompt for PIN securely)
|
|
42
|
+
easysign sign my_gem-1.0.0.gem
|
|
43
|
+
|
|
44
|
+
# Sign with timestamp
|
|
45
|
+
easysign sign my_gem-1.0.0.gem --timestamp --tsa http://timestamp.digicert.com
|
|
46
|
+
|
|
47
|
+
# Sign with custom output path
|
|
48
|
+
easysign sign archive.zip --output signed_archive.zip
|
|
49
|
+
|
|
50
|
+
# Use specific PKCS#11 library
|
|
51
|
+
easysign sign my_gem.gem --library /path/to/libeToken.dylib
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Sign a PDF
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Basic PDF signing (invisible signature)
|
|
58
|
+
easysign sign document.pdf
|
|
59
|
+
|
|
60
|
+
# PDF with visible signature annotation
|
|
61
|
+
easysign sign document.pdf --visible-signature --signature-position bottom-right
|
|
62
|
+
|
|
63
|
+
# PDF with timestamp and metadata
|
|
64
|
+
easysign sign document.pdf -t --visible-signature --signature-reason "Approved" --signature-location "New York"
|
|
65
|
+
|
|
66
|
+
# PDF signing on specific page
|
|
67
|
+
easysign sign document.pdf --visible-signature --signature-page 2
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> **Security Note:** The PIN is always entered interactively via a secure prompt.
|
|
71
|
+
> It is never passed as a command-line argument to prevent exposure in shell
|
|
72
|
+
> history, process listings, or log files.
|
|
73
|
+
|
|
74
|
+
### Verify a signature
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Basic verification
|
|
78
|
+
easysign verify signed.gem
|
|
79
|
+
|
|
80
|
+
# Output as JSON
|
|
81
|
+
easysign verify signed.gem --json
|
|
82
|
+
|
|
83
|
+
# Use custom trust store
|
|
84
|
+
easysign verify signed.gem --trust-store /path/to/ca-certs/
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### List available tokens
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
easysign list-slots
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Show signature information
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
easysign info signed.gem
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Ruby API
|
|
100
|
+
|
|
101
|
+
### Configuration
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
require 'easy_code_sign'
|
|
105
|
+
|
|
106
|
+
EasyCodeSign.configure do |config|
|
|
107
|
+
# Token provider (:safenet is currently supported)
|
|
108
|
+
config.provider = :safenet
|
|
109
|
+
|
|
110
|
+
# Path to PKCS#11 library (auto-detected if not specified)
|
|
111
|
+
config.pkcs11_library = '/usr/local/lib/libeToken.dylib'
|
|
112
|
+
|
|
113
|
+
# Token slot index (default: 0)
|
|
114
|
+
config.slot_index = 0
|
|
115
|
+
|
|
116
|
+
# Timestamp authority URL (optional)
|
|
117
|
+
config.timestamp_authority = 'http://timestamp.digicert.com'
|
|
118
|
+
|
|
119
|
+
# Hash algorithm for timestamps (default: :sha256)
|
|
120
|
+
config.timestamp_hash_algorithm = :sha256
|
|
121
|
+
|
|
122
|
+
# Require timestamp for all signatures (default: false)
|
|
123
|
+
config.require_timestamp = false
|
|
124
|
+
|
|
125
|
+
# Check certificate revocation during verification (default: true)
|
|
126
|
+
config.check_revocation = true
|
|
127
|
+
|
|
128
|
+
# Network timeout in seconds (default: 30)
|
|
129
|
+
config.network_timeout = 30
|
|
130
|
+
|
|
131
|
+
# Custom trust store path for verification (optional)
|
|
132
|
+
config.trust_store_path = '/path/to/custom/ca-certs'
|
|
133
|
+
|
|
134
|
+
# PIN callback for interactive PIN entry
|
|
135
|
+
config.pin_callback = ->(slot_info) {
|
|
136
|
+
print "Enter PIN for #{slot_info[:slot_index]}: "
|
|
137
|
+
$stdin.noecho(&:gets).chomp
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Signing
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
# Sign a gem
|
|
146
|
+
result = EasyCodeSign.sign('my_gem-1.0.0.gem', pin: '1234')
|
|
147
|
+
puts "Signed: #{result.file_path}"
|
|
148
|
+
puts "Signer: #{result.signer_name}"
|
|
149
|
+
|
|
150
|
+
# Sign with timestamp
|
|
151
|
+
result = EasyCodeSign.sign('my_gem-1.0.0.gem',
|
|
152
|
+
pin: '1234',
|
|
153
|
+
timestamp: true
|
|
154
|
+
)
|
|
155
|
+
puts "Timestamp: #{result.timestamp}"
|
|
156
|
+
|
|
157
|
+
# Sign with custom output path
|
|
158
|
+
result = EasyCodeSign.sign('archive.zip',
|
|
159
|
+
pin: '1234',
|
|
160
|
+
output_path: 'signed_archive.zip',
|
|
161
|
+
algorithm: :sha256_rsa
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Batch signing (single token session)
|
|
165
|
+
signer = EasyCodeSign.signer
|
|
166
|
+
results = signer.sign_batch(
|
|
167
|
+
['gem1.gem', 'gem2.gem', 'archive.zip'],
|
|
168
|
+
pin: '1234'
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Verification
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
# Verify a signed file
|
|
176
|
+
result = EasyCodeSign.verify('signed.gem')
|
|
177
|
+
|
|
178
|
+
if result.valid?
|
|
179
|
+
puts "Signature is valid!"
|
|
180
|
+
puts "Signed by: #{result.signer_name}"
|
|
181
|
+
puts "Organization: #{result.signer_organization}"
|
|
182
|
+
|
|
183
|
+
if result.timestamped?
|
|
184
|
+
puts "Timestamp: #{result.timestamp}"
|
|
185
|
+
puts "TSA: #{result.timestamp_authority}"
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
puts "Verification failed:"
|
|
189
|
+
result.errors.each { |e| puts " - #{e}" }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Detailed verification status
|
|
193
|
+
puts "Signature valid: #{result.signature_valid?}"
|
|
194
|
+
puts "Integrity valid: #{result.integrity_valid?}"
|
|
195
|
+
puts "Certificate valid: #{result.certificate_valid?}"
|
|
196
|
+
puts "Chain valid: #{result.chain_valid?}"
|
|
197
|
+
puts "Trusted: #{result.trusted?}"
|
|
198
|
+
|
|
199
|
+
# Get full result as hash
|
|
200
|
+
puts result.to_h
|
|
201
|
+
|
|
202
|
+
# Use custom trust store
|
|
203
|
+
trust_store = EasyCodeSign::Verification::TrustStore.new
|
|
204
|
+
trust_store.add_file('/path/to/custom_ca.pem')
|
|
205
|
+
result = EasyCodeSign.verify('signed.gem', trust_store: trust_store)
|
|
206
|
+
|
|
207
|
+
# Batch verification
|
|
208
|
+
verifier = EasyCodeSign.verifier
|
|
209
|
+
results = verifier.verify_batch(['file1.gem', 'file2.zip'])
|
|
210
|
+
results.each do |path, result|
|
|
211
|
+
puts "#{path}: #{result.valid? ? 'VALID' : 'INVALID'}"
|
|
212
|
+
end
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Working with Tokens
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
# List available token slots
|
|
219
|
+
slots = EasyCodeSign.list_slots
|
|
220
|
+
slots.each do |slot|
|
|
221
|
+
puts "Slot #{slot[:index]}: #{slot[:token_label]}"
|
|
222
|
+
puts " Serial: #{slot[:serial]}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Direct provider access
|
|
226
|
+
provider = EasyCodeSign.provider
|
|
227
|
+
provider.with_session(pin: '1234') do |session|
|
|
228
|
+
cert = session.certificate
|
|
229
|
+
puts "Certificate: #{cert.subject}"
|
|
230
|
+
puts "Expires: #{cert.not_after}"
|
|
231
|
+
|
|
232
|
+
chain = session.certificate_chain
|
|
233
|
+
puts "Chain length: #{chain.length}"
|
|
234
|
+
end
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Supported Timestamp Authorities
|
|
238
|
+
|
|
239
|
+
Common free TSA endpoints:
|
|
240
|
+
|
|
241
|
+
| Provider | URL |
|
|
242
|
+
|----------|-----|
|
|
243
|
+
| DigiCert | `http://timestamp.digicert.com` |
|
|
244
|
+
| GlobalSign | `http://timestamp.globalsign.com/tsa/r6advanced1` |
|
|
245
|
+
| Sectigo | `http://timestamp.sectigo.com` |
|
|
246
|
+
| SSL.com | `http://ts.ssl.com` |
|
|
247
|
+
|
|
248
|
+
## Error Handling
|
|
249
|
+
|
|
250
|
+
```ruby
|
|
251
|
+
begin
|
|
252
|
+
EasyCodeSign.sign('file.gem', pin: '1234')
|
|
253
|
+
rescue EasyCodeSign::TokenNotFoundError
|
|
254
|
+
puts "Hardware token not connected"
|
|
255
|
+
rescue EasyCodeSign::PinError => e
|
|
256
|
+
puts "PIN error: #{e.message}"
|
|
257
|
+
puts "Retries remaining: #{e.retries_remaining}" if e.retries_remaining
|
|
258
|
+
rescue EasyCodeSign::TokenLockedError
|
|
259
|
+
puts "Token is locked - contact your administrator"
|
|
260
|
+
rescue EasyCodeSign::TimestampAuthorityError => e
|
|
261
|
+
puts "Timestamp failed: #{e.message}"
|
|
262
|
+
puts "HTTP status: #{e.http_status}" if e.http_status
|
|
263
|
+
rescue EasyCodeSign::InvalidFileError => e
|
|
264
|
+
puts "Invalid file: #{e.message}"
|
|
265
|
+
rescue EasyCodeSign::Error => e
|
|
266
|
+
puts "Signing error: #{e.message}"
|
|
267
|
+
end
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Architecture
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
EasyCodeSign
|
|
274
|
+
├── Providers # Hardware token abstraction
|
|
275
|
+
│ ├── Base # Abstract provider interface
|
|
276
|
+
│ ├── Pkcs11Base # Shared PKCS#11 functionality
|
|
277
|
+
│ └── Safenet # SafeNet eToken implementation
|
|
278
|
+
├── Signable # File type handlers
|
|
279
|
+
│ ├── Base # Abstract signable interface
|
|
280
|
+
│ ├── GemFile # Ruby gem signing
|
|
281
|
+
│ └── ZipFile # JAR-style ZIP signing
|
|
282
|
+
├── Timestamp # RFC 3161 timestamping
|
|
283
|
+
│ ├── Client # TSA HTTP client
|
|
284
|
+
│ ├── Request # TimeStampReq builder
|
|
285
|
+
│ ├── Response # TimeStampResp parser
|
|
286
|
+
│ └── Verifier # Timestamp verification
|
|
287
|
+
├── Verification # Signature verification
|
|
288
|
+
│ ├── Result # Verification result
|
|
289
|
+
│ ├── TrustStore # CA certificate management
|
|
290
|
+
│ ├── CertificateChain# Chain validation
|
|
291
|
+
│ └── SignatureChecker# Cryptographic verification
|
|
292
|
+
├── Signer # Signing orchestrator
|
|
293
|
+
├── Verifier # Verification orchestrator
|
|
294
|
+
└── CLI # Command-line interface
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Security Considerations
|
|
298
|
+
|
|
299
|
+
- **PINs are never passed as CLI arguments** - Always entered via secure interactive prompt
|
|
300
|
+
- **PINs are never logged or stored** - Use `pin_callback` for programmatic secure entry
|
|
301
|
+
- **Hardware tokens protect private keys** - Keys never leave the HSM
|
|
302
|
+
- **Timestamps provide non-repudiation** - Signatures remain valid after certificate expiry
|
|
303
|
+
- **Certificate revocation is checked** - OCSP (real-time) with CRL fallback
|
|
304
|
+
- **System CA store is used by default** - Custom trust stores supported
|
|
305
|
+
|
|
306
|
+
## Development
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Install dependencies
|
|
310
|
+
bin/setup
|
|
311
|
+
|
|
312
|
+
# Run tests
|
|
313
|
+
bundle exec rake test
|
|
314
|
+
|
|
315
|
+
# Run linter
|
|
316
|
+
bundle exec rubocop
|
|
317
|
+
|
|
318
|
+
# Interactive console
|
|
319
|
+
bin/console
|
|
320
|
+
|
|
321
|
+
# Install locally
|
|
322
|
+
bundle exec rake install
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Contributing
|
|
326
|
+
|
|
327
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mpantel/easy_code_sign.
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "test"
|
|
8
|
+
t.libs << "lib"
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require "rubocop/rake_task"
|
|
13
|
+
|
|
14
|
+
RuboCop::RakeTask.new
|
|
15
|
+
|
|
16
|
+
task default: %i[test rubocop]
|