aa3a0fe16e5841fbb9de5d7584caf53819517a90
[myplc.git] / plc.d / ssl
1 #!/bin/bash
2 # $Id$
3 # $URL$
4 #
5 # priority: 300
6 #
7 # Generate SSL certificates
8 #
9 # Mark Huang <mlhuang@cs.princeton.edu>
10 # Copyright (C) 2006 The Trustees of Princeton University
11 #
12
13 # Source function library and configuration
14 . /etc/plc.d/functions
15 . /etc/planetlab/plc_config
16
17 # Be verbose
18 set -x
19
20 # Print the CNAME of an SSL certificate
21 ssl_cname ()
22 {
23     openssl x509 -noout -in $1 -subject | \
24         sed -n -e 's@.*/CN=\([^/]*\).*@\1@p' | \
25         lower
26 }
27
28 backup_file ()
29 {
30     filepath=$1
31     filename=$(basename ${filepath})
32     dir=$(dirname ${filepath})
33     mv -f ${filepath} ${dir}/${filename}-`date +%Y-%m-%d-%H-%M-%S`.bak
34 }
35
36 # Verify a certificate. If invalid, generate a new self-signed
37 # certificate.
38 verify_or_generate_certificate() {
39     crt=$1
40     key=$2
41     ca=$3
42     cname=$(lower $4)
43
44     # If the CA certificate does not exist, assume that the
45     # certificate is self-signed.
46     if [ ! -f $ca ] ; then
47         cp -a $crt $ca
48     fi
49
50     if [ -f $crt ] ; then
51         # Check if certificate is valid
52         # Backup if invalid or if the subject has changed
53         if openssl verify -CAfile $ca $crt | grep -q "error" || \
54             [ "$(ssl_cname $crt)" != "$cname" ] ; then
55             backup_file $crt
56             backup_file $ca
57             backup_file $key
58         fi
59     fi
60
61     if [ ! -f $crt ] ; then
62         # Set subject
63         subj=
64         if [ -n "$cname" ] ; then
65             subj="$subj/CN=$cname"
66         fi
67
68         # Generate new self-signed certificate
69         mkdir -p $(dirname $crt)
70         openssl req -new -x509 -days 3650 -set_serial $RANDOM \
71             -batch -subj "$subj" \
72             -nodes -keyout $key -out $crt
73         check
74
75         # The certificate it self-signed, so it is its own CA
76         cp -a $crt $ca
77     fi
78
79     # Fix permissions
80     chmod 644 $crt $ca
81 }
82
83 case "$1" in
84     start)
85
86         # Generate HTTPS certificates if necessary. We generate a
87         # certificate for each enabled server with a different
88         # hostname. These self-signed certificates may be overridden
89         # later.
90         MESSAGE=$"Generating SSL certificates for"
91         dialog "$MESSAGE"
92
93         for server in WWW API BOOT MONITOR; do
94             eval "a=\$PLC_${server}_ENABLED"
95             echo $a
96             if [ "$a" -ne 1 ] ; then
97                 echo "Skipping"
98                 continue
99             fi
100             dialog "$server"
101             ssl_key=PLC_${server}_SSL_KEY
102             ssl_crt=PLC_${server}_SSL_CRT
103             ca_ssl_crt=PLC_${server}_CA_SSL_CRT
104             hostname=PLC_${server}_HOST
105
106             # Check if we have already generated a certificate for
107             # the same hostname.
108             for previous_server in WWW API BOOT MONITOR; do
109                 if [ "$server" = "$previous_server" ] ; then
110                     break
111                 fi
112                 previous_ssl_key=PLC_${previous_server}_SSL_KEY
113                 previous_ssl_crt=PLC_${previous_server}_SSL_CRT
114                 previous_ca_ssl_crt=PLC_${previous_server}_CA_SSL_CRT
115                 previous_hostname=PLC_${previous_server}_HOST
116
117                 if [ -f ${!previous_ssl_crt} ] && \
118                     [ "$(ssl_cname ${!previous_ssl_crt})" = "${!hostname}" ] ; then
119                     cp -a ${!previous_ssl_key} ${!ssl_key}
120                     cp -a ${!previous_ssl_crt} ${!ssl_crt}
121                     cp -a ${!previous_ca_ssl_crt} ${!ca_ssl_crt}
122                     break
123                 fi
124             done
125
126             verify_or_generate_certificate \
127                 ${!ssl_crt} ${!ssl_key} ${!ca_ssl_crt} \
128                 ${!hostname}
129         done
130
131         # Install HTTPS certificates into both /etc/pki (Fedora Core
132         # 4) and /etc/httpd/conf (Fedora Core 2). If the API, boot,
133         # and web servers are all running on the same machine, the web
134         # server certificate takes precedence.
135         for server in API BOOT MONITOR WWW; do
136             enabled=PLC_${server}_ENABLED
137             if [ "${!enabled}" != "1" ] ; then
138                 continue
139             fi
140             ssl_key=PLC_${server}_SSL_KEY
141             ssl_crt=PLC_${server}_SSL_CRT
142             ssl_ca_crt=PLC_${server}_CA_SSL_CRT
143
144             symlink ${!ssl_crt} /etc/pki/tls/certs/localhost.crt
145             symlink ${!ssl_key} /etc/pki/tls/private/localhost.key
146             symlink ${!ssl_ca_crt} /etc/pki/tls/certs/server-chain.crt
147             symlink ${!ssl_crt} /etc/httpd/conf/ssl.crt/server.crt
148             symlink ${!ssl_key} /etc/httpd/conf/ssl.key/server.key
149         done
150
151         # Ensure that the server-chain gets used, as it is off by
152         # default.
153         sed -i -e 's/^#SSLCertificateChainFile /SSLCertificateChainFile /' \
154             /etc/httpd/conf.d/ssl.conf
155
156         result "$MESSAGE"
157         ;;
158 esac
159
160 exit $ERRORS