#!/bin/sh
#
# openvas-manage-certs - Manage certificate infrastructure for an OpenVAS installation
# Copyright (C) 2015-2016 Greenbone Networks GmbH
#
# Authors:
# - Michael Wiegand <michael.wiegand@greenbone.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

# The following TODOS are features deemed desirable which have not yet been
# implemented.
# TODO: Import a certificate
# Does the certificate contain a private key?
# Do we take the key generated for the signing request?

# Script and feed information which will be made available to user through
# command line options and automated tools.
SCRIPT_NAME="openvas-manage-certs"

# LOG_CMD defines the command to use for logging. To have logger log to stderr
# as well as syslog, add "-s" here.
LOG_CMD="logger -t $SCRIPT_NAME"

CA_CERTIFICATE=1
SERVER_CERTIFICATE=2
CLIENT_CERTIFICATE=3

log_write () {
  if [ $QUIET -ne 1 ]
  then
    $LOG_CMD -p daemon.info "$1"
    echo "$1"
  fi
}

log_err () {
  $LOG_CMD -p daemon.err "$1"
  >&2 echo "$1"
}

log_debug () {
  if [ $DEBUG -eq 1 ]
  then
    $LOG_CMD -p daemon.debug "$1"
    echo "$1"
  fi
}

log_verbose () {
  if [ $VERBOSE -eq 1 ]
  then
    log_write "$1"
  fi
}

set_defaults () {
  # Set default values for certificate parameters
  # Lifetime
  OPENVAS_CERTIFICATE_LIFETIME=${OPENVAS_CERTIFICATE_LIFETIME:-730}
  # Country
  OPENVAS_CERTIFICATE_COUNTRY=${OPENVAS_CERTIFICATE_COUNTRY:-"DE"}
  # State
  OPENVAS_CERTIFICATE_STATE=${OPENVAS_CERTIFICATE_STATE:-""}
  # Locality
  OPENVAS_CERTIFICATE_LOCALITY=${OPENVAS_CERTIFICATE_LOCALITY:-"Osnabrueck"}
  # Organization
  OPENVAS_CERTIFICATE_ORG=${OPENVAS_CERTIFICATE_ORG:-"OpenVAS Users"}
  # (Organization unit)
  OPENVAS_CERTIFICATE_ORG_UNIT=${OPENVAS_CERTIFICATE_ORG_UNIT:-""}

  # Hostname
  if [ -z "$OPENVAS_CERTIFICATE_HOSTNAME" ]
  then
    OPENVAS_CERTIFICATE_HOSTNAME=$(hostname --fqdn 2> /dev/null)
    if [ $? -ne 0 ]
    then
      OPENVAS_CERTIFICATE_HOSTNAME="localhost"
    fi
  fi

  # Certificate Authority (CA) Certificate Parameters
  # CA Lifetime
  OPENVAS_CA_CERTIFICATE_LIFETIME=${OPENVAS_CA_CERTIFICATE_LIFETIME:-3652}
  # Country
  OPENVAS_CA_CERTIFICATE_COUNTRY=${OPENVAS_CA_CERTIFICATE_COUNTRY:-"$OPENVAS_CERTIFICATE_COUNTRY"}
  # State
  OPENVAS_CA_CERTIFICATE_STATE=${OPENVAS_CA_CERTIFICATE_STATE:-"$OPENVAS_CERTIFICATE_STATE"}
  # Locality
  OPENVAS_CA_CERTIFICATE_LOCALITY=${OPENVAS_CA_CERTIFICATE_LOCALITY:-"$OPENVAS_CERTIFICATE_LOCALITY"}
  # Organization
  OPENVAS_CA_CERTIFICATE_ORG=${OPENVAS_CA_CERTIFICATE_ORG:-"$OPENVAS_CERTIFICATE_ORG"}
  # (Organization unit)
  OPENVAS_CA_CERTIFICATE_ORG_UNIT=${OPENVAS_CA_CERTIFICATE_ORG_UNIT:-"Certificate Authority for $OPENVAS_CERTIFICATE_HOSTNAME"}

  # Key size
  if [ -z "$OPENVAS_CERTIFICATE_KEYSIZE" ]
  then
    OPENVAS_CERTIFICATE_SECPARAM=${OPENVAS_CERTIFICATE_SECPARAM:-"high"}
  fi

  # Signature algorithm
  OPENVAS_CERTIFICATE_SIGNALG=${OPENVAS_CERTIFICATE_SIGNALG:-"SHA256"}

  # Location in file system where private keys are stored
  OPENVAS_KEY_LOCATION=${OPENVAS_KEY_LOCATION:-"@OPENVAS_STATE_DIR@/private/CA"}
  # Location in file system where certificates are stored
  OPENVAS_CERT_LOCATION=${OPENVAS_CERT_LOCATION:-"@OPENVAS_STATE_DIR@/CA"}

  # Prefix for generated files
  # If not set, files will be named "key.pem" and "cert.pem"
  # If set to "server", files will be named "serverkey.pem" and "servercert.pem"
  OPENVAS_CERT_PREFIX=${OPENVAS_CERT_PREFIX:-""}
}


print_help ()
{
  echo "Usage:"
  echo "  $0 [OPTION] - Manage certificate infrastructure for an OpenVAS installation"
  echo
  echo "Options:"
  echo "  -h             Print help"
  echo "  -a             Automatically set up default infrastructure for OpenVAS"
  echo "  -V             Verify existing OpenVAS certificate infrastructure"
  echo "  -C             Create a certificate authority (CA)"
  echo "  -I             Install a CA certificate"
  echo "  -R             Create a certificate request for a CA"
  echo "  -r             Create a certificate request"
  echo "  -c             Create a certificate request and sign it"
  echo "  -i             Install a certificate"
  echo "  -S             Sign a certificate request"
  echo "  -f             Force overwriting of existing files"
  echo
  echo "Certificate options:"
  echo "  -E             Create a server certificate"
  echo "  -L             Create a client certificate"
  echo "  -A             Skip CA generation in automatic mode"
  echo
  echo "Output control:"
  echo "  -d             Print debug output"
  echo "  -v             Print verbose messages"
  echo "  -q             Be quiet, only print error messages"
  echo
  echo "Configuration:"
  echo "  -e <file>      Read configuration from <file>"
  echo
  echo "All certificate generation options can be set either through the configuration"
  echo "  file or through environment variables like the following:"
  echo
  echo "  OPENVAS_CERTIFICATE_LIFETIME   Days until the certificate will expire"
  echo "  OPENVAS_CERTIFICATE_HOSTNAME   Name to use for the certificate"
  echo "  OPENVAS_CERTIFICATE_SIGNALG    Hash algorithm to use for signing"
  echo
  echo "  OPENVAS_CERTIFICATE_KEYSIZE    Size in bits of the generated key"
  echo "  or"
  echo "  OPENVAS_CERTIFICATE_SECPARAM   GnuTLS security level [low|medium|high|ultra]"
  echo
  echo "  OPENVAS_CERT_DIR               Directory where keys and certificates are stored"
  echo "                                 before installation"
  echo
  echo "  OPENVAS_CERT_PREFIX            Prefix for certificate filename (e.g. \"server\")"
  echo
  echo "For a complete list of options, please refer to the documentation."
  echo

  exit 0
}

# Ensure everything is ready to run, prepare temporary directory
set_up ()
{
  # Check if "certtool" binary is available
  if ! type certtool > /dev/null 2>&1
  then
    echo "ERROR: certtool binary not found!"
    exit 1
  fi

  # TODO: certtool version check?

  # Set directory to use for keys and certificates before installation
  if [ -z "$OPENVAS_CERT_DIR" ]
  then
    USE_TEMP_DIR=1
    OPENVAS_CERT_DIR=`mktemp -d`
    log_verbose "Using $OPENVAS_CERT_DIR to temporarily store files."
  else
    USE_TEMP_DIR=0
    if [ ! -w "$OPENVAS_CERT_DIR" ]
    then
      log_err "$OPENVAS_CERT_DIR has to exist and has to be writable. Aborting."
      exit 1
    fi
  fi

  # Logfile for certtool output
  CERTTOOL_LOGFILE="$OPENVAS_CERT_DIR/openvas-manage-certs.log"

  # Filename to use for generated private key
  OPENVAS_KEY_FILENAME=${OPENVAS_KEY_FILENAME:-"$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}key.pem"}
  # Filename to use for generated certificate
  OPENVAS_CERT_FILENAME=${OPENVAS_CERT_FILENAME:-"$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}cert.pem"}
  # Filename to use for generated certificate request
  OPENVAS_CERT_REQUEST_FILENAME=${OPENVAS_CERT_REQUEST_FILENAME:-"$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}request.pem"}
  # Filename to use for generated certificate template
  OPENVAS_CERT_TEMPLATE_FILENAME=${OPENVAS_CERT_TEMPLATE_FILENAME:-"$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}openvas-cert.cfg"}

  # Filename of CA private key used for signing certificates
  OPENVAS_SIGNING_CA_KEY_FILENAME=${OPENVAS_SIGNING_CA_KEY_FILENAME:-"$OPENVAS_KEY_LOCATION/cakey.pem"}
  # Filename of CA certificate used for signing certificates
  OPENVAS_SIGNING_CA_CERT_FILENAME=${OPENVAS_SIGNING_CA_CERT_FILENAME:-"$OPENVAS_CERT_LOCATION/cacert.pem"}
}

# Create installation directories with correct permissions
set_up_directories ()
{
  log_verbose "Setting up directories"

  if [ ! -d "$OPENVAS_CERT_LOCATION" ]
  then
    mkdir -p "$OPENVAS_CERT_LOCATION"
    if [ $? -ne 0 ]
    then
      log_err "ERROR: Failed to create certificate directory ($OPENVAS_CERT_LOCATION). Aborting."
      exit 1
    fi
  fi

  if [ ! -d "$OPENVAS_KEY_LOCATION" ]
  then
    mkdir -p "$OPENVAS_KEY_LOCATION"
    if [ $? -ne 0 ]
    then
      log_err "ERROR: Failed to create private key directory ($OPENVAS_KEY_LOCATION). Aborting."
      exit 1
    fi
  fi

  chmod 0700 "$OPENVAS_KEY_LOCATION"

  chmod a+rx "$OPENVAS_CERT_LOCATION"
}

# Apply file name prefix setting for generated files
set_prefix ()
{
  OPENVAS_CERT_PREFIX="$1"
  OPENVAS_KEY_FILENAME="$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}key.pem"
  OPENVAS_CERT_FILENAME="$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}cert.pem"
  OPENVAS_CERT_REQUEST_FILENAME="$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}request.pem"
  OPENVAS_CERT_TEMPLATE_FILENAME="$OPENVAS_CERT_DIR/${OPENVAS_CERT_PREFIX}openvas-cert.cfg"
}

# Create a private key
create_private_key ()
{
  log_verbose "Generating private key."

  umask 022

  if [ -z "$OPENVAS_CERTIFICATE_KEYSIZE" ]
  then
    CERTTOOL_PRIVKEY_PARAM="--sec-param $OPENVAS_CERTIFICATE_SECPARAM"
  else
    CERTTOOL_PRIVKEY_PARAM="--bits $OPENVAS_CERTIFICATE_KEYSIZE"
  fi

  # Create a private key
  certtool \
    --generate-privkey $CERTTOOL_PRIVKEY_PARAM \
    --outfile "$1" \
    >> "$CERTTOOL_LOGFILE" 2>&1
  if [ $? -ne 0 ]
  then
    log_err "ERROR: Failed to generate private key, see $CERTTOOL_LOGFILE for details. Aborting."
    exit 1
  fi

  log_write "Generated private key in $1."
}

# Create a certificate
create_certificate ()
{
  log_verbose "Generating certificate."

  umask 022

  rm -f "$OPENVAS_CERT_TEMPLATE_FILENAME"

  # Create template using parameters
  if [ $CERTIFICATE_TYPE -eq $CA_CERTIFICATE ]
  then
    if [ -n "$OPENVAS_CA_CERTIFICATE_LIFETIME" ]
    then
      echo "expiration_days = $OPENVAS_CA_CERTIFICATE_LIFETIME" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_COUNTRY" ]
    then
      echo "country = \"$OPENVAS_CA_CERTIFICATE_COUNTRY\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_STATE" ]
    then
      echo "state = \"$OPENVAS_CA_CERTIFICATE_STATE\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_LOCALITY" ]
    then
      echo "locality = \"$OPENVAS_CA_CERTIFICATE_LOCALITY\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_ORG" ]
    then
      echo "organization = \"$OPENVAS_CA_CERTIFICATE_ORG\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_ORG_UNIT" ]
    then
      echo "unit = \"$OPENVAS_CA_CERTIFICATE_ORG_UNIT\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CA_CERTIFICATE_HOSTNAME" ]
    then
      echo "cn = \"$OPENVAS_CA_CERTIFICATE_HOSTNAME\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
  else
    if [ -n "$OPENVAS_CERTIFICATE_LIFETIME" ]
    then
      echo "expiration_days = $OPENVAS_CERTIFICATE_LIFETIME" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_COUNTRY" ]
    then
      echo "country = \"$OPENVAS_CERTIFICATE_COUNTRY\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_STATE" ]
    then
      echo "state = \"$OPENVAS_CERTIFICATE_STATE\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_LOCALITY" ]
    then
      echo "locality = \"$OPENVAS_CERTIFICATE_LOCALITY\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_ORG" ]
    then
      echo "organization = \"$OPENVAS_CERTIFICATE_ORG\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_ORG_UNIT" ]
    then
      echo "unit = \"$OPENVAS_CERTIFICATE_ORG_UNIT\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
    if [ -n "$OPENVAS_CERTIFICATE_HOSTNAME" ]
    then
      echo "cn = \"$OPENVAS_CERTIFICATE_HOSTNAME\"" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    fi
  fi

  # Add key usage constraints if the certificate type is known
  if [ $CERTIFICATE_TYPE -eq $CA_CERTIFICATE ]
  then
    echo "ca" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    echo "cert_signing_key" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    echo "crl_signing_key" >> $OPENVAS_CERT_TEMPLATE_FILENAME
  fi
  if [ $CERTIFICATE_TYPE -eq $SERVER_CERTIFICATE ]
  then
    # This certificate will be used to encrypt data.
    # This is the keyEncipherment flag in RFC5280 terminology.
    echo "encryption_key" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    echo "tls_www_server" >> $OPENVAS_CERT_TEMPLATE_FILENAME
  fi
  if [ $CERTIFICATE_TYPE -eq $CLIENT_CERTIFICATE ]
  then
    # This certificate will be used to sign data.
    # This is the digitalSignature flag in RFC5280 terminology.
    echo "signing_key" >> $OPENVAS_CERT_TEMPLATE_FILENAME
    echo "tls_www_client" >> $OPENVAS_CERT_TEMPLATE_FILENAME
  fi

  if [ $DEBUG -eq 1 ]
  then
    echo "DEBUG: Using the following template ($OPENVAS_CERT_TEMPLATE_FILENAME):" >> "$CERTTOOL_LOGFILE"
    cat $OPENVAS_CERT_TEMPLATE_FILENAME >> "$CERTTOOL_LOGFILE"
  fi

  if [ $CREATE_SELF_SIGNED -eq 1 ]
  then
    # Create a self signed certificate
    log_verbose "  Generating self signed certificate."
    certtool \
      --generate-self-signed \
      --hash "$OPENVAS_CERTIFICATE_SIGNALG" \
      --load-privkey "$OPENVAS_KEY_FILENAME" \
      --outfile "$OPENVAS_CERT_FILENAME" \
      --template "$OPENVAS_CERT_TEMPLATE_FILENAME" \
      >> "$CERTTOOL_LOGFILE" 2>&1
    if [ $? -ne 0 ]
    then
      log_err "ERROR: Failed to create self signed certificate, see $CERTTOOL_LOGFILE for details. Aborting."
      exit 1
    fi

    log_write "Generated self signed certificate in $OPENVAS_CERT_FILENAME."
  else
    # Create a certificate request
    log_verbose "  Generating certificate request."
    certtool \
      --generate-request \
      --load-privkey "$OPENVAS_KEY_FILENAME" \
      --outfile "$OPENVAS_CERT_REQUEST_FILENAME" \
      --template "$OPENVAS_CERT_TEMPLATE_FILENAME" \
      >> "$CERTTOOL_LOGFILE" 2>&1
    if [ $? -ne 0 ]
    then
      log_err "ERROR: Failed to create certificate request, see $CERTTOOL_LOGFILE for details. Aborting."
      exit 1
    fi

    log_write "Generated certificate request in $OPENVAS_CERT_REQUEST_FILENAME."
  fi
}

sign_certificate ()
{
  log_verbose "Signing certificate request."

  if [ ! -s "$OPENVAS_CERT_REQUEST_FILENAME" ]
  then
    log_err "ERROR: Failed to find certificate request in $OPENVAS_CERT_REQUEST_FILENAME. Aborting."
    exit 1
  fi
  if [ ! -s "$OPENVAS_SIGNING_CA_CERT_FILENAME" ]
  then
    log_err "ERROR: Failed to find CA certificate in $OPENVAS_SIGNING_CA_CERT_FILENAME. Aborting."
    exit 1
  fi
  if [ ! -s "$OPENVAS_SIGNING_CA_KEY_FILENAME" ]
  then
    log_err "ERROR: Failed to find CA key in $OPENVAS_SIGNING_CA_KEY_FILENAME. Aborting."
    exit 1
  fi

  # Sign certificate
  certtool \
    --generate-certificate \
    --hash "$OPENVAS_CERTIFICATE_SIGNALG" \
    --load-request "$OPENVAS_CERT_REQUEST_FILENAME" \
    --outfile "$OPENVAS_CERT_FILENAME" \
    --load-ca-certificate "$OPENVAS_SIGNING_CA_CERT_FILENAME" \
    --load-ca-privkey "$OPENVAS_SIGNING_CA_KEY_FILENAME" \
    --template "$OPENVAS_CERT_TEMPLATE_FILENAME" >> "$CERTTOOL_LOGFILE" 2>&1
  if [ $? -ne 0 ]
  then
    log_err "ERROR: Failed to sign certificate, see $CERTTOOL_LOGFILE for details. Aborting."
    exit 1
  fi

  log_write "Signed certificate request in $OPENVAS_CERT_REQUEST_FILENAME with CA certificate in $OPENVAS_SIGNING_CA_CERT_FILENAME to generate certificate in $OPENVAS_CERT_FILENAME"
}

# Install a certificate
# Where should the certificate and the key be installed to?
install_cert ()
{
  log_verbose "Installing certificate and key."

  if [ ! -s "$OPENVAS_KEY_FILENAME" ] || [ ! -s "$OPENVAS_CERT_FILENAME" ]
  then
    log_err "ERROR: Files to install ($OPENVAS_KEY_FILENAME and $OPENVAS_CERT_FILENAME) not found. Aborting."
    exit 1
  fi

  if [ ! -d "$OPENVAS_CERT_LOCATION" ] || [ ! -d "$OPENVAS_KEY_LOCATION" ]
  then
    log_verbose "Install destinations do not exist as directories, attempting to create them."
    set_up_directories
  fi


  if [ ! -w "$OPENVAS_CERT_LOCATION" ] || [ ! -w "$OPENVAS_KEY_LOCATION" ]
  then
    log_err "ERROR: Install destinations are not writable. Aborting."
    exit 1
  fi

  KEY_INSTALL="$OPENVAS_KEY_LOCATION/${1}key.pem"
  if [ -f "$KEY_INSTALL" ] && [ $FORCE -ne 1 ]
  then
    echo "$KEY_INSTALL exists already, not overwriting."
    echo "Use '-f' parameter to overwrite existing files."
    exit 1
  else
    cp "$OPENVAS_KEY_FILENAME" "$KEY_INSTALL"
    if [ $? -ne 0 ]
    then
      log_err "Failed to install $OPENVAS_KEY_FILENAME to $KEY_INSTALL.  Aborting."
      exit 1
    else
      log_write "Installed private key to $KEY_INSTALL."
    fi
  fi

  CERT_INSTALL="$OPENVAS_CERT_LOCATION/${1}cert.pem"
  if [ -f "$CERT_INSTALL" ] && [ $FORCE -ne 1 ]
  then
    echo "$CERT_INSTALL exists already, not overwriting."
    echo "Use '-f' parameter to overwrite existing files."
    exit 1
  else
    cp "$OPENVAS_CERT_FILENAME" "$CERT_INSTALL"
    if [ $? -ne 0 ]
    then
      log_err "Failed to install $OPENVAS_CERT_FILENAME to $CERT_INSTALL.  Aborting."
      exit 1
    else
      log_write "Installed certificate to $CERT_INSTALL."
    fi
  fi
}

verify ()
{
  ALL_OK=1

  if [ -d "$OPENVAS_KEY_LOCATION" ]
  then
    echo "OK: Directory for keys ($OPENVAS_KEY_LOCATION) exists."
  else
    echo "ERROR: Directory for keys ($OPENVAS_KEY_LOCATION) not found!"
    ALL_OK=0
  fi
  if [ -d "$OPENVAS_CERT_LOCATION" ]
  then
    echo "OK: Directory for certificates ($OPENVAS_CERT_LOCATION) exists."
  else
    echo "ERROR: Directory for certificates ($OPENVAS_CERT_LOCATION) not found!"
    ALL_OK=0
  fi
  if [ -s "$OPENVAS_KEY_LOCATION/cakey.pem" ]
  then
    echo "OK: CA key found in $OPENVAS_KEY_LOCATION/cakey.pem"
  else
    echo "ERROR: CA key not found in $OPENVAS_KEY_LOCATION/cakey.pem"
    ALL_OK=0
  fi
  if [ -s "$OPENVAS_CERT_LOCATION/cacert.pem" ]
  then
    echo "OK: CA certificate found in $OPENVAS_CERT_LOCATION/cacert.pem"
  else
    echo "ERROR: CA certificate not found in $OPENVAS_CERT_LOCATION/cacert.pem"
    ALL_OK=0
  fi

  # TODO: Check file permissions

  certtool \
    --verify \
    --load-ca-certificate $OPENVAS_CERT_LOCATION/cacert.pem \
    --infile $OPENVAS_CERT_LOCATION/cacert.pem \
    >> "$CERTTOOL_LOGFILE" 2>&1
  if [ $? -eq 0 ]
  then
    echo "OK: CA certificate verified."
  else
    echo "ERROR: CA certificate failed verification, see $CERTTOOL_LOGFILE for details. Aborting."
    ALL_OK=0
  fi

  for cert in $(find $OPENVAS_CERT_LOCATION -name "*pem" ! -name cacert.pem)
  do
    certtool \
      --verify \
      --load-ca-certificate $OPENVAS_CERT_LOCATION/cacert.pem \
      --infile $cert \
      >> "$CERTTOOL_LOGFILE" 2>&1
    if [ $? -eq 0 ]
    then
      echo "OK: Certificate $cert verified."
    else
      echo "ERROR: Certificate $cert failed verification, see $CERTTOOL_LOGFILE for details. Aborting."
    ALL_OK=0
    fi
  done

  echo
  if [ $ALL_OK -eq 1 ]
  then
    echo "OK: Your OpenVAS certificate infrastructure passed validation."
  else
    echo "ERROR: Your OpenVAS certificate infrastructure did NOT pass validation."
    echo "       See messages above for details."
    exit 1
  fi

  exit 0
}


# Clean up
clean_up ()
{
  if [ $USE_TEMP_DIR -eq 1 ]
  then
    if [ $DEBUG -ne 1 ]
    then
      log_write "Removing temporary directory $OPENVAS_CERT_DIR."
      rm -rf $OPENVAS_CERT_DIR
    else
      echo "DEBUG: Not removing $OPENVAS_CERT_DIR in debug mode."
    fi
  fi
}

# Parse command line options
if [ $# -eq 0 ]
then
  print_help
fi

AUTO=0
AUTO_SKIP_CA=0
INSTALL_CERTIFICATE=0
INSTALL_CA=0
CREATE_CERTIFICATE=0
CREATE_SELF_SIGNED=0
CERTIFICATE_TYPE=0
CREATE_SERVER_CERTIFICATE=0
CREATE_CLIENT_CERTIFICATE=0
CREATE_CSR=0
CREATE_CA=0
SIGN_CERTIFICATE=0
VERIFY=0
VERBOSE=0
DEBUG=0
QUIET=0
FORCE=0

while getopts haAsiIcfdCSVvqe:ELrR OPTION
do
  case "$OPTION" in
    h)
      print_help
      ;;
    a)
      AUTO=1
      ;;
    A)
      AUTO_SKIP_CA=1
      ;;
    s)
      CREATE_CERTIFICATE=1
      CREATE_SELF_SIGNED=1
      ;;
    i)
      INSTALL_CERTIFICATE=1
      ;;
    I)
      INSTALL_CA=1
      ;;
    c)
      CREATE_CERTIFICATE=1
      CREATE_SELF_SIGNED=0
      ;;
    f)
      FORCE=1
      ;;
    d)
      DEBUG=1
      ;;
    C)
      CREATE_CA=1
      ;;
    S)
      SIGN_CERTIFICATE=1
      ;;
    v)
      VERBOSE=1
      ;;
    V)
      VERIFY=1
      ;;
    q)
      QUIET=1
      ;;
    e)
      CONFIGURATION_FILE="$OPTARG"
      ;;
    E)
      CERTIFICATE_TYPE=$SERVER_CERTIFICATE
      ;;
    L)
      CERTIFICATE_TYPE=$CLIENT_CERTIFICATE
      ;;
    r)
      CREATE_CSR=1
      ;;
    R)
      CERTIFICATE_TYPE=$CA_CERTIFICATE
      CREATE_CSR=1
      ;;
    \?)
      print_help
      ;;
  esac
done

if [ -n "$CONFIGURATION_FILE" ]
then
  if [ -r "$CONFIGURATION_FILE" ]
  then
    log_verbose "Reading configuration from $CONFIGURATION_FILE."
    . "$CONFIGURATION_FILE"
  else
    log_err "Configuration file $CONFIGURATION_FILE could not be read. Aborting."
    exit 1
  fi
fi

set_defaults

if [ $AUTO -eq 1 ]
then
  set_up

  CERTS_EXIST=0

  if [ $AUTO_SKIP_CA -eq 1 ]
  then
    if [ -s "$OPENVAS_CERT_LOCATION/servercert.pem" ] \
      || [ -s "$OPENVAS_CERT_LOCATION/clientcert.pem" ]
    then
      CERTS_EXIST=1
    fi
  else
    if [ -s "$OPENVAS_CERT_LOCATION/cacert.pem" ] \
      || [ -s "$OPENVAS_CERT_LOCATION/servercert.pem" ] \
      || [ -s "$OPENVAS_CERT_LOCATION/clientcert.pem" ]
    then
      CERTS_EXIST=1
    fi
  fi

  if [ $CERTS_EXIST -eq 1 ]
  then
    if [ $FORCE -ne 1 ]
    then
      echo "Existing certificate infrastructure found, aborting."
      echo "Use '-f' parameter to overwrite existing certificates."
      exit 1
    fi
  fi

  log_verbose "Creating new certificate infrastructure in automatic mode."

  if [ $AUTO_SKIP_CA -ne 1 ]
  then
    CERTIFICATE_TYPE=$CA_CERTIFICATE
    CREATE_SELF_SIGNED=1
    set_prefix "ca"
    create_private_key "$OPENVAS_KEY_FILENAME"
    create_certificate
    log_verbose "  CA certificate generated."
    install_cert "${OPENVAS_CERT_PREFIX}"
    log_verbose "  CA certificate and key installed."
    CREATE_SELF_SIGNED=0
  else
    log_verbose "Skipping CA creation as requested."
  fi

  CERTIFICATE_TYPE=$SERVER_CERTIFICATE
  set_prefix "server"
  create_private_key "$OPENVAS_KEY_FILENAME"
  create_certificate
  sign_certificate
  log_verbose "  Server certificate generated."
  install_cert "${OPENVAS_CERT_PREFIX}"
  log_verbose "  Server certificate and key installed."

  CERTIFICATE_TYPE=$CLIENT_CERTIFICATE
  set_prefix "client"
  create_private_key "$OPENVAS_KEY_FILENAME"
  create_certificate
  sign_certificate
  log_verbose "  Client certificate generated."
  install_cert "${OPENVAS_CERT_PREFIX}"
  log_verbose "  Client certificate and key installed."

  clean_up

  exit 0
fi

if [ $VERIFY -eq 1 ]
then
  set_up
  verify
fi

if [ $CREATE_CSR -eq 1 ]
then
  set_up
  if [ $CERTIFICATE_TYPE -eq $CA_CERTIFICATE ]
  then
    set_prefix "ca"
  fi
  create_private_key "$OPENVAS_KEY_FILENAME"
  create_certificate
fi

if [ $CREATE_CA -eq 1 ]
then
  set_up
  set_prefix "ca"
  create_private_key "$OPENVAS_KEY_FILENAME"
  CERTIFICATE_TYPE=$CA_CERTIFICATE
  CREATE_SELF_SIGNED=1
  create_certificate
fi

if [ $INSTALL_CA -eq 1 ]
then
  set_up
  install_cert "ca"
fi

if [ $CREATE_CERTIFICATE -eq 1 ]
then
  set_up
  create_private_key "$OPENVAS_KEY_FILENAME"
  create_certificate
  if [ $CREATE_SELF_SIGNED -ne 1 ]
  then
    sign_certificate
  fi

  if [ $INSTALL_CERTIFICATE -eq 1 ]
  then
    install_cert "$OPENVAS_CERT_PREFIX"
  fi
fi

if [ $SIGN_CERTIFICATE -eq 1 ]
then
  set_up
  sign_certificate
fi

if [ $INSTALL_CERTIFICATE -eq 1 ]
then
  set_up
  install_cert "$OPENVAS_CERT_PREFIX"
fi

# If the files have been installed, clean up the generation directory.
if [ $INSTALL_CERTIFICATE -eq 1 ] || [ $INSTALL_CA -eq 1 ]
then
  clean_up
fi

exit 0
