Module: HexaPDF::DigitalSignature::Signing

Defined in:
lib/hexapdf/digital_signature/signing.rb,
lib/hexapdf/digital_signature/signing/default_handler.rb,
lib/hexapdf/digital_signature/signing/timestamp_handler.rb,
lib/hexapdf/digital_signature/signing/signed_data_creator.rb

Overview

This module contains everything related to the signing of a PDF document, i.e. signing handlers and the actual code for signing.

Defined Under Namespace

Classes: DefaultHandler, SignedDataCreator, TimestampHandler

Class Method Summary collapse

Class Method Details

.embed_signature(io, signature) ⇒ Object

Embeds the given signature into the /Contents value of the newest signature dictionary of the PDF document given by the io argument.

This functionality can be used together with the support for external signing (see DefaultHandler and DefaultHandler#external_signing) to implement asynchronous signing.

Note: This will, most probably, only work on documents prepared for external signing by HexaPDF and not by other libraries.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/hexapdf/digital_signature/signing.rb', line 58

def self.embed_signature(io, signature)
  doc = HexaPDF::Document.new(io: io)
  signature_dict = doc.signatures.find {|sig| doc.revisions.current.object(sig) == sig }
  signature_dict_offset, signature_dict_length = locate_signature_dict(
    doc.revisions.current.xref_section,
    doc.revisions.parser.startxref_offset,
    signature_dict.oid
  )
  io.pos = signature_dict_offset
  signature_data = io.read(signature_dict_length)
  replace_signature_contents(signature_data, signature)
  io.pos = signature_dict_offset
  io.write(signature_data)
end

.locate_signature_dict(xref_section, start_xref_position, signature_oid) ⇒ Object

Uses the information in the given cross-reference section as well as the byte offset of the cross-reference section to calculate the offset and length of the signature dictionary with the given object id.



76
77
78
79
80
81
# File 'lib/hexapdf/digital_signature/signing.rb', line 76

def self.locate_signature_dict(xref_section, start_xref_position, signature_oid)
  data = xref_section.map {|oid, _gen, entry| [entry.pos, oid] if entry.in_use? }.compact.sort <<
    [start_xref_position, nil]
  index = data.index {|_pos, oid| oid == signature_oid }
  [data[index][0], data[index + 1][0] - data[index][0]]
end

.replace_signature_contents(signature_data, contents) ⇒ Object

Replaces the value of the /Contents key in the serialized signature_data with the value of contents.



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/hexapdf/digital_signature/signing.rb', line 85

def self.replace_signature_contents(signature_data, contents)
  signature_data.sub!(/Contents(?:\(.*?\)|<.*?>)/) do |match|
    length = match.size
    result = "Contents<#{contents.unpack1('H*')}"
    if length < result.size
      raise HexaPDF::Error, "The reserved space for the signature was too small " \
        "(#{(length - 10) / 2} vs #{(result.size - 10) / 2}) - use the handlers " \
        "#signature_size method to increase the reserved space"
    end
    "#{result.ljust(length - 1, '0')}>"
  end
end