- #!/bin/sh
- #
- # /usr/local/sbin/localmksslcerts
- # Copyright 2001-2004 Jonas Smedegaard <dr@jones.dk>
- #
- # $Id: localmksslcerts,v 1.19 2005-10-18 00:24:33 jonas Exp $
- #
- # Generate certificates for mail (and other) servers
- # Based on uw-imapd-ssl post-install script
- #
- # TODO: Use getopts
- # TODO: Add symlink from CA certificate to cacert.pem if non-existing
- # TODO: Default CA certificate is cacert.pem if --cacert not set
- set -e
- prg=$(basename $0)
- copyright="(C) 2001-2004 Jonas Smedegaard <dr@jones.dk>"
- # Set some defaults
- PATH="$PATH:/usr/bin/ssl"
- DAYS2EXPIRE="365"
- SSLCERTDIR="/etc/ssl/certs"
- SSLPRIVDIR="/etc/ssl/private"
- usage() {
- echo "$prg, $copyright
- Usage: $prg [--fqdn <FQDN>] [...] --daemon <daemon> [...] [--force]
- or: $prg <daemon> [<daemon>...] [-f]
- Options:
- --fqdn <FQDN> Fully Qualified Domain Name for this host.
- --cn <country> Country Name (2 letter code)
- --state <state> State or Province Name (full name)
- --loc <locality> Locality Name (eg, city)
- --org <organisation> Organisation/company
- --ou <department> Organisational unit/department
- --daemon <daemon> Daemon(s) in need for a certificate
- (certificate is generated for each daemon)
- --issuer <issuer> Email address of entity issuing certificate
- --cert Use certified host certificate
- --cacert <file> Where to store host certificate if missing
- --makeca Create CA certificate if missing
- -f, --force Force overwriting existing certificate(s)
- -h, --help This help text
- Examples:
- Create certs for UW imapd/popd, bound to default host cert if there:
- localmksslcerts imapd pop3d
- Create host cert for non-default hostname, overwriting stray files:
- localmksslcerts --fqdn mail.jones.dk --cert --force
- Create host cert for non-default hostname and bind to UW daemons:
- localmksslcerts --fqdn mail.jones.dk --cert --force imapd pop3d
- Create CA-signed host cert (and CA cert if not there):
- localmksslcerts --cert --cacert IT-guide_dr_Jones_CA
- If issuer is not given, \"postmaster@<localdomain>\" is used."
- exit 1
- }
- mkcerthash() {
- filebase="$1"
- filename="$filebase.pem"
- certhash="$(openssl x509 -noout -hash -in "$SSLCERTDIR/$filename")"
- hashfile="$certhash.0"
- ln -sf "$filename" "$SSLCERTDIR/$hashfile"
- }
- mkselfcert() {
- filebase="$1"
- cn="$2"
- state="$3"
- loc="$4"
- org="$5"
- ou="$6"
- fqdn="$7"
- issuer="$8"
- filename="$filebase.pem"
- openssl req -new -x509 -nodes \
- -days "$DAYS2EXPIRE" \
- -keyout "$SSLCERTDIR/$filename" \
- -out "$SSLCERTDIR/$filename" > /dev/null 2>&1 <<+
- $cn
- $state
- $loc
- $org
- $ou
- $fqdn
- $issuer
- +
- mkcerthash "$filebase"
- chown root:root "$SSLCERTDIR/$filename"
- chmod 0640 "$SSLCERTDIR/$filename"
- }
- mkcertreq() {
- filebase="$1"
- cn="$2"
- state="$3"
- loc="$4"
- org="$5"
- ou="$6"
- fqdn="$7"
- issuer="$8"
- filename="$filebase.pem"
- openssl req -new \
- -key "$SSLPRIVDIR/$filename" \
- -out "$SSLCERTDIR/$filename" > /dev/null 2>&1 <<+
- $cn
- $state
- $loc
- $org
- $ou
- $fqdn
- $issuer
- +
- chown root:root "$SSLCERTDIR/$filename"
- chmod 0640 "$SSLCERTDIR/$filename"
- }
- fqdn=''
- cn=''
- state=''
- loc=''
- org=''
- ou=''
- daemon=''
- daemons=''
- issuer=''
- cert=''
- cacert=''
- makeca=''
- force=''
- args=''
- TEMP=`getopt -o f --long help,fqdn:,cn:,state:,loc:,org:,ou:,daemon:,issuer:,cert,cacert:,makeca,force -n "$prg" -- "$@"`
- # Check for non-GNU getopt
- if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
- eval set -- "$TEMP"
- while true ; do
- case "$1" in
- --help) usage;;
- --fqdn) fqdn="$2"; shift 2;;
- --cn) cn="$2"; shift 2;;
- --state) state="$2"; shift 2;;
- --loc) loc="$2"; shift 2;;
- --org) org="$2"; shift 2;;
- --ou) ou="$2"; shift 2;;
- --daemon) daemons="$daemons$2 "; shift 2;;
- --issuer) issuer="$2"; shift 2;;
- --cert) cert=1; shift;;
- --cacert) cacert="$2"; shift 2;;
- --makeca) makeca=1; shift;;
- --force|-f) force=1; shift;;
- --) shift; break;;
- *) echo "Internal error!" ; exit 1 ;;
- esac
- done
- if [ -z "$issuer" ]; then
- DOMAINNAME="`hostname -d`"
- ISSUER="postmaster@$DOMAINNAME"
- fi
- if [ -z "$fqdn" ]; then
- if [ $# -gt 0 ]; then
- fqdn="`hostname -f`"
- else
- echo "Too few parameters!"
- usage
- fi
- fi
- for val in org ou; do
- if eval [ -z "\$$val" ]; then
- eval "$val=\"$fqdn\""
- fi
- done
- for val in cn state loc; do
- if eval [ -z "\$$val" ]; then
- eval "$val=\".\""
- fi
- done
- if [ -n "$cert" ]; then
- if [ ! -s "$SSLCERTDIR/$fqdn.pem" ] || [ ! -s "$SSLPRIVDIR/$fqdn.pem" ]; then
- echo "WARNING: Host certificate for \"$fqdn\" missing..."
- if [ -z "$cacert" ]; then
- echo "ERROR: The \"--cacert\" option is required when making a host certificate!"
- exit 1
- fi
- # Cleaning up - if allowed
- for file in "$SSLPRIVDIR/$fqdn.pem" "$SSLCERTDIR/$fqdn.csr" "$SSLCERTDIR/$fqdn.pem"; do
- if [ -e "$file" ]; then
- if [ -n "$force" ]; then
- rm -f "$file"
- else
- echo "ERROR: File \"$file\" already exists!"
- exit 1
- fi
- fi
- done
- if [ ! -s "$SSLCERTDIR/$cacert.pem" ] || [ ! -s "$SSLPRIVDIR/$cacert.pem" ]; then
- echo "WARNING: CAcert (certifying authority certificate) missing..."
- if [ -z "$makeca" ]; then
- echo "ERROR: The \"--makeca\" option is required when making a CAcert!"
- exit 1
- fi
- # Generate private key for CA certificate
- echo "Generating CAcert \"$cacert\"..."
- #FIXME: Make strength configurable
- openssl genrsa -des3 -out "$SSLPRIVDIR/$cacert.pem" 1024
- chown root:root "$SSLPRIVDIR/$cacert.pem"
- chmod 0400 "$SSLPRIVDIR/$cacert.pem"
- # Generate and pre-fill certification request
- #FIXME: Make validity configurable
- openssl req -new \
- -key "$SSLPRIVDIR/$cacert.pem" \
- -x509 -days 1095 \
- -out "$SSLCERTDIR/$cacert.pem"
- # Add hash to certified public certificate and cleanup
- mkcerthash $cacert
- fi
- echo "Generating host certificate for \"$fqdn\"..."
- # Generate private key for host certificate
- openssl genrsa -out "$SSLPRIVDIR/$fqdn.pem"
- chown root:root "$SSLPRIVDIR/$fqdn.pem"
- chmod 0600 "$SSLPRIVDIR/$fqdn.pem"
- # Generate and pre-fill certification request
- mkcertreq "$fqdn" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
- # Generate public certificate from certification request
- openssl x509 -req \
- -days $DAYS2EXPIRE \
- -CA "$SSLCERTDIR/$cacert.pem" \
- -CAkey "$SSLPRIVDIR/$cacert.pem" \
- -CAcreateserial -out "$SSLCERTDIR/$fqdn.pem" -in "$SSLCERTDIR/$fqdn.csr"
- # Add hash to certified public certificate and cleanup
- mkcerthash $fqdn
- rm "$SSLCERTDIR/$fqdn.csr"
- fi
- fi
- for daemon in $daemons $@; do
- if [ -f "$SSLCERTDIR/$daemon.pem" ]; then
- if [ -n "$force" ]; then
- rm -f "$SSLCERTDIR/$(openssl x509 -noout -hash < "$SSLCERTDIR/$daemon.pem").0"
- rm -f "$SSLCERTDIR/$daemon.pem"
- else
- echo "Ignoring certificate (/etc/ssl/certs/$daemon.pem already exists...)"
- continue
- fi
- fi
- if [ -n "$cert" ]; then
- echo "Attaching $daemon to certified certificate for $fqdn."
- ln -sf "$fqdn.pem" "$SSLCERTDIR/$daemon.pem"
- ln -sf "$fqdn.pem" "$SSLPRIVDIR/$daemon.pem"
- else
- echo -n "Generating self-certifying $daemon certificate..."
- mkselfcert "$daemon" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
- echo "Done!"
- fi
- done
|