Class: HexaPDF::DigitalSignature::Signing::TimestampHandler
- Inherits:
-
Object
- Object
- HexaPDF::DigitalSignature::Signing::TimestampHandler
- Defined in:
- lib/hexapdf/digital_signature/signing/timestamp_handler.rb
Overview
This is a signing handler for adding a timestamp signature (a PDF2.0 feature) to a PDF document. It is registered under the :timestamp name.
The timestamp is provided by a timestamp authority and establishes the document contents at the time indicated in the timestamp. Timestamping a PDF document is usually done in context of long term validation but can also be done standalone.
Usage
It is necessary to provide at least the URL of the timestamp authority server (TSA) via #tsa_url, everything else is optional and uses default values. The TSA server can optionally use HTTP basic authentication.
Example:
document.sign("output.pdf", handler: :timestamp, tsa_url: 'https://freetsa.org/tsr')
Instance Attribute Summary collapse
-
#contact_info ⇒ Object
The contact information.
-
#location ⇒ Object
The timestamping location.
-
#reason ⇒ Object
The reason for timestamping.
-
#signature_size ⇒ Object
Returns the size of the serialized signature that should be reserved.
-
#tsa_hash_algorithm ⇒ Object
The hash algorithm to use for timestamping.
-
#tsa_password ⇒ Object
The password for basic authentication to the TSA server.
-
#tsa_policy_id ⇒ Object
The policy OID to use for timestamping.
-
#tsa_url ⇒ Object
The URL of the timestamp authority server.
-
#tsa_username ⇒ Object
The username for basic authentication to the TSA server.
Instance Method Summary collapse
-
#finalize_objects(_signature_field, signature) ⇒ Object
Finalizes the signature field as well as the signature dictionary before writing.
-
#initialize(**arguments) ⇒ TimestampHandler
constructor
Creates a new TimestampHandler with the given attributes.
-
#sign(io, byte_range) ⇒ Object
Returns the DER serialized OpenSSL::PKCS7 structure containing the timestamp token for the given IO byte ranges.
Constructor Details
#initialize(**arguments) ⇒ TimestampHandler
Creates a new TimestampHandler with the given attributes.
106 107 108 109 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 106 def initialize(**arguments) @signature_size = nil arguments.each {|name, value| send("#{name}=", value) } end |
Instance Attribute Details
#contact_info ⇒ Object
The contact information. If used, will be set on the signature dictionary.
103 104 105 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 103 def contact_info @contact_info end |
#location ⇒ Object
The timestamping location. If used, will be set on the signature dictionary.
100 101 102 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 100 def location @location end |
#reason ⇒ Object
The reason for timestamping. If used, will be set on the signature dictionary.
97 98 99 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 97 def reason @reason end |
#signature_size ⇒ Object
Returns the size of the serialized signature that should be reserved.
112 113 114 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 112 def signature_size @signature_size || (sign(StringIO.new, [0, 0, 0, 0]).size * 1.5).to_i end |
#tsa_hash_algorithm ⇒ Object
The hash algorithm to use for timestamping. Defaults to SHA512.
82 83 84 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 82 def tsa_hash_algorithm @tsa_hash_algorithm end |
#tsa_password ⇒ Object
The password for basic authentication to the TSA server.
See: #tsa_username
79 80 81 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 79 def tsa_password @tsa_password end |
#tsa_policy_id ⇒ Object
The policy OID to use for timestamping. Defaults to nil.
85 86 87 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 85 def tsa_policy_id @tsa_policy_id end |
#tsa_url ⇒ Object
The URL of the timestamp authority server.
This value is required.
67 68 69 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 67 def tsa_url @tsa_url end |
#tsa_username ⇒ Object
The username for basic authentication to the TSA server.
If the username is not set, no basic authentication is done.
See: #tsa_password
74 75 76 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 74 def tsa_username @tsa_username end |
Instance Method Details
#finalize_objects(_signature_field, signature) ⇒ Object
Finalizes the signature field as well as the signature dictionary before writing.
117 118 119 120 121 122 123 124 125 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 117 def finalize_objects(_signature_field, signature) signature.document.version = '2.0' signature[:Type] = :DocTimeStamp signature[:Filter] = :'Adobe.PPKLite' signature[:SubFilter] = :'ETSI.RFC3161' signature[:Reason] = reason if reason signature[:Location] = location if location signature[:ContactInfo] = contact_info if contact_info end |
#sign(io, byte_range) ⇒ Object
Returns the DER serialized OpenSSL::PKCS7 structure containing the timestamp token for the given IO byte ranges.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/hexapdf/digital_signature/signing/timestamp_handler.rb', line 129 def sign(io, byte_range) hash_algorithm = tsa_hash_algorithm || 'SHA512' digest = OpenSSL::Digest.new(hash_algorithm) io.pos = byte_range[0] digest << io.read(byte_range[1]) io.pos = byte_range[2] digest << io.read(byte_range[3]) req = OpenSSL::Timestamp::Request.new req.algorithm = hash_algorithm req. = digest.digest req.policy_id = tsa_policy_id if tsa_policy_id url = URI(tsa_url) http_request = Net::HTTP::Post.new(url, 'Content-Type' => 'application/timestamp-query') http_request.body = req.to_der http_request.basic_auth(tsa_username, tsa_password) if tsa_username http_response = Net::HTTP.start(url.hostname, url.port, use_ssl: (url.scheme == 'https')) do |http| http.request(http_request) end if http_response.kind_of?(Net::HTTPOK) response = OpenSSL::Timestamp::Response.new(http_response.body) if response.status == 0 response.token.to_der else raise HexaPDF::Error, "Timestamp token could not be created: #{response.failure_info}" end elsif http_response.kind_of?(Net::) raise HexaPDF::Error, "Basic authentication to the server failed: #{http_response.body}" else raise HexaPDF::Error, "Invalid TSA server response: #{http_response.body}" end end |