Created
October 2, 2017 08:41
-
-
Save elico/d203aaf4667d592cb45b669d878ffe99 to your computer and use it in GitHub Desktop.
Siginging pdf with origami and OpenSSL on ruby 2.x+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'openssl' | |
require 'time' | |
begin | |
require 'origami' | |
rescue LoadError | |
abort 'origami not installed: gem install origami' | |
end | |
include Origami | |
input_files = ARGV | |
abort 'Missing file names to run' if ARGV.nil? | |
abort 'Usage: sign-pdf input.pdf [...]' if input_files.empty? | |
key = OpenSSL::PKey::RSA.new(2048) | |
cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC' | |
pass_phrase = 'Origami rocks' | |
key_secure = key.export cipher, pass_phrase | |
# Create the certificate | |
name = OpenSSL::X509::Name.parse '[email protected]/C=IL/ST=Shomron/L=Karney Shomron/CN=Mr Eliezer Croitoru (NgTech LTD)/O=ngtech.co.il' | |
issuername = OpenSSL::X509::Name.parse '[email protected]/C=IL/ST=Shomron/L=Karney Shomron/CN=Mr Eliezer Croitoru (NgTech LTD)/O=MyCA' | |
cert = OpenSSL::X509::Certificate.new | |
cert.version = 2 | |
cert.serial = 0 | |
cert.not_before = Time.now | |
cert.not_after = Time.now + (2 * 365 * 24 * 60 * 60) # 2 years | |
cert.public_key = key.public_key | |
cert.subject = name | |
cert.issuer = issuername | |
ef = OpenSSL::X509::ExtensionFactory.new | |
ef.subject_certificate = cert | |
cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true)) | |
cert.add_extension(ef.create_extension('keyUsage', 'nonRepudiation,digitalSignature', true)) | |
cert.add_extension(ef.create_extension('extendedKeyUsage', 'emailProtection,clientAuth', true)) | |
cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false)) | |
cert.sign(key, OpenSSL::Digest::SHA256.new) | |
puts cert.to_text | |
input_files.each do |file| | |
output_filename = file.dup.insert(file.rindex('.'), '_signed') | |
pdf = PDF.read(file) | |
page = pdf.get_page(1) | |
width = 200.0 | |
height = 50.0 | |
y = page.MediaBox[2].to_f - width - height | |
x = height | |
size = 8 | |
signedby = 'Eliezer Croitoru' | |
location = 'Karney Shomron, Israel' | |
contact = '[email protected]' # pdf.signature[pdf.signature.keys[6]] | |
reason = 'IRS' # pdf.signature[pdf.signature.keys[7]] | |
date = Time.now | |
# caption = "Digitally Signed By: #{signedby}\nContact: #{contact}\nLocation: #{location}\nReason: #{reason}\nDate: #{date} " | |
caption = "Digitally Signed By: #{signedby}\nContact: #{contact}\nLocation: #{location}\nReason: #{reason}\nDate: #{date.iso8601}" | |
text_annotation = Annotation::AppearanceStream.new | |
text_annotation.Type = Origami::Name.new('XObject') | |
text_annotation.Resources = Resources.new | |
text_annotation.Resources.ProcSet = [Origami::Name.new('Text')] | |
text_annotation.set_indirect(true) | |
text_annotation.Matrix = [1, 0, 0, 1, 0, 0] | |
text_annotation.BBox = [0, 0, width, height] | |
text_annotation.write(caption, x: size, y: (height / 2) - (size / 2), size: size) | |
# Add signature annotation (so it becomes visibles in PDF document) | |
# signature_annotation = Annotation::Widget::Signature.new | |
signature_annotation = Annotation::Widget::Signature.new.set_indirect(true) | |
signature_annotation.Rect = Rectangle[llx: x, lly: y + height, urx: x + width, ury: y] | |
# signature_annotation.set_normal_appearance(text_annotation) | |
signature_annotation.F = Annotation::Flags::PRINT | |
page.add_annotation(signature_annotation) | |
def cert_to_sha1(cert) | |
OpenSSL::Digest::SHA1.new(cert.to_der).to_s.upcase | |
end | |
puts "Certificate SHA1: #{cert_to_sha1(cert)}" | |
puts "Certificate SHA256: #{OpenSSL::Digest::SHA256.new(cert.to_der).to_s.upcase}" | |
puts "Certificate SHA512: #{OpenSSL::Digest::SHA512.new(cert.to_der).to_s.upcase}" | |
# Sign the PDF with the specified keys | |
pdf.sign(cert, key, | |
method: 'adbe.pkcs7.detached', | |
annotation: signature_annotation, | |
location: location, | |
contact: contact, | |
issuer: 'MyCA', | |
reason: reason) | |
# Save the resulting file | |
pdf.save(output_filename) | |
puts "Signed with Certificate SHA1: #{cert_to_sha1(OpenSSL::PKCS7.new(pdf.signature.Contents).certificates[0])}" | |
puts output_filename | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment