]> granicus.if.org Git - apache/blob - test/make_sni.sh
* Doing a PROPFIND on a large collection e.g. 50.000 elements can easily
[apache] / test / make_sni.sh
1 #!/bin/sh
2 #
3 # Licensed to the Apache Software Foundation (ASF) under one or more
4 # contributor license agreements.  See the NOTICE file distributed with
5 # this work for additional information regarding copyright ownership.
6 # The ASF licenses this file to You under the Apache License, Version 2.0
7 # (the "License"); you may not use this file except in compliance with
8 # the License.  You may obtain a copy of the License at
9 #
10 #     http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 # This script will populate a directory 'sni' with 3 sites, httpd.conf
19 # and certificates as to facilitate testing of TLS server name 
20 # indication support (RFC 4366) or SNI.
21 #
22 #
23 OPENSSL=${OPENSSL:-openssl}
24 DOMAIN=${DOMAIN:-my-sni-test.org}
25 DIR=${DIR:-$PWD/sni}
26
27 # List of hostnames automatically created by default.
28 NAMES=${NAMES:-ape nut pear apple banana}
29
30 # IP address these hostnames are bound to.
31 IP=${IP:-127.0.0.1}
32
33 # A certificate password for the .p12 files of the client
34 # authentication test. Normally not set. However some browsers
35 # require a password of at least 4 characters.
36 #
37 PASSWD=${PASSWD:-}
38
39 args=`getopt a:fd:D:p: $*`
40 if [ $? != 0 ]; then
41     echo "Syntax: $0 [-f] [-a IPaddress] [-d outdir] [-D domain ] [two or more vhost names ]"
42     echo "    -f        Force overwriting of outdir (default is $DIR)"
43     echo "    -d dir    Directory to create the SNI test server in (default is $DIR)"
44     echo "    -D domain Domain name to use for this test (default is $DOMAIN)"
45     echo "    -a IP     IP address to use for this virtual host (default is $IP)"
46     echo "    -p str    Password for the client certificate test (some browsers require a set password)"
47     echo "    [names]   List of optional vhost names (default is $NAMES)"
48     echo 
49     echo "Example:"
50     echo "    $0 -D SecureBlogsAreUs.com peter fred mary jane ardy"
51     echo
52     echo "Which will create peter.SecureBlogsAreUs.com, fred.SecureBlogsAreUs.com and"
53     echo "so on. Note that the _first_ FQDN is also the default for non SNI hosts. It"
54     echo "may make sense to give this host a generic name - and allow each of the real"
55     echo "SNI site as sub directories/URI's of this generic name; thus allowing the "
56     echo "few non-SNI browsers access."
57     exit 1
58 fi
59 set -- $args
60 for i
61 do
62     case "$i"
63     in
64         -f)
65             FORCE=1
66             shift;;
67         -a)
68             IP=$2; shift
69             shift;;
70         -d)
71             DIR=$2; shift
72             shift;;
73         -p)
74             PASSWD=$2; shift
75             shift;;
76         -D)
77             DOMAIN=$2; shift
78             shift;;
79         --) 
80             shift; break;
81     esac
82 done
83
84 if [ $# = 1 ]; then
85     echo "Aborted - just specifying one vhost makes no sense for SNI testing. Go wild !"
86     exit 1
87 fi
88
89 if [ $# -gt 0 ]; then
90     NAMES=$*
91 fi
92
93 if ! openssl version | grep -q OpenSSL; then
94     echo Aborted - your openssl is very old or misconfigured.
95     exit 1
96 fi
97
98 set `openssl version`
99 if test "0$2" \< "00.9"; then
100     echo Aborted - version of openssl too old, 0.9 or up required.
101     exit 1 
102 fi
103
104 if test -d ${DIR} -a "x$FORCE" != "x1"; then
105     echo Aborted - already an ${DIR} directory. Use the -f flag to overwrite.
106     exit 1
107 fi
108
109 mkdir -p ${DIR} || exit 1
110 mkdir -p ${DIR}/ssl ${DIR}/htdocs ${DIR}/logs || exit 1
111         
112 # Create a 'CA' - keep using different serial numbers
113 # as the browsers get upset if they see an identical 
114 # serial with a different pub-key.
115 #
116 # Note that we're not relying on the 'v3_ca' section as
117 # in the default openssl.conf file - so the certificate
118 # will be without the basicConstraints = CA:true and
119 # keyUsage = cRLSign, keyCertSign values. This is fine
120 # for most browsers.
121 #
122 serial=$RANDOM$$
123
124 openssl req -new -nodes -batch \
125     -x509  \
126     -days 10 -subj '/CN=Da Root/O=SNI testing/' -set_serial $serial \
127     -keyout ${DIR}/root.key -out ${DIR}/root.pem  \
128     || exit 2
129
130 CDIR=${DIR}/client-xs-control
131 mkdir -p ${CDIR}
132 # Create some certificate authorities for testing client controls
133 #
134 openssl req -new -nodes -batch \
135     -x509  \
136     -days 10 -subj '/CN=Da Second Root/O=SNI user access I/' -set_serial 2$serial$$\
137     -keyout ${CDIR}/xs-root-1.key -out ${CDIR}/xs-root-1.pem  \
138     || exit 2
139
140 openssl req -new -nodes -batch \
141     -x509  \
142     -days 10 -subj '/CN=Da Second Root/O=SNI user access II/' -set_serial 3$serial$$ \
143     -keyout ${CDIR}/xs-root-2.key -out ${CDIR}/xs-root-2.pem  \
144     || exit 2
145
146 # Create a chain of just the two access authorites:
147 cat ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-1.pem > ${CDIR}/xs-root-chain.pem
148
149 # And likewise a directory with the same information (using the
150 # required 'hash' naming format
151 #
152 mkdir -p ${CDIR}/xs-root-dir || exit 1
153 rm -f {$CDIR}/*.0
154 ln ${CDIR}/xs-root-1.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-1.pem`.0
155 ln ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-2.pem`.0
156
157 # Use the above two client certificate authorities to make a few users
158 for i in 1 2
159 do
160     # Create a certificate request for a test user.
161     #
162     openssl req -new -nodes -batch \
163         -days 9 -subj "/CN=User $i/O=SNI Test Crash Dummy Dept/" \
164         -keyout ${CDIR}/client-$i.key -out ${CDIR}/client-$i.req -batch  \
165                 || exit 3
166
167     # And get it signed by either our client cert issuing root authority.
168     #
169     openssl x509 -text -req \
170         -CA ${CDIR}/xs-root-$i.pem -CAkey ${CDIR}/xs-root-$i.key \
171         -set_serial 3$serial$$ -in ${CDIR}/client-$i.req -out ${CDIR}/client-$i.pem \
172                 || exit 4
173
174     # And create a pkcs#12 version for easy browser import.
175     #
176     openssl pkcs12 -export \
177         -inkey ${CDIR}/client-$i.key -in ${CDIR}/client-$i.pem -name "Client $i" \
178         -caname "Issuing client root $i" -certfile ${CDIR}/xs-root-$i.pem  \
179         -out ${CDIR}/client.p12 -passout pass:"$PASSWD" || exit 5
180
181     rm ${CDIR}/client-$i.req 
182 done
183
184 # Create the header for the example '/etc/hosts' file.
185 #
186 echo '# To append to your hosts file' > ${DIR}/hosts
187
188 # Create a header for the httpd.conf snipped.
189 #
190 cat > ${DIR}/httpd-sni.conf << EOM
191 # To append to your httpd.conf file'
192 Listen ${IP}:443
193 NameVirtualHost ${IP}:443
194
195 LoadModule ssl_module modules/mod_ssl.so
196
197 SSLRandomSeed startup builtin
198 SSLRandomSeed connect builtin
199
200 LogLevel debug
201 TransferLog ${DIR}/logs/access_log
202 ErrorLog ${DIR}/logs/error_log
203
204 # You'll get a warning about this.
205 #
206 SSLSessionCache none
207
208 # Note that this SSL configuration is far
209 # from complete - you propably will want
210 # to configure SSLSession Caches at the 
211 # very least.
212
213 <Directory />
214     Options None
215     AllowOverride None
216     Require all denied
217 </Directory>
218
219 <Directory "${DIR}/htdocs">
220     allow from all
221     Require all granted
222 </Directory>
223
224 # This first entry is also the default for non SNI
225 # supporting clients.
226 #
227 EOM
228
229 # Create the header of a sample BIND zone file.
230 #
231 (
232         echo "; Configuration sample to be added to the $DOMAIN zone file of BIND."
233         echo "\$ORIGIN $DOMAIN."
234 ) > ${DIR}/zone-file
235
236 ZADD="IN A $IP"
237 INFO="and also the site you see when the browser does not support SNI."
238
239 set -- ${NAMES}
240 DEFAULT=$1
241
242 for n in ${NAMES}
243 do
244     FQDN=$n.$DOMAIN
245     serial=`expr $serial + 1`
246
247     # Create a certificate request for this host.
248     #
249     openssl req -new -nodes -batch \
250         -days 9 -subj "/CN=$FQDN/O=SNI Testing/" \
251         -keyout ${DIR}/$n.key -out ${DIR}/$n.req -batch  \
252                 || exit 3
253
254     # And get it signed by our root authority.
255     #
256     openssl x509 -text -req \
257         -CA ${DIR}/root.pem -CAkey ${DIR}/root.key \
258         -set_serial $serial -in ${DIR}/$n.req -out ${DIR}/$n.pem \
259                 || exit 4
260
261     # Combine the key and certificate in one file.
262     #
263     cat ${DIR}/$n.pem ${DIR}/$n.key > ${DIR}/ssl/$n.crt
264     rm ${DIR}/$n.req ${DIR}/$n.key ${DIR}/$n.pem
265
266     LST="$LST
267     https://$FQDN/index.html"
268
269     # Create a /etc/host and bind-zone file example
270     #
271     echo "${IP}         $FQDN $n" >> ${DIR}/hosts
272     echo "$n    $ZADD" >> ${DIR}/zone-file
273     ZADD="IN CNAME $DEFAULT"
274
275     # Create and populate a docroot for this host.
276     #
277     mkdir -p ${DIR}/htdocs/$n || exit 1
278     echo We are $FQDN $INFO > ${DIR}/htdocs/$n/index.html || exit 1
279
280     # And change the info text - so that only the default/fallback site
281     # gets marked as such.
282     #
283     INFO="and you'd normally only see this site when there is proper SNI support."
284
285     # And create a configuration snipped.
286     #
287     cat >> ${DIR}/httpd-sni.conf << EOM
288 <VirtualHost ${IP}:443>
289     SSLEngine On
290     ServerName $FQDN:443
291     DocumentRoot ${DIR}/htdocs/$n
292     SSLCertificateChainFile ${DIR}/root.pem
293     SSLCertificateFile ${DIR}/ssl/$n.crt
294
295     # Uncomment the following lines if you
296     # want to only allow access to clients with
297     # a certificate issued/signed by some 
298     # selection of the issuing authorites
299     #
300     # SSLCACertificate ${CDIR}/xs-root-1.pem # just root 1
301     # SSLCACertificate ${CDIR}/xs-root-2.pem # just root 2
302     # SSLCACertificate ${CDIR}/xs-root-chain.pem # 1 & 2 
303     # SSLCACertificateDir ${CDIR}/xs-root-dir # 1 & 2 - but as a directory.
304     #
305     # SSLVerifyClient require
306     # SSLVerifyDepth 2
307     # 
308     TransferLog ${DIR}/logs/access_$n
309 </VirtualHost>
310
311 EOM
312
313 done
314
315 cat << EOM
316 SNI Files generated
317 ===================
318
319 The directory ${DIR}/sni has been populated with the following
320
321 -       root.key|pem    Certificate authority root and key. (You could
322                         import the root.pem key into your browser to
323                         quell warnings about an unknown authority).
324
325 -       hosts           /etc/hosts file with fake entries for the hosts
326
327 -       htdocs          directory with one docroot for each domain,
328                         each with a small sample file.
329
330 -       ssl             directory with an ssl cert (signed by root)
331                         for each of the domains).
332
333 -       logs            logfiles, one for each domain and an
334                         access_log for any misses.
335
336 The directory ${CDIR} contains optional test files to allow client
337 authentication testing:
338
339 -       client*pem/p12  Files for client authentication testing. These
340                         need to be imported into the browser.
341
342 -       xs-root-1/2     Certificate authority which has issued above
343                         client authentication certificates.
344
345 -       xs-root-dir     A directory specific for the SSLCACertificateDir
346                         directive.
347
348 -       xs-root-chain   A chain of the two client xs authorities for the
349                         SSLCACertificate directive.
350
351 SNI Test
352 ========
353
354 A directory ${DIR}/sni has been created. Run an apache
355 server against it with
356
357     .../httpd -f ${DIR}/httpd-sni.conf
358
359 and keep an eye on ${DIR}/logs/error_log. When everything 
360 is fine you will see entries like:
361
362     Feb 11 16:12:26 2008] [debug] Init: 
363         SSL server IP/port overlap: ape.*:443 (httpd-sni.conf:24) vs. jane.*:443 (httpd-sni.conf:42)
364
365 for each vhost configured and a concluding warning:
366
367     [Mon Feb 11 16:12:26 2008] [warn] Init: 
368         Name-based SSL virtual hosts only work for clients with TLS server name indication support (RFC 4366)
369
370 HOWEVER - If you see an entry like:
371
372     [Mon Feb 11 15:41:41 2008] [warn] Init: 
373         You should not use name-based virtual hosts in conjunction with SSL!!
374
375 then you are either using an OpenSSL which is too old and/or you need to ensure that the
376 TLS Extensions are compiled into openssl with the 'enable-tlsext' flag. Once you have
377 recompiled or reinstalled OpenSSL with TLS Extensions you will have to recompile mod_ssl
378 to allow it to recognize SNI support.
379
380 Meanwhile add 'hosts' to your c:\windows\system32\drivers\etc\hosts
381 or /etc/hosts file as to point the various URL's to your server:
382 $LST
383
384 and verify that each returns its own name (and an entry in its
385 own ${DIR}/logs) file).
386
387 NOTE
388 ====
389
390 Note that in the generated example the 'first' domain is special - and is the
391 catch all for non-SNI browsers. Depending on your circumstances it may make
392 sense to use a generic name - and have each of the SNI domains as subdirectories
393 (and hence URI's under this generic name). Thus allowing non SNI browsers also
394 access to those sites.
395 EOM
396 exit 0