hexapdf 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +69 -0
- data/data/hexapdf/cert/demo_cert.rb +22 -0
- data/data/hexapdf/cert/root-ca.crt +119 -0
- data/data/hexapdf/cert/signing.crt +125 -0
- data/data/hexapdf/cert/signing.key +52 -0
- data/data/hexapdf/cert/sub-ca.crt +125 -0
- data/lib/hexapdf/cli/info.rb +21 -1
- data/lib/hexapdf/configuration.rb +26 -0
- data/lib/hexapdf/content/graphics_state.rb +24 -5
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/document/signatures.rb +327 -0
- data/lib/hexapdf/document.rb +26 -0
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -2
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/layout/style.rb +2 -1
- data/lib/hexapdf/object.rb +5 -3
- data/lib/hexapdf/parser.rb +21 -9
- data/lib/hexapdf/rectangle.rb +0 -6
- data/lib/hexapdf/revision.rb +13 -6
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +2 -4
- data/lib/hexapdf/type/acro_form/field.rb +2 -0
- data/lib/hexapdf/type/acro_form/form.rb +9 -1
- data/lib/hexapdf/type/annotation.rb +36 -3
- data/lib/hexapdf/type/font.rb +5 -0
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_type3.rb +20 -0
- data/lib/hexapdf/type/object_stream.rb +3 -1
- data/lib/hexapdf/type/signature/adbe_pkcs7_detached.rb +125 -0
- data/lib/hexapdf/type/signature/adbe_x509_rsa_sha1.rb +99 -0
- data/lib/hexapdf/type/signature/handler.rb +112 -0
- data/lib/hexapdf/type/signature/verification_result.rb +92 -0
- data/lib/hexapdf/type/signature.rb +236 -0
- data/lib/hexapdf/type.rb +1 -0
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +24 -10
- data/test/hexapdf/content/test_graphics_state.rb +9 -1
- data/test/hexapdf/content/test_operator.rb +8 -3
- data/test/hexapdf/content/test_processor.rb +1 -1
- data/test/hexapdf/document/test_signatures.rb +225 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +8 -6
- data/test/hexapdf/layout/test_style.rb +11 -0
- data/test/hexapdf/test_document.rb +28 -0
- data/test/hexapdf/test_object.rb +7 -2
- data/test/hexapdf/test_parser.rb +14 -0
- data/test/hexapdf/test_rectangle.rb +0 -7
- data/test/hexapdf/test_revision.rb +44 -14
- data/test/hexapdf/test_writer.rb +44 -14
- data/test/hexapdf/type/acro_form/test_field.rb +11 -1
- data/test/hexapdf/type/acro_form/test_form.rb +5 -0
- data/test/hexapdf/type/signature/common.rb +71 -0
- data/test/hexapdf/type/signature/test_adbe_pkcs7_detached.rb +99 -0
- data/test/hexapdf/type/signature/test_adbe_x509_rsa_sha1.rb +66 -0
- data/test/hexapdf/type/signature/test_handler.rb +76 -0
- data/test/hexapdf/type/signature/test_verification_result.rb +47 -0
- data/test/hexapdf/type/test_annotation.rb +40 -2
- data/test/hexapdf/type/test_font.rb +4 -0
- data/test/hexapdf/type/test_font_simple.rb +5 -5
- data/test/hexapdf/type/test_font_type3.rb +16 -1
- data/test/hexapdf/type/test_object_stream.rb +9 -0
- data/test/hexapdf/type/test_signature.rb +131 -0
- metadata +21 -33
- data/test/data/cert/create.sh +0 -171
- data/test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF39.pem +0 -119
- data/test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF3A.pem +0 -125
- data/test/data/cert/root-ca/db/crlnumber +0 -1
- data/test/data/cert/root-ca/db/index +0 -2
- data/test/data/cert/root-ca/db/index.attr +0 -1
- data/test/data/cert/root-ca/db/index.attr.old +0 -1
- data/test/data/cert/root-ca/db/index.old +0 -1
- data/test/data/cert/root-ca/db/serial +0 -1
- data/test/data/cert/root-ca/db/serial.old +0 -1
- data/test/data/cert/root-ca/private/root-ca.key +0 -52
- data/test/data/cert/root-ca/root-ca.conf +0 -65
- data/test/data/cert/root-ca/root-ca.crt +0 -119
- data/test/data/cert/root-ca/root-ca.csr +0 -28
- data/test/data/cert/signature-1-pkcs7-detached.pdf +0 -182
- data/test/data/cert/sub-ca/certs/453FF080E3EDCD6A388D5368DFC320D9.pem +0 -125
- data/test/data/cert/sub-ca/db/crlnumber +0 -1
- data/test/data/cert/sub-ca/db/index +0 -1
- data/test/data/cert/sub-ca/db/index.attr +0 -1
- data/test/data/cert/sub-ca/db/index.old +0 -0
- data/test/data/cert/sub-ca/db/serial +0 -1
- data/test/data/cert/sub-ca/db/serial.old +0 -1
- data/test/data/cert/sub-ca/private/signing.key +0 -52
- data/test/data/cert/sub-ca/private/sub-ca.key +0 -52
- data/test/data/cert/sub-ca/signing.crt +0 -125
- data/test/data/cert/sub-ca/signing.csr +0 -28
- data/test/data/cert/sub-ca/signing.p12 +0 -0
- data/test/data/cert/sub-ca/sub-ca.conf +0 -65
- data/test/data/cert/sub-ca/sub-ca.crt +0 -125
- data/test/data/cert/sub-ca/sub-ca.csr +0 -28
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/type/signature'
|
|
5
|
+
require 'time'
|
|
6
|
+
require 'ostruct'
|
|
7
|
+
|
|
8
|
+
describe HexaPDF::Type::Signature::Handler do
|
|
9
|
+
before do
|
|
10
|
+
@time = Time.parse("2021-11-14 7:00")
|
|
11
|
+
@dict = {Name: "handler", M: @time}
|
|
12
|
+
@handler = HexaPDF::Type::Signature::Handler.new(@dict)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "returns the signer name" do
|
|
16
|
+
assert_equal("handler", @handler.signer_name)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "returns the signing time" do
|
|
20
|
+
assert_equal(@time, @handler.signing_time)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "needs an implementation of certificate_chain" do
|
|
24
|
+
assert_raises(RuntimeError) { @handler.certificate_chain }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "needs an implementation of signer_certificate" do
|
|
28
|
+
assert_raises(RuntimeError) { @handler.signer_certificate }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "store_verification_callback" do
|
|
32
|
+
before do
|
|
33
|
+
@result = HexaPDF::Type::Signature::VerificationResult.new
|
|
34
|
+
@context = OpenStruct.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "can allow self-signed certificates" do
|
|
38
|
+
[OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
|
|
39
|
+
OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN].each do |error|
|
|
40
|
+
[true, false].each do |allow_self_signed|
|
|
41
|
+
@result.messages.clear
|
|
42
|
+
@context.error = error
|
|
43
|
+
@handler.store_verification_callback(@result, allow_self_signed: allow_self_signed).
|
|
44
|
+
call(false, @context)
|
|
45
|
+
assert_equal(1, @result.messages.size)
|
|
46
|
+
assert_match(/self-signed certificate/i, @result.messages[0].content)
|
|
47
|
+
assert_equal(allow_self_signed ? :info : :error, @result.messages[0].type)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "verifies the signing time" do
|
|
54
|
+
result = HexaPDF::Type::Signature::VerificationResult.new
|
|
55
|
+
[
|
|
56
|
+
[true, '6:00', '8:00'],
|
|
57
|
+
[false, '7:30', '8:00'],
|
|
58
|
+
[false, '5:00', '6:00'],
|
|
59
|
+
].each do |success, not_before, not_after|
|
|
60
|
+
result.messages.clear
|
|
61
|
+
@handler.define_singleton_method(:signer_certificate) do
|
|
62
|
+
OpenStruct.new.tap do |struct|
|
|
63
|
+
struct.not_before = Time.parse("2021-11-14 #{not_before}")
|
|
64
|
+
struct.not_after = Time.parse("2021-11-14 #{not_after}")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
@handler.send(:verify_signing_time, result)
|
|
68
|
+
if success
|
|
69
|
+
assert(result.messages.empty?)
|
|
70
|
+
else
|
|
71
|
+
assert_equal(1, result.messages.size)
|
|
72
|
+
end
|
|
73
|
+
@handler.singleton_class.remove_method(:signer_certificate)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/type/signature'
|
|
5
|
+
|
|
6
|
+
describe HexaPDF::Type::Signature::VerificationResult do
|
|
7
|
+
describe "Message" do
|
|
8
|
+
it "accepts a type and a content argument on creation" do
|
|
9
|
+
m = HexaPDF::Type::Signature::VerificationResult::Message.new(:type, 'content')
|
|
10
|
+
assert_equal(:type, m.type)
|
|
11
|
+
assert_equal('content', m.content)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "allows sorting by type" do
|
|
15
|
+
info = HexaPDF::Type::Signature::VerificationResult::Message.new(:info, 'c')
|
|
16
|
+
warning = HexaPDF::Type::Signature::VerificationResult::Message.new(:warning, 'c')
|
|
17
|
+
error = HexaPDF::Type::Signature::VerificationResult::Message.new(:error, 'c')
|
|
18
|
+
assert_equal([error, warning, info], [info, error, warning].sort)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
before do
|
|
23
|
+
@result = HexaPDF::Type::Signature::VerificationResult.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "can add new messages" do
|
|
27
|
+
@result.log(:error, "content")
|
|
28
|
+
assert_equal(1, @result.messages.size)
|
|
29
|
+
assert_equal(:error, @result.messages[0].type)
|
|
30
|
+
assert_equal('content', @result.messages[0].content)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "reports success if no error messages have been logged" do
|
|
34
|
+
assert(@result.success?)
|
|
35
|
+
@result.log(:info, 'content')
|
|
36
|
+
assert(@result.success?)
|
|
37
|
+
@result.log(:error, 'failure')
|
|
38
|
+
refute(@result.success?)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "reports failure if there is at least one error message" do
|
|
42
|
+
@result.log(:info, 'content')
|
|
43
|
+
refute(@result.failure?)
|
|
44
|
+
@result.log(:error, 'failure')
|
|
45
|
+
assert(@result.failure?)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -25,12 +25,33 @@ describe HexaPDF::Type::Annotation::AppearanceDictionary do
|
|
|
25
25
|
@ap.delete(:D)
|
|
26
26
|
assert_equal(:n, @ap.down_appearance)
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
describe "set_appearance" do
|
|
30
|
+
it "sets the appearance for the given type" do
|
|
31
|
+
@ap.set_appearance(1, type: :normal)
|
|
32
|
+
@ap.set_appearance(2, type: :rollover)
|
|
33
|
+
@ap.set_appearance(3, type: :down)
|
|
34
|
+
|
|
35
|
+
assert_equal(1, @ap.normal_appearance)
|
|
36
|
+
assert_equal(2, @ap.rollover_appearance)
|
|
37
|
+
assert_equal(3, @ap.down_appearance)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "respects the provided state name" do
|
|
41
|
+
@ap.set_appearance(1, state_name: :X)
|
|
42
|
+
assert_equal(1, @ap.normal_appearance[:X])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "fails if an invalid appearance type is specified" do
|
|
46
|
+
assert_raises(ArgumentError) { @ap.set_appearance(5, type: :other) }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
28
49
|
end
|
|
29
50
|
|
|
30
51
|
describe HexaPDF::Type::Annotation do
|
|
31
52
|
before do
|
|
32
53
|
@doc = HexaPDF::Document.new
|
|
33
|
-
@annot = @doc.add({Type: :Annot, F: 0b100011})
|
|
54
|
+
@annot = @doc.add({Type: :Annot, F: 0b100011, Rect: [10, 10, 110, 60]})
|
|
34
55
|
end
|
|
35
56
|
|
|
36
57
|
it "must always be indirect" do
|
|
@@ -66,7 +87,24 @@ describe HexaPDF::Type::Annotation do
|
|
|
66
87
|
assert_same(stream.data, @annot.appearance.data)
|
|
67
88
|
|
|
68
89
|
@annot[:AP][:D] = {X: stream}
|
|
69
|
-
assert_same(stream.data, @annot.appearance(:down).data)
|
|
90
|
+
assert_same(stream.data, @annot.appearance(type: :down).data)
|
|
91
|
+
assert_same(stream.data, @annot.appearance(type: :down, state_name: :X).data)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe "create_appearance" do
|
|
95
|
+
it "creates the appearance stream directly underneath /AP" do
|
|
96
|
+
stream = @annot.create_appearance
|
|
97
|
+
assert_same(stream, @annot.appearance_dict.normal_appearance)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "respects the state name when creating the appearance" do
|
|
101
|
+
stream = @annot.create_appearance(type: :down, state_name: :X)
|
|
102
|
+
assert_same(stream, @annot.appearance_dict.down_appearance[:X])
|
|
103
|
+
|
|
104
|
+
@annot[:AS] = :X
|
|
105
|
+
stream = @annot.create_appearance(type: :down)
|
|
106
|
+
assert_same(stream, @annot.appearance_dict.down_appearance[:X])
|
|
107
|
+
end
|
|
70
108
|
end
|
|
71
109
|
|
|
72
110
|
describe "flags" do
|
|
@@ -25,7 +25,7 @@ describe HexaPDF::Type::FontSimple do
|
|
|
25
25
|
describe "encoding" do
|
|
26
26
|
it "fails if /Encoding is absent because encoding_from_font is not implemented" do
|
|
27
27
|
@font.delete(:Encoding)
|
|
28
|
-
assert_raises(
|
|
28
|
+
assert_raises(RuntimeError) { @font.encoding }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
describe "/Encoding is a name" do
|
|
@@ -35,7 +35,7 @@ describe HexaPDF::Type::FontSimple do
|
|
|
35
35
|
|
|
36
36
|
it "fails if /Encoding is an invalid name because encoding_from_font is not implemented" do
|
|
37
37
|
@font[:Encoding] = :SomethingUnknown
|
|
38
|
-
assert_raises(
|
|
38
|
+
assert_raises(RuntimeError) { @font.encoding }
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -47,12 +47,12 @@ describe HexaPDF::Type::FontSimple do
|
|
|
47
47
|
describe "no /BaseEncoding is specified" do
|
|
48
48
|
it "fails if the font is embedded because encoding_from_font is not implemented" do
|
|
49
49
|
@font[:FontDescriptor][:FontFile] = 5
|
|
50
|
-
assert_raises(
|
|
50
|
+
assert_raises(RuntimeError) { @font.encoding }
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
it "fails for a symbolic non-embedded font because encoding_from_font is not implemented" do
|
|
54
54
|
@font[:FontDescriptor].flag(:symbolic, clear_existing: true)
|
|
55
|
-
assert_raises(
|
|
55
|
+
assert_raises(RuntimeError) { @font.encoding }
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
it "returns the StandardEncoding for a non-symbolic non-embedded font" do
|
|
@@ -68,7 +68,7 @@ describe HexaPDF::Type::FontSimple do
|
|
|
68
68
|
|
|
69
69
|
it "fails if /BaseEncoding is invalid because encoding_from_font is not implemented" do
|
|
70
70
|
@font[:Encoding] = {BaseEncoding: :SomethingUnknown}
|
|
71
|
-
assert_raises(
|
|
71
|
+
assert_raises(RuntimeError) { @font.encoding }
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it "returns a difference encoding if /Differences is specified" do
|
|
@@ -9,10 +9,25 @@ describe HexaPDF::Type::FontType3 do
|
|
|
9
9
|
@doc = HexaPDF::Document.new
|
|
10
10
|
@font = @doc.add({Type: :Font, Subtype: :Type3, Encoding: :WinAnsiEncoding,
|
|
11
11
|
FirstChar: 32, LastChar: 34, Widths: [600, 0, 700],
|
|
12
|
-
FontBBox: [0,
|
|
12
|
+
FontBBox: [0, 100, 100, 0], FontMatrix: [0.002, 0, 0, 0.002, 0, 0],
|
|
13
13
|
CharProcs: {}})
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
describe "bounding_box" do
|
|
17
|
+
it "returns the font's bounding box" do
|
|
18
|
+
assert_equal([0, 0, 100, 100], @font.bounding_box)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "inverts the y-values if necessary based on /FontMatrix" do
|
|
22
|
+
@font[:FontMatrix][3] *= -1
|
|
23
|
+
assert_equal([0, -100, 100, 0], @font.bounding_box)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "returns the glyph scaling factor" do
|
|
28
|
+
assert_equal(0.002, @font.glyph_scaling_factor)
|
|
29
|
+
end
|
|
30
|
+
|
|
16
31
|
describe "validation" do
|
|
17
32
|
it "works for valid objects" do
|
|
18
33
|
assert(@font.validate)
|
|
@@ -104,6 +104,15 @@ describe HexaPDF::Type::ObjectStream do
|
|
|
104
104
|
assert_equal(0, @obj.value[:First])
|
|
105
105
|
assert_equal("", @obj.stream)
|
|
106
106
|
end
|
|
107
|
+
|
|
108
|
+
it "doesn't allow signature dictionaries to be compressed" do
|
|
109
|
+
@obj.add_object(HexaPDF::Dictionary.new({Type: :Sig}, oid: 1))
|
|
110
|
+
@obj.add_object(HexaPDF::Dictionary.new({Type: :DocTimeStamp}, oid: 2))
|
|
111
|
+
@obj.add_object(HexaPDF::Dictionary.new({ByteRange: [], Contents: ''}, oid: 3))
|
|
112
|
+
@obj.write_objects(@revision)
|
|
113
|
+
assert_equal(0, @obj.value[:N])
|
|
114
|
+
assert_equal("", @obj.stream)
|
|
115
|
+
end
|
|
107
116
|
end
|
|
108
117
|
|
|
109
118
|
it "fails validation if gen != 0" do
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/signature'
|
|
6
|
+
require_relative 'signature/common'
|
|
7
|
+
require 'stringio'
|
|
8
|
+
|
|
9
|
+
describe HexaPDF::Type::Signature::TransformParams do
|
|
10
|
+
before do
|
|
11
|
+
@doc = HexaPDF::Document.new
|
|
12
|
+
@params = @doc.add({Type: :TransformParams})
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "validation" do
|
|
16
|
+
it "checks the /Annots field for valid values" do
|
|
17
|
+
@params[:Annots] = [:Create, :Other, :Delete, :Other, :New]
|
|
18
|
+
refute(@params.validate(auto_correct: false))
|
|
19
|
+
@params.validate
|
|
20
|
+
assert_equal([:Create, :Delete], @params[:Annots].value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "checks the /Form field for valid values" do
|
|
24
|
+
@params[:Form] = [:Add, :Other, :Delete, :Other, :New]
|
|
25
|
+
refute(@params.validate(auto_correct: false))
|
|
26
|
+
@params.validate
|
|
27
|
+
assert_equal([:Add, :Delete], @params[:Form].value)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "checks the /EF field for valid values" do
|
|
31
|
+
@params[:EF] = [:Create, :Other, :Delete, :Other, :New]
|
|
32
|
+
refute(@params.validate(auto_correct: false))
|
|
33
|
+
@params.validate
|
|
34
|
+
assert_equal([:Create, :Delete], @params[:EF].value)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe HexaPDF::Type::Signature::SignatureReference do
|
|
40
|
+
before do
|
|
41
|
+
@doc = HexaPDF::Document.new
|
|
42
|
+
@sigref = @doc.add({Type: :SigRef})
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "validation" do
|
|
46
|
+
it "checks the existence of the /Data field for FieldMDP transforms" do
|
|
47
|
+
@sigref[:TransformMethod] = :FieldMDP
|
|
48
|
+
refute(@sigref.validate)
|
|
49
|
+
@sigref[:Data] = HexaPDF::Object.new('data', oid: 1)
|
|
50
|
+
assert(@sigref.validate)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe HexaPDF::Type::Signature do
|
|
56
|
+
before do
|
|
57
|
+
@doc = HexaPDF::Document.new
|
|
58
|
+
@sig = @doc.add({Type: :Sig, Filter: :'Adobe.PPKLite', SubFilter: :'ETSI.CAdES.detached'})
|
|
59
|
+
|
|
60
|
+
@pdf_data = 'Some data'
|
|
61
|
+
@pkcs7 = OpenSSL::PKCS7.sign(CERTIFICATES.signer_certificate, CERTIFICATES.signer_key,
|
|
62
|
+
@pdf_data, [CERTIFICATES.ca_certificate],
|
|
63
|
+
OpenSSL::PKCS7::DETACHED)
|
|
64
|
+
@sig[:Contents] = @pkcs7.to_der
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "returns the signer name" do
|
|
68
|
+
assert_equal('signer', @sig.signer_name)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "returns the signing time" do
|
|
72
|
+
assert_equal(@sig.signature_handler.signing_time, @sig.signing_time)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "returns the signing reason" do
|
|
76
|
+
@sig[:Reason] = 'reason'
|
|
77
|
+
assert_equal('reason', @sig.signing_reason)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "returns the signing location" do
|
|
81
|
+
@sig[:Location] = 'location'
|
|
82
|
+
assert_equal('location', @sig.signing_location)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "returns the signature type" do
|
|
86
|
+
assert_equal('ETSI.CAdES.detached', @sig.signature_type)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe "signature_handler" do
|
|
90
|
+
it "returns the signature handler" do
|
|
91
|
+
assert_kind_of(HexaPDF::Type::Signature::Handler, @sig.signature_handler)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "fails if the required handler is not available" do
|
|
95
|
+
@sig[:SubFilter] = :Unknown
|
|
96
|
+
assert_raises(HexaPDF::Error) { @sig.signature_handler }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "returns the signature contents" do
|
|
101
|
+
@sig[:Contents] = 'hallo'
|
|
102
|
+
assert_equal('hallo', @sig.contents)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "signed_data" do
|
|
106
|
+
it "reads the specified portions of the document" do
|
|
107
|
+
io = StringIO.new(MINIMAL_PDF)
|
|
108
|
+
doc = HexaPDF::Document.new(io: io)
|
|
109
|
+
@sig.document = doc
|
|
110
|
+
@sig[:ByteRange] = [0, 400, 500, 333]
|
|
111
|
+
assert_equal((MINIMAL_PDF[0, 400] << MINIMAL_PDF[500, 333]).b, @sig.signed_data)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "fails if the document isn't associated with an existing PDF file" do
|
|
115
|
+
assert_raises(HexaPDF::Error) { @sig.signed_data }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "invokes the signature handler for verification" do
|
|
120
|
+
handler = Object.new
|
|
121
|
+
store, kwargs = nil
|
|
122
|
+
handler.define_singleton_method(:verify) do |in_store, in_kwargs|
|
|
123
|
+
store, kwargs = in_store, in_kwargs
|
|
124
|
+
:result
|
|
125
|
+
end
|
|
126
|
+
@sig.define_singleton_method(:signature_handler) { handler }
|
|
127
|
+
assert_equal(:result, @sig.verify(allow_self_signed: true))
|
|
128
|
+
assert_kind_of(OpenSSL::X509::Store, store)
|
|
129
|
+
assert(kwargs[:allow_self_signed])
|
|
130
|
+
end
|
|
131
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hexapdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thomas Leitner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-12-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cmdparse
|
|
@@ -124,6 +124,11 @@ files:
|
|
|
124
124
|
- data/hexapdf/afm/Times-Italic.afm
|
|
125
125
|
- data/hexapdf/afm/Times-Roman.afm
|
|
126
126
|
- data/hexapdf/afm/ZapfDingbats.afm
|
|
127
|
+
- data/hexapdf/cert/demo_cert.rb
|
|
128
|
+
- data/hexapdf/cert/root-ca.crt
|
|
129
|
+
- data/hexapdf/cert/signing.crt
|
|
130
|
+
- data/hexapdf/cert/signing.key
|
|
131
|
+
- data/hexapdf/cert/sub-ca.crt
|
|
127
132
|
- data/hexapdf/cmap/83pv-RKSJ-H
|
|
128
133
|
- data/hexapdf/cmap/90ms-RKSJ-H
|
|
129
134
|
- data/hexapdf/cmap/90ms-RKSJ-V
|
|
@@ -254,6 +259,7 @@ files:
|
|
|
254
259
|
- lib/hexapdf/document/fonts.rb
|
|
255
260
|
- lib/hexapdf/document/images.rb
|
|
256
261
|
- lib/hexapdf/document/pages.rb
|
|
262
|
+
- lib/hexapdf/document/signatures.rb
|
|
257
263
|
- lib/hexapdf/encryption.rb
|
|
258
264
|
- lib/hexapdf/encryption/aes.rb
|
|
259
265
|
- lib/hexapdf/encryption/arc4.rb
|
|
@@ -396,6 +402,11 @@ files:
|
|
|
396
402
|
- lib/hexapdf/type/page.rb
|
|
397
403
|
- lib/hexapdf/type/page_tree_node.rb
|
|
398
404
|
- lib/hexapdf/type/resources.rb
|
|
405
|
+
- lib/hexapdf/type/signature.rb
|
|
406
|
+
- lib/hexapdf/type/signature/adbe_pkcs7_detached.rb
|
|
407
|
+
- lib/hexapdf/type/signature/adbe_x509_rsa_sha1.rb
|
|
408
|
+
- lib/hexapdf/type/signature/handler.rb
|
|
409
|
+
- lib/hexapdf/type/signature/verification_result.rb
|
|
399
410
|
- lib/hexapdf/type/trailer.rb
|
|
400
411
|
- lib/hexapdf/type/viewer_preferences.rb
|
|
401
412
|
- lib/hexapdf/type/xref_stream.rb
|
|
@@ -434,36 +445,6 @@ files:
|
|
|
434
445
|
- test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz
|
|
435
446
|
- test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz
|
|
436
447
|
- test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz
|
|
437
|
-
- test/data/cert/create.sh
|
|
438
|
-
- test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF39.pem
|
|
439
|
-
- test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF3A.pem
|
|
440
|
-
- test/data/cert/root-ca/db/crlnumber
|
|
441
|
-
- test/data/cert/root-ca/db/index
|
|
442
|
-
- test/data/cert/root-ca/db/index.attr
|
|
443
|
-
- test/data/cert/root-ca/db/index.attr.old
|
|
444
|
-
- test/data/cert/root-ca/db/index.old
|
|
445
|
-
- test/data/cert/root-ca/db/serial
|
|
446
|
-
- test/data/cert/root-ca/db/serial.old
|
|
447
|
-
- test/data/cert/root-ca/private/root-ca.key
|
|
448
|
-
- test/data/cert/root-ca/root-ca.conf
|
|
449
|
-
- test/data/cert/root-ca/root-ca.crt
|
|
450
|
-
- test/data/cert/root-ca/root-ca.csr
|
|
451
|
-
- test/data/cert/signature-1-pkcs7-detached.pdf
|
|
452
|
-
- test/data/cert/sub-ca/certs/453FF080E3EDCD6A388D5368DFC320D9.pem
|
|
453
|
-
- test/data/cert/sub-ca/db/crlnumber
|
|
454
|
-
- test/data/cert/sub-ca/db/index
|
|
455
|
-
- test/data/cert/sub-ca/db/index.attr
|
|
456
|
-
- test/data/cert/sub-ca/db/index.old
|
|
457
|
-
- test/data/cert/sub-ca/db/serial
|
|
458
|
-
- test/data/cert/sub-ca/db/serial.old
|
|
459
|
-
- test/data/cert/sub-ca/private/signing.key
|
|
460
|
-
- test/data/cert/sub-ca/private/sub-ca.key
|
|
461
|
-
- test/data/cert/sub-ca/signing.crt
|
|
462
|
-
- test/data/cert/sub-ca/signing.csr
|
|
463
|
-
- test/data/cert/sub-ca/signing.p12
|
|
464
|
-
- test/data/cert/sub-ca/sub-ca.conf
|
|
465
|
-
- test/data/cert/sub-ca/sub-ca.crt
|
|
466
|
-
- test/data/cert/sub-ca/sub-ca.csr
|
|
467
448
|
- test/data/fonts/Ubuntu-Title.ttf
|
|
468
449
|
- test/data/images/cmyk.jpg
|
|
469
450
|
- test/data/images/fillbytes.jpg
|
|
@@ -527,6 +508,7 @@ files:
|
|
|
527
508
|
- test/hexapdf/document/test_fonts.rb
|
|
528
509
|
- test/hexapdf/document/test_images.rb
|
|
529
510
|
- test/hexapdf/document/test_pages.rb
|
|
511
|
+
- test/hexapdf/document/test_signatures.rb
|
|
530
512
|
- test/hexapdf/encryption/common.rb
|
|
531
513
|
- test/hexapdf/encryption/test_aes.rb
|
|
532
514
|
- test/hexapdf/encryption/test_arc4.rb
|
|
@@ -635,6 +617,11 @@ files:
|
|
|
635
617
|
- test/hexapdf/type/annotations/test_markup_annotation.rb
|
|
636
618
|
- test/hexapdf/type/annotations/test_text.rb
|
|
637
619
|
- test/hexapdf/type/annotations/test_widget.rb
|
|
620
|
+
- test/hexapdf/type/signature/common.rb
|
|
621
|
+
- test/hexapdf/type/signature/test_adbe_pkcs7_detached.rb
|
|
622
|
+
- test/hexapdf/type/signature/test_adbe_x509_rsa_sha1.rb
|
|
623
|
+
- test/hexapdf/type/signature/test_handler.rb
|
|
624
|
+
- test/hexapdf/type/signature/test_verification_result.rb
|
|
638
625
|
- test/hexapdf/type/test_annotation.rb
|
|
639
626
|
- test/hexapdf/type/test_catalog.rb
|
|
640
627
|
- test/hexapdf/type/test_cid_font.rb
|
|
@@ -653,6 +640,7 @@ files:
|
|
|
653
640
|
- test/hexapdf/type/test_page.rb
|
|
654
641
|
- test/hexapdf/type/test_page_tree_node.rb
|
|
655
642
|
- test/hexapdf/type/test_resources.rb
|
|
643
|
+
- test/hexapdf/type/test_signature.rb
|
|
656
644
|
- test/hexapdf/type/test_trailer.rb
|
|
657
645
|
- test/hexapdf/type/test_xref_stream.rb
|
|
658
646
|
- test/hexapdf/utils/test_bit_field.rb
|
|
@@ -683,7 +671,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
683
671
|
- !ruby/object:Gem::Version
|
|
684
672
|
version: '0'
|
|
685
673
|
requirements: []
|
|
686
|
-
rubygems_version: 3.2.
|
|
674
|
+
rubygems_version: 3.2.32
|
|
687
675
|
signing_key:
|
|
688
676
|
specification_version: 4
|
|
689
677
|
summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|