#!/bin/bash # # all main functions to generate a PKI certificate chain # # # Set the CA variables # # pki_func_init() { # if [[ -n $1 ]] || [[ -n $2 ]] || [[ -n $3 ]]; then # FQ_CA_CERT=$1 # FQ_CA_KEYS=$2 # CNF_PATH=$3 # APP_INIT=1 # else # APP_INIT=0 # fi # } # # print text wrapped in a block # echo_block() { echo echo "***** ***** ***** *****" echo $1 echo "***** ***** ***** *****" } error_no_ca_file() { echo_block "ERROR: missing ca.crt.pem, ca.keys.pem" usage } # # Grab the latest serial # from the file, auto-increment # get_serial() { SERIAL=`head cfg/SERIAL` if [[ -z $SERIAL ]]; then SERIAL=11111 echo_block "WARN: no file 'SERIAL' found, using default 11111 as the serial # for CA" else PLUS1=$((SERIAL+1)) echo $PLUS1 > cfg/SERIAL fi } # # check the three parameters: $PARAM1, $PARAM2, $PARAM3 # the parameters are expected to be global # check_params() { if [[ ! -f cfg/ca.keys.pem ]] || [[ ! -f cfg/ca.crt.pem ]]; then if [[ ! -f cfg/ca-i.keys.pem ]] || [[ ! -f cfg/ca-i.crt.pem ]]; then echo_block "ERROR: missing ca certificat: cfg/ca.crt.pem, cfg/ca.keys.pem, cfg/ca-i.crt.pem, cfg/ca-i.keys.pem" usage fi fi # the parameter must be the URL (not the filename, .cnf) if [[ -n $PARAM1 ]]; then if [[ ${PARAM1: -4} == .cnf ]]; then if [[ ! -f "cfg/${PARAM1}" ]]; then echo_block "ERROR: file cfg/${PARAM1} is missing" usage else PARAM1=${PARAM1%.*} fi else if [[ ! -f "cfg/${PARAM1}.cnf" ]]; then echo_block "ERROR: file cfg/${PARAM1}.cnf is missing" usage fi fi else usage fi if [[ -z $PARAM2 ]]; then if [[ ! -f cfg/SERIAL ]]; then echo_block "ERROR: file cfg/SERIAL is missing" usage else get_serial PARAM2=$SERIAL fi else SERIAL=$PARAM2 fi if [[ -z $PARAM3 ]]; then PARAM3=2 fi } # ***** ***** ***** ***** ***** # # CERTIFICATE AUTHORITY (CA) # # ***** ***** ***** ***** ***** # This function will generate a CA Intermediate # IN: UNIQ_ID_CA, SERIAL # gen_ca() { UNIQ_ID_CA=$1 SERIAL=$2 echo_block "Create CA (${UNIQ_ID_CA})" # encrypt the key #openssl genrsa -aes256 -out ca.keys.pem 4096 #openssl genrsa -aes256 -password "pass:password" -out ca.keys.pem 4096 # key un-protected openssl genrsa -out "ca_${UNIQ_ID_CA}.keys.pem" 4096 # # Create Certificate (valid for 10 years, after the entire chain of trust expires) openssl req -config $CNF_PATH/ca.cnf -new -x509 -sha256 -days 3650 -extensions v3_ca \ -subj "/C=OO/O=ACME/CN=root.${UNIQ_ID_CA}" -set_serial ${SERIAL} \ -key ca_${UNIQ_ID_CA}.keys.pem -out ca_${UNIQ_ID_CA}.crt.pem # verify certificate (output to text file for review) openssl x509 -noout -text -in ca_${UNIQ_ID_CA}.crt.pem > ca_${UNIQ_ID_CA}_cert.info.txt } # # Create CA Intermediate PKI # # # # Generate a PKI chain # - the certificate chain is unique based on the serial # # - generate a new CA I # - generate server certificates # - generate client certificates # # INPUT: BASE SERIAL #, LOOP NUM # ca-i_gen_pki() { CDD=`pwd` ORG_URL=$PARAM1 NUM_CERTS=$(($PARAM3-1)) # create unique directory UNIQ_ID="${SERIAL}.${ORG_URL}" mkdir -p "distribution/ca_i_${UNIQ_ID}" # Create CA Intermediate # ca-i_gen_cert $ORG_URL $SERIAL # create directories, copy files, before generating client/server ca-i_create_shell # the client & server applications need to execute in their perspective directories cd "distribution/ca_i_${UNIQ_ID}" __ca-i_gen_client # __ca-i_gen_server # return to last path cd $CDD } # # Client Certificates # __ca-i_gen_client() { # create directories mkdir -p clients/data mkdir -p clients/distro mkdir -p clients/docs cd clients for NUM in $(seq 0 $NUM_CERTS) do get_serial gen_client_cert $ORG_URL $SERIAL done cd .. } # # Server Certificates # __ca-i_gen_server() { # create directories mkdir -p servers/data mkdir -p servers/distro mkdir -p servers/docs cd servers for NUM in $(seq 0 $NUM_CERTS) do get_serial gen_server_cert $ORG_URL $SERIAL done cd .. } # # Copies all applcations to the Lifecycle package # organize the ca-i directory # order matters: move these files last because they were copied above # ca-i_create_shell() { DEST_DIR="${CDD}/distribution/ca_i_${UNIQ_ID}" echo $UNIQ_ID > UNIQ_ID # client mkdir -p $DEST_DIR/clients/cfg cp $CDD/res/libs/gen_client.sh $DEST_DIR/clients/ cp $CDD/res/libs/pki_funcs.sh $DEST_DIR/clients/cfg cp $CDD/res/docs/README_C $DEST_DIR/clients/README cp $CDD/res/docs/SERIAL $DEST_DIR/clients/cfg/ cp "${CDD}/cfg/${ORG_URL}.cnf" $DEST_DIR/clients/cfg/ # generated files cp ca_i*.crt.pem $DEST_DIR/clients/cfg/ca-i.crt.pem cp ca_i*.keys.pem $DEST_DIR/clients/cfg/ca-i.keys.pem cp ca_cert-chain*.pem $DEST_DIR/clients/cfg/ca_cert-chain.crts.pem cp UNIQ_ID $DEST_DIR/clients/cfg/ # cp $DEST_DIR/ca_i*.crt.pem $DEST_DIR/clients/cfg/ca-i.crt.pem # cp $DEST_DIR/ca_i*.keys.pem $DEST_DIR/clients/cfg/ca-i.keys.pem # cp $DEST_DIR/ca_cert-chain*.pem $DEST_DIR/clients/cfg/ca_cert-chain.crts.pem # server mkdir -p $DEST_DIR/servers/cfg cp $CDD/res/libs/gen_server.sh $DEST_DIR/servers/ cp $CDD/res/libs/pki_funcs.sh $DEST_DIR/servers/cfg/ cp $CDD/res/docs/README_S $DEST_DIR/servers/README cp $CDD/res/docs/SERIAL $DEST_DIR/servers/cfg/ cp "${CDD}/cfg/${ORG_URL}.cnf" $DEST_DIR/servers/cfg/ # generated files cp ca_i*.crt.pem $DEST_DIR/servers/cfg/ca-i.crt.pem cp ca_i*.keys.pem $DEST_DIR/servers/cfg/ca-i.keys.pem cp ca_cert-chain*.pem $DEST_DIR/servers/cfg/ca_cert-chain.crts.pem cp UNIQ_ID $DEST_DIR/servers/cfg/ # cp $DEST_DIR/ca_i*.crt.pem $DEST_DIR/servers/cfg/ca-i.crt.pem # cp $DEST_DIR/ca_i*.keys.pem $DEST_DIR/servers/cfg/ca-i.keys.pem # cp $DEST_DIR/ca_cert-chain*.pem $DEST_DIR/servers/cfg/ca_cert-chain.crts.pem # CA-I mkdir -p $DEST_DIR/ca-i/data mkdir -p $DEST_DIR/ca-i/docs mkdir -p $DEST_DIR/ca-i/distro cp $CDD/res/docs/README_CAI $DEST_DIR/README cp $CDD/ca_*/ca_*.crt.pem $DEST_DIR/ca-i/data/ cp $CDD/ca_*/ca_*.info.txt $DEST_DIR/ca-i/docs/ # generated files mv ca_i*.pem $DEST_DIR/ca-i/data/ mv ca_i*.info.txt $DEST_DIR/ca-i/docs/ mv ca_i*.p12 $DEST_DIR/ca-i/distro mv ca_cert-chain*.pem $DEST_DIR/ca-i/distro # mv $DEST_DIR/ca_i*.pem $DEST_DIR/ca-i/data/ # mv $DEST_DIR/ca_i*.info.txt $DEST_DIR/ca-i/docs/ # mv $DEST_DIR/ca_i*.p12 $DEST_DIR/ca-i/distro # mv $DEST_DIR/ca_cert-chain*.pem $DEST_DIR/ca-i/distro } # This function will generate a CA Intermediate # # Requires: CNF file, CA cert, CA key # # IN: UNIQ_ID_CA, SERIAL # ca-i_gen_cert() { ORG_URL=$1 SERIAL=$2 DEST_DIR="." # DEST_DIR=$3 UNIQ_ID="${SERIAL}.${ORG_URL}" echo_block "Create CA Intermediate (${UNIQ_ID})" openssl genrsa -out "${DEST_DIR}/ca_i_${UNIQ_ID}.keys.pem" 4096 # Create Cert Signing Request (CSR) openssl req -config "cfg/ca.cnf" -new -sha256 \ -subj "/C=OO/O=ACME/OU=ACME Intermediate/CN=${UNIQ_ID}" \ -key "${DEST_DIR}/ca_i_${UNIQ_ID}.keys.pem" -out "${DEST_DIR}/ca_i_${UNIQ_ID}.csr.pem" # Create Certificate (valid for ~2 years, after the entire chain of trust expires) # CA signs Intermediate openssl x509 -req -days 750 -extfile "cfg/ca.cnf" -extensions v3_ca_i \ -CA cfg/ca.crt.pem -CAkey cfg/ca.keys.pem -set_serial ${SERIAL} \ -in "${DEST_DIR}/ca_i_${UNIQ_ID}.csr.pem" -out "${DEST_DIR}/ca_i_${UNIQ_ID}.crt.pem" # Package the Certificate Authority Certificates for distro (windoze needs this) openssl pkcs12 -export -password "pass:password" -inkey "${DEST_DIR}/ca_i_${UNIQ_ID}.keys.pem" \ -name "CA Intermediate Mobile Provision" -certfile cfg/ca.crt.pem \ -in "${DEST_DIR}/ca_i_${UNIQ_ID}.crt.pem" -out "${DEST_DIR}/ca_i_${UNIQ_ID}.p12" # verify certificate (output to text file for review) openssl x509 -noout -text -in "${DEST_DIR}/ca_i_${UNIQ_ID}.crt.pem" > "${DEST_DIR}/ca_i_${UNIQ_ID}.crt.info.txt" # create certifiate chain cat cfg/ca.crt.pem "${DEST_DIR}/ca_i_${UNIQ_ID}.crt.pem" > "${DEST_DIR}/ca_cert-chain_${UNIQ_ID}.crts.pem" } get_org_url() { ORG_URL=`head cfg/UNIQ_ID` if [[ -z $ORG_URL ]]; then echo_block "WARN: no file 'UNIQ_ID' found, using default 11111 as the serial # for CA" exit 1 fi } gen_client() { get_org_url get_client_cert $ORG_URL $SERIAL } # # Generate a Client Certificate # IN: UNIQ_ID, SERIAL # gen_client_cert() { ORG_URL=$1 SERIAL=$2 UNIQ_ID="${SERIAL}.${ORG_URL}" CERT_CHAIN="cfg/ca_cert-chain.crts.pem" echo_block "Generate Client Certificates (${UNIQ_ID})" openssl genrsa -out "data/client_${UNIQ_ID}.keys.pem" 4096 openssl req -new -key "data/client_${UNIQ_ID}.keys.pem" \ -subj "/C=OO/O=ACME/OU=ACME Standard/CN=client_${UNIQ_ID}" \ -out "data/client_${UNIQ_ID}.csr.pem" # CA Intermediate signs Client openssl x509 -req -days 365 \ -CA "cfg/ca-i.crt.pem" -CAkey "cfg/ca-i.keys.pem" -set_serial ${SERIAL} \ -in "data/client_${UNIQ_ID}.csr.pem" -out "data/client_${UNIQ_ID}.crt.pem" # Package the Certificates openssl pkcs12 -export -password "pass:password" -inkey "data/client_${UNIQ_ID}.keys.pem" \ -name "Client ${UNIQ_ID} VPN Certificate" -certfile $CERT_CHAIN -caname "client_${UNIQ_ID}@acme.xyz" \ -in "data/client_${UNIQ_ID}.crt.pem" -out "distro/client_${UNIQ_ID}.p12" # verify certificate (output to text file for review) openssl x509 -noout -text -in "data/client_${UNIQ_ID}.crt.pem" > "docs/client_${UNIQ_ID}.info.txt" } # # Generate a Server Certificate # IN: UNIQ_ID, SERIAL # gen_server_cert() { ORG_URL=$1 SERIAL=$2 UNIQ_ID="${SERIAL}.${ORG_URL}" CERT_CHAIN="cfg/ca_cert-chain.crts.pem" echo_block "Generate Server Certificates (${UNIQ_ID})" openssl genrsa -out "data/server_${UNIQ_ID}.keys.pem" 4096 openssl req -new -config "cfg/${ORG_URL}.cnf" -key "data/server_${UNIQ_ID}.keys.pem" \ -subj "/C=OO/O=ACME/OU=ACME Standard/CN=${UNIQ_ID}" \ -out "data/server_${UNIQ_ID}.csr.pem" # CA Intermediate signs Server openssl x509 -req -days 365 -extfile "cfg/${ORG_URL}.cnf" -extensions v3_server \ -CA "cfg/ca-i.crt.pem" -CAkey "cfg/ca-i.keys.pem" -set_serial ${SERIAL} \ -in "data/server_${UNIQ_ID}.csr.pem" -out "data/server_${UNIQ_ID}.crt.pem" # Package the Certificates openssl pkcs12 -export -password "pass:password" -inkey "data/server_${UNIQ_ID}.keys.pem" \ -name "Server ${UNIQ_ID} VPN Certificate" -certfile $CERT_CHAIN -caname "server_${UNIQ_ID}@acme.xyz" \ -in "data/server_${UNIQ_ID}.crt.pem" -out "distro/server_${UNIQ_ID}.p12" # verify certificate (output to text file for review) openssl x509 -noout -text -in "data/server_${UNIQ_ID}.crt.pem" > "docs/server_${UNIQ_ID}.crt.info.txt" }