A dead simple certificate authority for testing purposes


I don’t know about you, but I know I’d rather spend an hour writing a script to automate something than 30 minutes figuring out how to use an existing but annoying/terrible tool. I do that not because I am a glutton for punishment, but because I know I’ll have to use that terrible tool again in the future and I won’t remember how to use it anyway.
So when I needed certificates for a test environment I checked out OpenSSL’s built in CA tool, quickly decided against using it, and then wrote my own simpler tool.

Update: There’s a new version of this script available in a new post

Main Article

To use:

  1. make a directory to contain the script and the keys and certs it will generate
  2. copy/paste this code into a file in that directory. I called it make-cert, but use whatever name you like
  3. run it

The script takes one or more parameters that specify the CN of the cert you want it to generate. So

$ ./make-cert myserver.mydomain.com

will make a cert for myserver.mydomain.com. It will also take more than one CN on the command line, so

$ ./make-cert myserver.mydomain.com login.mydomain.com

will make a certificate for myserver.mydomain.com and another one for login.mydomain.com.

And here’s the code


    # a very, very simple cert authority  
    # Copyright 2011 Oracle  
    # christopher.johnson@oracle.com  

    # License agreement:  
    # ------------------  
    # This script is intended as a simple sample and/or for my own  
    # purposes. If you get any benefit from it then that's GREAT but  
    # there are NO warranties and NO support. If this script burns down  
    # your house, chases your dog away and spoils your milk please don't  
    # come crying to me.  

    baseAnswers() {  
        echo US  
        echo Massachusetts  
        echo Boston  
        echo Oracle  
        echo A-Team  
        echo $1  
        echo root@`hostname`  

    answers() {  
        baseAnswers $1  
        echo ''  
        echo ''  

    # better safe than sorry  
    umask 077  

    # these next two lines figure out where the script is on disk  
    SCRIPTPATH=`readlink -f $0`  
    SCRIPTDIR=`dirname $0`  

    # if you're running this from somewhere else...  
    if [  $SCRIPTDIR != "."    -a   $SCRIPTDIR != $PWD  ]; then  
        # then CD to that directory  
        cd $SCRIPTDIR  
        echo "Certificate and key files (.crt and .key) will be placed in $PWD"  

    if [ ! -e ca.crt -o ! -e ca.key ]; then  
        echo "Creating cert authority key & certificate"  
        baseAnswers "My Cert Authority" | openssl req -newkey rsa:1024 -keyout ca.key -nodes -x509 -days 365 -out ca.crt 2> /dev/null  

    if [ $# -eq 0 ] ; then  
        echo "This script creates one or more certificates."  
        echo "Provide one or more certificate CNs on the command line."  
        echo "Usage: `basename $0` <certcn> [certcn [...]]"  
        exit -1  

    for certCN in $@ ; do  
        echo Certificate for CN \"$certCN\"  
        echo =============================================  


        if [ -e $KEY ] ; then  
     echo " ERROR: Key file $KEY already exists"  
        if [ -e $REQ ] ; then  
     echo " ERROR: Request file $REQ already exists"  
        if [ -e $CRT ] ; then  
     echo " ERROR: Certificate file $CRT already exists"  

        if [ $ABORT -eq 1 ] ; then  
     echo ''  
     echo "If you wish to recreate a certificate for you must delete"  
     echo "any preexisting files for that CN before running this script."  
     echo ''  
     echo ''  
     answers $certCN | openssl req -newkey rsa:1024 -keyout $KEY -nodes -days 365 -out $REQ  2> /dev/null  

            # at this point we have a key file, but the cert is not signed by the CA  
     openssl x509 -req -in $REQ -out $CRT -CA ca.crt -CAkey ca.key -CAcreateserial -CAserial ca.serial 2> /dev/null  

     echo "Certificate created."  
     ls -l $KEY $REQ $CRT  

     echo 'Certificate information:'  
     openssl x509 -in $CRT -noout -issuer -subject -serial  


Note: an earlier version of this script was missing a $1 in the answers() function. The above script contains the correction.

Add Your Comment