initial commit of ca-scripts devel work
This commit is contained in:
commit
348a0df638
19 changed files with 1121 additions and 0 deletions
169
bin/ca-create-cert
Executable file
169
bin/ca-create-cert
Executable file
|
@ -0,0 +1,169 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
. "/home/alex/code/ca-scripts/lib/ca-functions"
|
||||||
|
|
||||||
|
ALT_NAMES=()
|
||||||
|
TPL_ONLY=0
|
||||||
|
CSR_ONLY=0
|
||||||
|
CRT_ONLY=0
|
||||||
|
MAKE_P12=0
|
||||||
|
|
||||||
|
# XXX: in the ca_extension_policy section of ca-config.tpl it states that the
|
||||||
|
# C= and O= DN values in a CSR have to match those of the CA
|
||||||
|
# should we have options here to change them when it will cause breakage?
|
||||||
|
usage() {
|
||||||
|
cat <<__EOT__
|
||||||
|
Usage:
|
||||||
|
$PROGNAME -t server [options] <hostname>
|
||||||
|
$PROGNAME -t client [options] <hostname>
|
||||||
|
$PROGNAME -t user [options] <username>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this helpful message!
|
||||||
|
-c, --encrypt Encrypt certificate private key with Triple-DES
|
||||||
|
-f, --config FILE Use config file instead of $CONFFILE
|
||||||
|
-t, --type Certificate type: "server", "client" or "user"
|
||||||
|
-n, --alt-name Alternative host name (can be provided multiple times)
|
||||||
|
-p, --pkcs12 Create PKCS#12 certificate archive from generated cert
|
||||||
|
-r, --csr-only Only generate CSR, don't sign it
|
||||||
|
-s, --crt-only Only sign certificate, requires CSR in place
|
||||||
|
-x, --tpl-only Only generate templates, do not create CSR or sign CRT
|
||||||
|
--country Certificate DN -- C
|
||||||
|
--state Certificate DN -- ST
|
||||||
|
--loc Certificate DN -- L
|
||||||
|
--org Certificate DN -- O
|
||||||
|
--org-unit Certificate DN -- OU
|
||||||
|
--email Certificate DN -- E
|
||||||
|
--comment Certificate nsComment field
|
||||||
|
|
||||||
|
__EOT__
|
||||||
|
}
|
||||||
|
|
||||||
|
short='hcf:t:n:prsx'
|
||||||
|
long='help,encrypt.config:,type:,alt-name:,csr-only,crt-only,tpl-only,pkcs12'
|
||||||
|
long="$long,country:,state:,loc:,org:,org-unit:,email:,comment:"
|
||||||
|
opts=$( getopt -o "$short" -l "$long" -n "$PROGNAME" -- "$@" )
|
||||||
|
if [ 0 -ne $? ]; then echo; usage; exit 1; fi
|
||||||
|
eval set -- "$opts";
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
-c|--encrypt) CRYPTKEY=""; shift;;
|
||||||
|
-f|--config) shift; CONFFILE="$1"; shift;;
|
||||||
|
-t|--type) shift; CA_CRT_TYPE="$1"; shift;;
|
||||||
|
-n|--alt-name) shift; ALT_NAMES+=("$1"); shift;;
|
||||||
|
-p|--pkcs12) MAKE_P12=1; shift;;
|
||||||
|
-r|--csr-only) CSR_ONLY=1; shift;;
|
||||||
|
-s|--crt-only) CRT_ONLY=1; shift;;
|
||||||
|
-x|--tpl-only) TPL_ONLY=1; shift;;
|
||||||
|
--country) shift; CA_CRT_C="$1"; shift;;
|
||||||
|
--state) shift; CA_CRT_ST="$1"; shift;;
|
||||||
|
--location) shift; CA_CRT_L="$1"; shift;;
|
||||||
|
--org) shift; CA_CRT_O="$1"; shift;;
|
||||||
|
--org-unit) shift; CA_CRT_OU="$1"; shift;;
|
||||||
|
--email) shift; CA_CRT_E="$1"; shift;;
|
||||||
|
--comment) shift; CA_CRT_COMMENT="$1"; shift;;
|
||||||
|
--) shift; break;;
|
||||||
|
*) echo "Unknown value '$1'"; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
CA_CRT_CN="$1";
|
||||||
|
|
||||||
|
# load up the configuration file
|
||||||
|
ca_load_conf
|
||||||
|
|
||||||
|
# parameter checking fun -- we need a type and a cn (either user or host name)
|
||||||
|
if [ -z "$CA_CRT_CN" ]; then
|
||||||
|
error "The host or username parameter is mandatory!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ 1 -eq "$CSR_ONLY" -a 1 -eq "$CRT_ONLY" ]; then
|
||||||
|
error "Options --csr-only and --crt-only are mutually exclusive."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CA_CRT_TYPE" = "user" ]; then
|
||||||
|
# append @$CA_DOMAIN to user CN if it's not already there
|
||||||
|
if [ "${CA_CRT_CN%%@*}" = "$CA_CRT_CN" ]; then
|
||||||
|
CA_CRT_CN="$CA_CRT_CN@$CA_DOMAIN";
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# fully qualify server or client CN with $CA_DOMAIN if it's not already
|
||||||
|
if [ "${CA_CRT_CN%%.*}" = "$CA_CRT_CN" ]; then
|
||||||
|
# however we may also want the unqualified one as an alt-name
|
||||||
|
ALT_NAMES+=("$CA_CRT_CN")
|
||||||
|
CA_CRT_CN="$CA_CRT_CN.$CA_DOMAIN"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
CNF_NAME=$( echo -n "$CA_CRT_CN" | tr -c '[:alnum:]@-' _ )".$CA_CRT_TYPE";
|
||||||
|
|
||||||
|
# if they've provided a comment, reformat it correctly
|
||||||
|
if [ -n "$CA_CRT_COMMENT" ]; then
|
||||||
|
CA_CRT_COMMENT="$( tr -d\" <<< $CA_CRT_COMMENT )"
|
||||||
|
CA_CRT_COMMENT="nsComment = \"$CA_CRT_COMMENT\"\n"
|
||||||
|
else
|
||||||
|
CA_CRT_COMMENT=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
CA_CRT_ALT_NAMES=""
|
||||||
|
# generate a list of alternative DNS names for server certificates
|
||||||
|
if [ "$CA_CRT_TYPE" = "server" ]; then
|
||||||
|
i=1
|
||||||
|
for ALT_NAME in "$CA_CRT_CN" "${ALT_NAMES[@]}"; do
|
||||||
|
# also fully-qualify unqualified alt-names too (see below)
|
||||||
|
if [ "${ALT_NAME%%.*}" = "$ALT_NAME" ]; then
|
||||||
|
CA_CRT_ALT_NAMES="${CA_CRT_ALT_NAMES}DNS.$i=$ALT_NAME.$CA_DOMAIN\n"
|
||||||
|
i=$(( $i+1 ))
|
||||||
|
fi
|
||||||
|
CA_CRT_ALT_NAMES="${CA_CRT_ALT_NAMES}DNS.$i=$ALT_NAME\n"
|
||||||
|
i=$(( $i+1 ))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ 1 -ne "$CRT_ONLY" ]; then
|
||||||
|
if [ 1 -eq "$TPL_ONLY" -o "$CSR_ONLY" -eq "$TPL_ONLY" ]; then
|
||||||
|
# dirty logic here that probably needs commenting!
|
||||||
|
# generate a *new* certificate request configuration if...
|
||||||
|
# a) --tpl-only is set, i.e. we only want to generate a config
|
||||||
|
# b) both --tpl-only and --csr-only are unset, i.e.
|
||||||
|
# we're just generating a csr/crt as per usual
|
||||||
|
# c) both --tpl-only and --csr-only are set, i.e.
|
||||||
|
# we're just generating the config and not the csr itself
|
||||||
|
ca_template "req-config" "$CA_HOME/cnf/$CNF_NAME.req.cnf"
|
||||||
|
fi
|
||||||
|
if [ 1 -ne "$TPL_ONLY" ]; then
|
||||||
|
if [ ! -f "$CA_HOME/cnf/$CNF_NAME.req.cnf" ]; then
|
||||||
|
error "Couldn't find CSR config $CA_HOME/cnf/$CNF_NAME.req.cnf!"
|
||||||
|
fi
|
||||||
|
# the above logic means that if you pass --csr-only but not
|
||||||
|
# --tpl-only, you can re-use a pre-existing config to generate
|
||||||
|
# a new csr, should you wish to do so...
|
||||||
|
openssl req -new $CRYPTKEY -config "$CA_HOME/cnf/$CNF_NAME.req.cnf" \
|
||||||
|
-keyout "$CA_HOME/key/$CNF_NAME.key" \
|
||||||
|
-out "$CA_HOME/csr/$CNF_NAME.csr"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ 1 -ne "$CSR_ONLY" ]; then
|
||||||
|
if [ 1 -eq "$TPL_ONLY" -o "$CRT_ONLY" -eq "$TPL_ONLY" ]; then
|
||||||
|
# same logic above applies here, but for generating the extensions
|
||||||
|
# configuration file and signed certificate instead
|
||||||
|
ca_template "$CA_CRT_TYPE-ext" "$CA_HOME/cnf/$CNF_NAME.ext.cnf"
|
||||||
|
fi
|
||||||
|
if [ 1 -ne "$TPL_ONLY" ]; then
|
||||||
|
# ensure relevant files are in place before continuing...
|
||||||
|
if [ ! -f "$CA_HOME/csr/$CNF_NAME.csr" ]; then
|
||||||
|
error "CSR not present in $CA_HOME/csr/$CNF_NAME.csr"
|
||||||
|
fi
|
||||||
|
if [ ! -f "$CA_HOME/cnf/$CNF_NAME.ext.cnf" ]; then
|
||||||
|
error "Couldn't find extensions in $CA_HOME/cnf/$CNF_NAME.ext.cnf"
|
||||||
|
fi
|
||||||
|
openssl ca -config "$CA_HOME/cnf/$CA_NAME.ca.cnf" \
|
||||||
|
-extfile "$CA_HOME/cnf/$CNF_NAME.ext.cnf" -batch \
|
||||||
|
-out "$CA_HOME/crt/$CNF_NAME.crt" \
|
||||||
|
-in "$CA_HOME/csr/$CNF_NAME.csr"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ 1 -eq "$MAKE_P12" ]; then
|
||||||
|
ca_gen_p12 "$CNF_NAME"
|
||||||
|
fi
|
72
bin/ca-init
Executable file
72
bin/ca-init
Executable file
|
@ -0,0 +1,72 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
. "/home/alex/code/ca-scripts/lib/ca-functions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<__EOT__
|
||||||
|
Usage: $PROGNAME [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this helpful message!
|
||||||
|
-c, --encrypt Encrypt CA private key with Triple-DES
|
||||||
|
-f, --config FILE Use config file instead of $CONFFILE
|
||||||
|
-i, --template FILE Use alternative index.html template
|
||||||
|
-o, --output FILE Generate CA index.html in FILE
|
||||||
|
|
||||||
|
__EOT__
|
||||||
|
}
|
||||||
|
|
||||||
|
short='hcf:i:o:'
|
||||||
|
long='help,encrypt,config:,template:,output:'
|
||||||
|
opts=$( getopt -o "$short" -l "$long" -n "$PROGNAME" -- "$@" )
|
||||||
|
if [ 0 -ne $? ]; then echo; usage; exit 1; fi
|
||||||
|
eval set -- "$opts";
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
-c|--encrypt) CRYPTKEY=""; shift;;
|
||||||
|
-f|--config) shift; CONFFILE="$1"; shift;;
|
||||||
|
-i|--template) shift; INDEXTPL="$1"; shift;;
|
||||||
|
-o|--output) shift; INDEXOUT="$1"; shift;;
|
||||||
|
--) shift; break;;
|
||||||
|
*) echo "Unknown value '$1'"; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# load up the configuration file
|
||||||
|
CA_CRT_TYPE="ca"
|
||||||
|
ca_load_conf
|
||||||
|
|
||||||
|
# create the directory structure that'll be populated by the scripts
|
||||||
|
mkdir -p $CA_HOME/{cnf,crl,crt,csr,db,idx,key,p12}
|
||||||
|
echo "01" > $CA_HOME/db/crlnumber
|
||||||
|
touch $CA_HOME/db/index.txt
|
||||||
|
touch $CA_HOME/db/.rand
|
||||||
|
chmod 600 $CA_HOME/db/.rand
|
||||||
|
chmod 700 $CA_HOME/key
|
||||||
|
|
||||||
|
# generate an openssl configuration for this CA
|
||||||
|
ca_template ca-config "$CA_HOME/cnf/$CA_NAME.ca.cnf"
|
||||||
|
|
||||||
|
# generate a self-signed cert that is valid for 10 years, with
|
||||||
|
# ... the private key in $CA_HOME/key/$CA_NAME.ca.key
|
||||||
|
# ... the certificate in $CA_HOME/crt/$CA_NAME.ca.crt
|
||||||
|
# ... using the config in $CA_HOME/cnf/$CA_NAME.ca.cnf
|
||||||
|
openssl req -new $CRYPTKEY -config "$CA_HOME/cnf/$CA_NAME.ca.cnf" \
|
||||||
|
-keyout "$CA_HOME/key/$CA_NAME.ca.key" \
|
||||||
|
-out "$CA_HOME/csr/$CA_NAME.ca.csr"
|
||||||
|
|
||||||
|
openssl ca -create_serial -selfsign -days 3652 -batch \
|
||||||
|
-name ca_scripts -extensions ca_x509_extensions \
|
||||||
|
-config "$CA_HOME/cnf/$CA_NAME.ca.cnf" \
|
||||||
|
-in "$CA_HOME/csr/$CA_NAME.ca.csr" \
|
||||||
|
-keyfile "$CA_HOME/key/$CA_NAME.ca.key" \
|
||||||
|
-out "$CA_HOME/crt/$CA_NAME.ca.crt"
|
||||||
|
|
||||||
|
# generate an initial CRL too (yes it will be empty, but we should serve it)
|
||||||
|
ca_gen_crl
|
||||||
|
if [ -n "$INDEXOUT" ]; then
|
||||||
|
ca_checksum
|
||||||
|
ca_template $INDEXTPL $INDEXOUT
|
||||||
|
fi
|
80
bin/ca-renew-cert
Executable file
80
bin/ca-renew-cert
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
. "/home/alex/code/ca-scripts/lib/ca-functions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<__EOT__
|
||||||
|
Usage: $PROGNAME -t <type> [options] <hostname|username|certpath>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this helpful message!
|
||||||
|
-f, --config FILE Use config file instead of $CONFFILE
|
||||||
|
-t, --type Certificate type: "server", "client" or "user"
|
||||||
|
|
||||||
|
__EOT__
|
||||||
|
}
|
||||||
|
|
||||||
|
short='hf:t:'
|
||||||
|
long='help,config:,type:'
|
||||||
|
opts=$( getopt -o "$short" -l "$long" -n "$PROGNAME" -- "$@" )
|
||||||
|
if [ 0 -ne $? ]; then echo; usage; exit 1; fi
|
||||||
|
eval set -- "$opts";
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
-f|--config) shift; CONFFILE="$1"; shift;;
|
||||||
|
-t|--type) shift; CA_CRT_TYPE="$1"; shift;;
|
||||||
|
--) shift; break;;
|
||||||
|
*) echo "Unknown value '$1'"; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
CNF_NAME="$1"
|
||||||
|
|
||||||
|
ca_load_conf
|
||||||
|
|
||||||
|
CNF_NAME=$( ca_find_cnf "$CNF_NAME" )
|
||||||
|
CRT="$CA_HOME/crt/$CNF_NAME.crt"
|
||||||
|
|
||||||
|
# make sure that configuration files are present as expected
|
||||||
|
if [ ! -f "$CA_HOME/cnf/$CNF_NAME.ext.cnf" ]; then
|
||||||
|
error "Couldn't find extensions in $CA_HOME/cnf/$CNF_NAME-ext.cnf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# according to the below URL we should create the new CRT using the old CSR
|
||||||
|
# and with the same serial as the previous certificate.
|
||||||
|
# http://blog.fupps.com/2007/11/30/x509ssl-certificate-prolongation/
|
||||||
|
# After some fun googling, I found the following URL which tells us how...
|
||||||
|
# http://ca.dutchgrid.nl/info/CA_gymnastics.html
|
||||||
|
# XXX: this is only *really* relevant for certs that have been used for code
|
||||||
|
# or e-mail encryption. should we regenerate client/server certs entirely?
|
||||||
|
# ... for the moment there's always the revoke/recreate route for people.
|
||||||
|
|
||||||
|
# acquire required info from old certificate
|
||||||
|
ENDDATE=$( openssl x509 -in "$CRT" -noout -enddate | cut -d= -f2 )
|
||||||
|
SERIAL=$( openssl x509 -in "$CRT" -noout -serial | cut -d= -f2 )
|
||||||
|
# work out new expiry date based on expiry date of current cert + 1 year
|
||||||
|
# these dates are "<year> <day of year>"
|
||||||
|
export TZ=UTC
|
||||||
|
NOWYEAR=$( date +%Y )
|
||||||
|
NOWDAYS=$( date +%j )
|
||||||
|
ENDYEAR=$( date +%Y -d "$ENDDATE + 1 year" )
|
||||||
|
ENDDAYS=$( date +%j -d "$ENDDATE + 1 year" )
|
||||||
|
CERTDATE=$( date +%Y-%m-%d -d "$ENDDATE" )
|
||||||
|
|
||||||
|
# and this does the maths to work out how many days there are from now
|
||||||
|
# (when we're creating the new cert) to the new expiry date
|
||||||
|
DAYS=$(( ($ENDYEAR-$NOWYEAR)*365 + ($ENDDAYS-$NOWDAYS) ))
|
||||||
|
|
||||||
|
# Now perform required CA gymnastics ;p
|
||||||
|
openssl x509 -req -set_serial "0x$SERIAL" -days "$DAYS" \
|
||||||
|
-CA "$CA_HOME/crt/$CA_NAME.ca.crt" \
|
||||||
|
-CAkey "$CA_HOME/key/$CA_NAME.ca.key" \
|
||||||
|
-extfile "$CA_HOME/cfg/$CNF_NAME.ext.cnf" \
|
||||||
|
-out "$CA_HOME/crt/$CNF_NAME.crt" \
|
||||||
|
-in "$CA_HOME/csr/$CNF_NAME.csr"
|
||||||
|
|
||||||
|
# This doesn't update the original certificate in the index, so let's do that
|
||||||
|
mv "$CA_HOME/idx/$SERIAL.pem" "$CA_HOME/idx/$SERIAL.$CERTDATE.pem"
|
||||||
|
cp "$CA_HOME/crt/$CNF_NAME.crt" "$CA_HOME/idx/$SERIAL.pem"
|
51
bin/ca-revoke-cert
Executable file
51
bin/ca-revoke-cert
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
. "/home/alex/code/ca-scripts/lib/ca-functions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<__EOT__
|
||||||
|
Usage: $PROGNAME -t <type> [options] <hostname|username|certpath>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this helpful message!
|
||||||
|
-f, --config FILE Use config file instead of $CONFFILE
|
||||||
|
-t, --type Certificate type: "server", "client" or "user"
|
||||||
|
-i, --template FILE Use alternative index.html template
|
||||||
|
-o, --output FILE Generate CA index.html in FILE
|
||||||
|
|
||||||
|
__EOT__
|
||||||
|
}
|
||||||
|
|
||||||
|
short='hf:t:i:o:'
|
||||||
|
long='help,config:,type:,template:,output:'
|
||||||
|
opts=$( getopt -o "$short" -l "$long" -n "$PROGNAME" -- "$@" )
|
||||||
|
if [ 0 -ne $? ]; then echo; usage; exit 1; fi
|
||||||
|
eval set -- "$opts";
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
-f|--config) shift; CONFFILE="$1"; shift;;
|
||||||
|
-t|--type) shift; CA_CRT_TYPE="$1"; shift;;
|
||||||
|
-i|--template) shift; INDEXTPL="$1"; shift;;
|
||||||
|
-o|--output) shift; INDEXOUT="$1"; shift;;
|
||||||
|
--) shift; break;;
|
||||||
|
*) echo "Unknown value '$1'"; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
CNF_NAME="$1"
|
||||||
|
|
||||||
|
ca_load_conf
|
||||||
|
|
||||||
|
CNF_NAME=$( ca_find_cnf "$CNF_NAME" "$TYPE" )
|
||||||
|
CRT="$CA_HOME/crt/$CNF_NAME.crt"
|
||||||
|
|
||||||
|
openssl ca -config $CA_HOME/cnf/$CA_NAME.ca.cnf \
|
||||||
|
-revoke $CRT -crl_reason superseded
|
||||||
|
|
||||||
|
ca_gen_crl
|
||||||
|
if [ -n "$INDEXOUT" ]; then
|
||||||
|
ca_checksum
|
||||||
|
ca_template $INDEXTPL $INDEXOUT
|
||||||
|
fi
|
||||||
|
|
45
ca-scripts.conf
Normal file
45
ca-scripts.conf
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# example ca-scripts configuration file
|
||||||
|
|
||||||
|
# REQUIRED: CA_HOME provides the path to the root of the CA directory tree
|
||||||
|
# this directory must exist and be writeable
|
||||||
|
#CA_HOME="/etc/ssl/ca"
|
||||||
|
CA_HOME="/tmp/ca"
|
||||||
|
|
||||||
|
# REQUIRED: CA_DOMAIN provides a template for other optional variables and
|
||||||
|
# the filenames that are generated within the directory tree
|
||||||
|
CA_DOMAIN="example.com"
|
||||||
|
|
||||||
|
# OPTIONAL: CA_NAME is the internal templating variable for filenames etc
|
||||||
|
# Defaults to:
|
||||||
|
# CA_NAME="$( echo $CA_DOMAIN | tr 'A-Z' 'a-z' | tr -c '-a-z0-9' '_' )"
|
||||||
|
|
||||||
|
# REQUIRED: CA_DN_* configures the Distinguished Name fields present in the
|
||||||
|
# CA certificate generated by ca-init
|
||||||
|
CA_DN_C="GB"
|
||||||
|
CA_DN_ST="London"
|
||||||
|
CA_DN_L="Example House, Mayfair"
|
||||||
|
CA_DN_O="Example Security Services Ltd."
|
||||||
|
CA_DN_OU="Example Internet Encryption Division"
|
||||||
|
CA_DN_CN="Example Security Services Root Certificate Authority"
|
||||||
|
|
||||||
|
# OPTIONAL: CA_DESC configures a single-line description for your CA
|
||||||
|
# using the CN= or O= line from your DN is recommended
|
||||||
|
# Default value:
|
||||||
|
# CA_DESC="$CA_DN_CN"
|
||||||
|
|
||||||
|
# OPTIONAL: CA_EMAIL provides an e-mail address that is embedded into all
|
||||||
|
# generated certificates as a point-of-contact
|
||||||
|
# Default value:
|
||||||
|
# CA_EMAIL="ca@$CA_DOMAIN"
|
||||||
|
|
||||||
|
# OPTIONAL: CA_CRT_URI and CA_CRL_URI provide locations where the CA
|
||||||
|
# certificate and revocation lists can be found
|
||||||
|
# Default value:
|
||||||
|
# CA_CRT_URI="http://$CA_DOMAIN/ca/$CA_NAME.ca.crt"
|
||||||
|
# CA_CRL_URI="http://$CA_DOMAIN/ca/$CA_NAME.ca.crl"
|
||||||
|
|
||||||
|
# OPTIONAL: CA_PATHLEN sets the maximum number of intermediate CA certificates
|
||||||
|
# that can be in the chain of authority between the root CA and the
|
||||||
|
# final certificate.
|
||||||
|
# Default value:
|
||||||
|
# CA_PATHLEN=0
|
61
doc/README
Normal file
61
doc/README
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
1. Creating a Certificate Authority.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To fully understand it's contents you're unfortunately going to need to read ca(1ssl),
|
||||||
|
req(1ssl), x509(1ssl), config(5ssl), and x509v3_config(5ssl). Particularly
|
||||||
|
important are the x509v3 extensions present in the certificate, which are
|
||||||
|
defined in the "stglab_x509_ca_extensions" section of the config file.
|
||||||
|
|
||||||
|
The ca-cert script configures some important files in db/, then creates a
|
||||||
|
certificate request and signs it. It also generates an initial (empty)
|
||||||
|
revocation list, then substitutes the correct fingerprints into the html
|
||||||
|
template for serving the CA certificate and CRL to the intranet.
|
||||||
|
|
||||||
|
2. Creating a certificate.
|
||||||
|
|
||||||
|
The create-cert script can generate three "types" of certificate -- server
|
||||||
|
certificates for securing a service with SSL/TLS, client certificates for
|
||||||
|
authenticating a client to these services, and user certificates for
|
||||||
|
authentication, S/MIME e-mail signing or encryption, and code signing. There
|
||||||
|
are minor but important differences in the extensions present in these
|
||||||
|
different certificate types, but these are set in the *-ext.tpl files in tpl/
|
||||||
|
and thus you shouldn't need to worry about them.
|
||||||
|
|
||||||
|
The create-cert script takes a number of arguments, of which the hostname or
|
||||||
|
username and the type are mandatory. It is also a very good idea to supply a
|
||||||
|
number of alternative DNS names when generating a server certificate, because
|
||||||
|
while the script will happily append "stglab.manchester.uk.ibm.com" to an
|
||||||
|
un-qualified host name, it won't append "transitives.com" and for the moment we
|
||||||
|
probably need that.
|
||||||
|
|
||||||
|
You should also provide a team name for the organisational unit, e.g.
|
||||||
|
"Manchester STG Lab Test", an e-mail address (preferably for the team rather
|
||||||
|
than an individual for server/client certificates), and a comment that reflects
|
||||||
|
the usage of the certificate, e.g. "Soak Infrastructure Live Server". Reasonable
|
||||||
|
defaults are provided for all of these for our team's use.
|
||||||
|
|
||||||
|
3. Renewing a certificate.
|
||||||
|
|
||||||
|
The renew-cert script does some painful certificate manipulation that is not
|
||||||
|
strictly necessary in most cases, and may in fact decrease SSL security
|
||||||
|
slightly. This is done because the normal renewal process re-generates the
|
||||||
|
certificate signing request and thus creates a new public/private keypair.
|
||||||
|
If the certificates are used for S/MIME encryption or code signing, this
|
||||||
|
renders all the encrypted e-mail unreadable and requires you to re-sign the
|
||||||
|
code with your new private key. The code in renew-cert re-signs the old
|
||||||
|
certificate request with a new expiry date and the extensions generated when
|
||||||
|
the original certificate was created, and avoids this problem.
|
||||||
|
|
||||||
|
Renewing a certificate is done by giving the hostname, username or path to
|
||||||
|
the certificate to renew-cert.sh.
|
||||||
|
|
||||||
|
4. Revoking a certificate.
|
||||||
|
|
||||||
|
Revoking a certificate is done by giving the hostname, username or path to
|
||||||
|
the certificat to revoke-cert.sh. This script also regenerates a new CRL in
|
||||||
|
both PEM and DER encodings (firefox prefers the latter while IE and other
|
||||||
|
browsers work better with the former), and re-generates the html file with the
|
||||||
|
new fingerprints.
|
||||||
|
|
17
doc/ca-cert.txt
Normal file
17
doc/ca-cert.txt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# a brief man-page for ca-cert.sh
|
||||||
|
# $Id: ca-cert.txt 2660 2009-07-24 18:49:52Z alexeb $
|
||||||
|
|
||||||
|
NAME
|
||||||
|
ca-cert.sh - generate a CA cert and perform initial db setup
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
ca-cert.sh
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This script generates a CSR and signs it to turn it into a root
|
||||||
|
certificate authority. It also sets up some important files in the CA
|
||||||
|
database directory, generates an initial empty revocation list, and
|
||||||
|
creates index.html from the template.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
This script takes no options.
|
97
doc/create-cert.txt
Normal file
97
doc/create-cert.txt
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# a brief man-page for create-cert.sh
|
||||||
|
# $Id: create-cert.txt 2660 2009-07-24 18:49:52Z alexeb $
|
||||||
|
|
||||||
|
NAME
|
||||||
|
create-cert.sh - generate a signed X.509 certificate
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
create-cert.sh -t server [options] <hostname>
|
||||||
|
create-cert.sh -t client [options] <hostname>
|
||||||
|
create-cert.sh -t user [options] <username>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The create-cert.sh script creates the configuration files necessary
|
||||||
|
for generating a signed X.509 certificate, creates a certificate
|
||||||
|
signing request using these configuration files, and signs that request
|
||||||
|
using the root CA key so that it is trusted by anything that has
|
||||||
|
imported the CA certificate.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-h, --help
|
||||||
|
Prints out a short synopsis of the arguments that this script takes.
|
||||||
|
|
||||||
|
-t, --type {server|client|user}
|
||||||
|
This argument is mandatory. create-cert.sh can create three types of
|
||||||
|
X.509 certificate: server, client, and user. These differ in the
|
||||||
|
X.509v3 extensions present, and in the uses the certificate is trusted
|
||||||
|
for.
|
||||||
|
|
||||||
|
Server certificates are used for securing SSL/TLS services, such as
|
||||||
|
TLS-encrypted LDAP connections or SSL HTTP. In this case the <hostname>
|
||||||
|
argument is used for the Common Name in the certificate, and any
|
||||||
|
additional alternative names supplied by -n are added to the X.509v3
|
||||||
|
"SubjectAltName" extension.
|
||||||
|
|
||||||
|
Client certificates are used for authenticating to SSL/TLS services.
|
||||||
|
For the most part they will be used by automated systems to identify
|
||||||
|
and authenticate to services they interact with.
|
||||||
|
|
||||||
|
User certificates are for individuals to authenticate themselves to
|
||||||
|
SSL/TLS services in the same manner as client certificates, but they
|
||||||
|
may also be used for S/MIME e-mail encryption and code signing.
|
||||||
|
|
||||||
|
-c, --comment "COMMENT"
|
||||||
|
This argument sets the "Netscape Comment" X.509 extension.
|
||||||
|
|
||||||
|
-n, --alt-name HOSTNAME
|
||||||
|
This argument adds an alternative hostname to the "SubjectAltName"
|
||||||
|
X.509v3 extension. It may be supplied multiple times to add more than
|
||||||
|
one additional hostname.
|
||||||
|
|
||||||
|
-l, --location LOCATION
|
||||||
|
This argument sets the "Location" field of the certificate's
|
||||||
|
distinguished name. Syggested values are "Maybrook House" and
|
||||||
|
"Jackson House", but the field is freeform text.
|
||||||
|
|
||||||
|
-o, --org-unit TEAMNAME
|
||||||
|
This argument sets the "Organisational Unit" field of the certificate's
|
||||||
|
distinguished name. Ideally this should begin with "Manchester STG Lab"
|
||||||
|
for consistency's sake, for example:
|
||||||
|
|
||||||
|
Manchester STG Lab Systems and Network Infrastructure
|
||||||
|
Manchester STG Lab Testing
|
||||||
|
Manchester STG Lab Starlight Development
|
||||||
|
|
||||||
|
-e, --email EMAIL
|
||||||
|
This argument sets the "E-Mail Address" field of the certificate's
|
||||||
|
distinguished name. As per current X.509 standards this is actually
|
||||||
|
removed from the DN of the CSR and placed into the "SubjectAltName"
|
||||||
|
extension in the signed certificate. In general it should be a team
|
||||||
|
alias rather than an individual's address for server and client certs.
|
||||||
|
|
||||||
|
-r, --csr-only
|
||||||
|
This argument causes create-cert.sh to only generate a new CSR. It will
|
||||||
|
not generate the request configuration files in cfg/ unless --tpl-only
|
||||||
|
is also passed; in this case it will just create the configuration
|
||||||
|
files instead. This allows you to re-generate a CSR after manually
|
||||||
|
tweaking the configuration files.
|
||||||
|
|
||||||
|
-s, --crt-only
|
||||||
|
This argument causes create-cert.sh to only sign an existing CSR. As
|
||||||
|
with --csr-only, it will not generate extension configuration files
|
||||||
|
unless --tpl-only is also passed; again in this case it will just
|
||||||
|
create the configuration files so that you can re-sign the same CSR
|
||||||
|
with new extensions.
|
||||||
|
|
||||||
|
-t, --tpl-only
|
||||||
|
This argument modifies the behaviour of the previous two options when
|
||||||
|
passed with them, as described above. On it's own it causes
|
||||||
|
create-cert.sh to generate both sets of configuration files, but
|
||||||
|
not generate either the signing request or the signed certificate.
|
||||||
|
|
||||||
|
DEFAULTS
|
||||||
|
* The LOCATION defaults to "Maybrook House"
|
||||||
|
* The TEAM defaults to "Manchester STG Lab Systems and Network Infrastructure"
|
||||||
|
* The EMAIL defaults to "mcr_lab_lsni@wwpdl.vnet.ibm.com"
|
||||||
|
* There is no COMMENT set by default
|
||||||
|
|
17
doc/create-p12.txt
Normal file
17
doc/create-p12.txt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# a brief man-page for create-p12.sh
|
||||||
|
# $Id: create-p12.txt 2660 2009-07-24 18:49:52Z alexeb $
|
||||||
|
|
||||||
|
NAME
|
||||||
|
create-p12.sh - create a PKCS#12 archive of a certificate and key
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
create-p12.sh /path/to/certificate
|
||||||
|
create-p12.sh <username>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This script exports a PKCS#12 archive containing a user's certificate,
|
||||||
|
private key, and the CA certificate. It will prompt for a password to
|
||||||
|
lock the archive with, and then place it in p12/.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
This script takes no options.
|
20
doc/renew-cert.txt
Normal file
20
doc/renew-cert.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# a brief man-page for renew-cert.sh
|
||||||
|
# $Id: renew-cert.txt 2660 2009-07-24 18:49:52Z alexeb $
|
||||||
|
|
||||||
|
NAME
|
||||||
|
renew-cert.sh - renew a previously generated cert for another year
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
renew-cert.sh /path/to/certificate
|
||||||
|
renew-cert.sh <hostname>
|
||||||
|
renew-cert.sh <username>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This script renews a certificate for another 365 days from it's current
|
||||||
|
end-date. It does some interesting hackery to re-sign the certificate
|
||||||
|
request generated when the certificate was initially signed, using the
|
||||||
|
same key-pair and the same serial, so that S/MIME encrypted e-mail and
|
||||||
|
previously signed code does not become unusable.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
This script takes no options.
|
18
doc/revoke-cert.txt
Normal file
18
doc/revoke-cert.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# a brief man-page for revoke-cert.sh
|
||||||
|
# $Id: revoke-cert.txt 2660 2009-07-24 18:49:52Z alexeb $
|
||||||
|
|
||||||
|
NAME
|
||||||
|
revoke-cert.sh - revoke a certificate and generate revocation list
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
revoke-cert.sh /path/to/certificate
|
||||||
|
revoke-cert.sh <hostname>
|
||||||
|
revoke-cert.sh <username>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This script revokes the provided certificate and updates the revocation
|
||||||
|
list. It generates both a PEM and a DER encoded version of the CRL for
|
||||||
|
different browsers, and updates the html page with the new fingerprints.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
This script takes no options.
|
198
lib/ca-functions
Normal file
198
lib/ca-functions
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#! /bin/bash
|
||||||
|
# common functions for ca-scripts
|
||||||
|
|
||||||
|
PROGNAME=$( basename $0 )
|
||||||
|
CONFFILE="/etc/ca-scripts.conf"
|
||||||
|
SHAREDIR="/home/alex/code/ca-scripts/tpl"
|
||||||
|
CRYPTKEY="-nodes"
|
||||||
|
|
||||||
|
INDEXTPL="index-html"
|
||||||
|
INDEXOUT=""
|
||||||
|
|
||||||
|
error() {
|
||||||
|
usage >&2
|
||||||
|
echo -e "ERROR: $1\n" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_check_var() {
|
||||||
|
local varname vartest
|
||||||
|
|
||||||
|
varname="$1"
|
||||||
|
vartest="$2"
|
||||||
|
eval "if [ ! $vartest \"\$$varname\" ]; then
|
||||||
|
echo '$varname value \"\$$varname\" failed \"$vartest\" test'
|
||||||
|
fi"
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_set_default() {
|
||||||
|
local varname vardef
|
||||||
|
|
||||||
|
varname="$1"
|
||||||
|
vardef="$2"
|
||||||
|
eval "if [ -z \"\$$varname\" ]; then
|
||||||
|
$varname=\"$vardef\";
|
||||||
|
fi"
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_load_conf() {
|
||||||
|
local varname vartest varerr vardef error ca_name
|
||||||
|
if [ ! -r "$CONFFILE" ]; then
|
||||||
|
error "Unable to find $CONFFILE."
|
||||||
|
fi
|
||||||
|
# XXX: seems like . <file> doesn't work if it's not relative to a directory
|
||||||
|
# look this up on the internet sometime to work out why...
|
||||||
|
if [ "$CONFFILE" = "$( basename $CONFFILE )" ]; then
|
||||||
|
CONFFILE="./$CONFFILE"
|
||||||
|
fi
|
||||||
|
. "$CONFFILE"
|
||||||
|
|
||||||
|
error=""
|
||||||
|
while read vartest varname; do
|
||||||
|
varerr=$( ca_check_var "$varname" "$vartest" )
|
||||||
|
if [ -n "$varerr" ]; then
|
||||||
|
error="$error\n $varerr"
|
||||||
|
fi
|
||||||
|
done <<__TESTS__
|
||||||
|
-d CA_HOME
|
||||||
|
-n CA_DOMAIN
|
||||||
|
-n CA_DN_C
|
||||||
|
-n CA_DN_ST
|
||||||
|
-n CA_DN_L
|
||||||
|
-n CA_DN_O
|
||||||
|
-n CA_DN_OU
|
||||||
|
-n CA_DN_CN
|
||||||
|
__TESTS__
|
||||||
|
if [ -n "$error" ]; then
|
||||||
|
error "Parsing config file $CONFFILE failed:\n$error"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$CA_CRT_TYPE" in
|
||||||
|
server|client|user|ca) :;;
|
||||||
|
'') error "The type option is mandatory!";;
|
||||||
|
*) error "Unrecognised type '$CA_CRT_TYPE'!";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# we need to do these first to use them in other default defs
|
||||||
|
# NOTE: bash's here-string syntax appends \n which tr turns to _ :(
|
||||||
|
ca_set_default CA_NAME "$( echo -n "$CA_DOMAIN" | tr -c '[:alnum:]@-' _ )"
|
||||||
|
ca_set_default CA_EMAIL "ca@$CA_DOMAIN"
|
||||||
|
|
||||||
|
while read varname vardef; do
|
||||||
|
ca_set_default "$varname" "$vardef"
|
||||||
|
done <<__DEFAULTS__
|
||||||
|
CA_DESC $CA_DN_CN
|
||||||
|
CA_CRT_URI http://$CA_DOMAIN/ca/$CA_NAME.ca.crt
|
||||||
|
CA_CRL_URI http://$CA_DOMAIN/ca/$CA_NAME.ca.crl
|
||||||
|
CA_PATHLEN 0
|
||||||
|
CA_CRT_C $CA_DN_C
|
||||||
|
CA_CRT_ST $CA_DN_ST
|
||||||
|
CA_CRT_L $CA_DN_L
|
||||||
|
CA_CRT_O $CA_DN_O
|
||||||
|
CA_CRT_OU $CA_DN_OU
|
||||||
|
CA_CRT_E $CA_EMAIL
|
||||||
|
__DEFAULTS__
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_sed_cmd() {
|
||||||
|
# MD5 in CA_CR[TL]_MD5_FP has a non alphabetic character :(
|
||||||
|
# XXX: pretty sure this is a dirty and wrong way of templating vars
|
||||||
|
set | awk -F\= '/^CA_[A-Z5_]*=/{print $1}' | while read ca_var; do
|
||||||
|
echo "s#%$ca_var%#${!ca_var}#;"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_template() {
|
||||||
|
local template dest
|
||||||
|
|
||||||
|
if [ -r "$1" ]; then
|
||||||
|
template="$1"
|
||||||
|
elif [ -r "$SHAREDIR/$1.tpl" ]; then
|
||||||
|
template="$SHAREDIR/$1.tpl"
|
||||||
|
else
|
||||||
|
error "Could not read from template $1"
|
||||||
|
fi
|
||||||
|
dest="$2"
|
||||||
|
|
||||||
|
sed -e "$(ca_sed_cmd)" <"$template" >"$dest"
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_gen_crl() {
|
||||||
|
openssl ca -config "$CA_HOME/cnf/$CA_NAME.ca.cnf" \
|
||||||
|
-gencrl -out "$CA_HOME/crl/$CA_NAME.ca.crl" -md sha1
|
||||||
|
openssl crl -in "$CA_HOME/crl/$CA_NAME.ca.crl" \
|
||||||
|
-out "$CA_HOME/crl/$CA_NAME.ca.crl.der" -outform DER
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_gen_p12() {
|
||||||
|
local cnf_name
|
||||||
|
cnf_name="$1"
|
||||||
|
openssl pkcs12 -export -descert -out $CA_HOME/p12/$cnf_name.p12 \
|
||||||
|
-in $CA_HOME/crt/$cnf_name.crt \
|
||||||
|
-inkey $CA_HOME/key/$cnf_name.key \
|
||||||
|
-certfile $CA_HOME/crt/$CA_NAME.ca.crt
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_checksum() {
|
||||||
|
CA_CRT_MD5_FP="$( openssl x509 -in $CA_HOME/crt/$CA_NAME.ca.crt \
|
||||||
|
-noout -md5 -fingerprint | cut -d= -f2 )"
|
||||||
|
CA_CRT_SHA_FP="$( openssl x509 -in $CA_HOME/crt/$CA_NAME.ca.crt \
|
||||||
|
-noout -sha1 -fingerprint | cut -d= -f2 )"
|
||||||
|
CA_CRL_MD5_FP="$( openssl crl -in $CA_HOME/crl/$CA_NAME.ca.crl \
|
||||||
|
-noout -md5 -fingerprint | cut -d= -f2 )"
|
||||||
|
CA_CRL_SHA_FP="$( openssl crl -in $CA_HOME/crl/$CA_NAME.ca.crl \
|
||||||
|
-noout -sha1 -fingerprint | cut -d= -f2 )"
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_cnf_name() {
|
||||||
|
local crt
|
||||||
|
crt="$1"
|
||||||
|
# work out what configuration files we should be using from the cert's CN
|
||||||
|
echo $( openssl x509 -in "$crt" -noout -nameopt sep_multiline,use_quote \
|
||||||
|
-subject | grep "CN=" | cut -d= -f2 | tr -c '[:alnum:]@-' _ )
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_find_cnf() {
|
||||||
|
local name _name
|
||||||
|
name="$1"
|
||||||
|
|
||||||
|
if [ -f "$name" ]; then
|
||||||
|
if ! grep -q "$CA_CRT_TYPE" <<<"$name"; then
|
||||||
|
error "Certificate '$name' does not appear to be of type '$CA_CRT_TYPE'"
|
||||||
|
else
|
||||||
|
echo "$(ca_cnf_name $name).$CA_CRT_TYPE"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
_name=$( echo -n "$name" | tr -c '[:alnum:]@-' _ )
|
||||||
|
if [ "$CA_CRT_TYPE" = "user" ]; then
|
||||||
|
# user names may have dots etc. in, so use munged version in match
|
||||||
|
# check if name is "user@domain", append $CA_DOMAIN if not
|
||||||
|
if [ "${_name%%@*}" = "$_name" \
|
||||||
|
-a -f "$CA_HOME/crt/${_name}@$CA_NAME.$CA_CRT_TYPE.crt" ];
|
||||||
|
then
|
||||||
|
# name is not fully-qualified, but a cert exists for it
|
||||||
|
echo "${_name}@$CA_NAME.$CA_CRT_TYPE"
|
||||||
|
elif [ -f "$CA_HOME/crt/$_name.$CA_CRT_TYPE.crt" ]; then
|
||||||
|
# name was fully-qualified and a cert exists
|
||||||
|
echo "$_name.$CA_CRT_TYPE"
|
||||||
|
else
|
||||||
|
error "Could not find $CA_CRT_TYPE certificate configuration matching '$name'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# check if name is fully-qualified -- contains more than 1 dot
|
||||||
|
# NOTE: we have to do this test with the unmunged name ...
|
||||||
|
if [ "${name%%.*}" = "$name" \
|
||||||
|
-a -f "$CA_HOME/crt/${_name}_$CA_NAME.$CA_CRT_TYPE.crt" ];
|
||||||
|
then
|
||||||
|
# name is not fully-qualified, but a cert exists for it
|
||||||
|
echo "${_name}_$CA_NAME.$CA_CRT_TYPE"
|
||||||
|
elif [ -f "$CA_HOME/crt/$_name.$CA_CRT_TYPE.crt" ]; then
|
||||||
|
# name was fully-qualified and a cert exists
|
||||||
|
echo "$_name.$CA_CRT_TYPE"
|
||||||
|
else
|
||||||
|
error "Could not find $CA_CRT_TYPE certificate configuration matching '$name'"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
160
tpl/ca-config.tpl
Normal file
160
tpl/ca-config.tpl
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
# CA configuration file template
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the CA configuration to use
|
||||||
|
[ ca ]
|
||||||
|
default_ca = ca_scripts
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines our CA configuration
|
||||||
|
[ ca_scripts ]
|
||||||
|
# interpolation variables defining the directories to use
|
||||||
|
dir = %CA_HOME% # root data directory of CA
|
||||||
|
db_dir = $dir/db # database files are kept here
|
||||||
|
csr_dir = $dir/csr # generated CSRs are kept here
|
||||||
|
crt_dir = $dir/crt # signed CRTs are kept here
|
||||||
|
key_dir = $dir/key # generated KEYs are kept here
|
||||||
|
crl_dir = $dir/crl # generated CRL is kept here
|
||||||
|
new_certs_dir = $dir/idx # default place for new CRTs
|
||||||
|
|
||||||
|
# required settings
|
||||||
|
database = $db_dir/index.txt # database index file
|
||||||
|
serial = $db_dir/serial # serial number index file
|
||||||
|
certificate = $crt_dir/%CA_NAME%.ca.crt # CA certificate
|
||||||
|
private_key = $key_dir/%CA_NAME%.ca.key # CA private key
|
||||||
|
crl = $crl_dir/%CA_NAME%.ca.crl # current CRL
|
||||||
|
RANDFILE = $db_dir/.rand # private random number file
|
||||||
|
|
||||||
|
# these two CA directives can be commented out so that v1 CRLs are created
|
||||||
|
crlnumber = $db_dir/crlnumber # crlnumber index file
|
||||||
|
crl_extensions = ca_crl_extensions # extensions in v2 CRL
|
||||||
|
|
||||||
|
# x509v3 certificate extensions and certificate signing policy
|
||||||
|
x509_extensions = ca_x509_default_extensions
|
||||||
|
copy_extensions = copy # copy extensions from CSR to CRT
|
||||||
|
policy = ca_extension_policy # policy on required CSR attributes
|
||||||
|
|
||||||
|
# leave these defaults
|
||||||
|
name_opt = oneline # Subject Name options - x509(1)
|
||||||
|
cert_opt = ca_default # Certificate field options - x509(1)
|
||||||
|
default_days = 365 # how long to certify for
|
||||||
|
default_crl_days= 365 # how long before next CRL
|
||||||
|
default_md = sha1 # which md to use.
|
||||||
|
preserve = no # keep passed DN ordering
|
||||||
|
unique_subject = no # recommended
|
||||||
|
email_in_dn = no # remove email from CSR DN when signing
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the CA's policy on required CSR attributes.
|
||||||
|
# It requires:
|
||||||
|
# the country [C] to be supplied in the CSR and match the CA
|
||||||
|
# the state or province [ST] to be supplied in the CSR
|
||||||
|
# the locality [L] to be supplied in the CSR
|
||||||
|
# the organisation name [O] to be supplied in the CSR and match the CA
|
||||||
|
# the organisational unit [OU] to be supplied in the CSR
|
||||||
|
# the server common name [CN] to be supplied in the CSR
|
||||||
|
# ... and an [emailAddress] may optionally be supplied in the CSR
|
||||||
|
# XXX: is this too restrictive or not restrictive enough?
|
||||||
|
# should options for ca-create-cert to change "match" values even exist?
|
||||||
|
[ ca_extension_policy ]
|
||||||
|
countryName = match
|
||||||
|
stateOrProvinceName = supplied
|
||||||
|
localityName = supplied
|
||||||
|
organizationName = match
|
||||||
|
organizationalUnitName = supplied
|
||||||
|
commonName = supplied
|
||||||
|
emailAddress = optional
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the default x509 extensions present in a cert signed by the CA.
|
||||||
|
# These should be replaced by a specific set of extensions per certificate.
|
||||||
|
[ ca_x509_default_extensions ]
|
||||||
|
|
||||||
|
# certificates signed by this CA by default are not CA certificates themselves
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
|
||||||
|
# old netscape certificate attributes
|
||||||
|
nsCertType = server
|
||||||
|
nsComment = "%CA_DESC% Certificate"
|
||||||
|
nsRevocationUrl = %CA_CRL_URI%
|
||||||
|
|
||||||
|
# key usage restrictions
|
||||||
|
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
|
||||||
|
issuerAltName = issuer:copy
|
||||||
|
subjectAltName = URI:%CA_CRT_URI%
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
authorityInfoAccess = caIssuers;URI:%CA_CRT_URI%
|
||||||
|
crlDistributionPoints = URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the x509 extensions present in the generated CA certificate.
|
||||||
|
[ ca_x509_extensions ]
|
||||||
|
|
||||||
|
# this certificate is authoritative and allowed to sign other certificates
|
||||||
|
# pathlen=1 implies there may be up to one intermediate CA in the chain
|
||||||
|
# that leads to this root CA certificate.
|
||||||
|
basicConstraints = critical,CA:TRUE,pathlen:%CA_PATHLEN%
|
||||||
|
|
||||||
|
# old netscape certificate attributes
|
||||||
|
nsCertType = objsign, sslCA, emailCA, objCA
|
||||||
|
nsComment = "%CA_DESC%"
|
||||||
|
nsRevocationUrl = %CA_CRL_URI%
|
||||||
|
nsCaRevocationUrl = %CA_CRL_URI%
|
||||||
|
|
||||||
|
# key usage restrictions
|
||||||
|
keyUsage = critical, cRLSign, keyCertSign
|
||||||
|
extendedKeyUsage = serverAuth, clientAuth, codeSigning, emailProtection, timeStamping
|
||||||
|
|
||||||
|
issuerAltName = @ca_altname
|
||||||
|
subjectAltName = @ca_altname
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
authorityInfoAccess = caIssuers;URI:%CA_CRT_URI%
|
||||||
|
crlDistributionPoints = URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This is a separate section defining the attributes in the CA's subjectAltName.
|
||||||
|
[ ca_altname ]
|
||||||
|
URI=%CA_CRT_URI%
|
||||||
|
DNS.1=%CA_DOMAIN%
|
||||||
|
DNS.2=*.%CA_DOMAIN%
|
||||||
|
email=%CA_EMAIL%
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the extensions present in the CRLs generated by this CA.
|
||||||
|
[ ca_crl_extensions ]
|
||||||
|
issuerAltName = issuer:copy
|
||||||
|
authorityKeyIdentifier = keyid:always, issuer:always
|
||||||
|
# the below is only supported in the very latest releases of openssl
|
||||||
|
# issuingDistributionPoint= URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the extensions present in the CSRs created by this CA.
|
||||||
|
[ ca_req_extensions ]
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, nonRepudiation, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines default settings for certificate requests and CA cert creation.
|
||||||
|
[ req ]
|
||||||
|
default_bits = 2048
|
||||||
|
default_md = sha1
|
||||||
|
distinguished_name = ca_req_dn
|
||||||
|
x509_extensions = ca_x509_extensions
|
||||||
|
req_extensions = ca_req_extensions
|
||||||
|
string_mask = nombstr
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------- #
|
||||||
|
# This defines the DN of the CA certificate.
|
||||||
|
[ ca_req_dn ]
|
||||||
|
C = %CA_DN_C%
|
||||||
|
ST = %CA_DN_ST%
|
||||||
|
L = %CA_DN_L%
|
||||||
|
O = %CA_DN_O%
|
||||||
|
OU = %CA_DN_OU%
|
||||||
|
CN = %CA_DN_CN%
|
17
tpl/client-ext.tpl
Normal file
17
tpl/client-ext.tpl
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
nsCertType = client
|
||||||
|
nsRevocationUrl = %CA_CRL_URI%
|
||||||
|
%CA_CRT_COMMENT%
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement, digitalSignature
|
||||||
|
extendedKeyUsage = clientAuth, timeStamping
|
||||||
|
|
||||||
|
issuerAltName = issuer:copy
|
||||||
|
subjectAltName = @client_altname
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
authorityInfoAccess = caIssuers;URI:%CA_CRT_URI%
|
||||||
|
crlDistributionPoints = URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
[ client_altname ]
|
||||||
|
URI=%CA_CRT_URI%
|
||||||
|
email=move
|
27
tpl/index-html.tpl
Normal file
27
tpl/index-html.tpl
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<HTML>
|
||||||
|
<HEAD><TITLE>%CA_DESC%</TITLE>
|
||||||
|
<STYLE>
|
||||||
|
BODY { font-family: arial,sans-serif; }
|
||||||
|
H1 { font-size: xx-large; margin-left: 50px; }
|
||||||
|
H3 { font-size: large; margin-top: 50px; margin-left: 50px; }
|
||||||
|
IMG { border: 0; }
|
||||||
|
P { width: 700px; margin-left: 100px; }
|
||||||
|
</STYLE>
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY>
|
||||||
|
<H1>%CA_DESC%</H1>
|
||||||
|
<H3>CA Certificate</H3>
|
||||||
|
<P>The CA certificate can be found
|
||||||
|
<A href="%CA_CRT_URI%">here</A></P>
|
||||||
|
<P>MD5 Fingerprint: %CA_CRT_MD5_FP%</P>
|
||||||
|
<P>SHA1 Fingerprint: %CA_CRT_SHA_FP%</P>
|
||||||
|
<H3>Certificate Revocation List</H3>
|
||||||
|
<P>The certificate revocation list can be found
|
||||||
|
<A href="%CA_CRL_URI%.der">here</A> (DER encoded)
|
||||||
|
or <A href="%CA_CRL_URI%">here</A> (PEM encoded)</P>
|
||||||
|
<P>MD5 Fingerprint: %CA_CRL_MD5_FP%</P>
|
||||||
|
<P>SHA1 Fingerprint: %CA_CRL_SHA_FP%</P>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
32
tpl/req-config.tpl
Normal file
32
tpl/req-config.tpl
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
[ req ]
|
||||||
|
default_bits = 2048
|
||||||
|
default_md = sha1
|
||||||
|
distinguished_name = req_dn
|
||||||
|
req_extensions = req_%CA_CRT_TYPE%_extensions
|
||||||
|
string_mask = nombstr
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
[ req_dn ]
|
||||||
|
C = %CA_CRT_C%
|
||||||
|
ST = %CA_CRT_ST%
|
||||||
|
L = %CA_CRT_L%
|
||||||
|
O = %CA_CRT_O%
|
||||||
|
OU = %CA_CRT_OU%
|
||||||
|
CN = %CA_CRT_CN%
|
||||||
|
emailAddress = %CA_CRT_E%
|
||||||
|
|
||||||
|
[ req_server_extensions ]
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
|
||||||
|
[ req_client_extensions ]
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement, digitalSignature
|
||||||
|
extendedKeyUsage = clientAuth, timeStamping
|
||||||
|
|
||||||
|
[ req_user_extensions ]
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement, digitalSignature, nonRepudiation, dataEncipherment
|
||||||
|
extendedKeyUsage = clientAuth, codeSigning, emailProtection
|
||||||
|
|
19
tpl/server-ext.tpl
Normal file
19
tpl/server-ext.tpl
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
nsCertType = server
|
||||||
|
nsRevocationUrl = %CA_CRL_URI%
|
||||||
|
%CA_CRT_COMMENT%
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
|
||||||
|
issuerAltName = issuer:copy
|
||||||
|
subjectAltName = @server_altname
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
authorityInfoAccess = caIssuers;URI:%CA_CRT_URI%
|
||||||
|
crlDistributionPoints = URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
[ server_altname ]
|
||||||
|
URI=%CA_CRT_URI%
|
||||||
|
email=move
|
||||||
|
%CA_CRT_ALT_NAMES%
|
||||||
|
|
18
tpl/user-ext.tpl
Normal file
18
tpl/user-ext.tpl
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
nsCertType = client, objsign, email
|
||||||
|
nsRevocationUrl = %CA_CRL_URI%
|
||||||
|
%CA_CRT_COMMENT%
|
||||||
|
keyUsage = critical, keyEncipherment, keyAgreement, digitalSignature, nonRepudiation, dataEncipherment
|
||||||
|
extendedKeyUsage = clientAuth, codeSigning, emailProtection
|
||||||
|
|
||||||
|
issuerAltName = issuer:copy
|
||||||
|
subjectAltName = @user_altname
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid,issuer:always
|
||||||
|
authorityInfoAccess = caIssuers;URI:%CA_CRT_URI%
|
||||||
|
crlDistributionPoints = URI:%CA_CRL_URI%
|
||||||
|
|
||||||
|
[ user_altname ]
|
||||||
|
URI=%CA_CRT_URI%
|
||||||
|
email=move
|
||||||
|
|
3
vims
Normal file
3
vims
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
gvim -p bin/* lib/*
|
||||||
|
gvim -p ca-scripts.conf tpl/*
|
||||||
|
gvim -p doc/*
|
Loading…
Reference in a new issue