Server setup
In the README.md there is a description how to run the different servers when they are already installed in the system. This doesn't work in case of testing new features like TLS 1.3.
This document will explain how to compile and configure different servers using current development versions of packages.
TODO: figure out what dependencies do the different projects require
TODO: handling of older, supported, branches of OpenSSL and GnuTLS
TODO: building the servers with clang with asan and ubsan enabled
The configurations listed below set up the servers with just one or two certificates and fairly simple configurations. From experience, working with different versions of those implementations, to provide complete coverage of the implementations, the following settings are known to have impact on server behaviour (e.g. there were bugs which manifested themselves with use of SNI virtual host, but not against a 'default' host):
- one vs many certificates set up (especially relevant for certificates with rsaEncryption vs rsassa-pss Subject Public Key Info)
- no SNI configured vs SNI configured
- testing of a default host vs SNI host of a SNI-enabled server
- different security levels (e.g. OpenSSL with cipherstring
@SECLEVEL=3
vs@SECLEVEL=0
or GnuTLSNORMAL
vsSECURE256:%PROFILE_HIGH
) - no client certificates, requesting client certificates, mandating client certificates
- ALPN (NPN) vs no ALPN configured
- session tickets enabled vs disabled (session ID behaviour in TLS 1.2)
- what kind of session tickets are used in TLS 1.3 (e.g. OpenSSL will use session-id-like tickets in TLS 1.3 if session tickets are disabled in TLS 1.2)
- support for TLS 1.3 0-RTT enabled vs disabled (e.g. even with 0-RTT disabled, the server needs to still be able to process 0-RTT Client Hello)
- supported versions enabled (e.g. when server that implements TLS 1.2 but enables TLS 1.1 as the highest one receives FALLBACK_SCSV in TLS 1.1 ClientHello, it MUST NOT abort the connection)
- changes to configuration before session is established and resumed (e.g. resuming a session with a cipher that is now disabled or processing 0-RTT data with cipher that is now disabled)
- integrated with different applications (as callbacks may cause the behaviour to be very different than vanilla library, or the application may use the API incorrectly – CVE-2019-1559)
- Large client and/or server certificates (e.g. https://10000-sans.badssl.com/ )
- key stored on an HSM or smartcard (as card may not support all signature methods or hashes)
- smartcard with different features supported – rsa-pss supported natively vs not, SHA-384 supported vs not, etc
- specific extension or feature of protocol being disabled, enabled and mandated (e.g. difference in behaviour when safe renegotiation is enabled vs. when it is required for connection, or when PHA is enabled, specific curves signature algorithms or ciphers disabled)
- server running under valgrind, compiled with asan, ubsan, etc. Verification that it doesn't suffer from unbounded memory growth (accounted for, but not promptly freed memory)
- force-enabled features that are deprecated in later protocol versions (e.g. PKCS#1 SHA-1 signatures enabled through config option while negotiating TLS 1.3 or secp256k1 curve enabled and TLS 1.3 negotiated)
- server running on different hardware (e.g. one that has assembly implementation of a "stitched" cipher vs one that doesn't, AES-NI vs no hardware acceleration, SSE3 vs no SSE3, etc.)
- interaction between server implementation versions with session resumption – what happens if a session started with previous version of library is resumed with a new one or vice versa (requires both versions to use the same ticket encryption key)
The servers require keys and certificates to function, following commands can be used to generate them and prepare for use with different libraries:
- Download and import bash library:
pushd /tmp && wget https://raw.githubusercontent.com/redhat-qe-security/certgen/master/certgen/lib.sh && source lib.sh
- Generate keys:
x509KeyGen ca && x509KeyGen server && x509KeyGen client && x509KeyGen -t ecdsa -s prime256v1 server-p256 && x509KeyGen -t ecdsa -s prime256v1 client-p256
- Sign certificates:
x509SelfSign ca && x509CertSign --CA ca server && x509CertSign --CA ca --DN "O=P-256 server" --DN 'CN=localhost' server-p256 && x509CertSign --CA ca -t webclient client && x509CertSign --CA ca -t webclient --DN "CN=P-256 Client" client-p256
- Export key and certificate to PKCS#12 files:
x509Key --pkcs12 --with-cert server && x509Key --pkcs12 --with-cert server-p256
- Generate NSS database and import keys and certificates to it
mkdir /tmp/nssdb && certutil -N -d sql:/tmp/nssdb --empty-password && certutil -A -d sql:/tmp/nssdb -n ca -i /tmp/ca/cert.pem -t 'cTC,cTC,' -a && pk12util -i /tmp/server/bundle.p12 -d sql:/tmp/nssdb -W '' && pk12util -i /tmp/server-p256/bundle.p12 -d sql:/tmp/nssdb -W ''
- Return to previous directory
popd
- Download the code:
git clone https://github.com/openssl/openssl.git
- Configure it so that it is easy to run (statically built)
cd openssl ./config no-shared
- Compile
make -j4
apps/openssl s_server -www -key /tmp/server/key.pem -cert \
/tmp/server/cert.pem -dkey /tmp/server-p256/key.pem -dcert \
/tmp/server-p256/cert.pem
apps/openssl s_server -www -key /tmp/server/key.pem -cert \
/tmp/server/cert.pem -verify 1 -CAfile /tmp/ca/cert.pem \
-dkey /tmp/server-p256/key.pem -dcert /tmp/server-p256/cert.pem
To update the repository, after the master
branch moved, execute the following command in the openssl
directory:
git pull origin master
Then you can compile it again, as in the steps above:
make clean
./config no-shared
make -j4
- Install dependencies (command for Fedora RHEL, for other distributions see the helpful info in gnutls
README.md
)(dnf -y install dash git autoconf libtool gettext-devel automake autogen \ nettle-devel p11-kit-devel autogen-libopts-devel libunistring-devel \ trousers-devel guile-devel libtasn1-devel libidn2-devel gawk gperf \ libtasn1-tools unbound-devel bison help2man gtk-doc texinfo texlive \ libev-devel patch wget
texlive
is probably an overkill) - Download the code:
git clone https://gitlab.com/gnutls/gnutls.git
- Configure so that it is easy to run:
cd gnutls ./bootstrap ./configure --disable-doc
- Compile:
make -j$(nproc)
To start the GnuTLS server, use the following commands:
cd doc/credentials
./gnutls-http-serv \
--priority NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:+DHE-PSK:+PSK \
-p 4433 -a -d 6
note: the configured PSKs are in the psk-passwd.txt
file
Similarly to OpenSSL, local code can be updated by running the following commands:
git pull origin master
Then to recompile use the following commands:
./configure --disable-doc
make -j$(nproc)
NSS is the Mozilla TLS implementation used by Firefox.
- Download the code:
(Because nss compilation creates a directory on the same level as nss and nspr directories live, I suggest to keep it contained inside the
mkdir nss-devel hg clone https://hg.mozilla.org/projects/nspr hg clone https://hg.mozilla.org/projects/nss
nss-devel
dir) - Compile:
cd nss USE_64=1 make nss_build_all
To run the server you need to find the directory containing the newest compile:
cd ..
NSS_DIR="$(pwd)/dist/$(cat dist/latest)"
Note: that this needs to be done every time the optimisation options of the compile, the compiler, or the system's kernel changes.
Start the server:
LD_LIBRARY_PATH="$NSS_DIR/lib" "$NSS_DIR/bin/selfserv" -d \
sql:/tmp/nssdb -p 4433 -V tls1.0: -H 1 -n server \
-e server-p256 -u
Or one that asks for client certificates:
LD_LIBRARY_PATH="$NSS_DIR/lib" "$NSS_DIR/bin/selfserv" -d \
sql:/tmp/nssdb -p 4433 -V tls1.0: -H 1 -n server \
-e server-p256 -u -r
The process to update the NSS repository is a bit different as it lives in two different directories and uses mercurial instead of git:
cd nspr
hg pull
hg up default
cd ../nss
hg pull
hg up default
cd ..
Recompilation is as easy as for other projects though:
cd nss
USE_64=1 make nss_clean_all
USE_64=1 make nss_build_all
cd ../
NSS_DIR="$(pwd)/dist/$(cat dist/latest)"
Note, it depends on python ecdsa module, see its README.md file for details.
- Download:
git clone https://github.com/tomato42/tlslite-ng.git
cd tlslite-ng
PYTHONPATH=. python scripts/tls.py server \
-c tests/serverX509Cert.pem -k tests/serverX509Key.pem \
-c tests/serverECCert.pem -k tests/serverECKey.pem \
localhost:4433
Or one that asks for client certificates:
PYTHONPATH=. python scripts/tls.py server \
-c tests/serverX509Cert.pem -k tests/serverX509Key.pem \
-c tests/serverECCert.pem -k tests/serverECKey.pem \
--reqcert localhost:4433
To update, only downloading new code is necessary:
git pull origin master
- Install server program:
unset GOPATH go install github.com/ueno/go-tlsdriver/cmd/server@latest
$HOME/go/bin/server --http \
--certfile tests/serverX509Cert.pem --keyfile tests/serverX509Key.pem \
--certfile tests/serverECCert.pem --keyfile tests/serverECKey.pem \
--address localhost:4433
Or one that asks for client certificates:
$HOME/go/bin/server --http \
--certfile tests/serverX509Cert.pem --keyfile tests/serverX509Key.pem \
--certfile tests/serverECCert.pem --keyfile tests/serverECKey.pem \
--client-auth RequestClientCert \
--address localhost:4433
To update, only downloading new code is necessary:
go install github.com/ueno/go-tlsdriver/cmd/server@latest
Like Go, Java doesn't ship with a command line utility to start a HTTPS server. The code that can be used to do that is in the 3rd-party-scripts
directory.
- Install the Java Development Kit (the
javac
command needs to be available) - Convert the key into a Java Key Store (jks) file:
openssl pkcs12 -export -in tests/serverX509Cert.pem -inkey tests/serverX509Key.pem -out key.p12 -name localhost -passout pass: keytool -importkeystore -destkeystore testkey.jks -srckeystore key.p12 -srcstoretype PKCS12 -srcstorepass '' -deststorepass password
- Compile the
SimpleHTTPSServer.java
:javac SimpleHTTPSServer.java
- Make sure the
testkey.jks
is in the same directory as theSimpleHTTPSServer.java
and start the server:java -cp . SimpleHTTPSServer