Insert digital signature into existing pdf file

前端 未结 2 712
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-02 21:30

I need to insert a digital signature into already existing pdf files, using a rails application server. (Basically, clients upload pdf files and the server signs them with a

2条回答
  •  广开言路
    2020-12-02 22:00

    After some research, recurring to the OpenSSL documentation and exploring the Origami solution, i built the code below, and managed to insert a locally generated signature/certificate into a pdf document. Now I just need to figure out how to use this with an external generated certificate (check version 2 below, where i solved it). I've opened a new question where you can find some details on a difficulty i had with OpenSSL and DER encoded certificates.

    To develop version 2, i also spent some time wondering how to add an annotation - so the signature becomes visible in Adobe reader - without adding a new page to the document. From origami documentation, i found the get_page method, which solved my last problem on this. I'm using Adobe Reader X, for the record.

    Hope you find this useful as I will ;-).

    VERSION 1 - Generate certificate and key file, and insert them directly into the document

    require 'openssl'
    
    begin
      require 'origami'
    rescue LoadError
      ORIGAMIDIR = "C:\RailsInstaller\Ruby1.9.3\lib\ruby\gems\1.9.1\gems\origami-1.2.4\lib"
      $: << ORIGAMIDIR
      require 'origami'
    end
    include Origami
    
    # Code below is based on documentation available on
    # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL.html
    key = OpenSSL::PKey::RSA.new 2048
    
    open 'private_key.pem', 'w' do |io| io.write key.to_pem end
    open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
    
    cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
    pass_phrase = 'Origami rocks'
    
    key_secure = key.export cipher, pass_phrase
    
    open 'private_key.pem', 'w' do |io|
      io.write key_secure
    end
    
    #Create the certificate
    
    name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example'
    
    cert = OpenSSL::X509::Certificate.new
    cert.version = 2
    cert.serial = 0
    cert.not_before = Time.now
    cert.not_after = Time.now + 3600
    
    cert.public_key = key.public_key
    cert.subject = name
    
    
    OUTPUTFILE = "test.pdf"
    
    contents = ContentStream.new.setFilter(:FlateDecode)
    contents.write OUTPUTFILE,
      :x => 350, :y => 750, :rendering => Text::Rendering::STROKE, :size => 30
    
    pdf = PDF.read('Sample.pdf')
    
    
    # Open certificate files
    
    #sigannot = Annotation::Widget::Signature.new
    #sigannot.Rect = Rectangle[:llx => 89.0, :lly => 386.0, :urx => 190.0, :ury => 353.0]
    
    #page.add_annot(sigannot)
    
    # Sign the PDF with the specified keys
    pdf.sign(cert, key, 
      :method => 'adbe.pkcs7.sha1',
      #:annotation => sigannot, 
      :location => "Portugal", 
      :contact => "myemail@email.tt", 
      :reason => "Proof of Concept"
    )
    
    # Save the resulting file
    pdf.save(OUTPUTFILE)
    

    VERSION 2 - Use existing certificates to sign a pdf document

    require 'openssl'
    
    begin
      require 'origami'
    rescue LoadError
      ORIGAMIDIR = "C:\RailsInstaller\Ruby1.9.3\lib\ruby\gems\1.9.1\gems\origami-1.2.4\lib"
      $: << ORIGAMIDIR
      require 'origami'
    end
    include Origami
    
    INPUTFILE = "Sample.pdf"
    @inputfile = String.new(INPUTFILE)
    OUTPUTFILE = @inputfile.insert(INPUTFILE.rindex("."),"_signed")
    CERTFILE = "certificate.pem"
    RSAKEYFILE = "private_key.pem"
    passphrase = "your passphrase"
    
    key4pem=File.read RSAKEYFILE
    
    key = OpenSSL::PKey::RSA.new key4pem, passphrase
    cert = OpenSSL::X509::Certificate.new(File.read CERTFILE)
    
    pdf = PDF.read(INPUTFILE)
    page = pdf.get_page(1)
    
    # Add signature annotation (so it becomes visibles in pdf document)
    
    sigannot = Annotation::Widget::Signature.new
    sigannot.Rect = Rectangle[:llx => 89.0, :lly => 386.0, :urx => 190.0, :ury => 353.0]
    
    page.add_annot(sigannot)
    
    # Sign the PDF with the specified keys
    pdf.sign(cert, key, 
      :method => 'adbe.pkcs7.sha1',
      :annotation => sigannot, 
      :location => "Portugal", 
      :contact => "myemail@email.tt", 
      :reason => "Proof of Concept"
    )
    
    # Save the resulting file
    pdf.save(OUTPUTFILE)
    

提交回复
热议问题