#!/bin/sh
# Copyright 2001  David Cantrell, Concord, California USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# DESCRIPTION: Secure Sockets Layer support
#
# ChangeLog:
# 25-Mar-2002    Cleanups for new dialog version <pjv>
#
# 23-May-2001    Modified the /etc/rc.d/rc.httpd file that's written out.
#
# 09-Mar-2001    Added the description line, which is for apacheconfig.
#
# 26-Feb-2001    Initial version.
#

OPENSSL="`which openssl`"
CONF=/etc/apache
CRT=$CONF/ssl.crt
KEY=$CONF/ssl.key
CSR=$CONF/ssl.csr

# Make sure we have the required components
if [ ! -x $OPENSSL ]; then
   exit
fi
if [ ! -d $CRT ]; then
   exit
fi
if [ ! -d $KEY ]; then
   exit
fi
if [ ! -d $CSR ]; then
   exit
fi

# Set some initial variables and locations
TMP=/var/log/setup/tmp
NEWCERT=n
if [ ! -d $TMP ]; then
   mkdir -p $TMP
   chmod 700 $TMP
fi

#
# Functions!
#

# Create a new certificate authority, using information from the user
create_new_ca() {
   # clean out any old temp files
   rm -rf $TMP/ca.key $TMP/ca.key.unsecure $TMP/ca.crt

   # let the user know what we're about to do
   dialog --title "CREATING A NEW CERTIFICATE AUTHORITY" --msgbox "The next several screens will take you through the steps needed to create a new Triple DES encrypted Certificate Authority (CA).  You will use this CA later to sign your Apache site certificate." 0 0

   # how long should the CA be valid for?
   dialog --title "VALID DURATION" --menu "How long shall this new certificate authority be valid?" 0 0 0 "30" "Thirty days" "60" "Sixty days" "90" "Ninety days" "365" "One year" "Other" "A different number of days" 2> $TMP/output

   if [ $? = 1 -o $? = 255 ]; then
      rm -f $TMP/output
      exit
   fi

   OUTPUT=`cat $TMP/output`
   rm -rf $TMP/output

   if [ "$OUTPUT" = "Other" ]; then
      dialog --title "ENTER A VALID DURATION" --inputbox "Enter the number of days for this certificate authority to be valid." 0 0 "30" 2> $TMP/output

      if [ $? = 1 -o $? = 255 ]; then
         rm -f $TMP/output
         exit
      fi

      DAYS=`cat $TMP/output`
      rm -rf $TMP/output
   else
      DAYS=$OUTPUT
   fi

   # back to plain text
   clear

   # generate a private key for the web server
   echo
   echo "GENERATING A NEW RSA PRIVATE KEY FOR THE CA..."
   echo
   if [ -f /etc/random-seed ]; then
      $OPENSSL genrsa -des3 -rand /etc/random-seed -out $TMP/ca.key 1024
   else
      $OPENSSL genrsa -des3 -out $TMP/ca.key 1024
   fi
   echo

   # create the CA
   echo
   echo "GENERATING THE NEW CERTIFICATE AUTHORITY..."
   echo
   $OPENSSL req -new -x509 -days $DAYS -key $TMP/ca.key -out $TMP/ca.crt
   $OPENSSL x509 -noout -text -in $TMP/ca.crt > $TMP/ca.crt.text

   # the new certificate has been created, show the user, then move it in place
   cat << EOF > $TMP/tmpca
The new certificate authority has been created with the information
below.  If everything looks good, press Enter and the CA will be
installed on the system.  If there are any errors, simply press
Ctrl+C and run the configuration tool again.

EOF
   cat $TMP/tmpca $TMP/ca.crt.text > $TMP/tmpca2
   mv $TMP/tmpca2 $TMP/ca.crt.text
   rm -rf $TMP/tmpca
   dialog --title "NEW CERTIFICATE AUTHORITY" --textbox $TMP/ca.crt.text 0 0

   # install the new certificate
   if [ "$HAVE_EXISTING" = "y" ]; then
      mv $CRT/ca.crt $CRT/ca.crt.backup 2>/dev/null
      mv $KEY/ca.key $KEY/ca.key.backup 2>/dev/null
   fi

   cp -a $TMP/ca.crt $CRT/ca.crt
   chown root.root $CRT/ca.crt
   chmod 644 $CRT/ca.crt

   cp -a $TMP/ca.key $KEY/ca.key
   chown root.root $KEY/ca.key
   chmod 644 $KEY/ca.key

   if [ "$HAVE_EXISTING" = "y" ]; then
      dialog --title "NEW CERTIFICATE AUTHORITY INSTALLED" --msgbox "Your new certificate authority has been installed.  The previous one was backed up to .backup files in the appropriate subdirectorys of $CONF." 0 0
   else
      dialog --title "NEW CERTIFICATE AUTHORITY INSTALLED" --msgbox "Your new certificate authority has been installed." 0 0
   fi
}

# Create a new site certificate and sign it
create_new_cert() {
   dialog --title "CREATING A NEW SITE CERTIFICATE" --msgbox "The next several screens will take you through the steps needed to create a new Triple DES encrypted Site Certificate." 0 0

   # back to plain text
   clear

   # generate a private key for the web server
   echo
   echo "GENERATING A NEW RSA PRIVATE KEY FOR THE WEB SERVER..."
   echo
   if [ -f /etc/random-seed ]; then
      $OPENSSL genrsa -des3 -rand /etc/random-seed -out $TMP/server.key 1024
   else
      $OPENSSL genrsa -des3 -out $TMP/server.key 1024
   fi
   echo

   # create the cert signing request
   echo
   echo "GENERATING THE NEW CERTIFICATE SIGNING REQUEST..."
   echo
   $OPENSSL req -new -key $TMP/server.key -out $TMP/server.csr
   echo

   # sign the cert
   echo
   echo "SIGNING THE NEW SITE CERTIFICATE..."
   echo
   sign_cert
   echo

   # the new certificate has been created, show the user, then move it in place
   $OPENSSL x509 -noout -text -in $TMP/server.crt > $TMP/server.crt.text
   cat << EOF > $TMP/tmpcert
The new site certificate has been created with the information
below.  If everything looks good, press Enter and it will be
installed on the system.  If there are any errors, simply press
Ctrl+C and run the configuration tool again.

EOF
   cat $TMP/tmpcert $TMP/server.crt.text > $TMP/tmpcert2
   mv $TMP/tmpcert2 $TMP/server.crt.text
   rm -rf $TMP/tmpcert
   dialog --title "NEW SITE CERTIFICATE" --textbox $TMP/server.crt.text 0 0

   # install the new certificate
   if [ "$HAVE_EXISTING" = "y" ]; then
      mv $CRT/server.crt $CRT/server.crt.backup 2>/dev/null
      mv $KEY/server.key $KEY/server.key.backup 2>/dev/null
      mv $CSR/server.csr $CSR/server.csr.backup 2>/dev/null
   fi

   cp -a $TMP/server.crt $CRT/server.crt
   chown root.root $CRT/server.crt
   chmod 644 $CRT/server.crt

   cp -a $TMP/server.key $KEY/server.key
   chown root.root $KEY/server.key
   chmod 644 $KEY/server.key

   cp -a $TMP/server.csr $CSR/server.csr
   chown root.root $CSR/server.csr
   chmod 644 $CSR/server.csr

   if [ "$HAVE_EXISTING" = "y" ]; then
      dialog --title "NEW SITE CERTIFICATE INSTALLED" --msgbox "Your new site certificate has been installed.  The previous one was backed up to .backup files in the appropriate subdirectorys of $CONF." 0 0
   else
      dialog --title "NEW SITE CERTIFICATE INSTALLED" --msgbox "Your new site certificate has been installed." 0 0
   fi

   NEWCERT=y
}

sign_cert() {
   ( cd $TMP
     rm -rf ca.db.certs 2>/dev/null
     mkdir ca.db.certs
     echo '01' > ca.db.serial
     cp /dev/null ca.db.index

     # create a ca.config file
     cat << EOF > ca.config
[ ca ]
default_ca              = CA_own
[ CA_own ]
dir                     = .
certs                   = \$dir
new_certs_dir           = \$dir/ca.db.certs
database                = \$dir/ca.db.index
serial                  = \$dir/ca.db.serial
RANDFILE                = \$dir/ca.db.rand
certificate             = \$dir/ca.crt
private_key             = \$dir/ca.key
default_days            = 365
default_crl_days        = 30
default_md              = md5
preserve                = no
policy                  = policy_anything
[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional
EOF

     $OPENSSL ca -config $TMP/ca.config -out $TMP/server.crt -infiles $TMP/server.csr
     $OPENSSL verify -CAfile $TMP/ca.crt $TMP/server.crt

     rm -rf ca.config
     rm -rf ca.db.serial.old
     rm -rf ca.db.index.old )
}

########
# main #
########

CA_CRT=n
CA_KEY=n
SITE_CRT=n
SITE_KEY=n
SITE_CSR=n

# Do we have a valid CA and site cert that this script can use?
if [ -f "$CRT/ca.crt" ]; then
   # CA cert found
   CA_CRT=$CRT/ca.crt
fi
if [ -f "$KEY/ca.key" ]; then
   # CA key found
   CA_KEY=$KEY/ca.key
fi
if [ -f "$CRT/server.crt" ]; then
   # site cert found
   SITE_CRT="$CRT/server.crt"
fi
if [ -f "$KEY/server.key" ]; then
   # site key found
   SITE_KEY="$KEY/server.key"
fi
if [ -f "$CSR/server.csr" ]; then
   # site csr found
   SITE_CSR="$CSR/server.csr"
fi

# Handle the CA
if [ ! "$CA_CRT" = "n" -a ! "$CA_KEY" = "n" ]; then
   dialog --title "EXISTING CERTIFICATE AUTHORITY FOUND" --menu "An existing certificate authority was found on your system.  Would you like to try and use this one or create a new one that you can use to sign site certificates?" 0 0 0 "NO" "No, I want to create a new certificate authority" "YES" "Yes, I want to use my existing certificate authority" 2> $TMP/output

   if [ $? = 1 -o $? = 255 ]; then
      rm -f $TMP/output
      exit
   fi

   OUTPUT=`cat $TMP/output`
   rm -rf $TMP/output

   if [ "$OUTPUT" = "NO" ]; then
      HAVE_EXISTING=y
      create_new_ca
   else
      cp -a $CRT/ca.crt $TMP
      cp -a $KEY/ca.key $TMP
   fi
else
   dialog --title "CREATE A NEW CERTIFICATE AUTHORITY" --menu "No existing certificate authority could be found on your system.  In order to create a working site certificate, you need to either provide this (as $CRT/ca.crt and $KEY/ca.key) or create a new one.  What would you like to do?" 0 0 0 "NEW" "Create a new certificate authority" "EXIT" "I will go find a certificate authority elsewhere" 2> $TMP/output

   if [ $? = 1 -o $? = 255 ]; then
      rm -f $TMP/output
      exit
   fi

   OUTPUT=`cat $TMP/output`
   rm -rf $TMP/output

   if [ "$OUTPUT" = "NEW" ]; then
      create_new_ca
   else
      exit
   fi
fi

# now create the site certificate
if [ ! "$SITE_CRT" = "n" -a ! "$SITE_KEY" = "n" -a ! "$SITE_CSR" = "n" ]; then
   dialog --title "EXISTING SITE CERTIFICATE FOUND" --menu "An existing site certificate was found on your system.  It is recommended that you generate a new site certificate and sign it, but if you want to continue using your existing one, you may.  What would you like to do?" 0 0 0 "NEW" "Create a new site certificate" "EXIT" "I want to continue using my existing site certificate" 2> $TMP/output

   if [ $? = 1 -o $? = 255 ]; then
      rm -f $TMP/output
      exit
   fi

   OUTPUT=`cat $TMP/output`
   rm -rf $TMP/output

   HAVE_EXISTING=n
   if [ "$OUTPUT" = "NEW" ]; then
      HAVE_EXISTING=y
      create_new_cert
   else
      exit
   fi
else
   create_new_cert
fi

# Ask the user if he/she wants to change rc.httpd
if [ "$NEWCERT" = "y" ]; then
   # shall we change how apache is started?
   dialog --title "ENABLE HTTPS AT BOOT TIME" --menu "A new site certificate was successfully created.  Would you like to enable the HTTPS server at boot time?" 0 0 0 "YES" "Yes, enable the HTTPS server" "NO" "No, do not enable the HTTPS server" 2> $TMP/output

   if [ $? = 1 -o $? = 255 ]; then
      rm -f $TMP/output
      exit
   fi

   OUTPUT=`cat $TMP/output`
   rm -rf $TMP/output

   if [ "$OUTPUT" = "YES" ]; then
      if [ -f /etc/rc.d/rc.httpd ]; then
         mv /etc/rc.d/rc.httpd /etc/rc.d/rc.httpd.backup
      fi

      cat << "EOF" > /etc/rc.d/rc.httpd
#!/bin/sh
#
# Start the Apache web server with SSL support
#

case "$1" in
   'start')
      /usr/sbin/apachectl startssl ;;
   'stop')
      /usr/sbin/apachectl stop ;;
   'restart')
      /usr/sbin/apachectl restart ;;
   *)
      echo "usage $0 start|stop|restart" ;;
esac
EOF

      chown root.root /etc/rc.d/rc.httpd
      chmod 755 /etc/rc.d/rc.httpd
   fi
fi

# Done!
clear
echo
echo "Done.  You may now start the HTTPS server with this command:"
echo
echo "   /usr/sbin/apachectl startssl"
echo

# Cleanup
rm -rf $TMP/output

