# 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 $
+# $Id: ssl,v 1.9 2006/07/17 21:28:55 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 -n -e 's@.*/CN=\([^/]*\).*@\1@p'
+}
+
+# Print the emailAddress of an SSL certificate
+ssl_email ()
+{
+ openssl x509 -noout -in $1 -subject | \
+ sed -n -e 's@.*/emailAddress=\([^/]*\).*@\1@p'
+}
+
+# Verify a certificate. If invalid, generate a new self-signed
+# certificate.
+verify_or_generate_certificate() {
+ crt=$1
+ key=$2
+ ca=$3
+ cname=$4
+ email=$5
+
+ # 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
+ verify=$(openssl verify -CAfile $ca $crt)
+ # Delete if invalid or if the subject has changed
+ if grep -q "error" <<<$verify || \
+ [ "$(ssl_cname $crt)" != "$cname" ] || \
+ [ "$(ssl_email $crt)" != "$email" ] ; then
+ rm -f $crt $ca
+ fi
+ fi
+
+ if [ ! -f $crt ] ; then
+ # Set subject
+ subj=
+ if [ -n "$cname" ] ; then
+ subj="$subj/CN=$cname"
+ fi
+ if [ -n "$email" ] ; then
+ subj="$subj/emailAddress=$email"
+ 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
+ chmod 644 $crt
+
+ # The certificate it self-signed, so it is its own CA
+ cp -a $crt $ca
+ fi
+}
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.
+ # Verify or generate MA/SA certificate if necessary. This
+ # self-signed certificate may be overridden later.
+ verify_or_generate_certificate \
+ $PLC_MA_SA_SSL_CRT $PLC_MA_SA_SSL_KEY $PLC_MA_SA_CA_SSL_CRT \
+ "$PLC_NAME Management and Slice Authority" \
+ $PLC_MAIL_SUPPORT_ADDRESS
+
+ # Make MA/SA key readable by apache so that the API can sign
+ # certificates
+ chown apache $PLC_MA_SA_SSL_KEY
+ chmod 600 $PLC_MA_SA_SSL_KEY
+
+ # Extract the public key of the root CA (if any) that signed
+ # the MA/SA certificate.
+ openssl x509 -in $PLC_MA_SA_CA_SSL_CRT -noout -pubkey >$PLC_MA_SA_CA_SSL_KEY_PUB
+ check
+ chmod 644 $PLC_MA_SA_CA_SSL_KEY_PUB
+
+ # 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.
for server in WWW API BOOT ; do
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
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
enabled=PLC_${server}_ENABLED