hexapdf 0.19.3 → 0.20.3
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 +74 -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/data/hexapdf/encoding/glyphlist.txt +4283 -4282
- data/data/hexapdf/encoding/zapfdingbats.txt +203 -202
- data/lib/hexapdf/cli/form.rb +9 -1
- data/lib/hexapdf/cli/info.rb +21 -1
- data/lib/hexapdf/configuration.rb +26 -0
- 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/security_handler.rb +5 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +5 -6
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/object.rb +5 -3
- data/lib/hexapdf/rectangle.rb +0 -6
- data/lib/hexapdf/revision.rb +13 -6
- data/lib/hexapdf/task/dereference.rb +12 -4
- data/lib/hexapdf/task/optimize.rb +3 -3
- 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 +37 -4
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +3 -1
- data/lib/hexapdf/type/signature/adbe_pkcs7_detached.rb +121 -0
- data/lib/hexapdf/type/signature/adbe_x509_rsa_sha1.rb +95 -0
- data/lib/hexapdf/type/signature/handler.rb +140 -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 +27 -11
- data/test/hexapdf/content/test_processor.rb +1 -1
- data/test/hexapdf/document/test_signatures.rb +225 -0
- data/test/hexapdf/encryption/test_security_handler.rb +11 -3
- data/test/hexapdf/task/test_optimize.rb +4 -1
- data/test/hexapdf/test_document.rb +28 -0
- data/test/hexapdf/test_object.rb +7 -2
- data/test/hexapdf/test_rectangle.rb +0 -7
- data/test/hexapdf/test_revision.rb +44 -14
- data/test/hexapdf/test_writer.rb +15 -3
- 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 +102 -0
- data/test/hexapdf/type/signature/test_verification_result.rb +47 -0
- data/test/hexapdf/type/test_annotation.rb +47 -3
- data/test/hexapdf/type/test_font_simple.rb +5 -5
- data/test/hexapdf/type/test_object_stream.rb +9 -0
- data/test/hexapdf/type/test_signature.rb +131 -0
- metadata +21 -3
|
@@ -133,7 +133,7 @@ module HexaPDF
|
|
|
133
133
|
#
|
|
134
134
|
# This method has to be implemented in subclasses.
|
|
135
135
|
def encoding_from_font
|
|
136
|
-
raise
|
|
136
|
+
raise "Needs to be implemented in subclass"
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
# Uses the given base encoding and the differences array to create a DifferenceEncoding
|
|
@@ -178,7 +178,9 @@ module HexaPDF
|
|
|
178
178
|
# Due to a bug in Adobe Acrobat, the Catalog may not be in an object stream if the
|
|
179
179
|
# document is encrypted
|
|
180
180
|
if obj.nil? || obj.null? || obj.gen != 0 || obj.kind_of?(Stream) || obj == encrypt_dict ||
|
|
181
|
-
(encrypt_dict && obj.type == :Catalog)
|
|
181
|
+
(encrypt_dict && obj.type == :Catalog) ||
|
|
182
|
+
obj.type == :Sig || obj.type == :DocTimeStamp ||
|
|
183
|
+
(obj.respond_to?(:key?) && obj.key?(:ByteRange) && obj.key?(:Contents))
|
|
182
184
|
delete_object(objects[index])
|
|
183
185
|
next
|
|
184
186
|
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
|
2
|
+
#
|
|
3
|
+
#--
|
|
4
|
+
# This file is part of HexaPDF.
|
|
5
|
+
#
|
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
+
# Copyright (C) 2014-2021 Thomas Leitner
|
|
8
|
+
#
|
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
16
|
+
#
|
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
20
|
+
# License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
#
|
|
25
|
+
# The interactive user interfaces in modified source and object code
|
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
|
28
|
+
#
|
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
|
31
|
+
# is created or manipulated using HexaPDF.
|
|
32
|
+
#
|
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
|
35
|
+
#++
|
|
36
|
+
|
|
37
|
+
require 'openssl'
|
|
38
|
+
require 'hexapdf/type/signature'
|
|
39
|
+
|
|
40
|
+
module HexaPDF
|
|
41
|
+
module Type
|
|
42
|
+
class Signature
|
|
43
|
+
|
|
44
|
+
# The signature handler for the adbe.pkcs7.detached sub-filter.
|
|
45
|
+
class AdbePkcs7Detached < Handler
|
|
46
|
+
|
|
47
|
+
# Creates a new signature handler for the given signature dictionary.
|
|
48
|
+
def initialize(signature_dict)
|
|
49
|
+
super
|
|
50
|
+
@pkcs7 = OpenSSL::PKCS7.new(signature_dict.contents)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the common name of the signer.
|
|
54
|
+
def signer_name
|
|
55
|
+
signer_certificate.subject.to_a.assoc("CN")&.[](1) || super
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns the time of signing.
|
|
59
|
+
def signing_time
|
|
60
|
+
signer_info.signed_time rescue super
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns the certificate chain.
|
|
64
|
+
def certificate_chain
|
|
65
|
+
@pkcs7.certificates
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns the signer certificate (an instance of OpenSSL::X509::Certificate).
|
|
69
|
+
def signer_certificate
|
|
70
|
+
info = signer_info
|
|
71
|
+
certificate_chain.find {|cert| cert.issuer == info.issuer && cert.serial == info.serial }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns the signer information object (an instance of OpenSSL::PKCS7::SignerInfo).
|
|
75
|
+
def signer_info
|
|
76
|
+
@pkcs7.signers.first
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Verifies the signature using the provided OpenSSL::X509::Store object.
|
|
80
|
+
def verify(store, allow_self_signed: false)
|
|
81
|
+
result = super
|
|
82
|
+
|
|
83
|
+
signer_info = self.signer_info
|
|
84
|
+
signer_certificate = self.signer_certificate
|
|
85
|
+
certificate_chain = self.certificate_chain
|
|
86
|
+
|
|
87
|
+
if certificate_chain.empty?
|
|
88
|
+
result.log(:error, "No certificates found in signature")
|
|
89
|
+
return result
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if @pkcs7.signers.size != 1
|
|
93
|
+
result.log(:error, "Exactly one signer needed, found #{@pkcs7.signers.size}")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
unless signer_certificate
|
|
97
|
+
result.log(:error, "Signer serial=#{signer_info.serial} issuer=#{signer_info.issuer} " \
|
|
98
|
+
"not found in certificates stored in PKCS7 object")
|
|
99
|
+
return result
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
key_usage = signer_certificate.extensions.find {|ext| ext.oid == 'keyUsage' }
|
|
103
|
+
unless key_usage.value.split(', ').include?("Digital Signature")
|
|
104
|
+
result.log(:error, "Certificate key usage is missing 'Digital Signature'")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
if @pkcs7.verify(certificate_chain, store, signature_dict.signed_data,
|
|
108
|
+
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY)
|
|
109
|
+
result.log(:info, "Signature valid")
|
|
110
|
+
else
|
|
111
|
+
result.log(:error, "Signature verification failed")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
result
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
|
2
|
+
#
|
|
3
|
+
#--
|
|
4
|
+
# This file is part of HexaPDF.
|
|
5
|
+
#
|
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
+
# Copyright (C) 2014-2021 Thomas Leitner
|
|
8
|
+
#
|
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
16
|
+
#
|
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
20
|
+
# License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
#
|
|
25
|
+
# The interactive user interfaces in modified source and object code
|
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
|
28
|
+
#
|
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
|
31
|
+
# is created or manipulated using HexaPDF.
|
|
32
|
+
#
|
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
|
35
|
+
#++
|
|
36
|
+
|
|
37
|
+
require 'openssl'
|
|
38
|
+
require 'hexapdf/type/signature'
|
|
39
|
+
|
|
40
|
+
module HexaPDF
|
|
41
|
+
module Type
|
|
42
|
+
class Signature
|
|
43
|
+
|
|
44
|
+
# The signature handler for the adbe.x509.rsa_sha1 sub-filter.
|
|
45
|
+
#
|
|
46
|
+
# Since this handler is deprecated with PDF 2.0 it only provides the implementation for
|
|
47
|
+
# reading and verifying signatures.
|
|
48
|
+
class AdbeX509RsaSha1 < Handler
|
|
49
|
+
|
|
50
|
+
# Returns the certificate chain.
|
|
51
|
+
def certificate_chain
|
|
52
|
+
return [] unless signature_dict.key?(:Cert)
|
|
53
|
+
[signature_dict[:Cert]].flatten.map {|str| OpenSSL::X509::Certificate.new(str) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns the signer certificate (an instance of OpenSSL::X509::Certificate).
|
|
57
|
+
def signer_certificate
|
|
58
|
+
certificate_chain.first
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Verifies the signature using the provided OpenSSL::X509::Store object.
|
|
62
|
+
def verify(store, allow_self_signed: false)
|
|
63
|
+
result = super
|
|
64
|
+
|
|
65
|
+
signer_certificate = self.signer_certificate
|
|
66
|
+
certificate_chain = self.certificate_chain
|
|
67
|
+
|
|
68
|
+
if certificate_chain.empty?
|
|
69
|
+
result.log(:error, "No certificates for verification found")
|
|
70
|
+
return result
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
signature = OpenSSL::ASN1.decode(signature_dict.contents)
|
|
74
|
+
if signature.tag != OpenSSL::ASN1::OCTET_STRING
|
|
75
|
+
result.log(:error, "PKCS1 signature object invalid, octet string expected")
|
|
76
|
+
return result
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
store.verify(signer_certificate, certificate_chain)
|
|
80
|
+
|
|
81
|
+
if signer_certificate.public_key.verify(OpenSSL::Digest.new('SHA1'),
|
|
82
|
+
signature.value, signature_dict.signed_data)
|
|
83
|
+
result.log(:info, "Signature valid")
|
|
84
|
+
else
|
|
85
|
+
result.log(:error, "Signature verification failed")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
result
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
|
2
|
+
#
|
|
3
|
+
#--
|
|
4
|
+
# This file is part of HexaPDF.
|
|
5
|
+
#
|
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
+
# Copyright (C) 2014-2021 Thomas Leitner
|
|
8
|
+
#
|
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
16
|
+
#
|
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
20
|
+
# License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
#
|
|
25
|
+
# The interactive user interfaces in modified source and object code
|
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
|
28
|
+
#
|
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
|
31
|
+
# is created or manipulated using HexaPDF.
|
|
32
|
+
#
|
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
|
35
|
+
#++
|
|
36
|
+
|
|
37
|
+
require 'hexapdf/type/signature'
|
|
38
|
+
|
|
39
|
+
module HexaPDF
|
|
40
|
+
module Type
|
|
41
|
+
class Signature
|
|
42
|
+
|
|
43
|
+
# The base signature handler providing common functionality.
|
|
44
|
+
#
|
|
45
|
+
# Specific signature handler need to override methods if necessary and implement the needed
|
|
46
|
+
# ones that don't have a default implementation.
|
|
47
|
+
class Handler
|
|
48
|
+
|
|
49
|
+
# The signature dictionary used by the handler.
|
|
50
|
+
attr_reader :signature_dict
|
|
51
|
+
|
|
52
|
+
# Creates a new signature handler for the given signature dictionary.
|
|
53
|
+
def initialize(signature_dict)
|
|
54
|
+
@signature_dict = signature_dict
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns the common name of the signer (/Name field of the signature dictionary).
|
|
58
|
+
def signer_name
|
|
59
|
+
@signature_dict[:Name]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns the time of signing (/M field of the signature dictionary).
|
|
63
|
+
def signing_time
|
|
64
|
+
@signature_dict[:M]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the certificate chain.
|
|
68
|
+
#
|
|
69
|
+
# Needs to be implemented by specific handlers.
|
|
70
|
+
def certificate_chain
|
|
71
|
+
raise "Needs to be implemented by specific handlers"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns the certificate used for signing.
|
|
75
|
+
#
|
|
76
|
+
# Needs to be implemented by specific handlers.
|
|
77
|
+
def signer_certificate
|
|
78
|
+
raise "Needs to be implemented by specific handlers"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Verifies general signature properties and prepares the provided OpenSSL::X509::Store
|
|
82
|
+
# object for use by concrete implementations.
|
|
83
|
+
#
|
|
84
|
+
# Needs to be called by specific handlers.
|
|
85
|
+
def verify(store, allow_self_signed: false)
|
|
86
|
+
result = VerificationResult.new
|
|
87
|
+
check_certified_signature(result)
|
|
88
|
+
verify_signing_time(result)
|
|
89
|
+
store.verify_callback =
|
|
90
|
+
store_verification_callback(result, allow_self_signed: allow_self_signed)
|
|
91
|
+
result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
protected
|
|
95
|
+
|
|
96
|
+
# Verifies that the signing time was within the validity period of the signer certificate.
|
|
97
|
+
def verify_signing_time(result)
|
|
98
|
+
time = signing_time
|
|
99
|
+
cert = signer_certificate
|
|
100
|
+
if time && cert && (time < cert.not_before || time > cert.not_after)
|
|
101
|
+
result.log(:error, "Signer certificate not valid at signing time")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
DOCMDP_PERMS_MESSAGE_MAP = { # :nodoc:
|
|
106
|
+
1 => "No changes allowed",
|
|
107
|
+
2 => "Form filling and signing allowed",
|
|
108
|
+
3 => "Form filling, signing and annotation manipulation allowed",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Sets an informational message on +result+ whether the signature is a certified signature.
|
|
112
|
+
def check_certified_signature(result)
|
|
113
|
+
sigref = signature_dict[:Reference]&.find {|ref| ref[:TransformMethod] == :DocMDP }
|
|
114
|
+
if sigref && signature_dict.document.catalog[:Perms]&.[](:DocMDP) == signature_dict
|
|
115
|
+
perms = sigref[:TransformParams]&.[](:P) || 2
|
|
116
|
+
result.log(:info, "Certified signature (#{DOCMDP_PERMS_MESSAGE_MAP[perms]})")
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Returns the block that should be used as the OpenSSL::X509::Store verification callback.
|
|
121
|
+
#
|
|
122
|
+
# +result+:: The VerificationResult object that should be updated if problems are found.
|
|
123
|
+
#
|
|
124
|
+
# +allow_self_signed+:: Specifies whether self-signed certificates are allowed.
|
|
125
|
+
def store_verification_callback(result, allow_self_signed: false)
|
|
126
|
+
lambda do |_success, context|
|
|
127
|
+
if context.error == OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
|
128
|
+
context.error == OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN
|
|
129
|
+
result.log(allow_self_signed ? :info : :error, "Self-signed certificate found")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
|
2
|
+
#
|
|
3
|
+
#--
|
|
4
|
+
# This file is part of HexaPDF.
|
|
5
|
+
#
|
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
+
# Copyright (C) 2014-2021 Thomas Leitner
|
|
8
|
+
#
|
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
16
|
+
#
|
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
20
|
+
# License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
#
|
|
25
|
+
# The interactive user interfaces in modified source and object code
|
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
|
28
|
+
#
|
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
|
31
|
+
# is created or manipulated using HexaPDF.
|
|
32
|
+
#
|
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
|
35
|
+
#++
|
|
36
|
+
|
|
37
|
+
require 'hexapdf/type/signature'
|
|
38
|
+
|
|
39
|
+
module HexaPDF
|
|
40
|
+
module Type
|
|
41
|
+
class Signature
|
|
42
|
+
|
|
43
|
+
# Holds the result information when verifying a signature.
|
|
44
|
+
class VerificationResult
|
|
45
|
+
|
|
46
|
+
# :nodoc:
|
|
47
|
+
MESSAGE_SORT_MAP = {
|
|
48
|
+
info: {warning: 1, error: 1, info: 0},
|
|
49
|
+
warning: {info: -1, error: 1, warning: 0},
|
|
50
|
+
error: {info: -1, warning: -1, error: 0},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# This structure represents a single status message, containing the type (:info, :warning,
|
|
54
|
+
# :error) and the content of the message.
|
|
55
|
+
Message = Struct.new(:type, :content) do
|
|
56
|
+
def <=>(other)
|
|
57
|
+
MESSAGE_SORT_MAP[type][other.type]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# An array with all result messages.
|
|
62
|
+
attr_reader :messages
|
|
63
|
+
|
|
64
|
+
# Creates an empty result object.
|
|
65
|
+
def initialize
|
|
66
|
+
@messages = []
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns +true+ if there are no error messages.
|
|
70
|
+
def success?
|
|
71
|
+
@messages.none? {|message| message.type == :error }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns +true+ if there is at least one error message.
|
|
75
|
+
def failure?
|
|
76
|
+
!success?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Adds a new message of the given type to this result object.
|
|
80
|
+
#
|
|
81
|
+
# +type+:: One of :info, :warning or :error.
|
|
82
|
+
#
|
|
83
|
+
# +content+:: The log message.
|
|
84
|
+
def log(type, content)
|
|
85
|
+
@messages << Message.new(type, content)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|