Setting tag myplc-5.3-5
[myplc.git] / plc.d / ssl
index 6480db3..f09294a 100755 (executable)
--- a/plc.d/ssl
+++ b/plc.d/ssl
 #!/bin/bash
 #
-# priority: 400
+# priority: 300
 #
 # Generate SSL certificates
 #
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: ssl,v 1.1 2006/04/06 21:51:59 mlhuang Exp $
-#
 
 # Source function library and configuration
 . /etc/plc.d/functions
+. /etc/planetlab/plc_config
+
+# Be verbose
+set -x
+
+# Print the CNAME of an SSL certificate
+ssl_cname ()
+{
+    openssl x509 -noout -in $1 -subject | \
+       sed -e 's|.*CN *= *\([-_a-zA-Z0-9.]*\).*|\1|' | \
+       lower
+}
+
+backup_file ()
+{
+    filepath=$1
+    filename=$(basename ${filepath})
+    dir=$(dirname ${filepath})
+    mv -f ${filepath} ${dir}/${filename}-`date +%Y-%m-%d-%H-%M-%S`.bak
+}
+
+# Verify a certificate. If invalid, generate a new self-signed
+# certificate.
+verify_or_generate_certificate() {
+    crt=$1
+    key=$2
+    ca=$3
+    cname=$(lower $4)
+
+    # If the CA certificate does not exist, assume that the
+    # certificate is self-signed.
+    if [ ! -f $ca ] ; then
+       cp -a $crt $ca
+    fi
+
+    if [ -f $crt ] ; then
+       # Check if certificate is valid
+       # Backup if invalid or if the subject has changed
+       if openssl verify -CAfile $ca $crt | grep -q "error" || \
+           [ "$(ssl_cname $crt)" != "$cname" ] ; then
+            backup_file $crt
+            backup_file $ca
+            backup_file $key
+       fi
+    fi
+
+    if [ ! -f $crt ] ; then
+        # Set subject
+       subj=
+       if [ -n "$cname" ] ; then
+           subj="$subj/CN=$cname"
+       fi
+
+       # Generate new self-signed certificate
+       mkdir -p $(dirname $crt)
+       openssl req -new -x509 -days 3650 -set_serial $RANDOM \
+           -batch -subj "$subj" \
+           -nodes -keyout $key -out $crt
+       check
+
+       # The certificate it self-signed, so it is its own CA
+       cp -a $crt $ca
+    fi
+
+    # Fix permissions
+    chmod 644 $crt $ca
+}
 
 case "$1" in
     start)
-       MESSAGE=$"Generating SSL certificates"
-       dialog "$MESSAGE"
-
-       # Generate self-signed SSL certificate(s). These nice
-       # commands come from the mod_ssl spec file for Fedora Core
-       # 2. We generate a certificate for each enabled server
-       # with a different hostname. These self-signed
-       # certificates may be overridden later.
-       for server in WWW API BOOT ; do
-           ssl_key=PLC_${server}_SSL_KEY
+
+       # Generate HTTPS certificates if necessary. We generate a
+       # certificate for each enabled server with a different
+       # hostname. These self-signed certificates may be overridden
+       # later.
+        MESSAGE=$"Generating SSL certificates for"
+        dialog "$MESSAGE"
+
+       for server in WWW API BOOT MONITOR; do
+           eval "a=\$PLC_${server}_ENABLED"
+            echo $a
+            if [ "$a" -ne 1 ] ; then
+               echo "Skipping"
+                continue
+            fi
+           dialog "$server"
+            ssl_key=PLC_${server}_SSL_KEY
            ssl_crt=PLC_${server}_SSL_CRT
+           ca_ssl_crt=PLC_${server}_CA_SSL_CRT
            hostname=PLC_${server}_HOST
 
            # Check if we have already generated a certificate for
            # the same hostname.
-           for previous_server in WWW API BOOT ; do
+           for previous_server in WWW API BOOT MONITOR; do
                if [ "$server" = "$previous_server" ] ; then
                    break
                fi
                previous_ssl_key=PLC_${previous_server}_SSL_KEY
                previous_ssl_crt=PLC_${previous_server}_SSL_CRT
+               previous_ca_ssl_crt=PLC_${previous_server}_CA_SSL_CRT
                previous_hostname=PLC_${previous_server}_HOST
 
                if [ -f ${!previous_ssl_crt} ] && \
                    [ "$(ssl_cname ${!previous_ssl_crt})" = "${!hostname}" ] ; then
                    cp -a ${!previous_ssl_key} ${!ssl_key}
                    cp -a ${!previous_ssl_crt} ${!ssl_crt}
+                   cp -a ${!previous_ca_ssl_crt} ${!ca_ssl_crt}
                    break
                fi
            done
 
-           # Check if self signed certificate is valid
-           if [ -f ${!ssl_crt} ] ; then
-               verify=$(openssl verify ${!ssl_crt})
-               # If self signed
-               if grep -q "self signed certificate" <<<$verify ; then
-                   # Delete if expired or hostname changed
-                   if grep -q "expired" <<<$verify || \
-                       [ "$(ssl_cname ${!ssl_crt})" != "${!hostname}" ] ; then
-                       rm -f ${!ssl_crt}
-                   fi
-               else
-                   echo "$verify" >&2
-               fi
-           fi
-
-           # Generate new self signed certificate
-           if [ ! -f ${!ssl_crt} ] ; then
-               mkdir -p $(dirname ${!ssl_crt})
-               openssl req -new -x509 -days 365 -set_serial $RANDOM \
-                   -nodes -keyout ${!ssl_key} -out ${!ssl_crt} <<EOF
---
-US
-NJ
-Princeton
-PlanetLab Federation
-$PLC_NAME Central
-${!hostname}
-$PLC_MAIL_SUPPORT_ADDRESS
-EOF
-               check
-               chmod 644 ${!ssl_crt}
-           fi
+           verify_or_generate_certificate \
+               ${!ssl_crt} ${!ssl_key} ${!ca_ssl_crt} \
+               ${!hostname}
        done
 
-       # API requires a public key for slice ticket verification
-       if [ ! -f $PLC_API_SSL_KEY_PUB ] ; then
-           openssl rsa -pubout <$PLC_API_SSL_KEY >$PLC_API_SSL_KEY_PUB
-           check
-       fi
-
-       # Install into both /etc/pki (Fedora Core 4) and
-       # /etc/httpd/conf (Fedora Core 2). If the API, boot, and
-       # web servers are all running on the same machine, the web
+       # Install HTTPS certificates into both /etc/pki (Fedora Core
+       # 4) and /etc/httpd/conf (Fedora Core 2). If the API, boot,
+       # and web servers are all running on the same machine, the web
        # server certificate takes precedence.
-       for server in API BOOT WWW ; do
+       for server in API BOOT MONITOR WWW; do
            enabled=PLC_${server}_ENABLED
            if [ "${!enabled}" != "1" ] ; then
                continue
            fi
            ssl_key=PLC_${server}_SSL_KEY
            ssl_crt=PLC_${server}_SSL_CRT
+           ssl_ca_crt=PLC_${server}_CA_SSL_CRT
 
            symlink ${!ssl_crt} /etc/pki/tls/certs/localhost.crt
            symlink ${!ssl_key} /etc/pki/tls/private/localhost.key
+           symlink ${!ssl_ca_crt} /etc/pki/tls/certs/server-chain.crt
            symlink ${!ssl_crt} /etc/httpd/conf/ssl.crt/server.crt
            symlink ${!ssl_key} /etc/httpd/conf/ssl.key/server.key
        done
 
+       # Ensure that the server-chain gets used, as it is off by
+       # default.
+       sed -i -e 's/^#SSLCertificateChainFile /SSLCertificateChainFile /' \
+           /etc/httpd/conf.d/ssl.conf
+
        result "$MESSAGE"
        ;;
 esac