- generate up to 5 sets of SSL certs: a root CA keypair/cert used to
authorMark Huang <mlhuang@cs.princeton.edu>
Fri, 23 Jun 2006 21:47:18 +0000 (21:47 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Fri, 23 Jun 2006 21:47:18 +0000 (21:47 +0000)
  sign the other 4 certs, an MA/SA keypair/cert used for signing slice
  tickets and other docs, and www/boot/api keypairs/certs
- /etc/planetlab/ssl is used to store the OpenSSL state; probably need
  to think of a better long-term solution

plc.d/ssl

index fc3fa74..0615d75 100755 (executable)
--- a/plc.d/ssl
+++ b/plc.d/ssl
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: ssl,v 1.3 2006/04/07 04:28:16 mlhuang Exp $
+# $Id: ssl,v 1.4 2006/04/25 21:18:19 mlhuang Exp $
 #
 
 # Source function library and configuration
 . /etc/plc.d/functions
 . /etc/planetlab/plc_config
 
+# Be verbose
+set -x
+
+mkcert ()
+{
+    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
+}
+
 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.
+       # 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
+
+       # 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
+       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
+       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
+
+           # 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
+
+       # 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
            ssl_crt=PLC_${server}_SSL_CRT
@@ -47,41 +136,28 @@ case "$1" in
                fi
            done
 
-           # Check if self signed certificate is valid
+           # Check if 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
+               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 new self signed certificate
+           # Generate and sign certificate
            if [ ! -f ${!ssl_crt} ] ; then
-               mkdir -p $(dirname ${!ssl_crt})
-               openssl req -new -x509 -days 365 -set_serial $RANDOM \
-                   -batch -subj "/CN=${!hostname}" \
-                   -nodes -keyout ${!ssl_key} -out ${!ssl_crt}
-               check
-               chmod 644 ${!ssl_crt}
+               mkcert ${!hostname} ${!ssl_key} ${!ssl_crt}
            fi
        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