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