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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
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.
25 OPENSSL=${OPENSSL:-openssl}
26 DOMAIN=${DOMAIN:-my-sni-test.org}
29 # List of hostnames automatically created by default.
30 NAMES=${NAMES:-ape nut pear apple banana}
32 # IP address these hostnames are bound to.
35 # A certificate password for the .p12 files of the client
36 # authentication test. Normally not set. However some browsers
37 # require a password of at least 4 characters.
41 args=`getopt a:fd:D:p: $*`
43 echo "Syntax: $0 [-f] [-a IPaddress] [-d outdir] [-D domain ] [two or more vhost names ]"
44 echo " -f Force overwriting of outdir (default is $DIR)"
45 echo " -d dir Directory to create the SNI test server in (default is $DIR)"
46 echo " -D domain Domain name to use for this test (default is $DOMAIN)"
47 echo " -a IP IP address to use for this virtual host (default is $IP)"
48 echo " -p str Password for the client certificate test (some browsers require a set password)"
49 echo " [names] List of optional vhost names (default is $NAMES)"
52 echo " $0 -D SecureBlogsAreUs.com peter fred mary jane ardy"
54 echo "Which will create peter.SecureBlogsAreUs.com, fred.SecureBlogsAreUs.com and"
55 echo "so on. Note that the _first_ FQDN is also the default for non SNI hosts. It"
56 echo "may make sense to give this host a generic name - and allow each of the real"
57 echo "SNI site as sub directories/URI's of this generic name; thus allowing the "
58 echo "few non-SNI browsers access."
87 echo "Aborted - just specifing one vhost makes no sense for SNI testing. Go wild !"
95 if ! openssl version | grep -q OpenSSL; then
96 echo Aborted - your openssl is very old or misconfigured.
100 set `openssl version`
101 if test "0$2" \< "00.9"; then
102 echo Aborted - version of openssl too old, 0.9 or up required.
106 if test -d ${DIR} -a "x$FORCE" != "x1"; then
107 echo Aborted - already an ${DIR} directory. Use the -f flag to overwrite.
111 mkdir -p ${DIR} || exit 1
112 mkdir -p ${DIR}/ssl ${DIR}/htdocs ${DIR}/logs || exit 1
114 # Create a 'CA' - keep using different serial numbers
115 # as the browsers get upset if they see an identical
116 # serial with a different pub-key.
118 # Note that we're not relying on the 'v3_ca' section as
119 # in the default openssl.conf file - so the certificate
120 # will be without the basicConstraints = CA:true and
121 # keyUsage = cRLSign, keyCertSign values. This is fine
126 openssl req -new -nodes -batch \
128 -days 10 -subj '/CN=Da Root/O=SNI testing/' -set_serial $serial \
129 -keyout ${DIR}/root.key -out ${DIR}/root.pem \
132 CDIR=${DIR}/client-xs-control
134 # Create some certificate authorities for testing client controls
136 openssl req -new -nodes -batch \
138 -days 10 -subj '/CN=Da Second Root/O=SNI user access I/' -set_serial 2$serial$$\
139 -keyout ${CDIR}/xs-root-1.key -out ${CDIR}/xs-root-1.pem \
142 openssl req -new -nodes -batch \
144 -days 10 -subj '/CN=Da Second Root/O=SNI user access II/' -set_serial 3$serial$$ \
145 -keyout ${CDIR}/xs-root-2.key -out ${CDIR}/xs-root-2.pem \
148 # Create a chain of just the two access authorites:
149 cat ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-1.pem > ${CDIR}/xs-root-chain.pem
151 # And likewise a directory with the same information (using the
152 # required 'hash' naming format
154 mkdir -p ${CDIR}/xs-root-dir || exit 1
156 ln ${CDIR}/xs-root-1.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-1.pem`.0
157 ln ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-2.pem`.0
159 # Use the above two client certificate authorities to make a few users
162 # Create a certificate request for a test user.
164 openssl req -new -nodes -batch \
165 -days 9 -subj "/CN=User $i/O=SNI Test Crash Dummy Dept/" \
166 -keyout ${CDIR}/client-$i.key -out ${CDIR}/client-$i.req -batch \
169 # And get it signed by either our client cert issuing root authority.
171 openssl x509 -text -req \
172 -CA ${CDIR}/xs-root-$i.pem -CAkey ${CDIR}/xs-root-$i.key \
173 -set_serial 3$serial$$ -in ${CDIR}/client-$i.req -out ${CDIR}/client-$i.pem \
176 # And create a pkcs#12 version for easy browser import.
178 openssl pkcs12 -export \
179 -inkey ${CDIR}/client-$i.key -in ${CDIR}/client-$i.pem -name "Client $i" \
180 -caname "Issuing client root $i" -certfile ${CDIR}/xs-root-$i.pem \
181 -out ${CDIR}/client.p12 -passout pass:"$PASSWD" || exit 5
183 rm ${CDIR}/client-$i.req
186 # Create the header for the example '/etc/hosts' file.
188 echo '# To append to your hosts file' > ${DIR}/hosts
190 # Create a header for the httpd.conf snipped.
192 cat > ${DIR}/httpd-sni.conf << EOM
193 # To append to your httpd.conf file'
195 NameVirtualHost ${IP}:443
197 LoadModule ssl_module modules/mod_ssl.so
199 SSLRandomSeed startup builtin
200 SSLRandomSeed connect builtin
203 TransferLog ${DIR}/logs/access_log
204 ErrorLog ${DIR}/logs/error_log
206 # You'll get a warning about this.
210 # Note that this SSL configuration is far
211 # from complete - you propably will want
212 # to configure SSLSession Caches at the
221 <Directory "${DIR}/htdocs">
226 # This first entry is also the default for non SNI
227 # supporting clients.
231 # Create the header of a sample BIND zone file.
234 echo "; Configuration sample to be added to the $DOMAIN zone file of BIND."
235 echo "\$ORIGIN $DOMAIN."
239 INFO="and also the site you see when the browser does not support SNI."
247 serial=`expr $serial + 1`
249 # Create a certificate request for this host.
251 openssl req -new -nodes -batch \
252 -days 9 -subj "/CN=$FQDN/O=SNI Testing/" \
253 -keyout ${DIR}/$n.key -out ${DIR}/$n.req -batch \
256 # And get it signed by our root authority.
258 openssl x509 -text -req \
259 -CA ${DIR}/root.pem -CAkey ${DIR}/root.key \
260 -set_serial $serial -in ${DIR}/$n.req -out ${DIR}/$n.pem \
263 # Combine the key and certificate in one file.
265 cat ${DIR}/$n.pem ${DIR}/$n.key > ${DIR}/ssl/$n.crt
266 rm ${DIR}/$n.req ${DIR}/$n.key ${DIR}/$n.pem
269 https://$FQDN/index.html"
271 # Create a /etc/host and bind-zone file example
273 echo "${IP} $FQDN $n" >> ${DIR}/hosts
274 echo "$n $ZADD" >> ${DIR}/zone-file
275 ZADD="IN CNAME $DEFAULT"
277 # Create and populate a docroot for this host.
279 mkdir -p ${DIR}/htdocs/$n || exit 1
280 echo We are $FQDN $INFO > ${DIR}/htdocs/$n/index.html || exit 1
282 # And change the info text - so that only the default/fallback site
283 # gets marked as such.
285 INFO="and you'd normally only see this site when there is proper SNI support."
287 # And create a configuration snipped.
289 cat >> ${DIR}/httpd-sni.conf << EOM
290 <VirtualHost ${IP}:443>
293 DocumentRoot ${DIR}/htdocs/$n
294 SSLCertificateChainFile ${DIR}/root.pem
295 SSLCertificateFile ${DIR}/ssl/$n.crt
297 # Uncomment the following lines if you
298 # want to only allow access to clients with
299 # a certificate issued/signed by some
300 # selection of the issuing authorites
302 # SSLCACertificate ${CDIR}/xs-root-1.pem # just root 1
303 # SSLCACertificate ${CDIR}/xs-root-2.pem # just root 2
304 # SSLCACertificate ${CDIR}/xs-root-chain.pem # 1 & 2
305 # SSLCACertificateDir ${CDIR}/xs-root-dir # 1 & 2 - but as a directory.
307 # SSLVerifyClient require
310 TransferLog ${DIR}/logs/access_$n
321 The directory ${DIR}/sni has been populated with the following
323 - root.key|pem Certificate authority root and key. (You could
324 import the root.pem key into your browser to
325 quell warnings about an unknown authority).
327 - hosts /etc/hosts file with fake entries for the hosts
329 - htdocs directory with one docroot for each domain,
330 each with a small sample file.
332 - ssl directory with an ssl cert (signed by root)
333 for each of the domains).
335 - logs logfiles, one for each domain and an
336 access_log for any misses.
338 The directory ${CDIR} contains optional test files to allow client
339 authentication testing:
341 - client*pem/p12 Files for client authentication testing. These
342 need to be imported into the browser.
344 - xs-root-1/2 Certificate authority which has issued above
345 client authentication certificates.
347 - xs-root-dir A directory specific for the SSLCACertificateDir
350 - xs-root-chain A chain of the two client xs authorities for the
351 SSLCACertificate directive.
356 A directory ${DIR}/sni has been created. Run an apache
357 server against it with
359 .../httpd -f ${DIR}/httpd-sni.conf
361 and keep an eye on ${DIR}/logs/error_log. When everything
362 is fine you will see entries like:
364 Feb 11 16:12:26 2008] [debug] Init:
365 SSL server IP/port overlap: ape.*:443 (httpd-sni.conf:24) vs. jane.*:443 (httpd-sni.conf:42)
367 for each vhost configured and a concluding warning:
369 [Mon Feb 11 16:12:26 2008] [warn] Init:
370 Name-based SSL virtual hosts only work for clients with TLS server name indication support (RFC 4366)
372 HOWEVER - If you see an entry like:
374 [Mon Feb 11 15:41:41 2008] [warn] Init:
375 You should not use name-based virtual hosts in conjunction with SSL!!
377 then you are either using an OpenSSL which is too old and/or you need to ensure that the
378 TLS Extensions are compiled into openssl with the 'enable-tlsext' flag. Once you have
379 recompiled or reinstalled OpenSSL with TLS Extensions you will have to recompile mod_ssl
380 to allow it to recognize SNI support.
382 Meanwhile add 'hosts' to your c:\windows\system32\drivers\etc\hosts
383 or /etc/hosts file as to point the various URL's to your server:
386 and verify that each returns its own name (and an entry in its
387 own ${DIR}/logs) file).
392 Note that in the generated example the 'first' domain is special - and is the
393 catch all for non-SNI browsers. Depending on your circumstances it may make
394 sense to use a generic name - and have each of the SNI domains as subdirectories
395 (and hence URI's under this generic name). Thus allowing non SNI browsers also
396 access to those sites.