pki_express 1.0.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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +3 -0
  3. data/.gitignore +28 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +4 -0
  6. data/README.md +24 -0
  7. data/Rakefile +1 -0
  8. data/lib/pki_express.rb +48 -0
  9. data/lib/pki_express/auth_complete_result.rb +22 -0
  10. data/lib/pki_express/auth_start_result.rb +77 -0
  11. data/lib/pki_express/authentication.rb +285 -0
  12. data/lib/pki_express/base_signer.rb +55 -0
  13. data/lib/pki_express/cades_signature_starter.rb +242 -0
  14. data/lib/pki_express/command_error.rb +14 -0
  15. data/lib/pki_express/commands.rb +21 -0
  16. data/lib/pki_express/enum.rb +9 -0
  17. data/lib/pki_express/error_codes.rb +46 -0
  18. data/lib/pki_express/installation_not_found_error.rb +8 -0
  19. data/lib/pki_express/name.rb +48 -0
  20. data/lib/pki_express/pades_horizontal_align.rb +9 -0
  21. data/lib/pki_express/pades_measurement_units.rb +8 -0
  22. data/lib/pki_express/pades_page_optimization.rb +51 -0
  23. data/lib/pki_express/pades_page_orientation.rb +9 -0
  24. data/lib/pki_express/pades_paper_size.rb +21 -0
  25. data/lib/pki_express/pades_signature_starter.rb +232 -0
  26. data/lib/pki_express/pades_size.rb +17 -0
  27. data/lib/pki_express/pades_text_horizontal_align.rb +8 -0
  28. data/lib/pki_express/pades_vertical_align.rb +9 -0
  29. data/lib/pki_express/pades_visual_auto_positioning.rb +22 -0
  30. data/lib/pki_express/pades_visual_image.rb +52 -0
  31. data/lib/pki_express/pades_visual_manual_positioning.rb +17 -0
  32. data/lib/pki_express/pades_visual_positioning.rb +28 -0
  33. data/lib/pki_express/pades_visual_rectangle.rb +74 -0
  34. data/lib/pki_express/pades_visual_representation.rb +22 -0
  35. data/lib/pki_express/pades_visual_text.rb +35 -0
  36. data/lib/pki_express/pk_certificate.rb +62 -0
  37. data/lib/pki_express/pki_brazil_certificate_fields.rb +58 -0
  38. data/lib/pki_express/pki_brazil_certificate_types.rb +19 -0
  39. data/lib/pki_express/pki_express_config.rb +26 -0
  40. data/lib/pki_express/pki_express_operator.rb +216 -0
  41. data/lib/pki_express/pki_italy_certificate_fields.rb +16 -0
  42. data/lib/pki_express/pki_italy_certificate_types.rb +11 -0
  43. data/lib/pki_express/signature_finisher.rb +298 -0
  44. data/lib/pki_express/signature_start_result.rb +13 -0
  45. data/lib/pki_express/signature_starter.rb +115 -0
  46. data/lib/pki_express/signer.rb +106 -0
  47. data/lib/pki_express/standard_signature_policies.rb +36 -0
  48. data/lib/pki_express/timestamp_authority.rb +51 -0
  49. data/lib/pki_express/validation_error.rb +8 -0
  50. data/lib/pki_express/validation_item.rb +43 -0
  51. data/lib/pki_express/validation_results.rb +121 -0
  52. data/lib/pki_express/version.rb +3 -0
  53. data/lib/pki_express/version_manager.rb +21 -0
  54. data/pki_express.gemspec +27 -0
  55. metadata +129 -0
@@ -0,0 +1,55 @@
1
+ module PkiExpress
2
+
3
+ class BaseSigner < PkiExpressOperator
4
+
5
+ def initialize(config=PkiExpressConfig.new)
6
+ super(config)
7
+ end
8
+
9
+ def verify_and_add_common_options(args)
10
+
11
+ if StandardSignaturePolicies::require_timestamp(@signature_policy) and
12
+ @timestamp_authority.nil?
13
+ raise 'The provided policy requires a timestamp authority and none was provided.'
14
+ end
15
+
16
+ # Set the signature policy.
17
+ unless @signature_policy.nil?
18
+ args << '--policy'
19
+ args << @signature_policy
20
+
21
+ # This operation evolved after version 1.5 to other signature policies.
22
+ if @signature_policy != StandardSignaturePolicies::XML_DSIG_BASIC and @signature_policy != StandardSignaturePolicies::NFE_PADRAO_NACIONAL
23
+ # This operation evolved after version 1.5 to other signature
24
+ # policies.
25
+ @version_manager.require_version('1.5')
26
+ end
27
+
28
+ if @signature_policy == StandardSignaturePolicies::COD_WITH_SHA1 or @signature_policy == StandardSignaturePolicies::COD_WITH_SHA256
29
+ # These policies can only be used on version greater than 1.6 of
30
+ # PKI Express.
31
+ @version_manager.require_version('1.6')
32
+ end
33
+
34
+ if @signature_policy == StandardSignaturePolicies::PKI_BRAZIL_PADES_ADR_BASICA or @signature_policy == StandardSignaturePolicies::PKI_BRAZIL_PADES_ADR_BASICA_WITH_LTV or @signature_policy == StandardSignaturePolicies::PKI_BRAZIL_PADES_ADR_TEMPO
35
+ # These policies can only be used on version greater than 1.12 of
36
+ # PKI Express.
37
+ @version_manager.require_version('1.12')
38
+ end
39
+ end
40
+
41
+ # Add timestamp authority.
42
+ if @timestamp_authority
43
+ tsp_args = @timestamp_authority.get_cmd_arguments
44
+ args.append(*tsp_args)
45
+
46
+
47
+ # This option can only be used on version greater than 1.5 of the
48
+ # PKI Express.
49
+ @version_manager.require_version('1.5')
50
+ end
51
+ end
52
+ protected :verify_and_add_common_options
53
+ end
54
+
55
+ end
@@ -0,0 +1,242 @@
1
+ module PkiExpress
2
+
3
+ class CadesSignatureStarter < SignatureStarter
4
+
5
+ attr_accessor :encapsulated_content
6
+
7
+ def initialize(config=PkiExpressConfig.new)
8
+ super(config)
9
+ @file_to_sign_path = nil
10
+ @data_file_path = nil
11
+ @encapsulated_content = true
12
+ end
13
+
14
+ # region The "file_to_sign" accessors
15
+
16
+ def file_to_sign
17
+ _get_file_to_sign
18
+ end
19
+
20
+ def _get_file_to_sign
21
+ unless @file_to_sign_path
22
+ return nil
23
+ end
24
+
25
+ File.read(@file_to_sign_path)
26
+ end
27
+ private :_get_file_to_sign
28
+
29
+ def file_to_sign=(content_raw)
30
+ _set_file_to_sign(content_raw)
31
+ end
32
+
33
+ def _set_file_to_sign(content_raw)
34
+ unless content_raw
35
+ raise 'The provided "file_to_sign" is not valid'
36
+ end
37
+
38
+ temp_file_path = self.create_temp_file
39
+ File.open(temp_file_path, 'wb') do |f|
40
+ f.write(content_raw)
41
+ end
42
+ @file_to_sign_path = temp_file_path
43
+ end
44
+ private :_set_file_to_sign
45
+
46
+ def file_to_sign_base64
47
+ _get_file_to_sign_base64
48
+ end
49
+
50
+ def _get_file_to_sign_base64
51
+ unless @file_to_sign_path
52
+ return nil
53
+ end
54
+
55
+ content = File.read(@file_to_sign_path)
56
+ Base64.encode64(content)
57
+ end
58
+ private :_get_file_to_sign_base64
59
+
60
+ def file_to_sign_base64=(content_base64)
61
+ _set_file_to_sign_base64(content_base64)
62
+ end
63
+
64
+ def _set_file_to_sign_base64(content_base64)
65
+ unless content_base64
66
+ raise 'The provided "file_to_sign_base64" is not valid'
67
+ end
68
+
69
+ begin
70
+ content_raw = Base64.decode64(content_base64)
71
+ rescue Error
72
+ raise 'The provided "file_to_sign_base64" is not Base64-encoded'
73
+ end
74
+
75
+ _set_file_to_sign(content_raw)
76
+ end
77
+ private :_set_file_to_sign_base64
78
+
79
+ def file_to_sign_path
80
+ _get_file_to_sign_path
81
+ end
82
+
83
+ def _get_file_to_sign_path
84
+ @file_to_sign_path
85
+ end
86
+ private :_get_file_to_sign_path
87
+
88
+ def file_to_sign_path=(path)
89
+ _set_file_to_sign_path(path)
90
+ end
91
+
92
+ def _set_file_to_sign_path(path)
93
+ unless path
94
+ raise 'The provided "file_to_sign_path" is not valid'
95
+ end
96
+ unless File.exists?(path)
97
+ raise 'The provided "file_to_sign_path" does not exist'
98
+ end
99
+
100
+ @file_to_sign_path = path
101
+ end
102
+ private :_set_file_to_sign_path
103
+
104
+ # endregion
105
+
106
+ # region The "data_file" accessors
107
+
108
+ def data_file
109
+ _get_data_file
110
+ end
111
+
112
+ def _get_data_file
113
+ unless @data_file_path
114
+ return nil
115
+ end
116
+
117
+ File.read(@data_file_path)
118
+ end
119
+ private :_get_data_file
120
+
121
+ def data_file=(content_raw)
122
+ _set_data_file(content_raw)
123
+ end
124
+
125
+ def _set_data_file(content_raw)
126
+ unless content_raw
127
+ raise 'The provided "data_file" is not valid'
128
+ end
129
+
130
+ temp_file_path = self.create_temp_file
131
+ File.open(temp_file_path, 'wb') do |f|
132
+ f.write(content_raw)
133
+ end
134
+ @data_file_path = temp_file_path
135
+ end
136
+ private :_set_data_file
137
+
138
+ def data_file_base64
139
+ _get_data_file_base64
140
+ end
141
+
142
+ def _get_data_file_base64
143
+ unless @data_file_path
144
+ return nil
145
+ end
146
+
147
+ content = File.read(@data_file_path)
148
+ Base64.encode64(content)
149
+ end
150
+ private :_get_data_file_base64
151
+
152
+ def data_file_base64=(content_base64)
153
+ _set_data_file_base64(content_base64)
154
+ end
155
+
156
+ def _set_data_file_base64(content_base64)
157
+ unless content_base64
158
+ raise 'The provided "data_file_base64" is not valid'
159
+ end
160
+
161
+ begin
162
+ content_raw = Base64.decode64(content_base64)
163
+ rescue Error
164
+ raise 'The provided "data_file_base64" is not Base64-encoded'
165
+ end
166
+
167
+ _set_data_file(content_raw)
168
+ end
169
+ private :_set_data_file_base64
170
+
171
+ def data_file_path
172
+ _get_data_file_path
173
+ end
174
+
175
+ def _get_data_file_path
176
+ @data_file_path
177
+ end
178
+ private :_get_data_file_path
179
+
180
+ def data_file_path=(path)
181
+ _set_data_file_path(path)
182
+ end
183
+
184
+ def _set_data_file_path(path)
185
+ unless path
186
+ raise 'The provided "data_file_path" is not valid'
187
+ end
188
+ unless File.exists?(path)
189
+ raise 'The provided "data_file_path" does not exist'
190
+ end
191
+
192
+ @data_file_path = path
193
+ end
194
+ private :_set_data_file_path
195
+
196
+ # endregion
197
+
198
+ def start
199
+
200
+ unless @file_to_sign_path
201
+ raise 'The file to be signed was not set'
202
+ end
203
+
204
+ unless @certificate_path
205
+ raise 'The certificate was not set'
206
+ end
207
+
208
+ # Generate transfer file.
209
+ transfer_file_id = get_transfer_filename
210
+
211
+ args = [
212
+ @file_to_sign_path,
213
+ @certificate_path,
214
+ File.expand_path(transfer_file_id, @config.transfer_data_folder),
215
+ ]
216
+
217
+ # Verify and add common options between signers.
218
+ verify_and_add_common_options(args)
219
+
220
+ if @data_file_path
221
+ args.append('--data-file')
222
+ args.append(@data_file_path)
223
+ end
224
+
225
+ unless @encapsulated_content
226
+ args.append('--detached')
227
+ end
228
+
229
+ # This operation can only be used on version greater than 1.3 of the
230
+ # PKI Express.
231
+ @version_manager.require_version('1.3')
232
+
233
+ # Invoke command.
234
+ result = invoke(Commands::START_CADES, args)
235
+
236
+ # Parse output and return model.
237
+ model = parse_output(result)
238
+ SignatureStartResult.new(model, transfer_file_id)
239
+ end
240
+ end
241
+
242
+ end
@@ -0,0 +1,14 @@
1
+ module PkiExpress
2
+ class CommandError < StandardError
3
+ attr_accessor :name, :code, :inner_error
4
+
5
+ def initialize(code, msg, inner_error=nil)
6
+ super(msg)
7
+
8
+ @name = self.class.name
9
+ @code = code
10
+ @inner_error = inner_error
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module PkiExpress
2
+ class Commands
3
+ SIGN_CADES = 'sign-cades',
4
+ SIGN_PADES = 'sign-pades',
5
+ SIGN_XML = 'sign-xml',
6
+ START_CADES = 'start-cades',
7
+ START_PADES = 'start-pades',
8
+ START_XML = 'start-xml',
9
+ COMPLETE_SIG = 'complete-sig',
10
+ OPEN_PADES = 'open-pades',
11
+ OPEN_CADES = 'open-cades',
12
+ EDIT_PDF = 'edit-pdf',
13
+ MERGE_CMS = 'merge-cms',
14
+ START_AUTH = 'start-auth',
15
+ COMPLETE_AUTH = 'complete-auth',
16
+ STAMP_PDF = 'stamp-pdf',
17
+ READ_CERT = 'read-cert',
18
+ GEN_KEY = 'gen-key',
19
+ CREATE_PFX = 'create-pfx'
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module PkiExpress
2
+ class Enum
3
+ VALUES = []
4
+
5
+ def self.contains?(value)
6
+ VALUES.include? (value)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ module PkiExpress
2
+ class ErrorCodes
3
+ OK = 0,
4
+ BAD_SYNTAX = 1,
5
+ UNKNOWN_ERROR = 2,
6
+ FILE_NOT_FOUND = 3,
7
+ BAD_CERTIFICATE = 4,
8
+ BAD_THUMBPRINT = 5,
9
+ BAD_HASH = 6,
10
+ BAD_DATA = 7,
11
+ BAD_SIGNATURE = 8,
12
+ BAD_ALGORITHM = 9,
13
+ BAD_POLICY = 10,
14
+ BAD_VISUAL_REP = 11,
15
+ UNDEFINED_FILE_REFERENCE = 12,
16
+ CERT_NOT_FOUND = 13,
17
+ VALIDATION_FAILED = 14,
18
+ IO_ERROR = 15,
19
+ NO_CERTS_WITH_KEY = 16,
20
+ NOT_ACTIVATED = 17,
21
+ ACTIVATION_ERROR = 18,
22
+ BAD_LICENSE = 19,
23
+ LICENSE_NEEDED = 20,
24
+ INVALID_LICENSE = 21,
25
+ ACCESS_DENIED = 22,
26
+ CERT_THUMB_NEEDED = 23,
27
+ BAD_PDF_CHANGES = 24,
28
+ UPDATE_NEEDED = 25,
29
+ DATA_FILE_NEEDED = 26,
30
+ NO_ENCAPSULATED_CONTENT = 27,
31
+ NONCE_NOT_FOUND = 28,
32
+ DIRECTORY_NOT_FOUND = 29,
33
+ TIMESTAMP_AUTHORITY_NOT_AVAILABLE = 30,
34
+ POLICY_REQUIRES_NETWORK = 31,
35
+ TIMESTAMP_OPTIONS_REQUIRED = 32,
36
+ CULTURE_NOT_FOUND = 33,
37
+ TIME_ZONE_NOT_FOUND = 34,
38
+ INVALID_UTC_OFFSET = 35,
39
+ KEY_SIZE_NOT_SUPPORTED = 36,
40
+ BAD_KEY_FORMAT = 37,
41
+ BAD_KEY = 38,
42
+ INVALID_TIMEOUT_VALUE = 39,
43
+
44
+ COMMAND_NOT_FOUND = 127
45
+ end
46
+ end
@@ -0,0 +1,8 @@
1
+ module PkiExpress
2
+ class InstallationNotFoundError < CommandError
3
+
4
+ def initialize(message, inner_error=nil)
5
+ super(ErrorCodes::COMMAND_NOT_FOUND, message, inner_error)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,48 @@
1
+ module PkiExpress
2
+
3
+ class Name
4
+
5
+ attr_accessor :country, :organization, :organization_unit, :dn_qualifier,
6
+ :state_name, :common_name, :serial_number, :locality, :title,
7
+ :surname, :given_name, :initials, :pseudonym,
8
+ :generation_qualifier, :email_address
9
+
10
+ def initialize(model)
11
+ @country = nil
12
+ @organization = nil
13
+ @organization_unit = nil
14
+ @dn_qualifier = nil
15
+ @state_name = nil
16
+ @common_name = nil
17
+ @serial_number = nil
18
+ @locality = nil
19
+ @title = nil
20
+ @surname = nil
21
+ @given_name = nil
22
+ @initials = nil
23
+ @pseudonym = nil
24
+ @generation_qualifier = nil
25
+ @email_address = nil
26
+
27
+
28
+ if model
29
+ @country = model.fetch(:country)
30
+ @organization = model.fetch(:organization)
31
+ @organization_unit = model.fetch(:organizationUnit)
32
+ @dn_qualifier = model.fetch(:dnQualifier)
33
+ @state_name = model.fetch(:stateName)
34
+ @common_name = model.fetch(:commonName)
35
+ @serial_number = model.fetch(:serialNumber)
36
+ @locality = model.fetch(:locality)
37
+ @title = model.fetch(:title)
38
+ @surname = model.fetch(:surname)
39
+ @given_name = model.fetch(:givenName)
40
+ @initials = model.fetch(:initials)
41
+ @pseudonym = model.fetch(:pseudonym)
42
+ @generation_qualifier = model.fetch(:generationQualifier)
43
+ @email_address = model.fetch(:emailAddress)
44
+ end
45
+ end
46
+ end
47
+
48
+ end