This is another article where I try to tame OpenSSL API using C++11. This time round I describe a small example showing how to verify signed data programatically. There are many message formats catering for different needs. In this example I show how to verify that the data is not tampered and is sent from a party identified by a PKI certificate. Please refer to my other article to learn how to verify a certificate.
A brief introduction
Again I want to emphasize that you should not implement this functionality as
you can use
This command checks that the data stored in
/tmp/data is not tampered. The
tool calculates a checksum (a digest) and verifies it with the signature stored
/tmp/signature. The signature has been signed with the private key paired
with the public key stored in test-key-pub.pem. If there’s a certificate
associated with the public key available, it can also be verified to see whether
the data hasn’t been signed by an intruder in the middle.
As you can see, there’s no need to invent the wheel if your requirements are simple enough. Depending on the circumstances this approach might not be sufficient or acceptable, and only then you should come to grips with your own implementation.
Producing or verifying a signature is rather expensive operation as it involves
asymmetric cryptography. In practice a digest is produced first (e.g. using
SHA1) and then the digest is signed with one of the asymmetric keys. The
verification comprises applying the same digest function to the received data
and checking whether the signature of that digest “matches” when using the other
key of the asymmetric pair. You don’t have to worry about these details though
as they are hidden behind the OpenSSL API. Hopefully this also allays concerns
about the use of the
openss dgst command which stands for “digest”. The
signature is simply another step in the process of digesting data.
The main three functions we are going to use are
first two of them are simply aliases (macros) of equivalent “digest”
functions. Of course you shouldn’t abuse them and better use the macros provided
to be explicit about the intentions. Please also note that in general
versions of OpenSSL API functions are recommended if available as they are more
general and allow you to use an engine. If you don’t intend to use an engine
First you initialise the algorithm, then there’s a one or more updates that feed the algorithm with data, and in the end you finalise the algorithm. The update step allows to process “streamed” data, i.e. you feed the algorithm with data as it arrives. If all data is available at once, you can make only one update call. In many situation though you might want to process data in chunks, e.g. when you read a large file or from a network socket.
More details about the API used in this example are available in the
manual so there’s no
point in duplicating them here. If you’re off-line and have openssl-devel (or
equivalent) package installed (which you should in order to compile this
example), you can also use info or man pages. Don’t forget to read about
Build and test
This is how I build the example on my Fedora 18 laptop:
I think that the most frustrating thing about keys, certificates and all this cryptographic stuff is testing. Creating test assets (key material, certificates etc.) can be truly onerous. But this is still not as hard as testing a full production system with real cryptographic material (very often hardware assisted), so let’s get on with it:
And finally we can run our verifier:
As the steps above are a bit tedious, you can use a test script I provide here. Simply give it the path to the verifier executable as an argument and that’s it. It creates a temporary scratch directory where it generates the assets and runs rudimentary tests using the executable provided. As I wanted to keep it dead simple, it doesn’t provide any additional options like preserving the scratch directory, setting verbosity level etc. It’ll probably evolve in future incarnations once I’ve got examples in my repository a bit reorganised.