Blame test/make_sni.sh

Packit 90a5c9
#!/bin/sh
Packit 90a5c9
#
Packit 90a5c9
# Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
# contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
# this work for additional information regarding copyright ownership.
Packit 90a5c9
# The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
# (the "License"); you may not use this file except in compliance with
Packit 90a5c9
# the License.  You may obtain a copy of the License at
Packit 90a5c9
#
Packit 90a5c9
#     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
#
Packit 90a5c9
# Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
# distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
# See the License for the specific language governing permissions and
Packit 90a5c9
# limitations under the License.
Packit 90a5c9
#
Packit 90a5c9
# This script will populate a directory 'sni' with 3 sites, httpd.conf
Packit 90a5c9
# and certificates as to facilitate testing of TLS server name 
Packit 90a5c9
# indication support (RFC 4366) or SNI.
Packit 90a5c9
#
Packit 90a5c9
#
Packit 90a5c9
OPENSSL=${OPENSSL:-openssl}
Packit 90a5c9
DOMAIN=${DOMAIN:-my-sni-test.org}
Packit 90a5c9
DIR=${DIR:-$PWD/sni}
Packit 90a5c9
Packit 90a5c9
# List of hostnames automatically created by default.
Packit 90a5c9
NAMES=${NAMES:-ape nut pear apple banana}
Packit 90a5c9
Packit 90a5c9
# IP address these hostnames are bound to.
Packit 90a5c9
IP=${IP:-127.0.0.1}
Packit 90a5c9
Packit 90a5c9
# A certificate password for the .p12 files of the client
Packit 90a5c9
# authentication test. Normally not set. However some browsers
Packit 90a5c9
# require a password of at least 4 characters.
Packit 90a5c9
#
Packit 90a5c9
PASSWD=${PASSWD:-}
Packit 90a5c9
Packit 90a5c9
args=`getopt a:fd:D:p: $*`
Packit 90a5c9
if [ $? != 0 ]; then
Packit 90a5c9
    echo "Syntax: $0 [-f] [-a IPaddress] [-d outdir] [-D domain ] [two or more vhost names ]"
Packit 90a5c9
    echo "    -f        Force overwriting of outdir (default is $DIR)"
Packit 90a5c9
    echo "    -d dir    Directory to create the SNI test server in (default is $DIR)"
Packit 90a5c9
    echo "    -D domain Domain name to use for this test (default is $DOMAIN)"
Packit 90a5c9
    echo "    -a IP     IP address to use for this virtual host (default is $IP)"
Packit 90a5c9
    echo "    -p str    Password for the client certificate test (some browsers require a set password)"
Packit 90a5c9
    echo "    [names]   List of optional vhost names (default is $NAMES)"
Packit 90a5c9
    echo 
Packit 90a5c9
    echo "Example:"
Packit 90a5c9
    echo "    $0 -D SecureBlogsAreUs.com peter fred mary jane ardy"
Packit 90a5c9
    echo
Packit 90a5c9
    echo "Which will create peter.SecureBlogsAreUs.com, fred.SecureBlogsAreUs.com and"
Packit 90a5c9
    echo "so on. Note that the _first_ FQDN is also the default for non SNI hosts. It"
Packit 90a5c9
    echo "may make sense to give this host a generic name - and allow each of the real"
Packit 90a5c9
    echo "SNI site as sub directories/URI's of this generic name; thus allowing the "
Packit 90a5c9
    echo "few non-SNI browsers access."
Packit 90a5c9
    exit 1
Packit 90a5c9
fi
Packit 90a5c9
set -- $args
Packit 90a5c9
for i
Packit 90a5c9
do
Packit 90a5c9
    case "$i"
Packit 90a5c9
    in
Packit 90a5c9
        -f)
Packit 90a5c9
            FORCE=1
Packit 90a5c9
            shift;;
Packit 90a5c9
        -a)
Packit 90a5c9
            IP=$2; shift
Packit 90a5c9
            shift;;
Packit 90a5c9
        -d)
Packit 90a5c9
            DIR=$2; shift
Packit 90a5c9
            shift;;
Packit 90a5c9
        -p)
Packit 90a5c9
            PASSWD=$2; shift
Packit 90a5c9
            shift;;
Packit 90a5c9
        -D)
Packit 90a5c9
            DOMAIN=$2; shift
Packit 90a5c9
            shift;;
Packit 90a5c9
        --) 
Packit 90a5c9
            shift; break;
Packit 90a5c9
    esac
Packit 90a5c9
done
Packit 90a5c9
Packit 90a5c9
if [ $# = 1 ]; then
Packit 90a5c9
    echo "Aborted - just specifying one vhost makes no sense for SNI testing. Go wild !"
Packit 90a5c9
    exit 1
Packit 90a5c9
fi
Packit 90a5c9
Packit 90a5c9
if [ $# -gt 0 ]; then
Packit 90a5c9
    NAMES=$*
Packit 90a5c9
fi
Packit 90a5c9
Packit 90a5c9
if ! openssl version | grep -q OpenSSL; then
Packit 90a5c9
    echo Aborted - your openssl is very old or misconfigured.
Packit 90a5c9
    exit 1
Packit 90a5c9
fi
Packit 90a5c9
Packit 90a5c9
set `openssl version`
Packit 90a5c9
if test "0$2" \< "00.9"; then
Packit 90a5c9
    echo Aborted - version of openssl too old, 0.9 or up required.
Packit 90a5c9
    exit 1 
Packit 90a5c9
fi
Packit 90a5c9
Packit 90a5c9
if test -d ${DIR} -a "x$FORCE" != "x1"; then
Packit 90a5c9
    echo Aborted - already an ${DIR} directory. Use the -f flag to overwrite.
Packit 90a5c9
    exit 1
Packit 90a5c9
fi
Packit 90a5c9
Packit 90a5c9
mkdir -p ${DIR} || exit 1
Packit 90a5c9
mkdir -p ${DIR}/ssl ${DIR}/htdocs ${DIR}/logs || exit 1
Packit 90a5c9
        
Packit 90a5c9
# Create a 'CA' - keep using different serial numbers
Packit 90a5c9
# as the browsers get upset if they see an identical 
Packit 90a5c9
# serial with a different pub-key.
Packit 90a5c9
#
Packit 90a5c9
# Note that we're not relying on the 'v3_ca' section as
Packit 90a5c9
# in the default openssl.conf file - so the certificate
Packit 90a5c9
# will be without the basicConstraints = CA:true and
Packit 90a5c9
# keyUsage = cRLSign, keyCertSign values. This is fine
Packit 90a5c9
# for most browsers.
Packit 90a5c9
#
Packit 90a5c9
serial=$RANDOM$$
Packit 90a5c9
Packit 90a5c9
openssl req -new -nodes -batch \
Packit 90a5c9
    -x509  \
Packit 90a5c9
    -days 10 -subj '/CN=Da Root/O=SNI testing/' -set_serial $serial \
Packit 90a5c9
    -keyout ${DIR}/root.key -out ${DIR}/root.pem  \
Packit 90a5c9
    || exit 2
Packit 90a5c9
Packit 90a5c9
CDIR=${DIR}/client-xs-control
Packit 90a5c9
mkdir -p ${CDIR}
Packit 90a5c9
# Create some certificate authorities for testing client controls
Packit 90a5c9
#
Packit 90a5c9
openssl req -new -nodes -batch \
Packit 90a5c9
    -x509  \
Packit 90a5c9
    -days 10 -subj '/CN=Da Second Root/O=SNI user access I/' -set_serial 2$serial$$\
Packit 90a5c9
    -keyout ${CDIR}/xs-root-1.key -out ${CDIR}/xs-root-1.pem  \
Packit 90a5c9
    || exit 2
Packit 90a5c9
Packit 90a5c9
openssl req -new -nodes -batch \
Packit 90a5c9
    -x509  \
Packit 90a5c9
    -days 10 -subj '/CN=Da Second Root/O=SNI user access II/' -set_serial 3$serial$$ \
Packit 90a5c9
    -keyout ${CDIR}/xs-root-2.key -out ${CDIR}/xs-root-2.pem  \
Packit 90a5c9
    || exit 2
Packit 90a5c9
Packit 90a5c9
# Create a chain of just the two access authorites:
Packit 90a5c9
cat ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-1.pem > ${CDIR}/xs-root-chain.pem
Packit 90a5c9
Packit 90a5c9
# And likewise a directory with the same information (using the
Packit 90a5c9
# required 'hash' naming format
Packit 90a5c9
#
Packit 90a5c9
mkdir -p ${CDIR}/xs-root-dir || exit 1
Packit 90a5c9
rm -f {$CDIR}/*.0
Packit 90a5c9
ln ${CDIR}/xs-root-1.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-1.pem`.0
Packit 90a5c9
ln ${CDIR}/xs-root-2.pem ${CDIR}/xs-root-dir/`openssl x509 -noout -hash -in ${CDIR}/xs-root-2.pem`.0
Packit 90a5c9
Packit 90a5c9
# Use the above two client certificate authorities to make a few users
Packit 90a5c9
for i in 1 2
Packit 90a5c9
do
Packit 90a5c9
    # Create a certificate request for a test user.
Packit 90a5c9
    #
Packit 90a5c9
    openssl req -new -nodes -batch \
Packit 90a5c9
        -days 9 -subj "/CN=User $i/O=SNI Test Crash Dummy Dept/" \
Packit 90a5c9
        -keyout ${CDIR}/client-$i.key -out ${CDIR}/client-$i.req -batch  \
Packit 90a5c9
                || exit 3
Packit 90a5c9
Packit 90a5c9
    # And get it signed by either our client cert issuing root authority.
Packit 90a5c9
    #
Packit 90a5c9
    openssl x509 -text -req \
Packit 90a5c9
        -CA ${CDIR}/xs-root-$i.pem -CAkey ${CDIR}/xs-root-$i.key \
Packit 90a5c9
        -set_serial 3$serial$$ -in ${CDIR}/client-$i.req -out ${CDIR}/client-$i.pem \
Packit 90a5c9
                || exit 4
Packit 90a5c9
Packit 90a5c9
    # And create a pkcs#12 version for easy browser import.
Packit 90a5c9
    #
Packit 90a5c9
    openssl pkcs12 -export \
Packit 90a5c9
        -inkey ${CDIR}/client-$i.key -in ${CDIR}/client-$i.pem -name "Client $i" \
Packit 90a5c9
        -caname "Issuing client root $i" -certfile ${CDIR}/xs-root-$i.pem  \
Packit 90a5c9
        -out ${CDIR}/client.p12 -passout pass:"$PASSWD" || exit 5
Packit 90a5c9
Packit 90a5c9
    rm ${CDIR}/client-$i.req 
Packit 90a5c9
done
Packit 90a5c9
Packit 90a5c9
# Create the header for the example '/etc/hosts' file.
Packit 90a5c9
#
Packit 90a5c9
echo '# To append to your hosts file' > ${DIR}/hosts
Packit 90a5c9
Packit 90a5c9
# Create a header for the httpd.conf snipped.
Packit 90a5c9
#
Packit 90a5c9
cat > ${DIR}/httpd-sni.conf << EOM
Packit 90a5c9
# To append to your httpd.conf file'
Packit 90a5c9
Listen ${IP}:443
Packit 90a5c9
NameVirtualHost ${IP}:443
Packit 90a5c9
Packit 90a5c9
LoadModule ssl_module modules/mod_ssl.so
Packit 90a5c9
Packit 90a5c9
SSLRandomSeed startup builtin
Packit 90a5c9
SSLRandomSeed connect builtin
Packit 90a5c9
Packit 90a5c9
LogLevel debug
Packit 90a5c9
TransferLog ${DIR}/logs/access_log
Packit 90a5c9
ErrorLog ${DIR}/logs/error_log
Packit 90a5c9
Packit 90a5c9
# You'll get a warning about this.
Packit 90a5c9
#
Packit 90a5c9
SSLSessionCache none
Packit 90a5c9
Packit 90a5c9
# Note that this SSL configuration is far
Packit 90a5c9
# from complete - you propably will want
Packit 90a5c9
# to configure SSLSession Caches at the 
Packit 90a5c9
# very least.
Packit 90a5c9
Packit 90a5c9
<Directory />
Packit 90a5c9
    Options None
Packit 90a5c9
    AllowOverride None
Packit 90a5c9
    Require all denied
Packit 90a5c9
</Directory>
Packit 90a5c9
Packit 90a5c9
<Directory "${DIR}/htdocs">
Packit 90a5c9
    allow from all
Packit 90a5c9
    Require all granted
Packit 90a5c9
</Directory>
Packit 90a5c9
Packit 90a5c9
# This first entry is also the default for non SNI
Packit 90a5c9
# supporting clients.
Packit 90a5c9
#
Packit 90a5c9
EOM
Packit 90a5c9
Packit 90a5c9
# Create the header of a sample BIND zone file.
Packit 90a5c9
#
Packit 90a5c9
(
Packit 90a5c9
        echo "; Configuration sample to be added to the $DOMAIN zone file of BIND."
Packit 90a5c9
        echo "\$ORIGIN $DOMAIN."
Packit 90a5c9
) > ${DIR}/zone-file
Packit 90a5c9
Packit 90a5c9
ZADD="IN A $IP"
Packit 90a5c9
INFO="and also the site you see when the browser does not support SNI."
Packit 90a5c9
Packit 90a5c9
set -- ${NAMES}
Packit 90a5c9
DEFAULT=$1
Packit 90a5c9
Packit 90a5c9
for n in ${NAMES}
Packit 90a5c9
do
Packit 90a5c9
    FQDN=$n.$DOMAIN
Packit 90a5c9
    serial=`expr $serial + 1`
Packit 90a5c9
Packit 90a5c9
    # Create a certificate request for this host.
Packit 90a5c9
    #
Packit 90a5c9
    openssl req -new -nodes -batch \
Packit 90a5c9
        -days 9 -subj "/CN=$FQDN/O=SNI Testing/" \
Packit 90a5c9
        -keyout ${DIR}/$n.key -out ${DIR}/$n.req -batch  \
Packit 90a5c9
                || exit 3
Packit 90a5c9
Packit 90a5c9
    # And get it signed by our root authority.
Packit 90a5c9
    #
Packit 90a5c9
    openssl x509 -text -req \
Packit 90a5c9
        -CA ${DIR}/root.pem -CAkey ${DIR}/root.key \
Packit 90a5c9
        -set_serial $serial -in ${DIR}/$n.req -out ${DIR}/$n.pem \
Packit 90a5c9
                || exit 4
Packit 90a5c9
Packit 90a5c9
    # Combine the key and certificate in one file.
Packit 90a5c9
    #
Packit 90a5c9
    cat ${DIR}/$n.pem ${DIR}/$n.key > ${DIR}/ssl/$n.crt
Packit 90a5c9
    rm ${DIR}/$n.req ${DIR}/$n.key ${DIR}/$n.pem
Packit 90a5c9
Packit 90a5c9
    LST="$LST
Packit 90a5c9
    https://$FQDN/index.html"
Packit 90a5c9
Packit 90a5c9
    # Create a /etc/host and bind-zone file example
Packit 90a5c9
    #
Packit 90a5c9
    echo "${IP}         $FQDN $n" >> ${DIR}/hosts
Packit 90a5c9
    echo "$n    $ZADD" >> ${DIR}/zone-file
Packit 90a5c9
    ZADD="IN CNAME $DEFAULT"
Packit 90a5c9
Packit 90a5c9
    # Create and populate a docroot for this host.
Packit 90a5c9
    #
Packit 90a5c9
    mkdir -p ${DIR}/htdocs/$n || exit 1
Packit 90a5c9
    echo We are $FQDN $INFO > ${DIR}/htdocs/$n/index.html || exit 1
Packit 90a5c9
Packit 90a5c9
    # And change the info text - so that only the default/fallback site
Packit 90a5c9
    # gets marked as such.
Packit 90a5c9
    #
Packit 90a5c9
    INFO="and you'd normally only see this site when there is proper SNI support."
Packit 90a5c9
Packit 90a5c9
    # And create a configuration snipped.
Packit 90a5c9
    #
Packit 90a5c9
    cat >> ${DIR}/httpd-sni.conf << EOM
Packit 90a5c9
<VirtualHost ${IP}:443>
Packit 90a5c9
    SSLEngine On
Packit 90a5c9
    ServerName $FQDN:443
Packit 90a5c9
    DocumentRoot ${DIR}/htdocs/$n
Packit 90a5c9
    SSLCertificateChainFile ${DIR}/root.pem
Packit 90a5c9
    SSLCertificateFile ${DIR}/ssl/$n.crt
Packit 90a5c9
Packit 90a5c9
    # Uncomment the following lines if you
Packit 90a5c9
    # want to only allow access to clients with
Packit 90a5c9
    # a certificate issued/signed by some 
Packit 90a5c9
    # selection of the issuing authorites
Packit 90a5c9
    #
Packit 90a5c9
    # SSLCACertificate ${CDIR}/xs-root-1.pem # just root 1
Packit 90a5c9
    # SSLCACertificate ${CDIR}/xs-root-2.pem # just root 2
Packit 90a5c9
    # SSLCACertificate ${CDIR}/xs-root-chain.pem # 1 & 2 
Packit 90a5c9
    # SSLCACertificateDir ${CDIR}/xs-root-dir # 1 & 2 - but as a directory.
Packit 90a5c9
    #
Packit 90a5c9
    # SSLVerifyClient require
Packit 90a5c9
    # SSLVerifyDepth 2
Packit 90a5c9
    # 
Packit 90a5c9
    TransferLog ${DIR}/logs/access_$n
Packit 90a5c9
</VirtualHost>
Packit 90a5c9
Packit 90a5c9
EOM
Packit 90a5c9
Packit 90a5c9
done
Packit 90a5c9
Packit 90a5c9
cat << EOM
Packit 90a5c9
SNI Files generated
Packit 90a5c9
===================
Packit 90a5c9
Packit 90a5c9
The directory ${DIR}/sni has been populated with the following
Packit 90a5c9
Packit 90a5c9
-       root.key|pem    Certificate authority root and key. (You could
Packit 90a5c9
                        import the root.pem key into your browser to
Packit 90a5c9
                        quell warnings about an unknown authority).
Packit 90a5c9
Packit 90a5c9
-       hosts           /etc/hosts file with fake entries for the hosts
Packit 90a5c9
Packit 90a5c9
-       htdocs          directory with one docroot for each domain,
Packit 90a5c9
                        each with a small sample file.
Packit 90a5c9
Packit 90a5c9
-       ssl             directory with an ssl cert (signed by root)
Packit 90a5c9
                        for each of the domains).
Packit 90a5c9
Packit 90a5c9
-       logs            logfiles, one for each domain and an
Packit 90a5c9
                        access_log for any misses.
Packit 90a5c9
Packit 90a5c9
The directory ${CDIR} contains optional test files to allow client
Packit 90a5c9
authentication testing:
Packit 90a5c9
Packit 90a5c9
-       client*pem/p12  Files for client authentication testing. These
Packit 90a5c9
                        need to be imported into the browser.
Packit 90a5c9
Packit 90a5c9
-       xs-root-1/2     Certificate authority which has issued above
Packit 90a5c9
                        client authentication certificates.
Packit 90a5c9
Packit 90a5c9
-       xs-root-dir     A directory specific for the SSLCACertificateDir
Packit 90a5c9
                        directive.
Packit 90a5c9
Packit 90a5c9
-       xs-root-chain   A chain of the two client xs authorities for the
Packit 90a5c9
                        SSLCACertificate directive.
Packit 90a5c9
Packit 90a5c9
SNI Test
Packit 90a5c9
========
Packit 90a5c9
Packit 90a5c9
A directory ${DIR}/sni has been created. Run an apache
Packit 90a5c9
server against it with
Packit 90a5c9
Packit 90a5c9
    .../httpd -f ${DIR}/httpd-sni.conf
Packit 90a5c9
Packit 90a5c9
and keep an eye on ${DIR}/logs/error_log. When everything 
Packit 90a5c9
is fine you will see entries like:
Packit 90a5c9
Packit 90a5c9
    Feb 11 16:12:26 2008] [debug] Init: 
Packit 90a5c9
        SSL server IP/port overlap: ape.*:443 (httpd-sni.conf:24) vs. jane.*:443 (httpd-sni.conf:42)
Packit 90a5c9
Packit 90a5c9
for each vhost configured and a concluding warning:
Packit 90a5c9
Packit 90a5c9
    [Mon Feb 11 16:12:26 2008] [warn] Init: 
Packit 90a5c9
        Name-based SSL virtual hosts only work for clients with TLS server name indication support (RFC 4366)
Packit 90a5c9
Packit 90a5c9
HOWEVER - If you see an entry like:
Packit 90a5c9
Packit 90a5c9
    [Mon Feb 11 15:41:41 2008] [warn] Init: 
Packit 90a5c9
        You should not use name-based virtual hosts in conjunction with SSL!!
Packit 90a5c9
Packit 90a5c9
then you are either using an OpenSSL which is too old and/or you need to ensure that the
Packit 90a5c9
TLS Extensions are compiled into openssl with the 'enable-tlsext' flag. Once you have
Packit 90a5c9
recompiled or reinstalled OpenSSL with TLS Extensions you will have to recompile mod_ssl
Packit 90a5c9
to allow it to recognize SNI support.
Packit 90a5c9
Packit 90a5c9
Meanwhile add 'hosts' to your c:\windows\system32\drivers\etc\hosts
Packit 90a5c9
or /etc/hosts file as to point the various URL's to your server:
Packit 90a5c9
$LST
Packit 90a5c9
Packit 90a5c9
and verify that each returns its own name (and an entry in its
Packit 90a5c9
own ${DIR}/logs) file).
Packit 90a5c9
Packit 90a5c9
NOTE
Packit 90a5c9
====
Packit 90a5c9
Packit 90a5c9
Note that in the generated example the 'first' domain is special - and is the
Packit 90a5c9
catch all for non-SNI browsers. Depending on your circumstances it may make
Packit 90a5c9
sense to use a generic name - and have each of the SNI domains as subdirectories
Packit 90a5c9
(and hence URI's under this generic name). Thus allowing non SNI browsers also
Packit 90a5c9
access to those sites.
Packit 90a5c9
EOM
Packit 90a5c9
exit 0