381 lines
11 KiB
Bash
381 lines
11 KiB
Bash
#!/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"
|
|
}
|
|
|