origami-docspring 2.2.0 → 2.3.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/examples/attachments/attachment.rb +7 -8
  4. data/examples/attachments/nested_document.rb +6 -5
  5. data/examples/encryption/encryption.rb +5 -4
  6. data/examples/events/events.rb +7 -6
  7. data/examples/flash/flash.rb +10 -9
  8. data/examples/forms/javascript.rb +14 -13
  9. data/examples/forms/xfa.rb +67 -66
  10. data/examples/javascript/hello_world.rb +6 -5
  11. data/examples/javascript/js_emulation.rb +26 -26
  12. data/examples/loop/goto.rb +12 -11
  13. data/examples/loop/named.rb +17 -16
  14. data/examples/signature/signature.rb +11 -11
  15. data/examples/uri/javascript.rb +25 -24
  16. data/examples/uri/open-uri.rb +5 -4
  17. data/examples/uri/submitform.rb +11 -10
  18. data/lib/origami/3d.rb +330 -334
  19. data/lib/origami/acroform.rb +267 -268
  20. data/lib/origami/actions.rb +266 -278
  21. data/lib/origami/annotations.rb +659 -670
  22. data/lib/origami/array.rb +192 -196
  23. data/lib/origami/boolean.rb +66 -70
  24. data/lib/origami/catalog.rb +360 -363
  25. data/lib/origami/collections.rb +132 -133
  26. data/lib/origami/compound.rb +125 -129
  27. data/lib/origami/destinations.rb +226 -237
  28. data/lib/origami/dictionary.rb +155 -154
  29. data/lib/origami/encryption.rb +967 -923
  30. data/lib/origami/extensions/fdf.rb +270 -275
  31. data/lib/origami/extensions/ppklite.rb +323 -328
  32. data/lib/origami/filespec.rb +170 -173
  33. data/lib/origami/filters/ascii.rb +162 -167
  34. data/lib/origami/filters/ccitt/tables.rb +248 -252
  35. data/lib/origami/filters/ccitt.rb +309 -312
  36. data/lib/origami/filters/crypt.rb +31 -34
  37. data/lib/origami/filters/dct.rb +47 -50
  38. data/lib/origami/filters/flate.rb +57 -60
  39. data/lib/origami/filters/jbig2.rb +50 -53
  40. data/lib/origami/filters/jpx.rb +40 -43
  41. data/lib/origami/filters/lzw.rb +151 -155
  42. data/lib/origami/filters/predictors.rb +250 -255
  43. data/lib/origami/filters/runlength.rb +111 -115
  44. data/lib/origami/filters.rb +319 -325
  45. data/lib/origami/font.rb +173 -177
  46. data/lib/origami/functions.rb +62 -66
  47. data/lib/origami/graphics/colors.rb +203 -208
  48. data/lib/origami/graphics/instruction.rb +79 -81
  49. data/lib/origami/graphics/path.rb +141 -144
  50. data/lib/origami/graphics/patterns.rb +156 -160
  51. data/lib/origami/graphics/render.rb +51 -47
  52. data/lib/origami/graphics/state.rb +144 -142
  53. data/lib/origami/graphics/text.rb +185 -188
  54. data/lib/origami/graphics/xobject.rb +818 -804
  55. data/lib/origami/graphics.rb +25 -26
  56. data/lib/origami/header.rb +63 -65
  57. data/lib/origami/javascript.rb +718 -651
  58. data/lib/origami/linearization.rb +284 -285
  59. data/lib/origami/metadata.rb +156 -135
  60. data/lib/origami/name.rb +98 -100
  61. data/lib/origami/null.rb +49 -51
  62. data/lib/origami/numeric.rb +133 -135
  63. data/lib/origami/obfuscation.rb +180 -182
  64. data/lib/origami/object.rb +634 -631
  65. data/lib/origami/optionalcontent.rb +147 -149
  66. data/lib/origami/outline.rb +46 -48
  67. data/lib/origami/outputintents.rb +76 -77
  68. data/lib/origami/page.rb +637 -596
  69. data/lib/origami/parser.rb +214 -221
  70. data/lib/origami/parsers/fdf.rb +44 -45
  71. data/lib/origami/parsers/pdf/lazy.rb +147 -154
  72. data/lib/origami/parsers/pdf/linear.rb +104 -109
  73. data/lib/origami/parsers/pdf.rb +109 -107
  74. data/lib/origami/parsers/ppklite.rb +44 -46
  75. data/lib/origami/pdf.rb +886 -896
  76. data/lib/origami/reference.rb +116 -120
  77. data/lib/origami/signature.rb +617 -625
  78. data/lib/origami/stream.rb +560 -558
  79. data/lib/origami/string.rb +366 -368
  80. data/lib/origami/template/patterns.rb +50 -52
  81. data/lib/origami/template/widgets.rb +111 -114
  82. data/lib/origami/trailer.rb +153 -157
  83. data/lib/origami/tree.rb +55 -57
  84. data/lib/origami/version.rb +19 -19
  85. data/lib/origami/webcapture.rb +87 -90
  86. data/lib/origami/xfa/config.rb +409 -414
  87. data/lib/origami/xfa/connectionset.rb +113 -117
  88. data/lib/origami/xfa/datasets.rb +38 -42
  89. data/lib/origami/xfa/localeset.rb +33 -37
  90. data/lib/origami/xfa/package.rb +49 -52
  91. data/lib/origami/xfa/pdf.rb +54 -59
  92. data/lib/origami/xfa/signature.rb +33 -37
  93. data/lib/origami/xfa/sourceset.rb +34 -38
  94. data/lib/origami/xfa/stylesheet.rb +35 -39
  95. data/lib/origami/xfa/template.rb +1630 -1634
  96. data/lib/origami/xfa/xdc.rb +33 -37
  97. data/lib/origami/xfa/xfa.rb +132 -123
  98. data/lib/origami/xfa/xfdf.rb +34 -38
  99. data/lib/origami/xfa/xmpmeta.rb +34 -38
  100. data/lib/origami/xfa.rb +50 -53
  101. data/lib/origami/xreftable.rb +462 -462
  102. data/lib/origami.rb +37 -38
  103. data/test/test_actions.rb +22 -20
  104. data/test/test_annotations.rb +54 -52
  105. data/test/test_forms.rb +23 -21
  106. data/test/test_native_types.rb +82 -78
  107. data/test/test_object_tree.rb +25 -24
  108. data/test/test_pages.rb +43 -41
  109. data/test/test_pdf.rb +2 -0
  110. data/test/test_pdf_attachment.rb +23 -21
  111. data/test/test_pdf_create.rb +16 -15
  112. data/test/test_pdf_encrypt.rb +69 -66
  113. data/test/test_pdf_parse.rb +131 -129
  114. data/test/test_pdf_parse_lazy.rb +53 -53
  115. data/test/test_pdf_sign.rb +67 -67
  116. data/test/test_streams.rb +145 -143
  117. data/test/test_xrefs.rb +46 -45
  118. metadata +64 -8
@@ -1,702 +1,694 @@
1
- =begin
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This file is part of Origami, PDF manipulation framework for Ruby
5
+ # Copyright (C) 2016 Guillaume Delugré.
6
+ #
7
+ # Origami is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Origami is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+ #
2
20
 
3
- This file is part of Origami, PDF manipulation framework for Ruby
4
- Copyright (C) 2016 Guillaume Delugré.
21
+ require 'openssl'
22
+ require 'digest/sha1'
5
23
 
6
- Origami is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
24
+ module Origami
25
+ class SignatureError < Error # :nodoc:
26
+ end
27
+
28
+ class PDF
29
+ #
30
+ # Verify a document signature.
31
+ # _:trusted_certs_: an array of trusted X509 certificates.
32
+ # _:use_system_store_: use the system store for certificate authorities.
33
+ # _:allow_self_signed_: allow self-signed certificates in the verification chain.
34
+ # _verify_cb_: block called when encountering a certificate that cannot be verified.
35
+ # Passed argument in the OpenSSL::X509::StoreContext.
36
+ #
37
+ def verify(trusted_certs: [],
38
+ use_system_store: false,
39
+ allow_self_signed: false,
40
+ &verify_cb)
41
+ digsig = signature
42
+ digsig = digsig.cast_to(Signature::DigitalSignature) unless digsig.is_a?(Signature::DigitalSignature)
43
+
44
+ signature = digsig.signature_data
45
+ chain = digsig.certificate_chain
46
+ subfilter = digsig.SubFilter.value
47
+
48
+ store = OpenSSL::X509::Store.new
49
+ store.set_default_paths if use_system_store
50
+ trusted_certs.each { |ca| store.add_cert(ca) }
51
+
52
+ store.verify_callback = ->(success, ctx) {
53
+ return true if success
54
+
55
+ error = ctx.error
56
+ is_self_signed = error == OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
57
+ error == OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN
58
+
59
+ return true if is_self_signed && allow_self_signed && verify_cb.nil?
60
+
61
+ verify_cb.call(ctx) unless verify_cb.nil?
62
+ }
63
+
64
+ data = extract_signed_data(digsig)
65
+ Signature.verify(subfilter.to_s, data, signature, store, chain)
66
+ end
10
67
 
11
- Origami is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
68
+ #
69
+ # Sign the document with the given key and x509 certificate.
70
+ # _certificate_:: The X509 certificate containing the public key.
71
+ # _key_:: The private key associated with the certificate.
72
+ # _method_:: The PDF signature identifier.
73
+ # _ca_:: Optional CA certificates used to sign the user certificate.
74
+ # _annotation_:: Annotation associated with the signature.
75
+ # _issuer_:: Issuer name.
76
+ # _location_:: Signature location.
77
+ # _contact_:: Signer contact.
78
+ # _reason_:: Signing reason.
79
+ #
80
+ def sign(certificate, key,
81
+ method: Signature::PKCS7_DETACHED,
82
+ ca: [],
83
+ annotation: nil,
84
+ issuer: nil,
85
+ location: nil,
86
+ contact: nil,
87
+ reason: nil)
88
+ unless certificate.is_a?(OpenSSL::X509::Certificate)
89
+ raise TypeError, "A OpenSSL::X509::Certificate object must be passed."
90
+ end
91
+
92
+ unless key.is_a?(OpenSSL::PKey::RSA)
93
+ raise TypeError, "A OpenSSL::PKey::RSA object must be passed."
94
+ end
95
+
96
+ unless ca.is_a?(::Array)
97
+ raise TypeError, "Expected an Array of CA certificates."
98
+ end
99
+
100
+ unless annotation.nil? || annotation.is_a?(Annotation::Widget::Signature)
101
+ raise TypeError, "Expected a Annotation::Widget::Signature object."
102
+ end
103
+
104
+ #
105
+ # XXX: Currently signing a linearized document will result in a broken document.
106
+ # Delinearize the document first until we find a proper way to handle this case.
107
+ #
108
+ if linearized?
109
+ delinearize!
110
+ end
111
+
112
+ digsig = Signature::DigitalSignature.new.set_indirect(true)
113
+
114
+ if annotation.nil?
115
+ annotation = Annotation::Widget::Signature.new
116
+ annotation.Rect = Rectangle[llx: 0.0, lly: 0.0, urx: 0.0, ury: 0.0]
117
+ end
118
+
119
+ annotation.V = digsig
120
+ add_fields(annotation)
121
+ self.Catalog.AcroForm.SigFlags =
122
+ InteractiveForm::SigFlags::SIGNATURES_EXIST | InteractiveForm::SigFlags::APPEND_ONLY
123
+
124
+ digsig.Type = :Sig
125
+ digsig.Contents = HexaString.new("\x00" * Signature.required_size(method, certificate, key, ca))
126
+ digsig.Filter = :'Adobe.PPKLite'
127
+ digsig.SubFilter = Name.new(method)
128
+ digsig.ByteRange = [0, 0, 0, 0]
129
+ digsig.Name = issuer
130
+
131
+ digsig.Location = HexaString.new(location) if location
132
+ digsig.ContactInfo = HexaString.new(contact) if contact
133
+ digsig.Reason = HexaString.new(reason) if reason
134
+
135
+ # PKCS1 signatures require a Cert entry.
136
+ if method == Signature::PKCS1_RSA_SHA1
137
+ digsig.Cert =
138
+ if ca.empty?
139
+ HexaString.new(certificate.to_der)
140
+ else
141
+ [HexaString.new(certificate.to_der)] + ca.map { |crt| HexaString.new(crt.to_der) }
142
+ end
143
+ end
144
+
145
+ #
146
+ # Flattening the PDF to get file view.
147
+ #
148
+ compile
149
+
150
+ #
151
+ # Creating an empty Xref table to compute signature byte range.
152
+ #
153
+ rebuild_dummy_xrefs
154
+
155
+ sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
156
+
157
+ digsig.ByteRange[0] = 0
158
+ digsig.ByteRange[1] = sig_offset
159
+ digsig.ByteRange[2] = sig_offset + digsig.Contents.to_s.bytesize
160
+
161
+ until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
162
+ digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
163
+ end
164
+
165
+ # From that point on, the file size remains constant
166
+
167
+ #
168
+ # Correct Xrefs variations caused by ByteRange modifications.
169
+ #
170
+ rebuild_xrefs
171
+
172
+ file_data = output
173
+ signable_data = file_data[digsig.ByteRange[0], digsig.ByteRange[1]] +
174
+ file_data[digsig.ByteRange[2], digsig.ByteRange[3]]
175
+
176
+ #
177
+ # Computes and inserts the signature.
178
+ #
179
+ signature = Signature.compute(method, signable_data, certificate, key, ca)
180
+ digsig.Contents[0, signature.size] = signature
181
+
182
+ #
183
+ # No more modification are allowed after signing.
184
+ #
185
+ freeze
186
+ end
15
187
 
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
188
+ #
189
+ # Returns whether the document contains a digital signature.
190
+ #
191
+ def signed?
192
+ self.Catalog.AcroForm.is_a?(Dictionary) and
193
+ self.Catalog.AcroForm.SigFlags.is_a?(Integer) and
194
+ (self.Catalog.AcroForm.SigFlags & InteractiveForm::SigFlags::SIGNATURES_EXIST != 0)
195
+ rescue InvalidReferenceError
196
+ false
197
+ end
18
198
 
19
- =end
199
+ #
200
+ # Enable the document Usage Rights.
201
+ # _rights_:: list of rights defined in UsageRights::Rights
202
+ #
203
+ def enable_usage_rights(cert, pkey, *rights)
204
+ # Always uses a detached PKCS7 signature for UR.
205
+ method = Signature::PKCS7_DETACHED
206
+
207
+ #
208
+ # Load key pair
209
+ #
210
+ key = pkey.is_a?(OpenSSL::PKey::RSA) ? pkey : OpenSSL::PKey::RSA.new(pkey)
211
+ certificate = cert.is_a?(OpenSSL::X509::Certificate) ? cert : OpenSSL::X509::Certificate.new(cert)
212
+
213
+ #
214
+ # Forge digital signature dictionary
215
+ #
216
+ digsig = Signature::DigitalSignature.new.set_indirect(true)
217
+
218
+ self.Catalog.AcroForm ||= InteractiveForm.new
219
+ # self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::APPEND_ONLY
220
+
221
+ digsig.Type = :Sig
222
+ digsig.Contents = HexaString.new("\x00" * Signature.required_size(method, certificate, key, []))
223
+ digsig.Filter = :'Adobe.PPKLite'
224
+ digsig.Name = "ARE Acrobat Product v8.0 P23 0002337"
225
+ digsig.SubFilter = Name.new(method)
226
+ digsig.ByteRange = [0, 0, 0, 0]
227
+
228
+ sigref = Signature::Reference.new
229
+ sigref.Type = :SigRef
230
+ sigref.TransformMethod = :UR3
231
+ sigref.Data = self.Catalog
232
+
233
+ sigref.TransformParams = UsageRights::TransformParams.new
234
+ sigref.TransformParams.P = true
235
+ sigref.TransformParams.Type = :TransformParams
236
+ sigref.TransformParams.V = UsageRights::TransformParams::VERSION
237
+
238
+ rights.each do |right|
239
+ sigref.TransformParams[right.first] ||= []
240
+ sigref.TransformParams[right.first].concat(right[1..])
241
+ end
242
+
243
+ digsig.Reference = [sigref]
244
+
245
+ self.Catalog.Perms ||= Perms.new
246
+ self.Catalog.Perms.UR3 = digsig
247
+
248
+ #
249
+ # Flattening the PDF to get file view.
250
+ #
251
+ compile
252
+
253
+ #
254
+ # Creating an empty Xref table to compute signature byte range.
255
+ #
256
+ rebuild_dummy_xrefs
257
+
258
+ sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
259
+
260
+ digsig.ByteRange[0] = 0
261
+ digsig.ByteRange[1] = sig_offset
262
+ digsig.ByteRange[2] = sig_offset + digsig.Contents.size
263
+
264
+ until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
265
+ digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
266
+ end
267
+
268
+ # From that point on, the file size remains constant
269
+
270
+ #
271
+ # Correct Xrefs variations caused by ByteRange modifications.
272
+ #
273
+ rebuild_xrefs
274
+
275
+ file_data = output
276
+ signable_data = file_data[digsig.ByteRange[0], digsig.ByteRange[1]] +
277
+ file_data[digsig.ByteRange[2], digsig.ByteRange[3]]
278
+
279
+ signature = Signature.compute(method, signable_data, certificate, key, [])
280
+ digsig.Contents[0, signature.size] = signature
281
+
282
+ #
283
+ # No more modification are allowed after signing.
284
+ #
285
+ freeze
286
+ end
20
287
 
21
- require 'openssl'
22
- require 'digest/sha1'
288
+ def usage_rights?
289
+ !self.Catalog.Perms.nil? and
290
+ (!self.Catalog.Perms.has_key?(:UR3) or !self.Catalog.Perms.has_key?(:UR))
291
+ end
23
292
 
24
- module Origami
293
+ def signature
294
+ raise SignatureError, "Not a signed document" unless signed?
295
+
296
+ each_field do |field|
297
+ return field.V if (field.FT == :Sig) && field.V.is_a?(Dictionary)
298
+ end
25
299
 
26
- class SignatureError < Error #:nodoc:
300
+ raise SignatureError, "Cannot find digital signature"
27
301
  end
28
302
 
29
- class PDF
30
- #
31
- # Verify a document signature.
32
- # _:trusted_certs_: an array of trusted X509 certificates.
33
- # _:use_system_store_: use the system store for certificate authorities.
34
- # _:allow_self_signed_: allow self-signed certificates in the verification chain.
35
- # _verify_cb_: block called when encountering a certificate that cannot be verified.
36
- # Passed argument in the OpenSSL::X509::StoreContext.
37
- #
38
- def verify(trusted_certs: [],
39
- use_system_store: false,
40
- allow_self_signed: false,
41
- &verify_cb)
303
+ private
42
304
 
43
- digsig = self.signature
44
- digsig = digsig.cast_to(Signature::DigitalSignature) unless digsig.is_a?(Signature::DigitalSignature)
305
+ #
306
+ # Verifies the ByteRange field of a digital signature and returned the signed data.
307
+ #
308
+ def extract_signed_data(digsig)
309
+ # Computes the boundaries of the Contents field.
310
+ start_sig = digsig[:Contents].file_offset
45
311
 
46
- signature = digsig.signature_data
47
- chain = digsig.certificate_chain
48
- subfilter = digsig.SubFilter.value
312
+ stream = StringScanner.new(original_data)
313
+ stream.pos = digsig[:Contents].file_offset
314
+ Object.typeof(stream).parse(stream)
315
+ end_sig = stream.pos
316
+ stream.terminate
49
317
 
50
- store = OpenSSL::X509::Store.new
51
- store.set_default_paths if use_system_store
52
- trusted_certs.each { |ca| store.add_cert(ca) }
318
+ r1, r2 = digsig.ranges
319
+ if (r1.begin != 0) ||
320
+ (r2.end != original_data.size) ||
321
+ (r1.end != start_sig) ||
322
+ (r2.begin != end_sig)
53
323
 
54
- store.verify_callback = -> (success, ctx) {
55
- return true if success
324
+ raise SignatureError, "Invalid signature byte range"
325
+ end
56
326
 
57
- error = ctx.error
58
- is_self_signed = (error == OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
59
- error == OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
327
+ original_data[r1] + original_data[r2]
328
+ end
329
+ end
60
330
 
61
- return true if is_self_signed && allow_self_signed && verify_cb.nil?
331
+ class Perms < Dictionary
332
+ include StandardObject
62
333
 
63
- verify_cb.call(ctx) unless verify_cb.nil?
64
- }
334
+ field :DocMDP, Type: Dictionary
335
+ field :UR, Type: Dictionary
336
+ field :UR3, Type: Dictionary, Version: "1.6"
337
+ end
65
338
 
66
- data = extract_signed_data(digsig)
67
- Signature.verify(subfilter.to_s, data, signature, store, chain)
68
- end
339
+ module Signature
340
+ PKCS1_RSA_SHA1 = "adbe.x509.rsa_sha1"
341
+ PKCS7_SHA1 = "adbe.pkcs7.sha1"
342
+ PKCS7_DETACHED = "adbe.pkcs7.detached"
69
343
 
70
- #
71
- # Sign the document with the given key and x509 certificate.
72
- # _certificate_:: The X509 certificate containing the public key.
73
- # _key_:: The private key associated with the certificate.
74
- # _method_:: The PDF signature identifier.
75
- # _ca_:: Optional CA certificates used to sign the user certificate.
76
- # _annotation_:: Annotation associated with the signature.
77
- # _issuer_:: Issuer name.
78
- # _location_:: Signature location.
79
- # _contact_:: Signer contact.
80
- # _reason_:: Signing reason.
81
- #
82
- def sign(certificate, key,
83
- method: Signature::PKCS7_DETACHED,
84
- ca: [],
85
- annotation: nil,
86
- issuer: nil,
87
- location: nil,
88
- contact: nil,
89
- reason: nil)
90
-
91
- unless certificate.is_a?(OpenSSL::X509::Certificate)
92
- raise TypeError, "A OpenSSL::X509::Certificate object must be passed."
93
- end
94
-
95
- unless key.is_a?(OpenSSL::PKey::RSA)
96
- raise TypeError, "A OpenSSL::PKey::RSA object must be passed."
97
- end
98
-
99
- unless ca.is_a?(::Array)
100
- raise TypeError, "Expected an Array of CA certificates."
101
- end
102
-
103
- unless annotation.nil? or annotation.is_a?(Annotation::Widget::Signature)
104
- raise TypeError, "Expected a Annotation::Widget::Signature object."
105
- end
106
-
107
- #
108
- # XXX: Currently signing a linearized document will result in a broken document.
109
- # Delinearize the document first until we find a proper way to handle this case.
110
- #
111
- if self.linearized?
112
- self.delinearize!
113
- end
114
-
115
- digsig = Signature::DigitalSignature.new.set_indirect(true)
116
-
117
- if annotation.nil?
118
- annotation = Annotation::Widget::Signature.new
119
- annotation.Rect = Rectangle[:llx => 0.0, :lly => 0.0, :urx => 0.0, :ury => 0.0]
120
- end
121
-
122
- annotation.V = digsig
123
- add_fields(annotation)
124
- self.Catalog.AcroForm.SigFlags =
125
- InteractiveForm::SigFlags::SIGNATURES_EXIST | InteractiveForm::SigFlags::APPEND_ONLY
126
-
127
- digsig.Type = :Sig
128
- digsig.Contents = HexaString.new("\x00" * Signature::required_size(method, certificate, key, ca))
129
- digsig.Filter = :"Adobe.PPKLite"
130
- digsig.SubFilter = Name.new(method)
131
- digsig.ByteRange = [0, 0, 0, 0]
132
- digsig.Name = issuer
133
-
134
- digsig.Location = HexaString.new(location) if location
135
- digsig.ContactInfo = HexaString.new(contact) if contact
136
- digsig.Reason = HexaString.new(reason) if reason
137
-
138
- # PKCS1 signatures require a Cert entry.
139
- if method == Signature::PKCS1_RSA_SHA1
140
- digsig.Cert =
141
- if ca.empty?
142
- HexaString.new(certificate.to_der)
143
- else
144
- [ HexaString.new(certificate.to_der) ] + ca.map{ |crt| HexaString.new(crt.to_der) }
145
- end
146
- end
147
-
148
- #
149
- # Flattening the PDF to get file view.
150
- #
151
- compile
152
-
153
- #
154
- # Creating an empty Xref table to compute signature byte range.
155
- #
156
- rebuild_dummy_xrefs
157
-
158
- sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
159
-
160
- digsig.ByteRange[0] = 0
161
- digsig.ByteRange[1] = sig_offset
162
- digsig.ByteRange[2] = sig_offset + digsig.Contents.to_s.bytesize
163
-
164
- until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
165
- digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
166
- end
167
-
168
- # From that point on, the file size remains constant
169
-
170
- #
171
- # Correct Xrefs variations caused by ByteRange modifications.
172
- #
173
- rebuild_xrefs
174
-
175
- file_data = output()
176
- signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] +
177
- file_data[digsig.ByteRange[2],digsig.ByteRange[3]]
178
-
179
- #
180
- # Computes and inserts the signature.
181
- #
182
- signature = Signature.compute(method, signable_data, certificate, key, ca)
183
- digsig.Contents[0, signature.size] = signature
184
-
185
- #
186
- # No more modification are allowed after signing.
187
- #
188
- self.freeze
189
- end
344
+ #
345
+ # PKCS1 class used for adbe.x509.rsa_sha1.
346
+ #
347
+ class PKCS1
348
+ class PKCS1Error < SignatureError; end
190
349
 
191
- #
192
- # Returns whether the document contains a digital signature.
193
- #
194
- def signed?
195
- begin
196
- self.Catalog.AcroForm.is_a?(Dictionary) and
197
- self.Catalog.AcroForm.SigFlags.is_a?(Integer) and
198
- (self.Catalog.AcroForm.SigFlags & InteractiveForm::SigFlags::SIGNATURES_EXIST != 0)
199
- rescue InvalidReferenceError
200
- false
201
- end
202
- end
350
+ def initialize(signature)
351
+ @signature_object = decode_pkcs1(signature)
352
+ end
203
353
 
204
- #
205
- # Enable the document Usage Rights.
206
- # _rights_:: list of rights defined in UsageRights::Rights
207
- #
208
- def enable_usage_rights(cert, pkey, *rights)
209
-
210
- # Always uses a detached PKCS7 signature for UR.
211
- method = Signature::PKCS7_DETACHED
212
-
213
- #
214
- # Load key pair
215
- #
216
- key = pkey.is_a?(OpenSSL::PKey::RSA) ? pkey : OpenSSL::PKey::RSA.new(pkey)
217
- certificate = cert.is_a?(OpenSSL::X509::Certificate) ? cert : OpenSSL::X509::Certificate.new(cert)
218
-
219
- #
220
- # Forge digital signature dictionary
221
- #
222
- digsig = Signature::DigitalSignature.new.set_indirect(true)
223
-
224
- self.Catalog.AcroForm ||= InteractiveForm.new
225
- #self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::APPEND_ONLY
226
-
227
- digsig.Type = :Sig
228
- digsig.Contents = HexaString.new("\x00" * Signature.required_size(method, certificate, key, []))
229
- digsig.Filter = :"Adobe.PPKLite"
230
- digsig.Name = "ARE Acrobat Product v8.0 P23 0002337"
231
- digsig.SubFilter = Name.new(method )
232
- digsig.ByteRange = [0, 0, 0, 0]
233
-
234
- sigref = Signature::Reference.new
235
- sigref.Type = :SigRef
236
- sigref.TransformMethod = :UR3
237
- sigref.Data = self.Catalog
238
-
239
- sigref.TransformParams = UsageRights::TransformParams.new
240
- sigref.TransformParams.P = true
241
- sigref.TransformParams.Type = :TransformParams
242
- sigref.TransformParams.V = UsageRights::TransformParams::VERSION
243
-
244
- rights.each do |right|
245
- sigref.TransformParams[right.first] ||= []
246
- sigref.TransformParams[right.first].concat(right[1..-1])
247
- end
248
-
249
- digsig.Reference = [ sigref ]
250
-
251
- self.Catalog.Perms ||= Perms.new
252
- self.Catalog.Perms.UR3 = digsig
253
-
254
- #
255
- # Flattening the PDF to get file view.
256
- #
257
- compile
258
-
259
- #
260
- # Creating an empty Xref table to compute signature byte range.
261
- #
262
- rebuild_dummy_xrefs
263
-
264
- sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
265
-
266
- digsig.ByteRange[0] = 0
267
- digsig.ByteRange[1] = sig_offset
268
- digsig.ByteRange[2] = sig_offset + digsig.Contents.size
269
-
270
- until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
271
- digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
272
- end
273
-
274
- # From that point on, the file size remains constant
275
-
276
- #
277
- # Correct Xrefs variations caused by ByteRange modifications.
278
- #
279
- rebuild_xrefs
280
-
281
- file_data = output()
282
- signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] +
283
- file_data[digsig.ByteRange[2],digsig.ByteRange[3]]
284
-
285
- signature = Signature.compute(method, signable_data, certificate, key, [])
286
- digsig.Contents[0, signature.size] = signature
287
-
288
- #
289
- # No more modification are allowed after signing.
290
- #
291
- self.freeze
292
- end
293
-
294
- def usage_rights?
295
- not self.Catalog.Perms.nil? and
296
- (not self.Catalog.Perms.has_key?(:UR3) or not self.Catalog.Perms.has_key?(:UR))
297
- end
354
+ def verify(certificate, chain, store, data)
355
+ store.verify(certificate, chain) and certificate.public_key.verify(OpenSSL::Digest.new('SHA1'), @signature_object.value, data)
356
+ end
298
357
 
299
- def signature
300
- raise SignatureError, "Not a signed document" unless self.signed?
358
+ def self.sign(certificate, key, data)
359
+ raise PKCS1Error, "Invalid key for certificate" unless certificate.check_private_key(key)
301
360
 
302
- self.each_field do |field|
303
- return field.V if field.FT == :Sig and field.V.is_a?(Dictionary)
304
- end
361
+ new encode_pkcs1 key.sign(OpenSSL::Digest.new('SHA1'), data)
362
+ end
305
363
 
306
- raise SignatureError, "Cannot find digital signature"
307
- end
364
+ def to_der
365
+ @signature_object.to_der
366
+ end
308
367
 
309
- private
368
+ private
310
369
 
370
+ def decode_pkcs1(data)
311
371
  #
312
- # Verifies the ByteRange field of a digital signature and returned the signed data.
372
+ # Extracts the first ASN.1 object from the data and discards the rest.
373
+ # Must be an octet string.
313
374
  #
314
- def extract_signed_data(digsig)
315
- # Computes the boundaries of the Contents field.
316
- start_sig = digsig[:Contents].file_offset
317
-
318
- stream = StringScanner.new(self.original_data)
319
- stream.pos = digsig[:Contents].file_offset
320
- Object.typeof(stream).parse(stream)
321
- end_sig = stream.pos
322
- stream.terminate
323
-
324
- r1, r2 = digsig.ranges
325
- if r1.begin != 0 or
326
- r2.end != self.original_data.size or
327
- r1.end != start_sig or
328
- r2.begin != end_sig
329
-
330
- raise SignatureError, "Invalid signature byte range"
331
- end
332
-
333
- self.original_data[r1] + self.original_data[r2]
334
- end
375
+ signature_len = 0
376
+ OpenSSL::ASN1.traverse(data) do |_, offset, hdr_len, len, _, _, tag|
377
+ raise PKCS1Error, "Invalid PKCS1 object, expected an ASN.1 octet string" unless tag == OpenSSL::ASN1::OCTET_STRING
335
378
 
336
- end
379
+ signature_len = offset + hdr_len + len
380
+ break
381
+ end
337
382
 
338
- class Perms < Dictionary
339
- include StandardObject
383
+ OpenSSL::ASN1.decode(data[0, signature_len])
384
+ end
340
385
 
341
- field :DocMDP, :Type => Dictionary
342
- field :UR, :Type => Dictionary
343
- field :UR3, :Type => Dictionary, :Version => "1.6"
386
+ def self.encode_pkcs1(data)
387
+ OpenSSL::ASN1::OctetString.new(data).to_der
388
+ end
389
+ private_class_method :encode_pkcs1
344
390
  end
345
391
 
346
- module Signature
392
+ def self.verify(method, data, signature, store, chain)
393
+ case method
394
+ when PKCS7_DETACHED
395
+ pkcs7 = OpenSSL::PKCS7.new(signature)
396
+ raise SignatureError, "Not a PKCS7 detached signature" unless pkcs7.detached?
397
+ pkcs7.verify([], store, data, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY)
398
+
399
+ when PKCS7_SHA1
400
+ pkcs7 = OpenSSL::PKCS7.new(signature)
401
+ pkcs7.verify([], store, nil, OpenSSL::PKCS7::BINARY) and pkcs7.data == Digest::SHA1.digest(data)
402
+
403
+ when PKCS1_RSA_SHA1
404
+ raise SignatureError, "Cannot verify RSA signature without a certificate" if chain.empty?
405
+ cert = chain.shift
406
+ pkcs1 = PKCS1.new(signature)
407
+ pkcs1.verify(cert, chain, store, data)
408
+
409
+ else
410
+ raise NotImplementedError, "Unsupported signature method #{method.inspect}"
411
+ end
412
+ end
347
413
 
348
- PKCS1_RSA_SHA1 = "adbe.x509.rsa_sha1"
349
- PKCS7_SHA1 = "adbe.pkcs7.sha1"
350
- PKCS7_DETACHED = "adbe.pkcs7.detached"
414
+ #
415
+ # Computes the required size in bytes for storing the signature.
416
+ #
417
+ def self.required_size(method, certificate, key, ca)
418
+ compute(method, "", certificate, key, ca).size
419
+ end
351
420
 
352
- #
353
- # PKCS1 class used for adbe.x509.rsa_sha1.
354
- #
355
- class PKCS1
356
- class PKCS1Error < SignatureError; end
421
+ #
422
+ # Computes the signature using the specified subfilter method.
423
+ #
424
+ def self.compute(method, data, certificate, key, ca)
425
+ case method
426
+ when PKCS7_DETACHED
427
+ OpenSSL::PKCS7.sign(certificate, key, data, ca, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der
357
428
 
358
- def initialize(signature)
359
- @signature_object = decode_pkcs1(signature)
360
- end
429
+ when PKCS7_SHA1
430
+ OpenSSL::PKCS7.sign(certificate, key, Digest::SHA1.digest(data), ca, OpenSSL::PKCS7::BINARY).to_der
361
431
 
362
- def verify(certificate, chain, store, data)
363
- store.verify(certificate, chain) and certificate.public_key.verify(OpenSSL::Digest::SHA1.new, @signature_object.value, data)
364
- end
432
+ when PKCS1_RSA_SHA1
433
+ PKCS1.sign(certificate, key, data).to_der
365
434
 
366
- def self.sign(certificate, key, data)
367
- raise PKCS1Error, "Invalid key for certificate" unless certificate.check_private_key(key)
435
+ else
436
+ raise NotImplementedError, "Unsupported signature method #{method.inspect}"
437
+ end
438
+ end
368
439
 
369
- self.new encode_pkcs1 key.sign(OpenSSL::Digest::SHA1.new, data)
370
- end
440
+ #
441
+ # Class representing a signature which can be embedded in DigitalSignature dictionary.
442
+ # It must be a direct object.
443
+ #
444
+ class Reference < Dictionary
445
+ include StandardObject
371
446
 
372
- def to_der
373
- @signature_object.to_der
374
- end
447
+ add_type_signature Type: :SigRef
375
448
 
376
- private
449
+ field :Type, Type: Name, Default: :SigRef
450
+ field :TransformMethod, Type: Name, Default: :DocMDP, Required: true
451
+ field :TransformParams, Type: Dictionary
452
+ field :Data, Type: Object
453
+ field :DigestMethod, Type: Name, Default: :MD5
454
+ field :DigestValue, Type: String
455
+ field :DigestLocation, Type: Array
377
456
 
378
- def decode_pkcs1(data)
379
- #
380
- # Extracts the first ASN.1 object from the data and discards the rest.
381
- # Must be an octet string.
382
- #
383
- signature_len = 0
384
- OpenSSL::ASN1.traverse(data) do |_, offset, hdr_len, len, _, _, tag|
385
- raise PKCS1Error, "Invalid PKCS1 object, expected an ASN.1 octet string" unless tag == OpenSSL::ASN1::OCTET_STRING
457
+ def initialize(hash = {}, parser = nil)
458
+ set_indirect(false)
386
459
 
387
- signature_len = offset + hdr_len + len
388
- break
389
- end
460
+ super
461
+ end
462
+ end
390
463
 
391
- OpenSSL::ASN1.decode(data[0, signature_len])
392
- end
464
+ class BuildData < Dictionary
465
+ include StandardObject
393
466
 
394
- def self.encode_pkcs1(data)
395
- OpenSSL::ASN1::OctetString.new(data).to_der
396
- end
397
- private_class_method :encode_pkcs1
398
- end
467
+ field :Name, Type: Name, Version: "1.5"
468
+ field :Date, Type: String, Version: "1.5"
469
+ field :R, Type: Number, Version: "1.5"
470
+ field :PreRelease, Type: Boolean, Default: false, Version: "1.5"
471
+ field :OS, Type: Array, Version: "1.5"
472
+ field :NonEFontNoWarn, Type: Boolean, Version: "1.5"
473
+ field :TrustedMode, Type: Boolean, Version: "1.5"
474
+ field :V, Type: Number, Version: "1.5"
399
475
 
400
- def self.verify(method, data, signature, store, chain)
401
- case method
402
- when PKCS7_DETACHED
403
- pkcs7 = OpenSSL::PKCS7.new(signature)
404
- raise SignatureError, "Not a PKCS7 detached signature" unless pkcs7.detached?
405
- pkcs7.verify([], store, data, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY)
406
-
407
- when PKCS7_SHA1
408
- pkcs7 = OpenSSL::PKCS7.new(signature)
409
- pkcs7.verify([], store, nil, OpenSSL::PKCS7::BINARY) and pkcs7.data == Digest::SHA1.digest(data)
410
-
411
- when PKCS1_RSA_SHA1
412
- raise SignatureError, "Cannot verify RSA signature without a certificate" if chain.empty?
413
- cert = chain.shift
414
- pkcs1 = PKCS1.new(signature)
415
- pkcs1.verify(cert, chain, store, data)
416
-
417
- else
418
- raise NotImplementedError, "Unsupported signature method #{method.inspect}"
419
- end
420
- end
476
+ def initialize(hash = {}, parser = nil)
477
+ set_indirect(false)
421
478
 
422
- #
423
- # Computes the required size in bytes for storing the signature.
424
- #
425
- def self.required_size(method, certificate, key, ca)
426
- self.compute(method, "", certificate, key, ca).size
427
- end
479
+ super
480
+ end
481
+ end
428
482
 
429
- #
430
- # Computes the signature using the specified subfilter method.
431
- #
432
- def self.compute(method, data, certificate, key, ca)
433
- case method
434
- when PKCS7_DETACHED
435
- OpenSSL::PKCS7.sign(certificate, key, data, ca, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der
483
+ class AppData < BuildData
484
+ field :REx, Type: String, Version: "1.6"
485
+ end
436
486
 
437
- when PKCS7_SHA1
438
- OpenSSL::PKCS7.sign(certificate, key, Digest::SHA1.digest(data), ca, OpenSSL::PKCS7::BINARY).to_der
487
+ class SigQData < BuildData
488
+ field :Preview, Type: Boolean, Default: false, Version: "1.7"
489
+ end
439
490
 
440
- when PKCS1_RSA_SHA1
441
- PKCS1.sign(certificate, key, data).to_der
491
+ class BuildProperties < Dictionary
492
+ include StandardObject
493
+
494
+ field :Filter, Type: BuildData, Version: "1.5"
495
+ field :PubSec, Type: BuildData, Version: "1.5"
496
+ field :App, Type: AppData, Version: "1.5"
497
+ field :SigQ, Type: SigQData, Version: "1.7"
498
+
499
+ def initialize(hash = {}, parser = nil)
500
+ set_indirect(false)
501
+
502
+ super
503
+ end
504
+
505
+ def pre_build # :nodoc:
506
+ self.Filter ||= BuildData.new
507
+ self.Filter.Name ||= :'Adobe.PPKLite'
508
+ self.Filter.R ||= 0x20020
509
+ self.Filter.V ||= 2
510
+ self.Filter.Date ||= Time.now.to_s
511
+
512
+ self.PubSec ||= BuildData.new
513
+ self.PubSec.NonEFontNoWarn ||= true
514
+ self.PubSec.Date ||= Time.now.to_s
515
+ self.PubSec.R ||= 0x20021
516
+
517
+ self.App ||= AppData.new
518
+ self.App.Name ||= :Reader
519
+ self.App.REx = "11.0.8"
520
+ self.App.TrustedMode ||= true
521
+ self.App.OS ||= [:Win]
522
+ self.App.R ||= 0xb0008
523
+
524
+ super
525
+ end
526
+ end
442
527
 
443
- else
444
- raise NotImplementedError, "Unsupported signature method #{method.inspect}"
445
- end
528
+ #
529
+ # Class representing a digital signature.
530
+ #
531
+ class DigitalSignature < Dictionary
532
+ include StandardObject
533
+
534
+ add_type_signature Filter: :'Adobe.PPKLite'
535
+ add_type_signature Filter: :'Adobe.PPKMS'
536
+
537
+ field :Type, Type: Name, Default: :Sig
538
+ field :Filter, Type: Name, Default: :'Adobe.PPKLite', Required: true
539
+ field :SubFilter, Type: Name
540
+ field :Contents, Type: String, Required: true
541
+ field :Cert, Type: [String, Array.of(String)]
542
+ field :ByteRange, Type: Array.of(Integer, length: 4)
543
+ field :Reference, Type: Array.of(Reference), Version: "1.5"
544
+ field :Changes, Type: Array
545
+ field :Name, Type: String
546
+ field :M, Type: String
547
+ field :Location, Type: String
548
+ field :Reason, Type: String
549
+ field :ContactInfo, Type: String
550
+ field :R, Type: Integer
551
+ field :V, Type: Integer, Default: 0, Version: "1.5"
552
+ field :Prop_Build, Type: BuildProperties, Version: "1.5"
553
+ field :Prop_AuthTime, Type: Integer, Version: "1.5"
554
+ field :Prop_AuthType, Type: Name, Version: "1.5"
555
+
556
+ def pre_build # :nodoc:
557
+ self.M = Origami::Date.now
558
+ self.Prop_Build ||= BuildProperties.new.pre_build
559
+
560
+ super
561
+ end
562
+
563
+ def to_s(indent: nil, tab: nil, eol: nil) # :nodoc:
564
+ # Must be deterministic, ignore parameters
565
+ indent_value = 1
566
+ tab_value = "\t"
567
+ eol_value = $/
568
+
569
+ content = TOKENS.first + eol_value
570
+
571
+ to_a.sort_by { |key, _| key }.reverse_each do |key, value|
572
+ content << tab_value * indent_value << key.to_s << " "
573
+ content << (value.is_a?(Dictionary) ? value.to_s(indent: indent_value + 1) : value.to_s) << eol_value
446
574
  end
447
575
 
448
- #
449
- # Class representing a signature which can be embedded in DigitalSignature dictionary.
450
- # It must be a direct object.
451
- #
452
- class Reference < Dictionary
453
- include StandardObject
576
+ content << tab_value * (indent_value - 1) << TOKENS.last
454
577
 
455
- add_type_signature :Type => :SigRef
578
+ output(content)
579
+ end
456
580
 
457
- field :Type, :Type => Name, :Default => :SigRef
458
- field :TransformMethod, :Type => Name, :Default => :DocMDP, :Required => true
459
- field :TransformParams, :Type => Dictionary
460
- field :Data, :Type => Object
461
- field :DigestMethod, :Type => Name, :Default => :MD5
462
- field :DigestValue, :Type => String
463
- field :DigestLocation, :Type => Array
581
+ def ranges
582
+ byte_range = self.ByteRange
464
583
 
465
- def initialize(hash = {}, parser = nil)
466
- set_indirect(false)
584
+ unless byte_range.is_a?(Array) && (byte_range.length == 4) && byte_range.all? { |i| i.is_a?(Integer) }
585
+ raise SignatureError, "Invalid ByteRange field value"
586
+ end
467
587
 
468
- super(hash, parser)
469
- end
588
+ byte_range.map(&:to_i).each_slice(2).map do |start, length|
589
+ (start...start + length)
470
590
  end
591
+ end
471
592
 
472
- class BuildData < Dictionary
473
- include StandardObject
593
+ def signature_data
594
+ raise SignatureError, "Invalid signature data" unless self[:Contents].is_a?(String)
474
595
 
475
- field :Name, :Type => Name, :Version => "1.5"
476
- field :Date, :Type => String, :Version => "1.5"
477
- field :R, :Type => Number, :Version => "1.5"
478
- field :PreRelease, :Type => Boolean, :Default => false, :Version => "1.5"
479
- field :OS, :Type => Array, :Version => "1.5"
480
- field :NonEFontNoWarn, :Type => Boolean, :Version => "1.5"
481
- field :TrustedMode, :Type => Boolean, :Version => "1.5"
482
- field :V, :Type => Number, :Version => "1.5"
596
+ self[:Contents]
597
+ end
483
598
 
484
- def initialize(hash = {}, parser = nil)
485
- set_indirect(false)
599
+ def certificate_chain
600
+ return [] unless key?(:Cert)
486
601
 
487
- super(hash, parser)
488
- end
602
+ chain = self.Cert
603
+ if !chain.is_a?(String) && !(chain.is_a?(Array) && chain.all? { |cert| cert.is_a?(String) })
604
+ return SignatureError, "Invalid embedded certificate chain"
489
605
  end
490
606
 
491
- class AppData < BuildData
492
- field :REx, :Type => String, :Version => "1.6"
493
- end
607
+ [chain].flatten.map! { |str| OpenSSL::X509::Certificate.new(str) }
608
+ end
494
609
 
495
- class SigQData < BuildData
496
- field :Preview, :Type => Boolean, :Default => false, :Version => "1.7"
497
- end
610
+ def signature_offset # :nodoc:
611
+ indent_value = 1
612
+ tab_value = "\t"
613
+ eol_value = $/
614
+ content = "#{no} #{generation} obj" + eol_value + TOKENS.first + eol_value
498
615
 
499
- class BuildProperties < Dictionary
500
- include StandardObject
501
-
502
- field :Filter, :Type => BuildData, :Version => "1.5"
503
- field :PubSec, :Type => BuildData, :Version => "1.5"
504
- field :App, :Type => AppData, :Version => "1.5"
505
- field :SigQ, :Type => SigQData, :Version => "1.7"
506
-
507
- def initialize(hash = {}, parser = nil)
508
- set_indirect(false)
509
-
510
- super(hash, parser)
511
- end
512
-
513
- def pre_build #:nodoc:
514
- self.Filter ||= BuildData.new
515
- self.Filter.Name ||= :"Adobe.PPKLite"
516
- self.Filter.R ||= 0x20020
517
- self.Filter.V ||= 2
518
- self.Filter.Date ||= Time.now.to_s
519
-
520
- self.PubSec ||= BuildData.new
521
- self.PubSec.NonEFontNoWarn ||= true
522
- self.PubSec.Date ||= Time.now.to_s
523
- self.PubSec.R ||= 0x20021
524
-
525
- self.App ||= AppData.new
526
- self.App.Name ||= :Reader
527
- self.App.REx = "11.0.8"
528
- self.App.TrustedMode ||= true
529
- self.App.OS ||= [ :Win ]
530
- self.App.R ||= 0xb0008
531
-
532
- super
533
- end
534
- end
616
+ to_a.sort_by { |key, _| key }.reverse_each do |key, value|
617
+ if key == :Contents
618
+ content << tab_value * indent_value + key.to_s + " "
535
619
 
536
- #
537
- # Class representing a digital signature.
538
- #
539
- class DigitalSignature < Dictionary
540
- include StandardObject
541
-
542
- add_type_signature :Filter => :"Adobe.PPKLite"
543
- add_type_signature :Filter => :"Adobe.PPKMS"
544
-
545
- field :Type, :Type => Name, :Default => :Sig
546
- field :Filter, :Type => Name, :Default => :"Adobe.PPKLite", :Required => true
547
- field :SubFilter, :Type => Name
548
- field :Contents, :Type => String, :Required => true
549
- field :Cert, :Type => [ String, Array.of(String) ]
550
- field :ByteRange, :Type => Array.of(Integer, length: 4)
551
- field :Reference, :Type => Array.of(Reference), :Version => "1.5"
552
- field :Changes, :Type => Array
553
- field :Name, :Type => String
554
- field :M, :Type => String
555
- field :Location, :Type => String
556
- field :Reason, :Type => String
557
- field :ContactInfo, :Type => String
558
- field :R, :Type => Integer
559
- field :V, :Type => Integer, :Default => 0, :Version => "1.5"
560
- field :Prop_Build, :Type => BuildProperties, :Version => "1.5"
561
- field :Prop_AuthTime, :Type => Integer, :Version => "1.5"
562
- field :Prop_AuthType, :Type => Name, :Version => "1.5"
563
-
564
- def pre_build #:nodoc:
565
- self.M = Origami::Date.now
566
- self.Prop_Build ||= BuildProperties.new.pre_build
567
-
568
- super
569
- end
570
-
571
- def to_s(indent: 1, tab: "\t", eol: $/) #:nodoc:
572
-
573
- # Must be deterministic.
574
- indent, tab, eol = 1, "\t", $/
575
-
576
- content = TOKENS.first + eol
577
-
578
- self.to_a.sort_by{ |key, _| key }.reverse_each do |key, value|
579
- content << tab * indent << key.to_s << " "
580
- content << (value.is_a?(Dictionary) ? value.to_s(indent: indent + 1) : value.to_s) << eol
581
- end
582
-
583
- content << tab * (indent - 1) << TOKENS.last
584
-
585
- output(content)
586
- end
587
-
588
- def ranges
589
- byte_range = self.ByteRange
590
-
591
- unless byte_range.is_a?(Array) and byte_range.length == 4 and byte_range.all? {|i| i.is_a?(Integer) }
592
- raise SignatureError, "Invalid ByteRange field value"
593
- end
594
-
595
- byte_range.map(&:to_i).each_slice(2).map do |start, length|
596
- (start...start + length)
597
- end
598
- end
599
-
600
- def signature_data
601
- raise SignatureError, "Invalid signature data" unless self[:Contents].is_a?(String)
602
-
603
- self[:Contents]
604
- end
605
-
606
- def certificate_chain
607
- return [] unless key?(:Cert)
608
-
609
- chain = self.Cert
610
- unless chain.is_a?(String) or (chain.is_a?(Array) and chain.all?{|cert| cert.is_a?(String)})
611
- return SignatureError, "Invalid embedded certificate chain"
612
- end
613
-
614
- [ chain ].flatten.map! {|str| OpenSSL::X509::Certificate.new(str) }
615
- end
616
-
617
- def signature_offset #:nodoc:
618
- indent, tab, eol = 1, "\t", $/
619
- content = "#{no} #{generation} obj" + eol + TOKENS.first + eol
620
-
621
- self.to_a.sort_by{ |key, _| key }.reverse_each do |key, value|
622
- if key == :Contents
623
- content << tab * indent + key.to_s + " "
624
-
625
- return content.size
626
- else
627
- content << tab * indent + key.to_s << " "
628
- content << (value.is_a?(Dictionary) ? value.to_s(indent: indent + 1) : value.to_s) << eol
629
- end
630
- end
631
-
632
- nil
633
- end
620
+ return content.size
621
+ else
622
+ content << tab_value * indent_value + key.to_s << " "
623
+ content << (value.is_a?(Dictionary) ? value.to_s(indent: indent_value + 1) : value.to_s) << eol_value
624
+ end
634
625
  end
635
626
 
627
+ nil
628
+ end
629
+ end
630
+ end
631
+
632
+ module UsageRights
633
+ module Rights
634
+ DOCUMENT_FULLSAVE = %i[Document FullSave]
635
+ DOCUMENT_ALL = DOCUMENT_FULLSAVE
636
+
637
+ ANNOTS_CREATE = %i[Annots Create]
638
+ ANNOTS_DELETE = %i[Annots Delete]
639
+ ANNOTS_MODIFY = %i[Annots Modify]
640
+ ANNOTS_COPY = %i[Annots Copy]
641
+ ANNOTS_IMPORT = %i[Annots Import]
642
+ ANNOTS_EXPORT = %i[Annots Export]
643
+ ANNOTS_ONLINE = %i[Annots Online]
644
+ ANNOTS_SUMMARYVIEW = %i[Annots SummaryView]
645
+ ANNOTS_ALL = %i[Annots Create Modify Copy Import Export Online SummaryView]
646
+
647
+ FORM_FILLIN = %i[Form FillIn]
648
+ FORM_IMPORT = %i[Form Import]
649
+ FORM_EXPORT = %i[Form Export]
650
+ FORM_SUBMITSTANDALONE = %i[Form SubmitStandAlone]
651
+ FORM_SPAWNTEMPLATE = %i[Form SpawnTemplate]
652
+ FORM_BARCODEPLAINTEXT = %i[Form BarcodePlaintext]
653
+ FORM_ONLINE = %i[Form Online]
654
+ FORM_ALL = %i[Form FillIn Import Export SubmitStandAlone SpawnTemplate BarcodePlaintext Online]
655
+
656
+ FORMEX_BARCODEPLAINTEXT = %i[FormEx BarcodePlaintext]
657
+ FORMEX_ALL = FORMEX_BARCODEPLAINTEXT
658
+
659
+ SIGNATURE_MODIFY = %i[Signature Modify]
660
+ SIGNATURE_ALL = SIGNATURE_MODIFY
661
+
662
+ EF_CREATE = %i[EF Create]
663
+ EF_DELETE = %i[EF Delete]
664
+ EF_MODIFY = %i[EF Modify]
665
+ EF_IMPORT = %i[EF Import]
666
+ EF_ALL = %i[EF Create Delete Modify Import]
667
+
668
+ ALL = [DOCUMENT_ALL, ANNOTS_ALL, FORM_ALL, SIGNATURE_ALL, EF_ALL]
636
669
  end
637
670
 
638
- module UsageRights
639
-
640
- module Rights
641
- DOCUMENT_FULLSAVE = %i[Document FullSave]
642
- DOCUMENT_ALL = DOCUMENT_FULLSAVE
643
-
644
- ANNOTS_CREATE = %i[Annots Create]
645
- ANNOTS_DELETE = %i[Annots Delete]
646
- ANNOTS_MODIFY = %i[Annots Modify]
647
- ANNOTS_COPY = %i[Annots Copy]
648
- ANNOTS_IMPORT = %i[Annots Import]
649
- ANNOTS_EXPORT = %i[Annots Export]
650
- ANNOTS_ONLINE = %i[Annots Online]
651
- ANNOTS_SUMMARYVIEW = %i[Annots SummaryView]
652
- ANNOTS_ALL = %i[Annots Create Modify Copy Import Export Online SummaryView]
653
-
654
- FORM_FILLIN = %i[Form FillIn]
655
- FORM_IMPORT = %i[Form Import]
656
- FORM_EXPORT = %i[Form Export]
657
- FORM_SUBMITSTANDALONE = %i[Form SubmitStandAlone]
658
- FORM_SPAWNTEMPLATE = %i[Form SpawnTemplate]
659
- FORM_BARCODEPLAINTEXT = %i[Form BarcodePlaintext]
660
- FORM_ONLINE = %i[Form Online]
661
- FORM_ALL = %i[Form FillIn Import Export SubmitStandAlone SpawnTemplate BarcodePlaintext Online]
662
-
663
- FORMEX_BARCODEPLAINTEXT = %i[FormEx BarcodePlaintext]
664
- FORMEX_ALL = FORMEX_BARCODEPLAINTEXT
665
-
666
- SIGNATURE_MODIFY = %i[Signature Modify]
667
- SIGNATURE_ALL = SIGNATURE_MODIFY
668
-
669
- EF_CREATE = %i[EF Create]
670
- EF_DELETE = %i[EF Delete]
671
- EF_MODIFY = %i[EF Modify]
672
- EF_IMPORT = %i[EF Import]
673
- EF_ALL = %i[EF Create Delete Modify Import]
674
-
675
- ALL = [ DOCUMENT_ALL, ANNOTS_ALL, FORM_ALL, SIGNATURE_ALL, EF_ALL ]
676
- end
677
-
678
- class TransformParams < Dictionary
679
- include StandardObject
671
+ class TransformParams < Dictionary
672
+ include StandardObject
680
673
 
681
- VERSION = Name.new("2.2")
674
+ VERSION = Name.new("2.2")
682
675
 
683
- field :Type, :Type => Name, :Default => :TransformParams
684
- field :Document, :Type => Array.of(Name)
685
- field :Msg, :Type => String
686
- field :V, :Type => Name, :Default => VERSION
687
- field :Annots, :Type => Array.of(Name)
688
- field :Form, :Type => Array.of(Name)
689
- field :FormEx, :Type => Array.of(Name)
690
- field :Signature, :Type => Array.of(Name)
691
- field :EF, :Type => Array.of(Name), :Version => "1.6"
692
- field :P, :Type => Boolean, :Default => false, :Version => "1.6"
676
+ field :Type, Type: Name, Default: :TransformParams
677
+ field :Document, Type: Array.of(Name)
678
+ field :Msg, Type: String
679
+ field :V, Type: Name, Default: VERSION
680
+ field :Annots, Type: Array.of(Name)
681
+ field :Form, Type: Array.of(Name)
682
+ field :FormEx, Type: Array.of(Name)
683
+ field :Signature, Type: Array.of(Name)
684
+ field :EF, Type: Array.of(Name), Version: "1.6"
685
+ field :P, Type: Boolean, Default: false, Version: "1.6"
693
686
 
694
- def initialize(hash = {}, parser = nil)
695
- set_indirect(false)
687
+ def initialize(hash = {}, parser = nil)
688
+ set_indirect(false)
696
689
 
697
- super(hash, parser)
698
- end
699
- end
690
+ super
691
+ end
700
692
  end
701
-
693
+ end
702
694
  end