origamindee 3.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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +89 -0
  3. data/COPYING.LESSER +165 -0
  4. data/README.md +131 -0
  5. data/bin/config/pdfcop.conf.yml +236 -0
  6. data/bin/pdf2pdfa +87 -0
  7. data/bin/pdf2ruby +333 -0
  8. data/bin/pdfcop +476 -0
  9. data/bin/pdfdecompress +97 -0
  10. data/bin/pdfdecrypt +91 -0
  11. data/bin/pdfencrypt +113 -0
  12. data/bin/pdfexplode +223 -0
  13. data/bin/pdfextract +277 -0
  14. data/bin/pdfmetadata +143 -0
  15. data/bin/pdfsh +12 -0
  16. data/bin/shell/console.rb +128 -0
  17. data/bin/shell/hexdump.rb +59 -0
  18. data/bin/shell/irbrc +69 -0
  19. data/examples/README.md +34 -0
  20. data/examples/attachments/attachment.rb +38 -0
  21. data/examples/attachments/nested_document.rb +51 -0
  22. data/examples/encryption/encryption.rb +28 -0
  23. data/examples/events/events.rb +72 -0
  24. data/examples/flash/flash.rb +37 -0
  25. data/examples/flash/helloworld.swf +0 -0
  26. data/examples/forms/javascript.rb +54 -0
  27. data/examples/forms/xfa.rb +115 -0
  28. data/examples/javascript/hello_world.rb +22 -0
  29. data/examples/javascript/js_emulation.rb +54 -0
  30. data/examples/loop/goto.rb +32 -0
  31. data/examples/loop/named.rb +33 -0
  32. data/examples/signature/signature.rb +65 -0
  33. data/examples/uri/javascript.rb +56 -0
  34. data/examples/uri/open-uri.rb +21 -0
  35. data/examples/uri/submitform.rb +47 -0
  36. data/lib/origami/3d.rb +364 -0
  37. data/lib/origami/acroform.rb +321 -0
  38. data/lib/origami/actions.rb +318 -0
  39. data/lib/origami/annotations.rb +711 -0
  40. data/lib/origami/array.rb +242 -0
  41. data/lib/origami/boolean.rb +90 -0
  42. data/lib/origami/catalog.rb +418 -0
  43. data/lib/origami/collections.rb +144 -0
  44. data/lib/origami/compound.rb +161 -0
  45. data/lib/origami/destinations.rb +252 -0
  46. data/lib/origami/dictionary.rb +192 -0
  47. data/lib/origami/encryption.rb +1084 -0
  48. data/lib/origami/extensions/fdf.rb +347 -0
  49. data/lib/origami/extensions/ppklite.rb +422 -0
  50. data/lib/origami/filespec.rb +197 -0
  51. data/lib/origami/filters/ascii.rb +211 -0
  52. data/lib/origami/filters/ccitt/tables.rb +267 -0
  53. data/lib/origami/filters/ccitt.rb +357 -0
  54. data/lib/origami/filters/crypt.rb +38 -0
  55. data/lib/origami/filters/dct.rb +54 -0
  56. data/lib/origami/filters/flate.rb +69 -0
  57. data/lib/origami/filters/jbig2.rb +57 -0
  58. data/lib/origami/filters/jpx.rb +47 -0
  59. data/lib/origami/filters/lzw.rb +170 -0
  60. data/lib/origami/filters/predictors.rb +292 -0
  61. data/lib/origami/filters/runlength.rb +129 -0
  62. data/lib/origami/filters.rb +364 -0
  63. data/lib/origami/font.rb +196 -0
  64. data/lib/origami/functions.rb +79 -0
  65. data/lib/origami/graphics/colors.rb +230 -0
  66. data/lib/origami/graphics/instruction.rb +98 -0
  67. data/lib/origami/graphics/path.rb +182 -0
  68. data/lib/origami/graphics/patterns.rb +174 -0
  69. data/lib/origami/graphics/render.rb +62 -0
  70. data/lib/origami/graphics/state.rb +149 -0
  71. data/lib/origami/graphics/text.rb +225 -0
  72. data/lib/origami/graphics/xobject.rb +918 -0
  73. data/lib/origami/graphics.rb +38 -0
  74. data/lib/origami/header.rb +75 -0
  75. data/lib/origami/javascript.rb +713 -0
  76. data/lib/origami/linearization.rb +330 -0
  77. data/lib/origami/metadata.rb +172 -0
  78. data/lib/origami/name.rb +135 -0
  79. data/lib/origami/null.rb +65 -0
  80. data/lib/origami/numeric.rb +181 -0
  81. data/lib/origami/obfuscation.rb +245 -0
  82. data/lib/origami/object.rb +760 -0
  83. data/lib/origami/optionalcontent.rb +183 -0
  84. data/lib/origami/outline.rb +54 -0
  85. data/lib/origami/outputintents.rb +85 -0
  86. data/lib/origami/page.rb +722 -0
  87. data/lib/origami/parser.rb +269 -0
  88. data/lib/origami/parsers/fdf.rb +56 -0
  89. data/lib/origami/parsers/pdf/lazy.rb +176 -0
  90. data/lib/origami/parsers/pdf/linear.rb +122 -0
  91. data/lib/origami/parsers/pdf.rb +118 -0
  92. data/lib/origami/parsers/ppklite.rb +57 -0
  93. data/lib/origami/pdf.rb +1108 -0
  94. data/lib/origami/reference.rb +134 -0
  95. data/lib/origami/signature.rb +702 -0
  96. data/lib/origami/stream.rb +705 -0
  97. data/lib/origami/string.rb +444 -0
  98. data/lib/origami/template/patterns.rb +56 -0
  99. data/lib/origami/template/widgets.rb +151 -0
  100. data/lib/origami/trailer.rb +190 -0
  101. data/lib/origami/tree.rb +62 -0
  102. data/lib/origami/version.rb +23 -0
  103. data/lib/origami/webcapture.rb +100 -0
  104. data/lib/origami/xfa/config.rb +453 -0
  105. data/lib/origami/xfa/connectionset.rb +146 -0
  106. data/lib/origami/xfa/datasets.rb +49 -0
  107. data/lib/origami/xfa/localeset.rb +42 -0
  108. data/lib/origami/xfa/package.rb +59 -0
  109. data/lib/origami/xfa/pdf.rb +73 -0
  110. data/lib/origami/xfa/signature.rb +42 -0
  111. data/lib/origami/xfa/sourceset.rb +43 -0
  112. data/lib/origami/xfa/stylesheet.rb +44 -0
  113. data/lib/origami/xfa/template.rb +1691 -0
  114. data/lib/origami/xfa/xdc.rb +42 -0
  115. data/lib/origami/xfa/xfa.rb +146 -0
  116. data/lib/origami/xfa/xfdf.rb +43 -0
  117. data/lib/origami/xfa/xmpmeta.rb +43 -0
  118. data/lib/origami/xfa.rb +62 -0
  119. data/lib/origami/xreftable.rb +557 -0
  120. data/lib/origami.rb +47 -0
  121. data/test/dataset/calc.pdf +85 -0
  122. data/test/dataset/crypto.pdf +36 -0
  123. data/test/dataset/empty.pdf +49 -0
  124. data/test/test_actions.rb +27 -0
  125. data/test/test_annotations.rb +68 -0
  126. data/test/test_forms.rb +30 -0
  127. data/test/test_native_types.rb +83 -0
  128. data/test/test_object_tree.rb +33 -0
  129. data/test/test_pages.rb +60 -0
  130. data/test/test_pdf.rb +20 -0
  131. data/test/test_pdf_attachment.rb +34 -0
  132. data/test/test_pdf_create.rb +24 -0
  133. data/test/test_pdf_encrypt.rb +102 -0
  134. data/test/test_pdf_parse.rb +134 -0
  135. data/test/test_pdf_parse_lazy.rb +69 -0
  136. data/test/test_pdf_sign.rb +97 -0
  137. data/test/test_streams.rb +184 -0
  138. data/test/test_xrefs.rb +67 -0
  139. metadata +280 -0
@@ -0,0 +1,702 @@
1
+ =begin
2
+
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
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.
10
+
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.
15
+
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/>.
18
+
19
+ =end
20
+
21
+ require 'openssl'
22
+ require 'digest/sha1'
23
+
24
+ module Origami
25
+
26
+ class SignatureError < Error #:nodoc:
27
+ end
28
+
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)
42
+
43
+ digsig = self.signature
44
+ digsig = digsig.cast_to(Signature::DigitalSignature) unless digsig.is_a?(Signature::DigitalSignature)
45
+
46
+ signature = digsig.signature_data
47
+ chain = digsig.certificate_chain
48
+ subfilter = digsig.SubFilter.value
49
+
50
+ store = OpenSSL::X509::Store.new
51
+ store.set_default_paths if use_system_store
52
+ trusted_certs.each { |ca| store.add_cert(ca) }
53
+
54
+ store.verify_callback = -> (success, ctx) {
55
+ return true if success
56
+
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)
60
+
61
+ return true if is_self_signed && allow_self_signed && verify_cb.nil?
62
+
63
+ verify_cb.call(ctx) unless verify_cb.nil?
64
+ }
65
+
66
+ data = extract_signed_data(digsig)
67
+ Signature.verify(subfilter.to_s, data, signature, store, chain)
68
+ end
69
+
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
190
+
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
203
+
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
298
+
299
+ def signature
300
+ raise SignatureError, "Not a signed document" unless self.signed?
301
+
302
+ self.each_field do |field|
303
+ return field.V if field.FT == :Sig and field.V.is_a?(Dictionary)
304
+ end
305
+
306
+ raise SignatureError, "Cannot find digital signature"
307
+ end
308
+
309
+ private
310
+
311
+ #
312
+ # Verifies the ByteRange field of a digital signature and returned the signed data.
313
+ #
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
335
+
336
+ end
337
+
338
+ class Perms < Dictionary
339
+ include StandardObject
340
+
341
+ field :DocMDP, :Type => Dictionary
342
+ field :UR, :Type => Dictionary
343
+ field :UR3, :Type => Dictionary, :Version => "1.6"
344
+ end
345
+
346
+ module Signature
347
+
348
+ PKCS1_RSA_SHA1 = "adbe.x509.rsa_sha1"
349
+ PKCS7_SHA1 = "adbe.pkcs7.sha1"
350
+ PKCS7_DETACHED = "adbe.pkcs7.detached"
351
+
352
+ #
353
+ # PKCS1 class used for adbe.x509.rsa_sha1.
354
+ #
355
+ class PKCS1
356
+ class PKCS1Error < SignatureError; end
357
+
358
+ def initialize(signature)
359
+ @signature_object = decode_pkcs1(signature)
360
+ end
361
+
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
365
+
366
+ def self.sign(certificate, key, data)
367
+ raise PKCS1Error, "Invalid key for certificate" unless certificate.check_private_key(key)
368
+
369
+ self.new encode_pkcs1 key.sign(OpenSSL::Digest::SHA1.new, data)
370
+ end
371
+
372
+ def to_der
373
+ @signature_object.to_der
374
+ end
375
+
376
+ private
377
+
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
386
+
387
+ signature_len = offset + hdr_len + len
388
+ break
389
+ end
390
+
391
+ OpenSSL::ASN1.decode(data[0, signature_len])
392
+ end
393
+
394
+ def self.encode_pkcs1(data)
395
+ OpenSSL::ASN1::OctetString.new(data).to_der
396
+ end
397
+ private_class_method :encode_pkcs1
398
+ end
399
+
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
421
+
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
428
+
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
436
+
437
+ when PKCS7_SHA1
438
+ OpenSSL::PKCS7.sign(certificate, key, Digest::SHA1.digest(data), ca, OpenSSL::PKCS7::BINARY).to_der
439
+
440
+ when PKCS1_RSA_SHA1
441
+ PKCS1.sign(certificate, key, data).to_der
442
+
443
+ else
444
+ raise NotImplementedError, "Unsupported signature method #{method.inspect}"
445
+ end
446
+ end
447
+
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
454
+
455
+ add_type_signature :Type => :SigRef
456
+
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
464
+
465
+ def initialize(hash = {}, parser = nil)
466
+ set_indirect(false)
467
+
468
+ super(hash, parser)
469
+ end
470
+ end
471
+
472
+ class BuildData < Dictionary
473
+ include StandardObject
474
+
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"
483
+
484
+ def initialize(hash = {}, parser = nil)
485
+ set_indirect(false)
486
+
487
+ super(hash, parser)
488
+ end
489
+ end
490
+
491
+ class AppData < BuildData
492
+ field :REx, :Type => String, :Version => "1.6"
493
+ end
494
+
495
+ class SigQData < BuildData
496
+ field :Preview, :Type => Boolean, :Default => false, :Version => "1.7"
497
+ end
498
+
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
535
+
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
634
+ end
635
+
636
+ end
637
+
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
680
+
681
+ VERSION = Name.new("2.2")
682
+
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"
693
+
694
+ def initialize(hash = {}, parser = nil)
695
+ set_indirect(false)
696
+
697
+ super(hash, parser)
698
+ end
699
+ end
700
+ end
701
+
702
+ end