Jumpnow Technologies

home

Signing code with OpenSSL

13 Feb 2021

There are dedicated tools for signing code like minisign or signify.

This is post is about understanding the idea.

Providing a cryptographic hash like an md5 or sha256 checksum for a file you distribute only gives the receiver integrity verification, proof that a file has not been corrupted or tampered with.

Including a digital signature adds authentication and non-repuditation.

Public key cryptography is used to generate digital signatures.

In software development this is also called code signing.

The general algorithm:

To Sign

  1. Generate a hash of the data file
  2. Encrypt the hash with a private key producing a signature file
  3. Distribute the data and signature files

To Verify

  1. Generate a hash of the data file
  2. Use the public key to unencrypt the signature file
  3. Check that the two values match

Obviously the crypto hash algorithm has to be the same in both signing and verification.

So why not just sign the original file?

Public key cryptography is slow and the size of the file you can encrypt with an algorithm like RSA is limited. By hashing the data first and only signing the hash, we only need to encrypt a small file.

The OpenSSL command line utility provides all the tools we need to digitally sign files.

$ openssl version
OpenSSL 1.1.1f  31 Mar 2020

I am using OpenSSL 1.1.1f on an Ubuntu 20.04 machine for these examples.

Create an elliptic-curve public/private key pair with genpkey

Generate a private key using one of the standard NIST curves P-384

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out ec-private.pem

And now a public key based on the private key

$ openssl pkey -in ec-private.pem -pubout -out ec-public.pem

The key sizes are relatively small

$ ls -l ec-*
-rw------- 1 scott scott 306 Aug 29 09:50 ec-private.pem
-rw-rw-r-- 1 scott scott 215 Aug 29 09:50 ec-public.pem

The private key ec-private.pem should be kept secret.

The public key ec-public.pem is meant to be shared.

Signing

Openssl can do the signing, both hashing and encrypting, in one command.

Create a signature file like this

$ openssl dgst -sign ec-private.pem -out data.sig data

The signature file is small

$ ls -l data*
-rw-r--r-- 1 scott scott 415867 Aug 29 10:38 data
-rw-rw-r-- 1 scott scott    103 Aug 29 10:40 data.sig

It should be distributed with the data file.

Hash algorithm

The default hashing (digest) algorithm is sha256.

You can change this by adding another argument to the signing command.

For instance to use sha3-512

$ openssl dgst -sha3-512 -sign ec-private.pem -out data.sig data

The available hash algorithms are

$ openssl list --digest-commands
blake2b512        blake2s256        gost              md4
md5               rmd160            sha1              sha224
sha256            sha3-224          sha3-256          sha3-384
sha3-512          sha384            sha512            sha512-224
sha512-256        shake128          shake256          sm3

Verifying

Verification requires the public key and knowledge of the hashing algorithm that was used.

If the default sha256 was used

$ openssl dgst -verify ec-public.pem -signature data.sig data
Verified OK

A failure looks like this

$ openssl dgst -verify ec-public.pem -signature data.sig modified-data
Verification Failure

If a different hash algorithm was used, this needs to be specified or the check will fail.

$ openssl dgst -sha3-512 -sign ec-private.pem -out data.sig data

$ openssl dgst -verify ec-public.pem -signature data.sig data
Verification Failure

$ openssl dgst -sha3-512 -verify ec-public.pem -signature data.sig data
Verified OK

The shell variable $? is set to zero (success) or one (failure) as you would expect.

Encrypting the Private Key

For additional protection of the private key, you can encrypt it with a password.

The extra -aes256 argument will encrypt the private key using the AES algorithm.

$ openssl genpkey -aes256 -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out ec-private.pem
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

Now whenever you use the private key, you will need the password

$ openssl pkey -in ec-private.pem -pubout -out ec-public.pem
Enter pass phrase for ec-private.pem:

$ openssl dgst -sign ec-private.pem -out data.sig data
Enter pass phrase for ec-private.pem:

The private key is slightly larger

$ ls -l ec-*
-rw------- 1 scott scott 464 Aug 29 10:59 ec-private.pem
-rw-rw-r-- 1 scott scott 215 Aug 29 11:00 ec-public.pem

Prompting for pass phrase is the default, but you can provide the password using other methods with the -passin argument

Directly in the command

$ openssl dgst -sign ec-private.pem -passin pass:the-password -out data.sig data

Using an environment variable

$ SECRET=the-password
$ openssl dgst -sign ec-private.pem -passin env:SECRET -out data.sig data

Using a pathname where the argument can be a file

$ echo the-password > secret
$ openssl dgst -sign private.pem -passin file:secret -out data.sig data

There are other options to provide the password. See the Pass Phrase section of the openssl(1) man page.

A password on the private key does not affect how the public key is used.

Using RSA keys

RSA public key cryptography uses larger keys and is more CPU intensive, but can be used in a similar fashion.

Generating a 4096-bit RSA private key

$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out rsa-private.pem
..........................................++++
...................................................++++

Generating a public key from the private key is the same

$ openssl pkey -in rsa-private.pem -pubout -out rsa-public.pem

The keys are larger

$ ls -l rsa*
-rw------- 1 scott scott 3272 Aug 29 11:10 rsa-private.pem
-rw-rw-r-- 1 scott scott  800 Aug 29 11:11 rsa-public.pem

Using the RSA keys for signing and verification are the same

$ openssl dgst -sign rsa-private.pem -out data.sig data

$ openssl dgst -verify rsa-public.pem -signature data.sig data

The signature is also larger with RSA keys

$ ls -l data*
-rw-r--r-- 1 scott scott 415867 Aug 29 10:38 data
-rw-rw-r-- 1 scott scott    512 Aug 29 11:25 data.sig

The commands for using different hash algorithms and encrypting the private key are the same.

Additional Reading