#!/bin/bash
+# $Id$
+# $URL$
#
-# 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.5 2006/06/23 21:47:18 mlhuang Exp $
-#
# Source function library and configuration
. /etc/plc.d/functions
# Be verbose
set -x
-mkcert ()
+# Print the CNAME of an SSL certificate
+ssl_cname ()
{
- CN=$1
- KEY=$2
- CRT=$3
-
- # Generate a temporary CSR. We could save the CSR, but it's not
- # worth the trouble.
- csr=$(mktemp /tmp/csr.XXXXXX)
-
- mkdir -p $(dirname $KEY)
- openssl req -config /etc/planetlab/ssl/openssl.cnf \
- -new -extensions v3_req -days 365 -set_serial $RANDOM \
- -batch -subj "/CN=$CN" \
- -nodes -keyout $KEY -out $csr
- check
- chmod 600 $KEY
-
- # Generate and sign certificate from CSR
- serial=$(cat /etc/planetlab/ssl/serial)
-
- openssl ca -config /etc/planetlab/ssl/openssl.cnf \
- -keyfile $PLC_ROOT_CA_SSL_KEY \
- -cert $PLC_ROOT_CA_SSL_CRT \
- -batch -infiles $csr
- check
-
- mv /etc/planetlab/ssl/$serial.pem $CRT
- chmod 644 $CRT
-
- # Delete CSR
- rm -f $csr
+ openssl x509 -noout -in $1 -subject | \
+ sed -n -e 's@.*/CN=\([^/]*\).*@\1@p' | \
+ lower
}
-case "$1" in
- start)
- MESSAGE=$"Generating SSL certificates"
- dialog "$MESSAGE"
-
- # Check if root CA certificate is valid
- if [ -f $PLC_ROOT_CA_SSL_CRT ] ; then
- verify=$(openssl verify $PLC_ROOT_CA_SSL_CRT)
- # If self signed, assume that we generated it
- if grep -q "self signed certificate" <<<$verify ; then
- # Delete if expired or PLC name or e-mail address has changed
- if grep -q "expired" <<<$verify || \
- [ "$(ssl_cname $PLC_ROOT_CA_SSL_CRT)" != "$PLC_NAME Root CA" ] || \
- [ "$(ssl_email $PLC_ROOT_CA_SSL_CRT)" != "$PLC_MAIL_SUPPORT_ADDRESS" ] ; then
- rm -f $PLC_ROOT_CA_SSL_CRT
- fi
- fi
- fi
+backup_file ()
+{
+ filepath=$1
+ filename=$(basename ${filepath})
+ dir=$(dirname ${filepath})
+ mv -f ${filepath} ${dir}/${filename}-`date +%Y-%m-%d-%H-%M-%S`.bak
+}
- # Generate root CA key pair and certificate
- if [ ! -f $PLC_ROOT_CA_SSL_CRT ] ; then
- mkdir -p $(dirname $PLC_ROOT_CA_SSL_CRT)
- openssl req -config /etc/planetlab/ssl/openssl.cnf \
- -new -x509 -extensions v3_ca -days 3650 -set_serial $RANDOM \
- -batch -subj "/CN=$PLC_NAME Root CA/emailAddress=$PLC_MAIL_SUPPORT_ADDRESS" \
- -nodes -keyout $PLC_ROOT_CA_SSL_KEY -out $PLC_ROOT_CA_SSL_CRT
- check
- chmod 600 $PLC_ROOT_CA_SSL_KEY
- chmod 644 $PLC_ROOT_CA_SSL_CRT
-
- # API certificate verification requires a public key
- openssl rsa -pubout <$PLC_ROOT_CA_SSL_KEY >$PLC_ROOT_CA_SSL_KEY_PUB
- check
- chmod 644 $PLC_ROOT_CA_SSL_KEY_PUB
-
- # Reset DB
- >/etc/planetlab/ssl/index.txt
- echo "01" >/etc/planetlab/ssl/serial
+# 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
- # Check if MA/SA certificate is valid
- if [ -f $PLC_MA_SA_SSL_CRT ] ; then
- verify=$(openssl verify -CAfile $PLC_ROOT_CA_SSL_CRT $PLC_MA_SA_SSL_CRT)
- # Delete if expired or not signed correctly
- if grep -q "error" <<<$verify ; then
- rm -f $PLC_MA_SA_SSL_CRT
- fi
+ if [ ! -f $crt ] ; then
+ # Set subject
+ subj=
+ if [ -n "$cname" ] ; then
+ subj="$subj/CN=$cname"
fi
- # Generate MA/SA key pair and certificate
- if [ ! -f $PLC_MA_SA_SSL_CRT ] ; then
- mkcert "$PLC_NAME Management and Slice Authority" \
- $PLC_MA_SA_SSL_KEY $PLC_MA_SA_SSL_CRT
+ # 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
- # make readable by apache to sign certificates
- chown apache $PLC_MA_SA_SSL_KEY
- chmod 600 $PLC_MA_SA_SSL_KEY
+ # The certificate it self-signed, so it is its own CA
+ cp -a $crt $ca
+ fi
- # API requires a public key for slice ticket verification
- openssl rsa -pubout <$PLC_MA_SA_SSL_KEY >$PLC_MA_SA_SSL_KEY_PUB
- check
- chmod 644 $PLC_MA_SA_SSL_KEY_PUB
- fi
+ # Fix permissions
+ chmod 644 $crt $ca
+}
- # Generate HTTPS certificate(s). We generate a certificate for
- # each enabled server with a different hostname.
- for server in WWW API BOOT ; do
- ssl_key=PLC_${server}_SSL_KEY
+case "$1" in
+ start)
+
+ # 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 certificate is valid
- if [ -f ${!ssl_crt} ] ; then
- verify=$(openssl verify -CAfile $PLC_ROOT_CA_SSL_CRT ${!ssl_crt})
- # Delete if expired or hostname changed. These
- # certificates do not necessarily have to be signed by
- # the root CA; they may be signed by a third party,
- # e.g., Entrust or Verisign.
- if grep -q "expired" <<<$verify || \
- [ "$(ssl_cname ${!ssl_crt})" != "${!hostname}" ] ; then
- rm -f ${!ssl_crt}
- fi
- fi
-
- # Generate and sign certificate
- if [ ! -f ${!ssl_crt} ] ; then
- mkcert ${!hostname} ${!ssl_key} ${!ssl_crt}
- fi
+ verify_or_generate_certificate \
+ ${!ssl_crt} ${!ssl_key} ${!ca_ssl_crt} \
+ ${!hostname}
done
# 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