Imagine a locked room with a big window. If I am the only person with a key to room, and I tape a poster up inside the window, everyone can read it, and everyone can state with a pretty high degree of certainty that I was the person that I put up the poster. This is analogy to how you can use PKI to sign a document.
UPDATE: I’ve taken Kashyap’s advice and cleanup the following steps.
In order for the message signature to be verifiable, we generate a pair of keys, one that is kept private, and one that is made public. Data encrypted with the private key can then be decrypted with only the corresponding public key. So, to sign a message, it is encrypted with the private key.
There are ways to make this more efficient, such as signing a hash of the message, but the principal is the same.
I am going to use the same set of cryptographic tools that Mozilla provides for securing web traffic. These tools fall under then name Network Security Services or NSS for short.
The first step is to provide a Certificate Authority (CA) Certificate. This is a certificate used to sign other certificates. This is actually supposed to be part of a chain. In the browser, there are a list of CA certs that are accepted by default. For our purposes here, I am going to self sign one. Figuring out how to set this up for your organization has been left as an exercise to the reader.
We need a place to put the certificate. For NSS, this is called an NSS database. I am going to create one in a directory I call alias, because that is the name of the NSS database used in Apache HTTPD. To generate:
mkdir alias certutil -N -d ./alias/
Now create a self-signed CA certificate. Type the command:
certutil -S -s "CN=CA Issuer" -n CACert -x -t "CT,C,C" -v 120 -m 1234 -d alias/
You will be prompted to type. This is used to generate entropy, or randomness, for the underlying cryptography.
The security conscious folks out there are squirming in their seats reading this, because a self-signed CA cert is BAD under most circumstances. However, this is proof-of-concept type stuff. You always need to get a certificate signed by a CA…this is just the simple way to do it for development.
Now that we have a CA cert, we need to generate a Key. With NSS, you can generate the Key and the certificate signing request in one step:
certutil -R -s "CN=Adam Young, O=RedHat , L=Westford, ST=MA, C=US" -p "617-555-1212" -o mycert.req -d alias
You see the same entropy generation prompt as before.
You can list the keys using:
certutil -K -d ./alias/
Which produces output along the lines of:
certutil: Checking token "NSS Certificate DB" in slot "NSS User Private Key and Certificate Services" < 0> rsa 99f6d153a007f8fb2d79312d454749eb92e4db99 NSS Certificate DB:myissuer < 1> rsa b8472a65af1c2da900fb0eb953d9c278d615a580 NSS Certificate DB:ayoung
Note that there is one in there for the CA certificate we produced before.
To sign the key run the following:
certutil -C -m 2345 -i mycert.req -o mycert.crt -c myissuer -d ./alias/ -6
The -6 option allows to add extensions to the certificate, specifically the ones that we need to sign email. The private and public keys are held in the NSS database.
Now that we have a useful certificate and key pair that we can use to sign a document. To Sign auth_token.json run:
cmsutil -S -d alias -N ayoung -i signme.txt -o signed.p7s
The signed message is put into signed.p7s. The file extension alludes to the PKCS 7 standard that CMS grew out of.
Here is everything as a single Makefile.
TARGETS = alias mycert.req noise.dat mycert.crt all: $(TARGETS) alias : noise.dat mkdir alias certutil -N -d alias certutil -S -s "CN=CA Issuer" -n CACert -x -t "CT,C,C" -v 120 -m 1234 -d alias/ -z noise.dat mycert.req : alias certutil -R -s "CN=Joe Admin, O=RedHat , L=Westford, ST=MA, C=US" -p "617-555-1212" -o mycert.req -d alias -n joeadmin -z noise.dat mycert.crt : mycert.req certutil -C -m 2345 -i mycert.req -o mycert.crt -c CACert -d ./alias --extKeyUsage "clientAuth,emailProtection" certutil -A -d ./alias/ -i mycert.crt -n joeadmin -t "u,u,u" noise.dat : head -c 20 /dev/urandom > noise.dat clean: rm -rf $(TARGETS)
It is possible I’ve typeo’d some things, but the Makefile ran after a “make clean” so I should have generated everything from scratch.