posted 2010-03-16
This article is a follow-up to Replacing a Certificate in IIS without Downtime; I realized that it is probably non-obvious how one would acquire the signed certificate in the first place.
You can go read the intro to the first article for the long explanation. In short, IIS makes it completely impossible to generate a new certificate request for a site without taking that site offline. So we're going to cheat and use OpenSSL.
OpenSSL comes with just about every Linux distribution, so if you have a Linux machine handy, you can use it to perform all of these steps. Otherwise, go get Cygwin and install it along with its OpenSSL package.
Since we're going to use a new certificate/key, we need to generate a new CSR. OpenSSL can do this, but it's ugly. I created a shell script, vhost-ssl-request, to do it:
#!/bin/bash # # vhost-ssl-request # # Generate a certificate signing request (CSR) for a virtual host. # # How many bits to use for the key? NUM_BITS=2048 function usage() { echo "Usage: $0 [-b NUM_BITS] <vhost>" echo '' echo -n ' <vhost> ' echo 'Your virtual hostname, i.e. the common name on the certificate.' echo '' echo -n ' -b NUM_BITS ' echo "Create keys of length NUM_BITS (default ${NUM_BITS})." echo '' } # Some exit codes. EXIT_BAD_ARGS=1 EXIT_KEY_EXISTS=2 EXIT_CSR_EXISTS=3 while getopts "b:" option; do case $option in b ) NUM_BITS=$OPTARG;; * ) usage exit $EXIT_BAD_ARGS;; esac done # Get rid of the -b option if it was passed. shift $((OPTIND-1)) if [ $# -lt 1 ]; then usage exit $EXIT_BAD_ARGS fi VHOST=$1 KEYFILE=${VHOST}.key TODAY=$(date +"%Y-%m-%d") CSRFILE=${VHOST}-${TODAY}.csr # Make sure the key/CSR don't already exist before we proceed. if [ -f $KEYFILE ]; then echo "Key file $KEYFILE already exists. Bailing." exit $EXIT_KEY_EXISTS fi if [ -f $CSRFILE ]; then echo "CSR file $CSRFILE already exists. Bailing." exit $EXIT_CSR_EXISTS fi # Generate the private key. openssl genrsa -out $KEYFILE $NUM_BITS # The private key is private! Make it read-only. chmod 400 $KEYFILE # Generate the signing request. # Always uses SHA-2, since SHA-1 is on its way out: # # https://googleonlinesecurity.blogspot.com/2014/09/gradually-sunsetting-sha-1.html # openssl req -new -sha256 -key $KEYFILE -out $CSRFILE
Note the default NUM_BITS=4096
. Change it if you care. Run
the thing, and pass it the name of your site (i.e. the certificate's
common name).
user $ ./vhost-ssl-request www.example.com
This will output two files in the current directory, www.example.com.key, your private key, and www.example.com-<date>.csr, the certificate signing request.
You've got the CSR; just send it off to whomever is going to sign it. Generally, once they have verified that you own the common name in question, you will receive a certificate file back. Let's call it www.example.com.crt.
Now, IIS won't import a certificate/key pair as separate files, because it's a fucker. So before we import the pair, we need to convert it to PKCS12 format (a pfx file). OpenSSL can do this, but first, let's combine the certificate/key pair into one pem file.
user $ cat www.example.com.key www.example.com.crt > www.example.com.pem
Now, convert the pem file to pfx, with which IIS and Windows are in love:
user $ openssl pkcs12 -in www.example.com.pem -export -out www.example.com.pfx
You will be prompted for a password. Enter something short and memorable—we're going to use it once in about 10 seconds, and then never need it again.
We're almost done. The rest of the steps follow the previous article, beginning at Importing the New Certificate/Key Pair.