Hi,
after fiddling around a lot these days I'm giving up and asking you due to the lack of documentation of Ruby OpenSSL and too less knowledge to figure it out on my own.
I want to sign an arbitrary document with a private key / certificate pair to get either a detached signature (p7s file) or a self containing one (pkcs7 file).
Let me illustrate my steps and problems by showing what I tried:
1. For testing purposes I created a private key and a certificate with OpenSSL
openssl genrsa -out app_key.pem 1024
openssl req -new -key app_key.pem -x509 -days 365 -out app_cert.pem
2. In Ruby I load those files and the document I want to sign
private_key = File.read('app_key.pem')
certificate = File.read('app_cert.pem')
data = File.read('test.pdf')
3. I use those files with Ruby OpenSSL classes
key = OpenSSL::PKey::RSA.new(private_key)
crt = OpenSSL::X509::Certificate.new(certificate)
4. I create a detached signature:
signed = OpenSSL::PKCS7::sign(crt, key, data, [], OpenSSL::PKCS7::DETACHED)
This actually works and gives me an p7s file. When using OpenSSL::PKCS7::BINARY it seems to me that I get a pkcs7 file which is containing the payload of my testfile.
The problem here:
This convenient methods seems to use a SHA-1 hash for signing the document – but I need to utilize at least SHA-256 or better SHA-512 as it is a legal requirement for my application (qualified digital signatures as defined in SiG of German law).
So I tried another way which was outlined on the web at https://www.koders.com/ruby/fid1543851B1354DA253F0B0D3E21DFDED96E30FFF4.aspx
Continuing by step 3.) I did the following:
p7 = OpenSSL::PKCS7::PKCS7.new(OpenSSL::PKCS7::SIGNED)
Problem: OpenSSL::PKCS7::SIGNED is undefined… and I don't know what to specify here, else.
signer = OpenSSL::PKCS7::Signer.new(crt, key, Digest::SHA1.new)
Here it seems to me that I can modify the digest algorithmus – but using Digest::SHA256.new or Digest::SHA512.new fails.
Weird is, that I in irb the following works:
require 'digest/sha2'
Digest::SHA512.hexdigest('test')
=> "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"
Anyway… going in with SHA1.
p7.add_signer(signer, key)
This command complained that the 2nd parameter is too much. So I stripped this and get the error that signer is the wrong type.
signer actually is from kind of SignerInfo.
Next step would be:
p7.add_certificate(cert)
…which makes no problem.
But the next methods throws an error because of the second parameter. The 2nd parameter should have been to specify wether the signatur should be detached or containing the payload (compare OpenSSL::PKCS7::DETACHED, OpenSSL::PKCS7::BINARY above)
p7.add_data(data, true)
In the end I would have been able to put out the signature either in PEM or DER format:
p7.to_pem
p7.to_der
So here's my question:
How can I sign a PDF document to get a detached signature in p7s format which was created by the usage of a private key, a certificate and SHA512 for hashing?
Just for your interest… I'm currently working on an open source project (http://github.com/yves-vogl/kimei) which should allow signing documents which a private key / certificate as a webservice.
To make it compliant with european law, especially when signing documents like invoices, it need to have the format mentioned above and to utilize a private key / certficate from a smartcard provided by the government.
To implement the latter feature I talked to Victor Costan who built "smartcard", a STL for accessing smartcard readers by their PCSC interface. If you are interested in this or would like to help - just tell us. This would be really appreciated.
Cheers from Germany,
Yves