Recently we had cause to fill in some paperwork and it required a signature. In this case the company in question asked us to print the form, sign it, scan it and send them the scan. There are various ways built into the various word processors and similar tools that can be used to digitally sign documents, but I thought I might just scribble down how you might do it using the SSL certificate on your website.

So lets assume you have a lovely document: example.docx and want to return it to someone along with a signature. You also run a website and therefore have an SSL certificate STAR.example.com.crt and its corresponding private key STAR.example.com.key. What can you do with that lot?

The first step would be to generate a hash that represents the document - we don’t really want to process all the data in a potentially large word document. To do that we’ll use the sha256sum tool:

sha256sum example.docx > example.docx.sha256.txt

That will have create a file example.docx.sha256.txt containing the SHA256 hash of the example.docx file contents. It will look something like this

3b48a6df1a241a9619d58d06afa0168abdc0a6e20b269f53fc44eb6c91480e32  example.docx

We’re going to generate a signature now for that file, the hash is of course much smaller than the word document which makes this quick and easy. To generate the signature we’ll use openssl and our private key, saving the signature into a file called example.docx.signature.

openssl dgst -sha256 -sign STAR.example.key -out example.docx.signature example.docx.sha256.txt 

We can then send the company our completed form example.docx, the hash file for the form (example.docx.sha256.txt) and the signature (example.docx.signature).

But what are they to do with these three files? Well they would start by going and getting our SSL certificate from our website, that is publicly accessible, so in this example we’re running example.com and we can use OpenSSL to get the certificate:

	openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null|openssl x509 -pubkey -noout -outform PEM -outform PEM > my-copy-of_example.com.pubkey

So that’s telling OpenSSL to connect to example.com on port 443 (the default for HTTPS) and get the certificate for example.com (just in case the host is running with multiple certifcates on the one IP address). We then throw that information through OpenSSL again to generate just the bit we need which is the actually just the public key part of the certificate they have installed on their website and we save that into a file called my-copy-of_example.com.pubkey

Now they have a copy of our public certificate key they can check the signature we sent was signed with our private certifiate key - that only we have access to.

openssl dgst -sha256 -verify my-copy-of_example.com.pubkey -signature example.docx.signature example.docx.sha256.txt

This will either spit out Verified OK or Verification Failure. So what have they proved? They have proved that that signature contained in the example.docx.sha256.txt file matches is correct for the contents of the example.docx.sha256.txt file, showing that that file has not been tampered with. How is that useful? Given that file contains the SHA256 hash of the original word document (example.docx) they can themselves generate the SHA256 for that file and compare their generated hash to the one we supplied if they are the same they know the contents of the example.docx is the same and it has not been tampered with.

Lets run though it all with a real example. So taking a work in the public domain - you can download a PDF copy of Jules Verne’s 20,000 Leagues under the Sea from the Internet Archive, it’s about 13MB in size so large enough that we’d not want to pass all that data through OpenSSL to sign so we’ll use our trick of signing the hash instead. If the Internet Archive have changed their copy of the file the one I’m working with can be fetched directly, in fact really you’ll want to be verifying that the copy I am supplying is the copy I say it is!

So the files you’ll need to download:

Once you have these three files you’ll want a copy of the public key part of the website:

openssl s_client -connect sundivenetworks.net:443 -servername sundivenetworks.net -showcerts </dev/null 2>/dev/null|openssl x509 -pubkey -noout -outform PEM -outform PEM > my-copy-of_sundivenetworks.net.pubkey

Check the signature you’ve obtained from us:

openssl dgst -sha256 -verify my-copy-of_sundivenetworks.net.pubkey -signature twentythousandle00verniala.pdf.signature twentythousandle00verniala.pdf.sha256.txt

You should get a Verified OK telling you that the private key that corresponds to our public key did indeed generate that signature and the signature is valid for that hash file.

Now go and grab the novel either from us or the copy from the Internet Archive (download the PDF). Now you have that file you want to generate your own SHA256 of the novel:

sha256sum twentythousandle00verniala.pdf > my-copy-of_twentythousandle00verniala.pdf.sha256.txt

Compare the output of your hash to the contents of the hash you downloaded from us:

cat my-copy-of_twentythousandle00verniala.pdf.sha256.txt twentythousandle00verniala.pdf.sha256.txt

They should be the same (hash - the ordering in the file may be different) if the contents of the novel is the same as it was when I generated our hash and signed it - they will certainly be the same if you downloaded the file from us. So you’ve proved that file has not been tampered with since I signed it!