OpenSSL key and Certificate Signing Requests (CSR) generation script

Generating keys and CSR requests for your Public Key Infrastructure (PKI) needs is tedious and annoying without proper tools. Remembering openssl commands and syntax requires a constant visit to the man page or the googles. So what does any good geek do when faced with a repetitive problem? They write a script or download a tool. I wrote a script because I love reinventing the wheel.

The script below (after the jump) creates a customized openssl config file and generates private keys and CSRs. The input to the script is a flat file with either FQDNs, email addresses, or whatever your want that is plugged into the Common Name field of the key/CSR. The script is nothing more than a glorified for loop that helps reduce errors and ensures consistency across a large key base.

This can be really useful when setting up EAP-TLS for your WiFi or other device authentication.

Please leave any feedback you may have in the comments.


#!/bin/bash ########################################## # Batch key and CSR generation # script # author: timothy.lisko@privacywonk.net # date: 2011-11-14 # v2.0 # Directions: # 1. Update variables below based on business/tech requirements # 2. Create text file with Unique identifier (e.g. FQDN, IP address, Serial Number, unique name) # 3. From command line Execute script ./createkeys.sh filename -password-switch(e.g. $ ./createkeys.sh clientIPs -nopass) # 4. Password Switches # -nopass = generates keys with no password protection # -pass = generates keys with password protection # 5. A directory will be created based on the filename given as input and all CSR and Keys will be hosted there. ########################################## build_config () { cat > $1 <<EOM #EDIT Below to match your business needs default_days = 3650 #1 year = 365 #2 years = 730, 3 years = 1095 4yrs = 1460 5yrs = 1825 default_crl_days= 30 # how long before next CRL default_md = sha256 # which md to use. preserve = no # keep passed DN ordering #################################################################### [ req ] default_bits = 2048 #Default Message Digest, change to highest supported by your version of OpenSSL + End Points. default_md = sha256 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = US countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = [EDIT] localityName = Locality Name (eg, city) localityName_default = [EDIT] 0.organizationName = Organization Name (eg, company) 0.organizationName_default = [EDIT] organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = [EDIT] commonName = Common Name (eg, your name or your server\'s hostname) commonName_max = 64 commonName_default = $DeviceID emailAddress = Email Address emailAddress_max = 64 emailAddress_default = [EDIT] # SET-ex3 = SET extension number 3 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 [ usr_cert ] basicConstraints=CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement nsComment = "Certificate for Fort Awesome Uses" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement subjectKeyIdentifier = hash #subjectAltName = @alt_names #[alt_names] #IP.1 = 192.168.0.75 [ v3_ca ] # Extensions for a typical CA subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = CA:true keyUsage = cRLSign, keyCertSign EOM } FILE=$1 OPT=$2 case $OPT in -pass) if [ $# -ne 0 ] && [ -f "$1" ] ; then /bin/mkdir `pwd`/"$1-keys" echo "Creating Private key and Certificate Signing Requests (CSR) directory at: `pwd`/"$1-keys"" DATADIR="$1-keys" for DeviceID in `/bin/cat $1` do SSLEAY="./openssl-custom.cnf" build_config $SSLEAY $DeviceID PASSPHRASE=`/bin/cat /dev/urandom| tr -dc 'a-zA-Z0-9-_!@#$%^&*()_+{}|:<>?='|fold -w 20| head -n 1| grep -i '[!@#$%^&*()_+{}|:<>?=]'` echo $PASSPHRASE > $DATADIR/tmp.file echo "Generating Key and CSR for $DeviceID..." #Generate Keys with Password Protection /usr/bin/openssl req -batch -config $SSLEAY -out $DATADIR/$DeviceID.csr -new -newkey rsa:2048 -passout file:$DATADIR/tmp.file -keyout $DATADIR/$DeviceID.key echo "$DeviceID - $PASSPHRASE" >> $DATADIR/passwords rm -rf $SSLEAY rm -rf $DATADIR/tmp.file #chmod $640 $DeviceID.csr cat $DATADIR/$DeviceID.csr done echo "Private key and Certificate Signing Requests (CSR) can be found at: `pwd`/"$1-keys"" fi ;; -nopass) if [ $# -ne 0 ] && [ -f "$1" ] ; then /bin/mkdir `pwd`/"$1-keys" echo "Creating Private key and Certificate Signing Requests (CSR) directory at: `pwd`/"$1-keys"" DATADIR="$1-keys" for DeviceID in `/bin/cat $1` do SSLEAY="./openssl-custom.cnf" build_config $SSLEAY $DeviceID echo "Generating Key and CSR for $DeviceID..." #Generate Keys without Password Protection /usr/bin/openssl req -batch -nodes -config $SSLEAY -out $DATADIR/$DeviceID.csr -new -newkey rsa:2048 -keyout $DATADIR/$DeviceID.key rm -rf $SSLEAY #chmod $640 $DeviceID.csr cat $DATADIR/$DeviceID.csr done echo "Private key and Certificate Signing Requests (CSR) can be found at: `pwd`/"$1-keys"" fi ;; *) echo -e "WARNING: Invalid command line parameters supplied\n" echo "Usage:" echo "./createkeys.sh input-file -password-switch" echo "Input File:" echo -e " The input file should contain one unique ID per line" echo -e " the unique IDs may be IPs, FQDN, Device Serial numbers, etc." echo "Password switches:" echo -e "\t-pass - creates keys with randomly generated password protection" echo -e "\t-nopass - creates keys with no password protection" exit 0 ;; esac