#!/bin/bash
#
# Copyright: Patrick Koppen
# License:   GPLv3
# Version:   1.0
# Date:      19.05.2011

set -e

etc=/etc/burp
dir=${etc}/CA
conf=${etc}/CA.cnf

name=$(hostname -f)
ca_days=3650
size=2048

def_umask=022
sec_umask=077

function help() {
  cat <<EOF
$0: Help:
    -h|--help            show help
    -i|--init            inititalize CA
    -k|--key             generate new key
    -r|--request         generate certificate sign request
    -s|--sign            sign csr (use --ca <ca> and --name <name>)
       --batch           do not prompt for anything
       --revoke <number> revoke certificate with serial number
       --crl             generate certificate revoke list
    -d|--dir <dir>       ca output dir (default: $dir)
    -c|--config          config file (default: $conf)
    -n|--name            name (default: $name)
    -D|--days            valid days for certificate (default in config file)
       --ca_days         valid days for CA certificate (default: $ca_days)
    -S|--size            key size (default: $size)
    -a|--ca              ca name if different from name
EOF
}

if ! options=$(getopt -o hid:c:n:krsa:D:S: \
    -l help,init,dir:,config:,name:,key:,request:,sign,ca:,ca_days,revoke:,crl,batch,days:,size: -- "$@")
then
    exit 1
fi

eval set -- "$options"

while [ $# -gt 0 ]
do
    case $1 in
    -h|--help) help; exit ;;
    -i|--init) init=yes ;;
    -k|--key) key=yes ;;
    -r|--request) request=yes ;;
    -s|--sign) sign=yes ;;
       --batch) batch="-batch" ;;
       --revoke) revoke=$2; shift ;;
       --crl) crl=yes ;;
    -d|--dir)  dir=$2; shift ;;
    -c|--config)  conf=$2; shift ;;
    -n|--name)  name=$2; shift ;;
    -D|--days)  days="-days $2"; shift ;;
       --ca_days)  ca_days=$2; shift ;;
    -S|--size)  days=$2; shift ;;
    -a|--ca)  ca=$2; shift ;;
    --) shift; break;;
    -*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    *) break;;
    esac
    shift
done

if [ -z "$ca" ]; then
  ca=${name}
fi

# init CA
if [ "$init" = "yes" ]; then
  echo "Init... ${ca}"
  if [ ! -f ${conf} ]; then
     echo "$0: error - config ${conf} missing" 1>&2; exit 1
  fi
  if [ -d ${dir} ]; then
     echo "$0: error - ${dir} exists, ca initialized" 1>&2; exit 1
  fi
  
  mkdir ${dir}
  mkdir ${dir}/certs
  mkdir ${dir}/newcerts

  umask ${sec_umask}
  openssl genrsa -out ${dir}/CA_${ca}.key ${size}
  umask ${def_umask}
  TEMP=$(mktemp || /tmp/temp.$$)
  cat <<-EOF > ${TEMP}
	RANDFILE                = /dev/urandom

	[ req ]
	distinguished_name      = req_distinguished_name
	prompt                  = no

	[ v3_ca ]
	basicConstraints=CA:true
	subjectKeyIdentifier=hash
	authorityKeyIdentifier=keyid,issuer:always

	[ req_distinguished_name ]
	commonName                      = ${ca}
EOF
  CA_DIR=${dir} openssl req -config ${TEMP} -new -x509 -days $ca_days \
    -key ${dir}/CA_${ca}.key -out ${dir}/CA_${ca}.crt -extensions v3_ca
  rm -f $TEMP

  : > ${dir}/index.txt
  echo "00" > ${dir}/serial.txt
  echo "00" > ${dir}/crlnumber.txt

fi

# generate key
if [ "$key" = "yes" ]; then
  echo "genrating key ${name}"
  umask ${sec_umask}
  openssl genrsa -out ${dir}/${name}.key ${size}
  umask ${def_umask}
fi

# generate signing request 
if [ "$request" = "yes" ]; then
  echo "genrating request ${name}"
  TEMP=$(mktemp || /tmp/temp.$$)
  cat <<-EOF > ${TEMP}
	RANDFILE                = /dev/urandom

	[ req ]
	distinguished_name      = req_distinguished_name
	prompt                  = no

	[ v3_req ]
	basicConstraints=CA:false

	[ req_distinguished_name ]
	commonName                      = ${name}

EOF
  openssl req -config ${TEMP} -new -key ${dir}/${name}.key \
    -out ${dir}/${name}.csr -extensions v3_req
  rm -f $TEMP
fi


# sign 
if [ "$sign" = "yes" ]; then
  serial=$(cat ${dir}/serial.txt)
  CA_DIR=${dir} openssl ca -config ${conf} -name ca \
    -in ${dir}/${name}.csr -out $dir/${name}.crt ${days}\
    -keyfile ${dir}/CA_${ca}.key -cert ${dir}/CA_${ca}.crt \
    ${batch}
  if [ ! -f ${dir}/newcerts/${serial}.pem ]; then
    exit
  fi
  mv ${dir}/newcerts/${serial}.pem ${dir}/certs/${serial}.pem
  c_rehash ${dir}/certs
fi

#revoke
if [ -n "$revoke" ]; then
  CA_DIR=${dir} openssl ca -config ${conf} -name ca \
    -revoke ${dir}/certs/${revoke}.pem \
    -keyfile ${dir}/CA_${ca}.key -cert ${dir}/CA_${ca}.crt \
    ${batch}
fi

#crl
if [ -n "$crl" ]; then
  CA_DIR=${dir} openssl ca -config ${conf} -name ca \ 
   -gencrl -out ${dir}/CA_${ca}.crl \
   -keyfile ${dir}/CA_${ca}.key -cert ${dir}/CA_${ca}.crt 
fi
