From 27594090a1f9dac970ecd6ce00f5f0e17c97906e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Trojnara?= Date: Tue, 19 Sep 2023 22:29:35 +0200 Subject: [PATCH] stunnel-5.71 --- Makefile.am | 2 +- Makefile.in | 2 +- NEWS.md | 17 + TODO.md | 2 + configure | 144 +-- configure.ac | 129 +-- doc/stunnel.8.in | 121 ++- doc/stunnel.html.in | 46 +- doc/stunnel.pl.8.in | 19 +- doc/stunnel.pl.html.in | 24 +- doc/stunnel.pl.pod.in | 20 +- doc/stunnel.pod.in | 121 ++- src/Makefile.am | 21 +- src/Makefile.in | 69 +- src/client.c | 11 +- src/ctx.c | 27 + src/dhparam.c | 46 +- src/evc.mak | 2 +- src/mingw.mak | 4 +- src/mingw.mk | 2 +- src/network.c | 6 +- src/ocsp.c | 909 ++++++++++++++++++ src/options.c | 100 +- src/os2.mak | 9 +- src/os2.mak.in | 78 ++ src/protocol.c | 5 +- src/prototypes.h | 121 ++- src/str.c | 1 + src/stunnel.c | 1 - src/ui_win_cli.c | 4 +- src/vc.mak | 2 +- src/verify.c | 341 +------ src/version.h | 2 +- tests/certs/Makefile.am | 4 +- tests/certs/Makefile.in | 4 +- tests/certs/maketestcert.sh | 245 +++-- tests/certs/openssl_intermediate.cnf | 74 ++ .../{openssltest.cnf => openssl_root.cnf} | 44 +- tests/maketest.py | 454 +++++++-- tests/plugins/p27_ocsp.py | 331 +++++++ tools/Makefile.am | 10 +- tools/Makefile.in | 10 +- tools/ca-certs.pem | 244 ++--- tools/{stunnel.spec => stunnel.spec.in} | 2 +- 44 files changed, 2862 insertions(+), 968 deletions(-) create mode 100644 src/ocsp.c create mode 100644 src/os2.mak.in create mode 100644 tests/certs/openssl_intermediate.cnf rename tests/certs/{openssltest.cnf => openssl_root.cnf} (61%) create mode 100644 tests/plugins/p27_ocsp.py rename tools/{stunnel.spec => stunnel.spec.in} (99%) diff --git a/Makefile.am b/Makefile.am index 4cd480df..a8edb008 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ EXTRA_DIST = .travis.yml makedh.sh $(doc_DATA) distcleancheck_listfiles = find . -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' distclean-local: - rm -rf autom4te.cache + rm -rf autom4te.cache version.txt sign: cp -f $(distdir).tar.gz $(distdir)-win64-installer.exe $(distdir)-android.zip ../dist diff --git a/Makefile.in b/Makefile.in index 1f3998a8..c0bf7973 100644 --- a/Makefile.in +++ b/Makefile.in @@ -879,7 +879,7 @@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status libtool distclean-local: - rm -rf autom4te.cache + rm -rf autom4te.cache version.txt sign: cp -f $(distdir).tar.gz $(distdir)-win64-installer.exe $(distdir)-android.zip ../dist diff --git a/NEWS.md b/NEWS.md index 780495ea..2af3cfb7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,23 @@ # stunnel change log +### Version 5.71, 2023.09.19, urgency: MEDIUM +* Security bugfixes + - OpenSSL DLLs updated to version 3.1.3. +* Bugfixes + - Fixed the console output of tstunnel.exe. +* Features sponsored by SAE IT-systems + - OCSP stapling is requested and verified in the client mode. + - Using "verifyChain" automatically enables OCSP + stapling in the client mode. + - OCSP stapling is always available in the server mode. + - An inconclusive OCSP verification breaks TLS negotiation. + This can be disabled with "OCSPrequire = no". + - Added the "TIMEOUTocsp" option to control the maximum + time allowed for connecting an OCSP responder. +* Features + - Added support for Red Hat OpenSSL 3.x patches. + ### Version 5.70, 2023.07.12, urgency: HIGH * Security bugfixes - OpenSSL DLLs updated to version 3.0.9. diff --git a/TODO.md b/TODO.md index 77e344f5..42253a3d 100644 --- a/TODO.md +++ b/TODO.md @@ -22,6 +22,8 @@ A sponsor could allocate my time to get them faster. * MSI installer for Windows. * Add 'leastconn' failover strategy to order defined 'connect' targets by the number of active connections. +* MariaDB (formerly MySQL) protocol negotiation: + [MariaDB Handshake Protocol](https://mariadb.com/kb/en/connection/) ### Low priority features These features will unlikely ever be supported. diff --git a/configure b/configure index 53a8f88b..d475f3ff 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for stunnel 5.70. +# Generated by GNU Autoconf 2.71 for stunnel 5.71. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, @@ -618,8 +618,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='stunnel' PACKAGE_TARNAME='stunnel' -PACKAGE_VERSION='5.70' -PACKAGE_STRING='stunnel 5.70' +PACKAGE_VERSION='5.71' +PACKAGE_STRING='stunnel 5.71' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1369,7 +1369,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures stunnel 5.70 to adapt to many kinds of systems. +\`configure' configures stunnel 5.71 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1440,7 +1440,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of stunnel 5.70:";; + short | recursive ) echo "Configuration of stunnel 5.71:";; esac cat <<\_ACEOF @@ -1561,7 +1561,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -stunnel configure 5.70 +stunnel configure 5.71 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2071,7 +2071,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by stunnel $as_me 5.70, which was +It was created by stunnel $as_me 5.71, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3347,7 +3347,7 @@ fi # Define the identity of the package. PACKAGE='stunnel' - VERSION='5.70' + VERSION='5.71' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -3528,23 +3528,23 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -printf "%s\n" "#define HOST \"$host\"" >>confdefs.h +printf "%s\n" "#define HOST \"${host}\"" >>confdefs.h cat >>confdefs.h <<_ACEOF -#define `echo CPU_$host_cpu | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 +#define `echo CPU_${host_cpu} | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 _ACEOF cat >>confdefs.h <<_ACEOF -#define `echo VENDOR_$host_vendor | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 +#define `echo VENDOR_${host_vendor} | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 _ACEOF cat >>confdefs.h <<_ACEOF -#define `echo OS_$host_os | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 +#define `echo OS_${host_os} | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_` 1 _ACEOF -case "$host_os" in +case "${host_os}" in *darwin*) # OSX does not declare ucontext without _XOPEN_SOURCE @@ -4588,9 +4588,9 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bashcompdir" >&5 printf %s "checking for bashcompdir... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_bashcompdir" >&5 -printf "%s\n" "$with_bashcompdir" >&6; } -bashcompdir=$with_bashcompdir +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${with_bashcompdir}" >&5 +printf "%s\n" "${with_bashcompdir}" >&6; } +bashcompdir=${with_bashcompdir} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** thread model" >&5 @@ -4953,7 +4953,7 @@ printf "%s\n" "$ac_cv_path_EGREP" >&6; } if test ${with_threads+y} then : withval=$with_threads; - case "$withval" in + case "${withval}" in ucontext) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: UCONTEXT mode selected" >&5 printf "%s\n" "$as_me: UCONTEXT mode selected" >&6;} @@ -5727,9 +5727,9 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - CC="$PTHREAD_CC" + LIBS="${PTHREAD_LIBS} ${LIBS}" + CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}" + CC="${PTHREAD_CC}" printf "%s\n" "#define USE_PTHREAD 1" >>confdefs.h @@ -6500,9 +6500,9 @@ if test "x$ax_pthread_ok" = "xyes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: PTHREAD thread model detected" >&5 printf "%s\n" "$as_me: PTHREAD thread model detected" >&6;} - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - CC="$PTHREAD_CC" + LIBS="${PTHREAD_LIBS} ${LIBS}" + CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}" + CC="${PTHREAD_CC}" printf "%s\n" "#define USE_PTHREAD 1" >>confdefs.h @@ -6531,7 +6531,7 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** compiler/linker flags" >&5 printf "%s\n" "$as_me: **************************************** compiler/linker flags" >&6;} -if test "$GCC" = yes; then +if test "${GCC}" = yes; then @@ -15588,7 +15588,7 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** PTY device files" >&5 printf "%s\n" "$as_me: **************************************** PTY device files" >&6;} -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then as_ac_File=`printf "%s\n" "ac_cv_file_"/dev/ptmx"" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/dev/ptmx\"" >&5 printf %s "checking for \"/dev/ptmx\"... " >&6; } @@ -15647,18 +15647,18 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** entropy sources" >&5 printf "%s\n" "$as_me: **************************************** entropy sources" >&6;} -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then # Check whether --with-egd-socket was given. if test ${with_egd_socket+y} then : - withval=$with_egd_socket; EGD_SOCKET="$withval" + withval=$with_egd_socket; EGD_SOCKET="${withval}" fi - if test -n "$EGD_SOCKET"; then + if test -n "${EGD_SOCKET}"; then -printf "%s\n" "#define EGD_SOCKET \"$EGD_SOCKET\"" >>confdefs.h +printf "%s\n" "#define EGD_SOCKET \"${EGD_SOCKET}\"" >>confdefs.h fi @@ -15667,7 +15667,7 @@ printf "%s\n" "#define EGD_SOCKET \"$EGD_SOCKET\"" >>confdefs.h # Check whether --with-random was given. if test ${with_random+y} then : - withval=$with_random; RANDOM_FILE="$withval" + withval=$with_random; RANDOM_FILE="${withval}" else $as_nop # Check for random device @@ -15698,10 +15698,10 @@ fi fi - if test -n "$RANDOM_FILE"; then + if test -n "${RANDOM_FILE}"; then -printf "%s\n" "#define RANDOM_FILE \"$RANDOM_FILE\"" >>confdefs.h +printf "%s\n" "#define RANDOM_FILE \"${RANDOM_FILE}\"" >>confdefs.h fi else @@ -15712,7 +15712,7 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** default group" >&5 printf "%s\n" "$as_me: **************************************** default group" >&6;} DEFAULT_GROUP=nobody -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then grep '^nogroup:' /etc/group >/dev/null && DEFAULT_GROUP=nogroup else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cross-compilation: assuming nogroup is not available" >&5 @@ -15720,8 +15720,8 @@ printf "%s\n" "$as_me: WARNING: cross-compilation: assuming nogroup is not avail fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for default group" >&5 printf %s "checking for default group... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_GROUP" >&5 -printf "%s\n" "$DEFAULT_GROUP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${DEFAULT_GROUP}" >&5 +printf "%s\n" "${DEFAULT_GROUP}" >&6; } # Check whether --enable-largefile was given. @@ -16482,8 +16482,8 @@ fi # Add BeOS libraries -if test "x$host_os" = "xbeos"; then - LIBS="$LIBS -lbe -lroot -lbind" +if test "x${host_os}" = "xbeos"; then + LIBS="${LIBS} -lbe -lroot -lbind" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** library functions" >&5 @@ -16630,7 +16630,7 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 printf %s "checking for getaddrinfo... " >&6; } -case "$host_os" in +case "${host_os}" in *androideabi*) # http://stackoverflow.com/questions/7818246/segmentation-fault-in-getaddrinfo { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (buggy Android implementation)" >&5 @@ -16674,7 +16674,7 @@ esac # poll() is not recommended on Mac OS X <= 10.3 and broken on Mac OS X 10.4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken poll() implementation" >&5 printf %s "checking for broken poll() implementation... " >&6; } -case "$host_os" in +case "${host_os}" in darwin0-8.*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (poll() disabled)" >&5 printf "%s\n" "yes (poll() disabled)" >&6; } @@ -16711,7 +16711,7 @@ printf %s "checking whether to enable IPv6 support... " >&6; } if test ${enable_ipv6+y} then : enableval=$enable_ipv6; - case "$enableval" in + case "${enableval}" in yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } @@ -16745,7 +16745,7 @@ printf %s "checking whether to enable FIPS support... " >&6; } if test ${enable_fips+y} then : enableval=$enable_fips; - case "$enableval" in + case "${enableval}" in yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } use_fips="yes" @@ -16780,7 +16780,7 @@ printf %s "checking whether to enable systemd socket activation support... " >&6 if test ${enable_systemd+y} then : enableval=$enable_systemd; - case "$enableval" in + case "${enableval}" in yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sd_listen_fds" >&5 @@ -16957,13 +16957,13 @@ printf %s "checking whether to enable TCP wrappers support... " >&6; } if test ${enable_libwrap+y} then : enableval=$enable_libwrap; - case "$enableval" in + case "${enableval}" in yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define USE_LIBWRAP 1" >>confdefs.h - LIBS="$LIBS -lwrap" + LIBS="${LIBS} -lwrap" ;; no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -16980,8 +16980,8 @@ else $as_nop printf "%s\n" "autodetecting" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hosts_access in -lwrap" >&5 printf %s "checking for hosts_access in -lwrap... " >&6; } - valid_LIBS="$LIBS" - LIBS="$valid_LIBS -lwrap" + valid_LIBS="${LIBS}" + LIBS="${valid_LIBS} -lwrap" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17010,7 +17010,7 @@ else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - LIBS="$valid_LIBS" + LIBS="${valid_LIBS}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libwrap library not found" >&5 printf "%s\n" "$as_me: libwrap library not found" >&6;} @@ -17039,7 +17039,7 @@ iterate_ssl_dir() { : # - empty prefix for main_dir in "/usr/local" "/opt" "/opt/local" "/usr/local/opt" "/opt/csw" "/usr/pkg" "/usr/lib" "/usr" ""; do for sub_dir in "/ssl" "/openssl" "/ossl" ""; do - check_ssl_dir "$1$main_dir$sub_dir" && return 0 + check_ssl_dir "$1${main_dir}${sub_dir}" && return 0 done done return 1 @@ -17047,21 +17047,21 @@ iterate_ssl_dir() { : find_ssl_dir() { : # try Android *first* - case "$host_os" in + case "${host_os}" in *androideabi*) - iterate_ssl_dir "$ANDROID_NDK/sysroot" && return + iterate_ssl_dir "${ANDROID_NDK}/sysroot" && return ;; esac - test -d "$lt_sysroot" && iterate_ssl_dir "$lt_sysroot" && return - test "$prefix" != "NONE" && iterate_ssl_dir "$prefix" && return - test -d "$ac_default_prefix" && iterate_ssl_dir "$ac_default_prefix" && return + test -d "${lt_sysroot}" && iterate_ssl_dir "${lt_sysroot}" && return + test "${prefix}" != "NONE" && iterate_ssl_dir "${prefix}" && return + test -d "${ac_default_prefix}" && iterate_ssl_dir "${ac_default_prefix}" && return iterate_ssl_dir "" && return # try Xcode *last* if test -x "/usr/bin/xcrun"; then sdk_path=`/usr/bin/xcrun --sdk macosx --show-sdk-path` - check_ssl_dir "$sdk_path/usr" && return + check_ssl_dir "${sdk_path}/usr" && return fi check_ssl_dir "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr" } @@ -17073,13 +17073,13 @@ printf %s "checking for TLS directory... " >&6; } # Check whether --with-ssl was given. if test ${with_ssl+y} then : - withval=$with_ssl; check_ssl_dir "$withval" + withval=$with_ssl; check_ssl_dir "${withval}" else $as_nop find_ssl_dir fi -if test -z "$SSLDIR"; then +if test -z "${SSLDIR}"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } as_fn_error $? " @@ -17087,15 +17087,15 @@ Could not find your TLS library installation dir Use --with-ssl option to fix this problem " "$LINENO" 5 fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SSLDIR" >&5 -printf "%s\n" "$SSLDIR" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${SSLDIR}" >&5 +printf "%s\n" "${SSLDIR}" >&6; } -printf "%s\n" "#define SSLDIR \"$SSLDIR\"" >>confdefs.h +printf "%s\n" "#define SSLDIR \"${SSLDIR}\"" >>confdefs.h -valid_CPPFLAGS="$CPPFLAGS"; CPPFLAGS="$CPPFLAGS -I$SSLDIR/include" -valid_LIBS="$LIBS"; LIBS="$LIBS -L$SSLDIR/lib64 -L$SSLDIR/lib -lssl -lcrypto" +valid_CPPFLAGS="${CPPFLAGS}"; CPPFLAGS="${CPPFLAGS} -I${SSLDIR}/include" +valid_LIBS="${LIBS}"; LIBS="${LIBS} -L${SSLDIR}/lib64 -L${SSLDIR}/lib -lssl -lcrypto" ac_fn_c_check_func "$LINENO" "FIPS_mode_set" "ac_cv_func_FIPS_mode_set" if test "x$ac_cv_func_FIPS_mode_set" = xyes @@ -17110,8 +17110,8 @@ then : fi -if test "x$use_fips" = "xauto"; then - if test "x$ac_cv_func_FIPS_mode_set" = "xyes" -o "x$ac_cv_func_OSSL_PROVIDER_available" = "xyes"; then +if test "x${use_fips}" = "xauto"; then + if test "x${ac_cv_func_FIPS_mode_set}" = "xyes" -o "x${ac_cv_func_OSSL_PROVIDER_available}" = "xyes"; then printf "%s\n" "#define USE_FIPS 1" >>confdefs.h @@ -17126,18 +17126,22 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether DH parameters need to be updated" >&5 printf %s "checking whether DH parameters need to be updated... " >&6; } # only build src/dhparam.c if sources are located in the current directory -if test -f src/stunnel.c && ! grep -q " built for $PACKAGE_STRING " src/dhparam.c; then +if test -f src/stunnel.c && ! grep -q " built for ${PACKAGE_STRING} " src/dhparam.c; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } - $(dirname $0)/makedh.sh "$PACKAGE_STRING" >src/dhparam.c + $(dirname $0)/makedh.sh "${PACKAGE_STRING}" >src/dhparam.c else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi -SYSROOT="$lt_sysroot" -CPPFLAGS="$valid_CPPFLAGS" -LIBS="$valid_LIBS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating version.txt" >&5 +printf "%s\n" "$as_me: updating version.txt" >&6;} +echo "${PACKAGE_VERSION}" >version.txt + +SYSROOT="${lt_sysroot}" +CPPFLAGS="${valid_CPPFLAGS}" +LIBS="${valid_LIBS}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: **************************************** write the results" >&5 printf "%s\n" "$as_me: **************************************** write the results" >&6;} @@ -17666,7 +17670,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by stunnel $as_me 5.70, which was +This file was extended by stunnel $as_me 5.71, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17734,7 +17738,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -stunnel config.status 5.70 +stunnel config.status 5.71 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 4f3f0938..5f159170 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Process this file with autoconf to produce a configure script. -AC_INIT([stunnel],[5.70]) +AC_INIT([stunnel],[5.71]) AC_MSG_NOTICE([**************************************** initialization]) AC_CONFIG_AUX_DIR(auto) AC_CONFIG_MACRO_DIR([m4]) @@ -10,13 +10,13 @@ AM_INIT_AUTOMAKE([foreign]) AC_CANONICAL_HOST AC_SUBST([host]) -AC_DEFINE_UNQUOTED([HOST], ["$host"], [Host description]) +AC_DEFINE_UNQUOTED([HOST], ["${host}"], [Host description]) define([esc], [`echo ]$1[ | tr abcdefghijklmnopqrstuvwxyz.- ABCDEFGHIJKLMNOPQRSTUVWXYZ__ | tr -dc ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_`]) -AC_DEFINE_UNQUOTED(esc(CPU_$host_cpu)) -AC_DEFINE_UNQUOTED(esc(VENDOR_$host_vendor)) -AC_DEFINE_UNQUOTED(esc(OS_$host_os)) +AC_DEFINE_UNQUOTED(esc(CPU_${host_cpu})) +AC_DEFINE_UNQUOTED(esc(VENDOR_${host_vendor})) +AC_DEFINE_UNQUOTED(esc(OS_${host_os})) -case "$host_os" in +case "${host_os}" in *darwin*) # OSX does not declare ucontext without _XOPEN_SOURCE AC_DEFINE([_XOPEN_SOURCE], [500], [Use X/Open 5 with POSIX 1995]) @@ -44,8 +44,8 @@ AC_ARG_WITH([bashcompdir], [PKG_CHECK_VAR([with_bashcompdir], [bash-completion], [completionsdir], , [with_bashcompdir="${datarootdir}/bash-completion/completions"])]) AC_MSG_CHECKING([for bashcompdir]) -AC_MSG_RESULT([$with_bashcompdir]) -AC_SUBST([bashcompdir], [$with_bashcompdir]) +AC_MSG_RESULT([${with_bashcompdir}]) +AC_SUBST([bashcompdir], [${with_bashcompdir}]) AC_MSG_NOTICE([**************************************** thread model]) # thread detection should be done first, as it may change the CC variable @@ -53,7 +53,7 @@ AC_MSG_NOTICE([**************************************** thread model]) AC_ARG_WITH(threads, [ --with-threads=model select threading model (ucontext/pthread/fork)], [ - case "$withval" in + case "${withval}" in ucontext) AC_MSG_NOTICE([UCONTEXT mode selected]) AC_DEFINE([USE_UCONTEXT], [1], [Define to 1 to select UCONTEXT mode]) @@ -61,9 +61,9 @@ AC_ARG_WITH(threads, pthread) AC_MSG_NOTICE([PTHREAD mode selected]) AX_PTHREAD() - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - CC="$PTHREAD_CC" + LIBS="${PTHREAD_LIBS} ${LIBS}" + CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}" + CC="${PTHREAD_CC}" AC_DEFINE([USE_PTHREAD], [1], [Define to 1 to select PTHREAD mode]) ;; fork) @@ -71,16 +71,16 @@ AC_ARG_WITH(threads, AC_DEFINE([USE_FORK], [1], [Define to 1 to select FORK mode]) ;; *) - AC_MSG_ERROR([Unknown thread model \"${withval}\"]) + AC_MSG_ERROR([Unknown thread model "${withval}"]) ;; esac ], [ # do not attempt to autodetect UCONTEXT threading AX_PTHREAD([ AC_MSG_NOTICE([PTHREAD thread model detected]) - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - CC="$PTHREAD_CC" + LIBS="${PTHREAD_LIBS} ${LIBS}" + CFLAGS="${CFLAGS} ${PTHREAD_CFLAGS}" + CC="${PTHREAD_CC}" AC_DEFINE([USE_PTHREAD], [1], [Define to 1 to select PTHREAD mode]) ], [ AC_MSG_NOTICE([FORK thread model detected]) @@ -89,7 +89,7 @@ AC_ARG_WITH(threads, ]) AC_MSG_NOTICE([**************************************** compiler/linker flags]) -if test "$GCC" = yes; then +if test "${GCC}" = yes; then AX_APPEND_COMPILE_FLAGS([-Wall]) AX_APPEND_COMPILE_FLAGS([-Wextra]) AX_APPEND_COMPILE_FLAGS([-Wpedantic]) @@ -136,7 +136,7 @@ AC_CHECK_TYPES([struct sockaddr_un], [], [], [#include ]) AC_CHECK_TYPES([struct addrinfo], [], [], [#include ]) AC_MSG_NOTICE([**************************************** PTY device files]) -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then AC_CHECK_FILE("/dev/ptmx", AC_DEFINE([HAVE_DEV_PTMX], [1], [Define to 1 if you have '/dev/ptmx' device.])) AC_CHECK_FILE("/dev/ptc", AC_DEFINE([HAVE_DEV_PTS_AND_PTC], [1], @@ -147,28 +147,28 @@ fi AC_MSG_NOTICE([**************************************** entropy sources]) -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then AC_ARG_WITH(egd-socket, [ --with-egd-socket=FILE Entropy Gathering Daemon socket path], - [EGD_SOCKET="$withval"] + [EGD_SOCKET="${withval}"] ) - if test -n "$EGD_SOCKET"; then - AC_DEFINE_UNQUOTED([EGD_SOCKET], ["$EGD_SOCKET"], + if test -n "${EGD_SOCKET}"; then + AC_DEFINE_UNQUOTED([EGD_SOCKET], ["${EGD_SOCKET}"], [Entropy Gathering Daemon socket path]) fi # Check for user-specified random device AC_ARG_WITH(random, [ --with-random=FILE read randomness from file (default=/dev/urandom)], - [RANDOM_FILE="$withval"], + [RANDOM_FILE="${withval}"], [ # Check for random device AC_CHECK_FILE("/dev/urandom", RANDOM_FILE="/dev/urandom") ] ) - if test -n "$RANDOM_FILE"; then + if test -n "${RANDOM_FILE}"; then AC_SUBST([RANDOM_FILE]) - AC_DEFINE_UNQUOTED([RANDOM_FILE], ["$RANDOM_FILE"], [Random file path]) + AC_DEFINE_UNQUOTED([RANDOM_FILE], ["${RANDOM_FILE}"], [Random file path]) fi else AC_MSG_WARN([cross-compilation: assuming entropy sources are not available]) @@ -176,13 +176,13 @@ fi AC_MSG_NOTICE([**************************************** default group]) DEFAULT_GROUP=nobody -if test "x$cross_compiling" = "xno"; then +if test "x${cross_compiling}" = "xno"; then grep '^nogroup:' /etc/group >/dev/null && DEFAULT_GROUP=nogroup else AC_MSG_WARN([cross-compilation: assuming nogroup is not available]) fi AC_MSG_CHECKING([for default group]) -AC_MSG_RESULT([$DEFAULT_GROUP]) +AC_MSG_RESULT([${DEFAULT_GROUP}]) AC_SUBST([DEFAULT_GROUP]) AC_SYS_LARGEFILE @@ -222,8 +222,8 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([shl_load], [dld]) # Add BeOS libraries -if test "x$host_os" = "xbeos"; then - LIBS="$LIBS -lbe -lroot -lbind" +if test "x${host_os}" = "xbeos"; then + LIBS="${LIBS} -lbe -lroot -lbind" fi AC_MSG_NOTICE([**************************************** library functions]) @@ -242,7 +242,7 @@ AC_CHECK_FUNCS(getcontext __makecontext_v2) # sockets AC_CHECK_FUNCS(poll gethostbyname2 endhostent getnameinfo) AC_MSG_CHECKING([for getaddrinfo]) -case "$host_os" in +case "${host_os}" in *androideabi*) # http://stackoverflow.com/questions/7818246/segmentation-fault-in-getaddrinfo AC_MSG_RESULT([no (buggy Android implementation)]) @@ -267,7 +267,7 @@ getaddrinfo(NULL, NULL, NULL, NULL); esac # poll() is not recommended on Mac OS X <= 10.3 and broken on Mac OS X 10.4 AC_MSG_CHECKING([for broken poll() implementation]) -case "$host_os" in +case "${host_os}" in darwin[0-8].*) AC_MSG_RESULT([yes (poll() disabled)]) AC_DEFINE([BROKEN_POLL], [1], [Define to 1 if you have a broken 'poll' implementation.]) @@ -285,7 +285,7 @@ AC_MSG_CHECKING([whether to enable IPv6 support]) AC_ARG_ENABLE(ipv6, [ --disable-ipv6 disable IPv6 support], [ - case "$enableval" in + case "${enableval}" in yes) AC_MSG_RESULT([yes]) AC_DEFINE([USE_IPv6], [1], [Define to 1 to enable IPv6 support]) @@ -293,7 +293,7 @@ AC_ARG_ENABLE(ipv6, no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) - AC_MSG_ERROR([bad value \"${enableval}\"]) + AC_MSG_ERROR([bad value "${enableval}"]) ;; esac ], [ @@ -309,7 +309,7 @@ AC_MSG_CHECKING([whether to enable FIPS support]) AC_ARG_ENABLE(fips, [ --disable-fips disable OpenSSL FIPS support], [ - case "$enableval" in + case "${enableval}" in yes) AC_MSG_RESULT([yes]) use_fips="yes" AC_DEFINE([USE_FIPS], [1], @@ -319,7 +319,7 @@ AC_ARG_ENABLE(fips, use_fips="no" ;; *) AC_MSG_RESULT([error]) - AC_MSG_ERROR([bad value \"${enableval}\"]) + AC_MSG_ERROR([bad value "${enableval}"]) ;; esac ], @@ -334,7 +334,7 @@ AC_MSG_CHECKING([whether to enable systemd socket activation support]) AC_ARG_ENABLE(systemd, [ --disable-systemd disable systemd socket activation support], [ - case "$enableval" in + case "${enableval}" in yes) AC_MSG_RESULT([yes]) AC_SEARCH_LIBS([sd_listen_fds], [systemd systemd-daemon]) AC_DEFINE([USE_SYSTEMD], [1], @@ -343,7 +343,7 @@ AC_ARG_ENABLE(systemd, no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) - AC_MSG_ERROR([Bad value \"${enableval}\"]) + AC_MSG_ERROR([Bad value "${enableval}"]) ;; esac ], @@ -369,24 +369,24 @@ AC_MSG_CHECKING([whether to enable TCP wrappers support]) AC_ARG_ENABLE(libwrap, [ --disable-libwrap disable TCP wrappers support], [ - case "$enableval" in + case "${enableval}" in yes) AC_MSG_RESULT([yes]) AC_DEFINE([USE_LIBWRAP], [1], [Define to 1 to enable TCP wrappers support]) - LIBS="$LIBS -lwrap" + LIBS="${LIBS} -lwrap" ;; no) AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([error]) - AC_MSG_ERROR([Bad value \"${enableval}\"]) + AC_MSG_ERROR([Bad value "${enableval}"]) ;; esac ], [ AC_MSG_RESULT([autodetecting]) AC_MSG_CHECKING([for hosts_access in -lwrap]) - valid_LIBS="$LIBS" - LIBS="$valid_LIBS -lwrap" + valid_LIBS="${LIBS}" + LIBS="${valid_LIBS} -lwrap" AC_LINK_IFELSE( [ AC_LANG_PROGRAM( @@ -399,7 +399,7 @@ AC_ARG_ENABLE(libwrap, AC_MSG_NOTICE([libwrap support enabled]) ], [ AC_MSG_RESULT([no]) - LIBS="$valid_LIBS" + LIBS="${valid_LIBS}" AC_MSG_NOTICE([libwrap library not found]) ] ) @@ -421,7 +421,7 @@ iterate_ssl_dir() { : # - empty prefix for main_dir in "/usr/local" "/opt" "/opt/local" "/usr/local/opt" "/opt/csw" "/usr/pkg" "/usr/lib" "/usr" ""; do for sub_dir in "/ssl" "/openssl" "/ossl" ""; do - check_ssl_dir "$1$main_dir$sub_dir" && return 0 + check_ssl_dir "$1${main_dir}${sub_dir}" && return 0 done done return 1 @@ -429,21 +429,21 @@ iterate_ssl_dir() { : find_ssl_dir() { : # try Android *first* - case "$host_os" in + case "${host_os}" in *androideabi*) - iterate_ssl_dir "$ANDROID_NDK/sysroot" && return + iterate_ssl_dir "${ANDROID_NDK}/sysroot" && return ;; esac - test -d "$lt_sysroot" && iterate_ssl_dir "$lt_sysroot" && return - test "$prefix" != "NONE" && iterate_ssl_dir "$prefix" && return - test -d "$ac_default_prefix" && iterate_ssl_dir "$ac_default_prefix" && return + test -d "${lt_sysroot}" && iterate_ssl_dir "${lt_sysroot}" && return + test "${prefix}" != "NONE" && iterate_ssl_dir "${prefix}" && return + test -d "${ac_default_prefix}" && iterate_ssl_dir "${ac_default_prefix}" && return iterate_ssl_dir "" && return # try Xcode *last* if test -x "/usr/bin/xcrun"; then sdk_path=`/usr/bin/xcrun --sdk macosx --show-sdk-path` - check_ssl_dir "$sdk_path/usr" && return + check_ssl_dir "${sdk_path}/usr" && return fi check_ssl_dir "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr" } @@ -452,26 +452,26 @@ SSLDIR="" AC_MSG_CHECKING([for TLS directory]) AC_ARG_WITH(ssl, [ --with-ssl=DIR location of installed TLS libraries/include files], - [check_ssl_dir "$withval"], + [check_ssl_dir "${withval}"], [find_ssl_dir] ) -if test -z "$SSLDIR"; then +if test -z "${SSLDIR}"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([ Could not find your TLS library installation dir Use --with-ssl option to fix this problem ]) fi -AC_MSG_RESULT([$SSLDIR]) +AC_MSG_RESULT([${SSLDIR}]) AC_SUBST([SSLDIR]) -AC_DEFINE_UNQUOTED([SSLDIR], ["$SSLDIR"], [TLS directory]) +AC_DEFINE_UNQUOTED([SSLDIR], ["${SSLDIR}"], [TLS directory]) -valid_CPPFLAGS="$CPPFLAGS"; CPPFLAGS="$CPPFLAGS -I$SSLDIR/include" -valid_LIBS="$LIBS"; LIBS="$LIBS -L$SSLDIR/lib64 -L$SSLDIR/lib -lssl -lcrypto" +valid_CPPFLAGS="${CPPFLAGS}"; CPPFLAGS="${CPPFLAGS} -I${SSLDIR}/include" +valid_LIBS="${LIBS}"; LIBS="${LIBS} -L${SSLDIR}/lib64 -L${SSLDIR}/lib -lssl -lcrypto" AC_CHECK_FUNCS(FIPS_mode_set OSSL_PROVIDER_available) -if test "x$use_fips" = "xauto"; then - if test "x$ac_cv_func_FIPS_mode_set" = "xyes" -o "x$ac_cv_func_OSSL_PROVIDER_available" = "xyes"; then +if test "x${use_fips}" = "xauto"; then + if test "x${ac_cv_func_FIPS_mode_set}" = "xyes" -o "x${ac_cv_func_OSSL_PROVIDER_available}" = "xyes"; then AC_DEFINE([USE_FIPS], [1], [Define to 1 to enable OpenSSL FIPS support]) AC_MSG_NOTICE([FIPS support enabled]) else @@ -481,16 +481,19 @@ fi AC_MSG_CHECKING([whether DH parameters need to be updated]) # only build src/dhparam.c if sources are located in the current directory -if test -f src/stunnel.c && ! grep -q " built for $PACKAGE_STRING " src/dhparam.c; then +if test -f src/stunnel.c && ! grep -q " built for ${PACKAGE_STRING} " src/dhparam.c; then AC_MSG_RESULT([yes]) - $(dirname $0)/makedh.sh "$PACKAGE_STRING" >src/dhparam.c + $(dirname $0)/makedh.sh "${PACKAGE_STRING}" >src/dhparam.c else AC_MSG_RESULT([no]) fi -SYSROOT="$lt_sysroot" -CPPFLAGS="$valid_CPPFLAGS" -LIBS="$valid_LIBS" +AC_MSG_NOTICE([updating version.txt]) +echo "${PACKAGE_VERSION}" >version.txt + +SYSROOT="${lt_sysroot}" +CPPFLAGS="${valid_CPPFLAGS}" +LIBS="${valid_LIBS}" AC_MSG_NOTICE([**************************************** write the results]) AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile tools/Makefile tests/Makefile tests/certs/Makefile]) diff --git a/doc/stunnel.8.in b/doc/stunnel.8.in index e8c5831f..ccc25d36 100644 --- a/doc/stunnel.8.in +++ b/doc/stunnel.8.in @@ -71,7 +71,7 @@ .\" ======================================================================== .\" .IX Title "stunnel 8" -.TH stunnel 8 "2023.07.08" "5.70" "stunnel TLS Proxy" +.TH stunnel 8 "2023.08.14" "5.71" "stunnel TLS Proxy" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -163,7 +163,8 @@ An address parameter of an option may be either: .IP "\(bu" 4 A port number. .IP "\(bu" 4 -A colon-separated pair of \s-1IP\s0 address (either IPv4, IPv6, or domain name) and port number. +A colon-separated pair of \s-1IP\s0 address (either IPv4, IPv6, or domain name) and +port number. .IP "\(bu" 4 A Unix socket path (Unix only). .SS "\s-1GLOBAL OPTIONS\s0" @@ -176,7 +177,8 @@ directory to chroot \fBstunnel\fR process and \fIexec\fR are located inside the jail and the patches have to be relative to the directory specified with \fBchroot\fR. .Sp -Several functions of the operating system also need their files to be located within the chroot jail, e.g.: +Several functions of the operating system also need their files to be located +within the chroot jail, e.g.: .RS 4 .IP "\(bu" 4 Delayed resolver typically needs /etc/nsswitch.conf and /etc/resolv.conf. @@ -225,7 +227,8 @@ select hardware or software cryptographic engine .Sp default: software-only cryptography .Sp -See Examples section for an engine configuration to use the certificate and the corresponding private key from a cryptographic device. +See Examples section for an engine configuration to use the certificate and the +corresponding private key from a cryptographic device. .IP "\fBengineCtrl\fR = COMMAND[:PARAMETER]" 4 .IX Item "engineCtrl = COMMAND[:PARAMETER]" control hardware engine @@ -278,8 +281,8 @@ pixel image. .IX Item "log = append | overwrite" log file handling .Sp -This option allows you to choose whether the log file (specified with the \fIoutput\fR -option) is appended or overwritten when opened or re-opened. +This option allows you to choose whether the log file (specified with the +\&\fIoutput\fR option) is appended or overwritten when opened or re-opened. .Sp default: append .IP "\fBoutput\fR = \s-1FILE\s0" 4 @@ -395,32 +398,33 @@ This parameter is also used as the certificate identifier when a hardware engine is enabled. .IP "\fBcheckEmail\fR = \s-1EMAIL\s0" 4 .IX Item "checkEmail = EMAIL" -email address of the peer certificate subject +verify the email address of the end-entity (leaf) peer certificate subject .Sp Certificates are accepted if no subject checks were specified, or the email -address of the peer certificate matches any of the email addresses specified -with \fIcheckEmail\fR. +address of the end-entity (leaf) peer certificate matches any of the email +addresses specified with \fIcheckEmail\fR. .Sp Multiple \fIcheckEmail\fR options are allowed in a single service section. .Sp This option requires OpenSSL 1.0.2 or later. .IP "\fBcheckHost\fR = \s-1HOST\s0" 4 .IX Item "checkHost = HOST" -host of the peer certificate subject +verify the host of the end-entity (leaf) peer certificate subject .Sp Certificates are accepted if no subject checks were specified, or the host name -of the peer certificate matches any of the hosts specified with \fIcheckHost\fR. +of the end-entity (leaf) peer certificate matches any of the hosts specified +with \fIcheckHost\fR. .Sp Multiple \fIcheckHost\fR options are allowed in a single service section. .Sp This option requires OpenSSL 1.0.2 or later. .IP "\fBcheckIP\fR = \s-1IP\s0" 4 .IX Item "checkIP = IP" -\&\s-1IP\s0 address of the peer certificate subject +verify the \s-1IP\s0 address of the end-entity (leaf) peer certificate subject .Sp Certificates are accepted if no subject checks were specified, or the \s-1IP\s0 -address of the peer certificate matches any of the \s-1IP\s0 addresses specified with -\&\fIcheckIP\fR. +address of the end-entity (leaf) peer certificate matches any of the \s-1IP\s0 +addresses specified with \fIcheckIP\fR. .Sp Multiple \fIcheckIP\fR options are allowed in a single service section. .Sp @@ -458,7 +462,8 @@ configuration file. Supported commands are described on the .Sp Several \fIconfig\fR lines can be used to specify multiple configuration commands. .Sp -Use \fIcurves\fR option instead of enabling \fIconfig = Curves:list_curves\fR to support elliptic curves. +Use \fIcurves\fR option instead of enabling \fIconfig = Curves:list_curves\fR to +support elliptic curves. .Sp This option requires OpenSSL 1.0.2 or later. .IP "\fBconnect\fR = [\s-1HOST:\s0]PORT" 4 @@ -610,7 +615,8 @@ use \s-1IDENT\s0 (\s-1RFC 1413\s0) username checking .IX Item "include = DIRECTORY" include all configuration file parts located in \s-1DIRECTORY\s0 .Sp -The files are included in the ascending alphabetical order of their names. The recommended filename convention is +The files are included in the ascending alphabetical order of their names. The +recommended filename convention is .Sp for global options: .Sp @@ -652,7 +658,7 @@ By default, the \s-1IP\s0 address of the outgoing interface is used as the sourc remote connections. Use this option to bind a static local \s-1IP\s0 address instead. .IP "\fB\s-1OCSP\s0\fR = \s-1URL\s0" 4 .IX Item "OCSP = URL" -select \s-1OCSP\s0 responder for certificate verification +select \s-1OCSP\s0 responder for the end-entity (leaf) peer certificate verification .IP "\fBOCSPaia\fR = yes | no" 4 .IX Item "OCSPaia = yes | no" validate certificates with their \s-1AIA OCSP\s0 responders @@ -675,6 +681,15 @@ send and verify the \s-1OCSP\s0 nonce extension This option protects the \s-1OCSP\s0 protocol against replay attacks. Due to its computational overhead, the nonce extension is usually only supported on internal (e.g. corporate) responders, and not on public \s-1OCSP\s0 responders. +.IP "\fBOCSPrequire\fR = yes | no" 4 +.IX Item "OCSPrequire = yes | no" +require a conclusive \s-1OCSP\s0 response +.Sp +Disable this option to allow a connection even though no conclusive \s-1OCSP\s0 +response was retrieved from stapling and a direct request to the \s-1OCSP\s0 +responder. +.Sp +default: yes .IP "\fBoptions\fR = \s-1SSL_OPTIONS\s0" 4 .IX Item "options = SSL_OPTIONS" \&\fBOpenSSL\fR library options @@ -702,8 +717,8 @@ default: \& options = NO_SSLv3 .Ve .Sp -Use \fIsslVersionMax\fR or \fIsslVersionMin\fR option instead of disabling specific \s-1TLS\s0 protocol -versions when compiled with \fBOpenSSL 1.1.0\fR or later. +Use \fIsslVersionMax\fR or \fIsslVersionMin\fR option instead of disabling specific +\&\s-1TLS\s0 protocol versions when compiled with \fBOpenSSL 1.1.0\fR or later. .IP "\fBprotocol\fR = \s-1PROTO\s0" 4 .IX Item "protocol = PROTO" application protocol to negotiate \s-1TLS\s0 @@ -891,19 +906,35 @@ The meaning of each level is described below: Everything is permitted. .IP "level 1" 4 .IX Item "level 1" -The security level corresponds to a minimum of 80 bits of security. Any parameters offering below 80 bits of security are excluded. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys shorter than 1024 bits and \s-1ECC\s0 keys shorter than 160 bits are prohibited. All export cipher suites are prohibited since they all offer less than 80 bits of security. \s-1SSL\s0 version 2 is prohibited. Any cipher suite using \s-1MD5\s0 for the \s-1MAC\s0 is also prohibited. +The security level corresponds to a minimum of 80 bits of security. Any +parameters offering below 80 bits of security are excluded. As a result \s-1RSA, +DSA\s0 and \s-1DH\s0 keys shorter than 1024 bits and \s-1ECC\s0 keys shorter than 160 bits are +prohibited. All export cipher suites are prohibited since they all offer less +than 80 bits of security. \s-1SSL\s0 version 2 is prohibited. Any cipher suite using +\&\s-1MD5\s0 for the \s-1MAC\s0 is also prohibited. .IP "level 2" 4 .IX Item "level 2" -Security level set to 112 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys shorter than 2048 bits and \s-1ECC\s0 keys shorter than 224 bits are prohibited. In addition to the level 1 exclusions any cipher suite using \s-1RC4\s0 is also prohibited. \s-1SSL\s0 version 3 is also not allowed. Compression is disabled. +Security level set to 112 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys +shorter than 2048 bits and \s-1ECC\s0 keys shorter than 224 bits are prohibited. In +addition to the level 1 exclusions any cipher suite using \s-1RC4\s0 is also +prohibited. \s-1SSL\s0 version 3 is also not allowed. Compression is disabled. .IP "level 3" 4 .IX Item "level 3" -Security level set to 128 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys shorter than 3072 bits and \s-1ECC\s0 keys shorter than 256 bits are prohibited. In addition to the level 2 exclusions cipher suites not offering forward secrecy are prohibited. \s-1TLS\s0 versions below 1.1 are not permitted. Session tickets are disabled. +Security level set to 128 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys +shorter than 3072 bits and \s-1ECC\s0 keys shorter than 256 bits are prohibited. In +addition to the level 2 exclusions cipher suites not offering forward secrecy +are prohibited. \s-1TLS\s0 versions below 1.1 are not permitted. Session tickets are +disabled. .IP "level 4" 4 .IX Item "level 4" -Security level set to 192 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys shorter than 7680 bits and \s-1ECC\s0 keys shorter than 384 bits are prohibited. Cipher suites using \s-1SHA1\s0 for the \s-1MAC\s0 are prohibited. \s-1TLS\s0 versions below 1.2 are not permitted. +Security level set to 192 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys +shorter than 7680 bits and \s-1ECC\s0 keys shorter than 384 bits are prohibited. +Cipher suites using \s-1SHA1\s0 for the \s-1MAC\s0 are prohibited. \s-1TLS\s0 versions below 1.2 are +not permitted. .IP "level 5" 4 .IX Item "level 5" -Security level set to 256 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys shorter than 15360 bits and \s-1ECC\s0 keys shorter than 512 bits are prohibited. +Security level set to 256 bits of security. As a result \s-1RSA, DSA\s0 and \s-1DH\s0 keys +shorter than 15360 bits and \s-1ECC\s0 keys shorter than 512 bits are prohibited. .IP "default: 2" 4 .IX Item "default: 2" .RE @@ -925,16 +956,19 @@ default: no .IX Item "setgid = GROUP (Unix only)" Unix group id .Sp -As a global option: \fBsetgid()\fR to the specified group in daemon mode and clear all other groups. +As a global option: \fBsetgid()\fR to the specified group in daemon mode and clear +all other groups. .Sp -As a service-level option: set the group of the Unix socket specified with \*(L"accept\*(R". +As a service-level option: set the group of the Unix socket specified with +\&\*(L"accept\*(R". .IP "\fBsetuid\fR = \s-1USER\s0 (Unix only)" 4 .IX Item "setuid = USER (Unix only)" Unix user id .Sp As a global option: \fBsetuid()\fR to the specified user in daemon mode. .Sp -As a service-level option: set the owner of the Unix socket specified with \*(L"accept\*(R". +As a service-level option: set the owner of the Unix socket specified with +\&\*(L"accept\*(R". .IP "\fBsessionCacheSize\fR = \s-1NUM_ENTRIES\s0" 4 .IX Item "sessionCacheSize = NUM_ENTRIES" session cache size @@ -1048,7 +1082,8 @@ linked OpenSSL library. .Sp Availability of specific protocols depends on the linked OpenSSL library. .Sp -The \fIsslVersionMax\fR option is only available when compiled with \fBOpenSSL 1.1.0\fR and later. +The \fIsslVersionMax\fR option is only available when compiled with +\&\fBOpenSSL 1.1.0\fR and later. .Sp default: all .IP "\fBsslVersionMin\fR = \s-1SSL_VERSION\s0" 4 @@ -1062,7 +1097,8 @@ linked OpenSSL library. .Sp Availability of specific protocols depends on the linked OpenSSL library. .Sp -The \fIsslVersionMin\fR option is only available when compiled with \fBOpenSSL 1.1.0\fR and later. +The \fIsslVersionMin\fR option is only available when compiled with +\&\fBOpenSSL 1.1.0\fR and later. .Sp default: TLSv1 .IP "\fBstack\fR = \s-1BYTES\s0 (except for \s-1FORK\s0 model)" 4 @@ -1117,10 +1153,13 @@ time to wait for expected data time to wait for close_notify (set to 0 for buggy \s-1MSIE\s0) .IP "\fBTIMEOUTconnect\fR = \s-1SECONDS\s0" 4 .IX Item "TIMEOUTconnect = SECONDS" -time to wait to connect to a remote host +time to wait to connect a remote host .IP "\fBTIMEOUTidle\fR = \s-1SECONDS\s0" 4 .IX Item "TIMEOUTidle = SECONDS" time to keep an idle connection +.IP "\fBTIMEOUTocsp\fR = \s-1SECONDS\s0" 4 +.IX Item "TIMEOUTocsp = SECONDS" +time to wait to connect an \s-1OCSP\s0 responder .IP "\fBtransparent\fR = none | source | destination | both (Unix only)" 4 .IX Item "transparent = none | source | destination | both (Unix only)" enable transparent proxy support on selected platforms @@ -1234,19 +1273,21 @@ and \fIverifyPeer\fR options. .RS 4 .IP "level 0" 4 .IX Item "level 0" -Request and ignore the peer certificate. +Request and ignore the peer certificate chain. .IP "level 1" 4 .IX Item "level 1" -Verify the peer certificate if present. +Verify the peer certificate chain if present. .IP "level 2" 4 .IX Item "level 2" -Verify the peer certificate. +Verify the peer certificate chain. .IP "level 3" 4 .IX Item "level 3" -Verify the peer against a locally installed certificate. +Verify the peer certificate chain and the end-entity (leaf) peer certificate +against a locally installed certificate. .IP "level 4" 4 .IX Item "level 4" -Ignore the chain and only verify the peer certificate. +Ignore the peer certificate chain and only verify the end-entity (leaf) peer +certificate against a locally installed certificate. .IP "default" 4 .IX Item "default" No verify. @@ -1266,9 +1307,9 @@ specified with \fICAfile\fR, or in the directory specified with \fICApath\fR. default: no .IP "\fBverifyPeer\fR = yes | no" 4 .IX Item "verifyPeer = yes | no" -verify the peer certificate +verify the end-entity (leaf) peer certificate .Sp -The peer certificate needs to be stored either in the file +The end-entity (leaf) peer certificate needs to be stored either in the file specified with \fICAfile\fR, or in the directory specified with \fICApath\fR. .Sp default: no @@ -1432,7 +1473,8 @@ The client key is automatically selected based on the list of CAs trusted by the \& connect = example.com:8443 .Ve .PP -An example of advanced engine configuration to use the certificate and the corresponding private key from a pkcs11 engine: +An example of advanced engine configuration to use the certificate and the +corresponding private key from a pkcs11 engine: .PP .Vb 3 \& engine = pkcs11 @@ -1448,7 +1490,8 @@ An example of advanced engine configuration to use the certificate and the corre \& key = pkcs11:token=MyToken;object=MyKey .Ve .PP -An example of advanced engine configuration to use the certificate and the corresponding private key from a SoftHSM token: +An example of advanced engine configuration to use the certificate and the +corresponding private key from a SoftHSM token: .PP .Vb 3 \& engine = pkcs11 diff --git a/doc/stunnel.html.in b/doc/stunnel.html.in index 77a3836b..d3d3e3e8 100644 --- a/doc/stunnel.html.in +++ b/doc/stunnel.html.in @@ -478,9 +478,9 @@
checkEmail = EMAIL
-

email address of the peer certificate subject

+

verify the email address of the end-entity (leaf) peer certificate subject

-

Certificates are accepted if no subject checks were specified, or the email address of the peer certificate matches any of the email addresses specified with checkEmail.

+

Certificates are accepted if no subject checks were specified, or the email address of the end-entity (leaf) peer certificate matches any of the email addresses specified with checkEmail.

Multiple checkEmail options are allowed in a single service section.

@@ -490,9 +490,9 @@
checkHost = HOST
-

host of the peer certificate subject

+

verify the host of the end-entity (leaf) peer certificate subject

-

Certificates are accepted if no subject checks were specified, or the host name of the peer certificate matches any of the hosts specified with checkHost.

+

Certificates are accepted if no subject checks were specified, or the host name of the end-entity (leaf) peer certificate matches any of the hosts specified with checkHost.

Multiple checkHost options are allowed in a single service section.

@@ -502,9 +502,9 @@
checkIP = IP
-

IP address of the peer certificate subject

+

verify the IP address of the end-entity (leaf) peer certificate subject

-

Certificates are accepted if no subject checks were specified, or the IP address of the peer certificate matches any of the IP addresses specified with checkIP.

+

Certificates are accepted if no subject checks were specified, or the IP address of the end-entity (leaf) peer certificate matches any of the IP addresses specified with checkIP.

Multiple checkIP options are allowed in a single service section.

@@ -778,7 +778,7 @@ prime256v1 (OpenSSL older than 1.1.1)
OCSP = URL
-

select OCSP responder for certificate verification

+

select OCSP responder for the end-entity (leaf) peer certificate verification

OCSPaia = yes | no
@@ -806,6 +806,16 @@ prime256v1 (OpenSSL older than 1.1.1)

This option protects the OCSP protocol against replay attacks. Due to its computational overhead, the nonce extension is usually only supported on internal (e.g. corporate) responders, and not on public OCSP responders.

+ +
OCSPrequire = yes | no
+
+ +

require a conclusive OCSP response

+ +

Disable this option to allow a connection even though no conclusive OCSP response was retrieved from stapling and a direct request to the OCSP responder.

+ +

default: yes

+
options = SSL_OPTIONS
@@ -1328,7 +1338,7 @@ sslVersionMin = SSL_VERSION
TIMEOUTconnect = SECONDS
-

time to wait to connect to a remote host

+

time to wait to connect a remote host

TIMEOUTidle = SECONDS
@@ -1336,6 +1346,12 @@ sslVersionMin = SSL_VERSION

time to keep an idle connection

+ +
TIMEOUTocsp = SECONDS
+
+ +

time to wait to connect an OCSP responder

+
transparent = none | source | destination | both (Unix only)
@@ -1470,31 +1486,31 @@ transparent = destination
level 0
-

Request and ignore the peer certificate.

+

Request and ignore the peer certificate chain.

level 1
-

Verify the peer certificate if present.

+

Verify the peer certificate chain if present.

level 2
-

Verify the peer certificate.

+

Verify the peer certificate chain.

level 3
-

Verify the peer against a locally installed certificate.

+

Verify the peer certificate chain and the end-entity (leaf) peer certificate against a locally installed certificate.

level 4
-

Ignore the chain and only verify the peer certificate.

+

Ignore the peer certificate chain and only verify the end-entity (leaf) peer certificate against a locally installed certificate.

default
@@ -1521,9 +1537,9 @@ transparent = destination
verifyPeer = yes | no
-

verify the peer certificate

+

verify the end-entity (leaf) peer certificate

-

The peer certificate needs to be stored either in the file specified with CAfile, or in the directory specified with CApath.

+

The end-entity (leaf) peer certificate needs to be stored either in the file specified with CAfile, or in the directory specified with CApath.

default: no

diff --git a/doc/stunnel.pl.8.in b/doc/stunnel.pl.8.in index 0573eb71..9c3c873d 100644 --- a/doc/stunnel.pl.8.in +++ b/doc/stunnel.pl.8.in @@ -71,7 +71,7 @@ .\" ======================================================================== .\" .IX Title "stunnel 8" -.TH stunnel 8 "2023.07.08" "5.70" "stunnel TLS Proxy" +.TH stunnel 8 "2023.08.14" "5.71" "stunnel TLS Proxy" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -664,7 +664,7 @@ Domyślnie używane jest \s-1IP\s0 najbardziej zewnętrznego interfejsu w stron serwera, do którego nawiązywane jest połączenie. .IP "\fB\s-1OCSP\s0\fR = \s-1URL\s0" 4 .IX Item "OCSP = URL" -responder \s-1OCSP\s0 do weryfikacji certyfikatów +responder \s-1OCSP\s0 do weryfikacji certyfikatu drugiej strony połączenia .IP "\fBOCSPaia\fR = yes | no" 4 .IX Item "OCSPaia = yes | no" weryfikuj certyfikaty przy użyciu respondertów \s-1AIA\s0 @@ -687,6 +687,18 @@ Opcja \fBOCSPnonce\fR zabezpiecza protokół \s-1OCSP\s0 przed atakami powtórze Ze względu na złożoność obliczeniową rozszerzenie nonce jest zwykle wspierane jedynie przez wewnętrzne (np. korporacyjne), a nie przez publiczne respondery \&\s-1OCSP.\s0 +.IP "\fBOCSPrequire\fR = yes | no" 4 +.IX Item "OCSPrequire = yes | no" +wymagaj rozstrzygającej odpowiedzi respondera \s-1OCSP\s0 +.IP "\fBOCSPrequire\fR = yes | no" 4 +.IX Item "OCSPrequire = yes | no" +Wyłączenie tej opcji pozwala na zaakceptowanie połączenia pomimo braku +otrzymania rozstrzygającej odpowiedzi \s-1OCSP\s0 ze staplingu i bezpośredniego +żądania wysłanego do respondera. +.Sp +default: yes +.Sp +domyślnie: yes .IP "\fBoptions\fR = \s-1OPCJE_SSL\s0" 4 .IX Item "options = OPCJE_SSL" opcje biblioteki \fBOpenSSL\fR @@ -1132,6 +1144,9 @@ czas oczekiwania na nawiązanie połączenia .IP "\fBTIMEOUTidle\fR = \s-1LICZBA_SEKUND\s0" 4 .IX Item "TIMEOUTidle = LICZBA_SEKUND" maksymalny czas utrzymywania bezczynnego połączenia +.IP "\fBTIMEOUTocsp\fR = \s-1LICZBA_SEKUND\s0" 4 +.IX Item "TIMEOUTocsp = LICZBA_SEKUND" +czas oczekiwania na nawiązanie połączenia z serwerem \s-1OCSP\s0 .IP "\fBtransparent\fR = none | source | destination | both (tylko Unix)" 4 .IX Item "transparent = none | source | destination | both (tylko Unix)" tryb przezroczystego proxy na wspieranych platformach diff --git a/doc/stunnel.pl.html.in b/doc/stunnel.pl.html.in index 28ad5469..b74ebc91 100644 --- a/doc/stunnel.pl.html.in +++ b/doc/stunnel.pl.html.in @@ -768,7 +768,7 @@ prime256v1 (OpenSSL starszy niż 1.1.1)
OCSP = URL
-

responder OCSP do weryfikacji certyfikatów

+

responder OCSP do weryfikacji certyfikatu drugiej strony połączenia

OCSPaia = yes | no
@@ -796,6 +796,22 @@ prime256v1 (OpenSSL starszy niż 1.1.1)

Opcja OCSPnonce zabezpiecza protokół OCSP przed atakami powtórzeniowymi. Ze względu na złożoność obliczeniową rozszerzenie nonce jest zwykle wspierane jedynie przez wewnętrzne (np. korporacyjne), a nie przez publiczne respondery OCSP.

+ +
OCSPrequire = yes | no
+
+ +

wymagaj rozstrzygającej odpowiedzi respondera OCSP

+ +
+
OCSPrequire = yes | no
+
+ +

Wyłączenie tej opcji pozwala na zaakceptowanie połączenia pomimo braku otrzymania rozstrzygającej odpowiedzi OCSP ze staplingu i bezpośredniego żądania wysłanego do respondera.

+ +

default: yes

+ +

domyślnie: yes

+
options = OPCJE_SSL
@@ -1328,6 +1344,12 @@ sslVersionMin = WERSJA_SSL

maksymalny czas utrzymywania bezczynnego połączenia

+
+
TIMEOUTocsp = LICZBA_SEKUND
+
+ +

czas oczekiwania na nawiązanie połączenia z serwerem OCSP

+
transparent = none | source | destination | both (tylko Unix)
diff --git a/doc/stunnel.pl.pod.in b/doc/stunnel.pl.pod.in index 748a992f..9c8d05d7 100644 --- a/doc/stunnel.pl.pod.in +++ b/doc/stunnel.pl.pod.in @@ -698,7 +698,7 @@ serwera, do którego nawiązywane jest połączenie. =item B = URL -responder OCSP do weryfikacji certyfikatów +responder OCSP do weryfikacji certyfikatu drugiej strony połączenia =item B = yes | no @@ -725,6 +725,20 @@ Ze względu na złożoność obliczeniową rozszerzenie nonce jest zwykle wspier jedynie przez wewnętrzne (np. korporacyjne), a nie przez publiczne respondery OCSP. +=item B = yes | no + +wymagaj rozstrzygającej odpowiedzi respondera OCSP + +=item B = yes | no + +Wyłączenie tej opcji pozwala na zaakceptowanie połączenia pomimo braku +otrzymania rozstrzygającej odpowiedzi OCSP ze staplingu i bezpośredniego +żądania wysłanego do respondera. + +default: yes + +domyślnie: yes + =item B = OPCJE_SSL opcje biblioteki B @@ -1212,6 +1226,10 @@ czas oczekiwania na nawiązanie połączenia maksymalny czas utrzymywania bezczynnego połączenia +=item B = LICZBA_SEKUND + +czas oczekiwania na nawiązanie połączenia z serwerem OCSP + =item B = none | source | destination | both (tylko Unix) tryb przezroczystego proxy na wspieranych platformach diff --git a/doc/stunnel.pod.in b/doc/stunnel.pod.in index 75217301..fa1ec99d 100644 --- a/doc/stunnel.pod.in +++ b/doc/stunnel.pod.in @@ -136,7 +136,8 @@ A port number. =item * -A colon-separated pair of IP address (either IPv4, IPv6, or domain name) and port number. +A colon-separated pair of IP address (either IPv4, IPv6, or domain name) and +port number. =item * @@ -156,7 +157,8 @@ B keeps B in a chrooted jail. I, I, I and I are located inside the jail and the patches have to be relative to the directory specified with B. -Several functions of the operating system also need their files to be located within the chroot jail, e.g.: +Several functions of the operating system also need their files to be located +within the chroot jail, e.g.: =over 4 @@ -215,7 +217,8 @@ select hardware or software cryptographic engine default: software-only cryptography -See Examples section for an engine configuration to use the certificate and the corresponding private key from a cryptographic device. +See Examples section for an engine configuration to use the certificate and the +corresponding private key from a cryptographic device. =item B = COMMAND[:PARAMETER] @@ -276,8 +279,8 @@ pixel image. log file handling -This option allows you to choose whether the log file (specified with the I -option) is appended or overwritten when opened or re-opened. +This option allows you to choose whether the log file (specified with the +I option) is appended or overwritten when opened or re-opened. default: append @@ -412,11 +415,11 @@ engine is enabled. =item B = EMAIL -email address of the peer certificate subject +verify the email address of the end-entity (leaf) peer certificate subject Certificates are accepted if no subject checks were specified, or the email -address of the peer certificate matches any of the email addresses specified -with I. +address of the end-entity (leaf) peer certificate matches any of the email +addresses specified with I. Multiple I options are allowed in a single service section. @@ -424,10 +427,11 @@ This option requires OpenSSL 1.0.2 or later. =item B = HOST -host of the peer certificate subject +verify the host of the end-entity (leaf) peer certificate subject Certificates are accepted if no subject checks were specified, or the host name -of the peer certificate matches any of the hosts specified with I. +of the end-entity (leaf) peer certificate matches any of the hosts specified +with I. Multiple I options are allowed in a single service section. @@ -435,11 +439,11 @@ This option requires OpenSSL 1.0.2 or later. =item B = IP -IP address of the peer certificate subject +verify the IP address of the end-entity (leaf) peer certificate subject Certificates are accepted if no subject checks were specified, or the IP -address of the peer certificate matches any of the IP addresses specified with -I. +address of the end-entity (leaf) peer certificate matches any of the IP +addresses specified with I. Multiple I options are allowed in a single service section. @@ -481,7 +485,8 @@ I manual page. Several I lines can be used to specify multiple configuration commands. -Use I option instead of enabling I to support elliptic curves. +Use I option instead of enabling I to +support elliptic curves. This option requires OpenSSL 1.0.2 or later. @@ -648,7 +653,8 @@ use IDENT (RFC 1413) username checking include all configuration file parts located in DIRECTORY -The files are included in the ascending alphabetical order of their names. The recommended filename convention is +The files are included in the ascending alphabetical order of their names. The +recommended filename convention is for global options: @@ -688,7 +694,7 @@ remote connections. Use this option to bind a static local IP address instead. =item B = URL -select OCSP responder for certificate verification +select OCSP responder for the end-entity (leaf) peer certificate verification =item B = yes | no @@ -715,6 +721,16 @@ This option protects the OCSP protocol against replay attacks. Due to its computational overhead, the nonce extension is usually only supported on internal (e.g. corporate) responders, and not on public OCSP responders. +=item B = yes | no + +require a conclusive OCSP response + +Disable this option to allow a connection even though no conclusive OCSP +response was retrieved from stapling and a direct request to the OCSP +responder. + +default: yes + =item B = SSL_OPTIONS B library options @@ -738,8 +754,8 @@ default: options = NO_SSLv2 options = NO_SSLv3 -Use I or I option instead of disabling specific TLS protocol -versions when compiled with B or later. +Use I or I option instead of disabling specific +TLS protocol versions when compiled with B or later. =item B = PROTO @@ -955,23 +971,39 @@ Everything is permitted. =item level 1 -The security level corresponds to a minimum of 80 bits of security. Any parameters offering below 80 bits of security are excluded. As a result RSA, DSA and DH keys shorter than 1024 bits and ECC keys shorter than 160 bits are prohibited. All export cipher suites are prohibited since they all offer less than 80 bits of security. SSL version 2 is prohibited. Any cipher suite using MD5 for the MAC is also prohibited. +The security level corresponds to a minimum of 80 bits of security. Any +parameters offering below 80 bits of security are excluded. As a result RSA, +DSA and DH keys shorter than 1024 bits and ECC keys shorter than 160 bits are +prohibited. All export cipher suites are prohibited since they all offer less +than 80 bits of security. SSL version 2 is prohibited. Any cipher suite using +MD5 for the MAC is also prohibited. =item level 2 -Security level set to 112 bits of security. As a result RSA, DSA and DH keys shorter than 2048 bits and ECC keys shorter than 224 bits are prohibited. In addition to the level 1 exclusions any cipher suite using RC4 is also prohibited. SSL version 3 is also not allowed. Compression is disabled. +Security level set to 112 bits of security. As a result RSA, DSA and DH keys +shorter than 2048 bits and ECC keys shorter than 224 bits are prohibited. In +addition to the level 1 exclusions any cipher suite using RC4 is also +prohibited. SSL version 3 is also not allowed. Compression is disabled. =item level 3 -Security level set to 128 bits of security. As a result RSA, DSA and DH keys shorter than 3072 bits and ECC keys shorter than 256 bits are prohibited. In addition to the level 2 exclusions cipher suites not offering forward secrecy are prohibited. TLS versions below 1.1 are not permitted. Session tickets are disabled. +Security level set to 128 bits of security. As a result RSA, DSA and DH keys +shorter than 3072 bits and ECC keys shorter than 256 bits are prohibited. In +addition to the level 2 exclusions cipher suites not offering forward secrecy +are prohibited. TLS versions below 1.1 are not permitted. Session tickets are +disabled. =item level 4 -Security level set to 192 bits of security. As a result RSA, DSA and DH keys shorter than 7680 bits and ECC keys shorter than 384 bits are prohibited. Cipher suites using SHA1 for the MAC are prohibited. TLS versions below 1.2 are not permitted. +Security level set to 192 bits of security. As a result RSA, DSA and DH keys +shorter than 7680 bits and ECC keys shorter than 384 bits are prohibited. +Cipher suites using SHA1 for the MAC are prohibited. TLS versions below 1.2 are +not permitted. =item level 5 -Security level set to 256 bits of security. As a result RSA, DSA and DH keys shorter than 15360 bits and ECC keys shorter than 512 bits are prohibited. +Security level set to 256 bits of security. As a result RSA, DSA and DH keys +shorter than 15360 bits and ECC keys shorter than 512 bits are prohibited. =item default: 2 @@ -994,9 +1026,11 @@ default: no Unix group id -As a global option: setgid() to the specified group in daemon mode and clear all other groups. +As a global option: setgid() to the specified group in daemon mode and clear +all other groups. -As a service-level option: set the group of the Unix socket specified with "accept". +As a service-level option: set the group of the Unix socket specified with +"accept". =item B = USER (Unix only) @@ -1004,7 +1038,8 @@ Unix user id As a global option: setuid() to the specified user in daemon mode. -As a service-level option: set the owner of the Unix socket specified with "accept". +As a service-level option: set the owner of the Unix socket specified with +"accept". =item B = NUM_ENTRIES @@ -1121,7 +1156,8 @@ linked OpenSSL library. Availability of specific protocols depends on the linked OpenSSL library. -The I option is only available when compiled with B and later. +The I option is only available when compiled with +B and later. default: all @@ -1136,7 +1172,8 @@ linked OpenSSL library. Availability of specific protocols depends on the linked OpenSSL library. -The I option is only available when compiled with B and later. +The I option is only available when compiled with +B and later. default: TLSv1 @@ -1197,12 +1234,16 @@ time to wait for close_notify (set to 0 for buggy MSIE) =item B = SECONDS -time to wait to connect to a remote host +time to wait to connect a remote host =item B = SECONDS time to keep an idle connection +=item B = SECONDS + +time to wait to connect an OCSP responder + =item B = none | source | destination | both (Unix only) enable transparent proxy support on selected platforms @@ -1323,23 +1364,25 @@ and I options. =item level 0 -Request and ignore the peer certificate. +Request and ignore the peer certificate chain. =item level 1 -Verify the peer certificate if present. +Verify the peer certificate chain if present. =item level 2 -Verify the peer certificate. +Verify the peer certificate chain. =item level 3 -Verify the peer against a locally installed certificate. +Verify the peer certificate chain and the end-entity (leaf) peer certificate +against a locally installed certificate. =item level 4 -Ignore the chain and only verify the peer certificate. +Ignore the peer certificate chain and only verify the end-entity (leaf) peer +certificate against a locally installed certificate. =item default @@ -1361,9 +1404,9 @@ default: no =item B = yes | no -verify the peer certificate +verify the end-entity (leaf) peer certificate -The peer certificate needs to be stored either in the file +The end-entity (leaf) peer certificate needs to be stored either in the file specified with I, or in the directory specified with I. default: no @@ -1533,7 +1576,8 @@ The client key is automatically selected based on the list of CAs trusted by the accept = 127.0.0.1:8080 connect = example.com:8443 -An example of advanced engine configuration to use the certificate and the corresponding private key from a pkcs11 engine: +An example of advanced engine configuration to use the certificate and the +corresponding private key from a pkcs11 engine: engine = pkcs11 engineCtrl = MODULE_PATH:opensc-pkcs11.so @@ -1547,7 +1591,8 @@ An example of advanced engine configuration to use the certificate and the corre cert = pkcs11:token=MyToken;object=MyCert key = pkcs11:token=MyToken;object=MyKey -An example of advanced engine configuration to use the certificate and the corresponding private key from a SoftHSM token: +An example of advanced engine configuration to use the certificate and the +corresponding private key from a SoftHSM token: engine = pkcs11 engineCtrl = MODULE_PATH:softhsm2.dll diff --git a/src/Makefile.am b/src/Makefile.am index d71a491d..eae899b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ common_headers = common.h prototypes.h version.h common_sources = tls.c str.c file.c client.c log.c options.c protocol.c common_sources += network.c resolver.c ssl.c ctx.c verify.c sthreads.c -common_sources += fd.c dhparam.c cron.c stunnel.c +common_sources += ocsp.c fd.c dhparam.c cron.c stunnel.c unix_sources = pty.c libwrap.c ui_unix.c shared_sources = env.c win32_gui_sources = ui_win_gui.c resources.h resources.rc @@ -37,12 +37,14 @@ stunnel_CPPFLAGS += -DCONFDIR='"$(sysconfdir)/stunnel"' # TLS library stunnel_LDFLAGS = -L$(SSLDIR)/lib64 -L$(SSLDIR)/lib -lssl -lcrypto -# stunnel3 script +# Apply substitutions edit = sed \ - -e 's|@bindir[@]|$(bindir)|g' -stunnel3: Makefile + -e 's|@bindir[@]|$(bindir)|g' \ + -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' +stunnel3 os2.mak: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel3: $(srcdir)/stunnel3.in +os2.mak: $(srcdir)/os2.mak.in # Unix shared library pkglib_LTLIBRARIES = libstunnel.la @@ -64,7 +66,14 @@ mingw64: clean-local: rm -rf ../obj ../bin -# Remaining files to be included +############################################################################### +# Remaining files to be included # +############################################################################### + +dist_noinst_DATA = os2.mak +EXTRA_DIST += os2.mak.in +CLEANFILES += os2.mak + EXTRA_DIST += $(win32_gui_sources) $(win32_cli_sources) EXTRA_DIST += make.bat makece.bat makew32.bat -EXTRA_DIST += mingw.mk mingw.mak evc.mak vc.mak os2.mak +EXTRA_DIST += mingw.mk mingw.mak evc.mak vc.mak diff --git a/src/Makefile.in b/src/Makefile.in index b083685a..475d824e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -22,6 +22,7 @@ + VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ @@ -105,7 +106,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_noinst_DATA) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = @@ -159,9 +161,9 @@ am__objects_3 = stunnel-tls.$(OBJEXT) stunnel-str.$(OBJEXT) \ stunnel-protocol.$(OBJEXT) stunnel-network.$(OBJEXT) \ stunnel-resolver.$(OBJEXT) stunnel-ssl.$(OBJEXT) \ stunnel-ctx.$(OBJEXT) stunnel-verify.$(OBJEXT) \ - stunnel-sthreads.$(OBJEXT) stunnel-fd.$(OBJEXT) \ - stunnel-dhparam.$(OBJEXT) stunnel-cron.$(OBJEXT) \ - stunnel-stunnel.$(OBJEXT) + stunnel-sthreads.$(OBJEXT) stunnel-ocsp.$(OBJEXT) \ + stunnel-fd.$(OBJEXT) stunnel-dhparam.$(OBJEXT) \ + stunnel-cron.$(OBJEXT) stunnel-stunnel.$(OBJEXT) am__objects_4 = stunnel-pty.$(OBJEXT) stunnel-libwrap.$(OBJEXT) \ stunnel-ui_unix.$(OBJEXT) am_stunnel_OBJECTS = $(am__objects_2) $(am__objects_3) \ @@ -192,12 +194,13 @@ am__depfiles_remade = ./$(DEPDIR)/env.Plo \ ./$(DEPDIR)/stunnel-ctx.Po ./$(DEPDIR)/stunnel-dhparam.Po \ ./$(DEPDIR)/stunnel-fd.Po ./$(DEPDIR)/stunnel-file.Po \ ./$(DEPDIR)/stunnel-libwrap.Po ./$(DEPDIR)/stunnel-log.Po \ - ./$(DEPDIR)/stunnel-network.Po ./$(DEPDIR)/stunnel-options.Po \ - ./$(DEPDIR)/stunnel-protocol.Po ./$(DEPDIR)/stunnel-pty.Po \ - ./$(DEPDIR)/stunnel-resolver.Po ./$(DEPDIR)/stunnel-ssl.Po \ - ./$(DEPDIR)/stunnel-sthreads.Po ./$(DEPDIR)/stunnel-str.Po \ - ./$(DEPDIR)/stunnel-stunnel.Po ./$(DEPDIR)/stunnel-tls.Po \ - ./$(DEPDIR)/stunnel-ui_unix.Po ./$(DEPDIR)/stunnel-verify.Po + ./$(DEPDIR)/stunnel-network.Po ./$(DEPDIR)/stunnel-ocsp.Po \ + ./$(DEPDIR)/stunnel-options.Po ./$(DEPDIR)/stunnel-protocol.Po \ + ./$(DEPDIR)/stunnel-pty.Po ./$(DEPDIR)/stunnel-resolver.Po \ + ./$(DEPDIR)/stunnel-ssl.Po ./$(DEPDIR)/stunnel-sthreads.Po \ + ./$(DEPDIR)/stunnel-str.Po ./$(DEPDIR)/stunnel-stunnel.Po \ + ./$(DEPDIR)/stunnel-tls.Po ./$(DEPDIR)/stunnel-ui_unix.Po \ + ./$(DEPDIR)/stunnel-verify.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -224,6 +227,7 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac +DATA = $(dist_noinst_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ config.h.in # Read a list of newline-separated strings from the standard input, @@ -377,7 +381,7 @@ top_srcdir = @top_srcdir@ common_headers = common.h prototypes.h version.h common_sources = tls.c str.c file.c client.c log.c options.c \ protocol.c network.c resolver.c ssl.c ctx.c verify.c \ - sthreads.c fd.c dhparam.c cron.c stunnel.c + sthreads.c ocsp.c fd.c dhparam.c cron.c stunnel.c unix_sources = pty.c libwrap.c ui_unix.c shared_sources = env.c win32_gui_sources = ui_win_gui.c resources.h resources.rc stunnel.ico \ @@ -385,12 +389,10 @@ win32_gui_sources = ui_win_gui.c resources.h resources.rc stunnel.ico \ win32_cli_sources = ui_win_cli.c stunnel_SOURCES = $(common_headers) $(common_sources) $(unix_sources) bin_SCRIPTS = stunnel3 - -# Remaining files to be included -EXTRA_DIST = stunnel3.in $(win32_gui_sources) $(win32_cli_sources) \ - make.bat makece.bat makew32.bat mingw.mk mingw.mak evc.mak \ - vc.mak os2.mak -CLEANFILES = stunnel3 +EXTRA_DIST = stunnel3.in os2.mak.in $(win32_gui_sources) \ + $(win32_cli_sources) make.bat makece.bat makew32.bat mingw.mk \ + mingw.mak evc.mak vc.mak +CLEANFILES = stunnel3 os2.mak # Red Hat "by design" bug #82369 @@ -402,15 +404,21 @@ stunnel_CPPFLAGS = -I$(SYSROOT)/usr/kerberos/include \ # TLS library stunnel_LDFLAGS = -L$(SSLDIR)/lib64 -L$(SSLDIR)/lib -lssl -lcrypto -# stunnel3 script +# Apply substitutions edit = sed \ - -e 's|@bindir[@]|$(bindir)|g' + -e 's|@bindir[@]|$(bindir)|g' \ + -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' # Unix shared library pkglib_LTLIBRARIES = libstunnel.la libstunnel_la_SOURCES = $(shared_sources) libstunnel_la_LDFLAGS = -avoid-version + +############################################################################### +# Remaining files to be included # +############################################################################### +dist_noinst_DATA = os2.mak all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am @@ -603,6 +611,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-libwrap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-network.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-ocsp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-options.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-protocol.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stunnel-pty.Po@am__quote@ # am--include-marker @@ -824,6 +833,20 @@ stunnel-sthreads.obj: sthreads.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-sthreads.obj `if test -f 'sthreads.c'; then $(CYGPATH_W) 'sthreads.c'; else $(CYGPATH_W) '$(srcdir)/sthreads.c'; fi` +stunnel-ocsp.o: ocsp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ocsp.o -MD -MP -MF $(DEPDIR)/stunnel-ocsp.Tpo -c -o stunnel-ocsp.o `test -f 'ocsp.c' || echo '$(srcdir)/'`ocsp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ocsp.Tpo $(DEPDIR)/stunnel-ocsp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ocsp.c' object='stunnel-ocsp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ocsp.o `test -f 'ocsp.c' || echo '$(srcdir)/'`ocsp.c + +stunnel-ocsp.obj: ocsp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-ocsp.obj -MD -MP -MF $(DEPDIR)/stunnel-ocsp.Tpo -c -o stunnel-ocsp.obj `if test -f 'ocsp.c'; then $(CYGPATH_W) 'ocsp.c'; else $(CYGPATH_W) '$(srcdir)/ocsp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-ocsp.Tpo $(DEPDIR)/stunnel-ocsp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ocsp.c' object='stunnel-ocsp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stunnel-ocsp.obj `if test -f 'ocsp.c'; then $(CYGPATH_W) 'ocsp.c'; else $(CYGPATH_W) '$(srcdir)/ocsp.c'; fi` + stunnel-fd.o: fd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stunnel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stunnel-fd.o -MD -MP -MF $(DEPDIR)/stunnel-fd.Tpo -c -o stunnel-fd.o `test -f 'fd.c' || echo '$(srcdir)/'`fd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/stunnel-fd.Tpo $(DEPDIR)/stunnel-fd.Po @@ -1014,7 +1037,8 @@ distdir-am: $(DISTFILES) done check-am: all-am check: check-am -all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) config.h +all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) $(DATA) \ + config.h installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ @@ -1066,6 +1090,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/stunnel-libwrap.Po -rm -f ./$(DEPDIR)/stunnel-log.Po -rm -f ./$(DEPDIR)/stunnel-network.Po + -rm -f ./$(DEPDIR)/stunnel-ocsp.Po -rm -f ./$(DEPDIR)/stunnel-options.Po -rm -f ./$(DEPDIR)/stunnel-protocol.Po -rm -f ./$(DEPDIR)/stunnel-pty.Po @@ -1133,6 +1158,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/stunnel-libwrap.Po -rm -f ./$(DEPDIR)/stunnel-log.Po -rm -f ./$(DEPDIR)/stunnel-network.Po + -rm -f ./$(DEPDIR)/stunnel-ocsp.Po -rm -f ./$(DEPDIR)/stunnel-options.Po -rm -f ./$(DEPDIR)/stunnel-protocol.Po -rm -f ./$(DEPDIR)/stunnel-pty.Po @@ -1184,9 +1210,10 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ .PRECIOUS: Makefile -stunnel3: Makefile +stunnel3 os2.mak: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel3: $(srcdir)/stunnel3.in +os2.mak: $(srcdir)/os2.mak.in ############################################################################### # Win32 executables # diff --git a/src/client.c b/src/client.c index 226c4baa..d9b9f36d 100644 --- a/src/client.c +++ b/src/client.c @@ -553,6 +553,12 @@ NOEXPORT void ssl_start(CLI *c) { } if(c->opt->option.client) { #ifndef OPENSSL_NO_TLSEXT +#ifndef OPENSSL_NO_OCSP + if(!SSL_set_tlsext_status_type(c->ssl, TLSEXT_STATUSTYPE_ocsp)) { + sslerror("OCSP: SSL_set_tlsext_status_type"); + throw_exception(c, 1); + } +#endif /* !defined(OPENSSL_NO_OCSP) */ /* c->opt->sni should always be initialized at this point, * either explicitly with "sni" * or implicitly with "protocolHost" or "connect" */ @@ -1312,7 +1318,7 @@ NOEXPORT void auth_user(CLI *c) { s_log(LOG_WARNING, "Unknown service 'auth': using default 113"); ident.in.sin_port=htons(113); } - if(s_connect(c, &ident, addr_len(&ident))) + if(s_connect(c, &ident, addr_len(&ident), c->opt->timeout_connect)) throw_exception(c, 1); s_log(LOG_DEBUG, "IDENT server connected"); remote_port=ntohs(c->peer_addr.in.sin_port); @@ -1548,7 +1554,8 @@ NOEXPORT SOCKET connect_remote(CLI *c) { c->idx=(idx_start+idx_try)%c->connect_addr.num; if(!connect_init(c, c->connect_addr.addr[c->idx].sa.sa_family) && !s_connect(c, &c->connect_addr.addr[c->idx], - addr_len(&c->connect_addr.addr[c->idx]))) { + addr_len(&c->connect_addr.addr[c->idx]), + c->opt->timeout_connect)) { if(c->ssl) { SSL_SESSION *sess=SSL_get1_session(c->ssl); if(sess) { diff --git a/src/ctx.c b/src/ctx.c index c02f500b..cdbe8b9a 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -140,6 +140,8 @@ typedef long SSL_OPTIONS_TYPE; #endif int context_init(SERVICE_OPTIONS *section) { /* init TLS context */ + s_log(LOG_DEBUG, "Initializing context [%s]", section->servname); + /* create a new TLS context */ #if OPENSSL_VERSION_NUMBER>=0x10100000L #if OPENSSL_VERSION_NUMBER>=0x30000000L @@ -325,6 +327,12 @@ int context_init(SERVICE_OPTIONS *section) { /* init TLS context */ if(verify_init(section)) return 1; /* FAILED */ + /* OCSP stapling */ +#ifndef OPENSSL_NO_OCSP + if(ocsp_init(section)) + return 1; /* FAILED */ +#endif /* OPENSSL_NO_OCSP */ + /* initialize the DH/ECDH key agreement */ #ifndef OPENSSL_NO_TLSEXT if(!section->option.client) @@ -341,6 +349,25 @@ int context_init(SERVICE_OPTIONS *section) { /* init TLS context */ return 0; /* OK */ } +/**************************************** cleanup TLS context */ + +/* + * free anything allocate from context_init() and callbacks + * also free any cached data allocated in client.c + */ +void context_cleanup(SERVICE_OPTIONS *section) { + s_log(LOG_DEBUG, "Cleaning up context [%s]", section->servname); + +#ifndef OPENSSL_NO_OCSP + ocsp_cleanup(section); +#endif /* !defined(OPENSSL_NO_OCSP) */ + str_free(section->chain); + if(section->session) + SSL_SESSION_free(section->session); + if(section->ctx) + SSL_CTX_free(section->ctx); +} + /**************************************** SNI callback */ #ifndef OPENSSL_NO_TLSEXT diff --git a/src/dhparam.c b/src/dhparam.c index 9c99f6f8..3eefbdfa 100644 --- a/src/dhparam.c +++ b/src/dhparam.c @@ -4,28 +4,28 @@ #define DN_new DH_new DH *get_dh2048(void) { static unsigned char dhp_2048[] = { - 0xbd, 0xcc, 0x7f, 0xd9, 0x3c, 0x70, 0x5f, 0x10, 0xe3, 0x4b, 0x15, 0x30, - 0x13, 0x66, 0x3e, 0x1d, 0x64, 0x8d, 0xcd, 0x68, 0x52, 0xe8, 0xfb, 0x8d, - 0x05, 0x5d, 0xd2, 0xe7, 0x37, 0xae, 0xfb, 0x5f, 0x66, 0x11, 0x4a, 0xe4, - 0xe6, 0x98, 0x7f, 0x6f, 0xdc, 0x54, 0xdd, 0xfe, 0x19, 0xc0, 0x4b, 0x75, - 0xbe, 0x69, 0xb2, 0x97, 0xc5, 0x43, 0x1a, 0x5f, 0xd1, 0xd3, 0xfb, 0x28, - 0xb3, 0xba, 0x4b, 0x4c, 0xd5, 0x9f, 0xf4, 0x39, 0x82, 0xd2, 0xa3, 0x02, - 0x95, 0x5d, 0x51, 0x34, 0x27, 0x45, 0xfe, 0x16, 0x55, 0xc9, 0x3b, 0x07, - 0x40, 0xbd, 0x18, 0xe3, 0xab, 0x2e, 0xf0, 0xe3, 0xe9, 0x9e, 0x52, 0x54, - 0x45, 0xb6, 0xd2, 0x1a, 0x70, 0x9d, 0xaa, 0xf9, 0xdb, 0x70, 0x86, 0x0d, - 0x68, 0x00, 0xb3, 0x5a, 0xed, 0xe1, 0x0e, 0x38, 0x52, 0x47, 0xbd, 0xa3, - 0x3f, 0x75, 0xbc, 0x61, 0x09, 0x66, 0x18, 0x42, 0x7c, 0x7d, 0x6d, 0x4b, - 0x6a, 0x39, 0x1b, 0xb5, 0x37, 0x12, 0x31, 0x54, 0x43, 0x70, 0x4b, 0xe6, - 0x83, 0xeb, 0x1b, 0xad, 0xb9, 0x32, 0x06, 0xaf, 0x32, 0x6b, 0xd5, 0x9a, - 0x18, 0xe9, 0x00, 0x04, 0x27, 0x8e, 0x9a, 0x7a, 0xd7, 0xe6, 0x5a, 0xbd, - 0xa4, 0x8c, 0xf5, 0x0d, 0x31, 0xc2, 0x88, 0x4d, 0x9c, 0x02, 0x88, 0xbd, - 0x6f, 0x5a, 0x17, 0x5f, 0x79, 0xbc, 0xd1, 0x93, 0xf4, 0x06, 0xab, 0x14, - 0xa4, 0xc0, 0x9e, 0x68, 0x39, 0x01, 0xcf, 0x21, 0xe2, 0x58, 0x7f, 0x2a, - 0xa5, 0x9e, 0x77, 0x10, 0x12, 0x56, 0x28, 0x9b, 0xa3, 0x53, 0x62, 0xee, - 0xa0, 0x13, 0xed, 0xe8, 0x09, 0xe9, 0xcd, 0x93, 0x0e, 0x36, 0x66, 0x52, - 0x42, 0x26, 0x7c, 0x09, 0x2c, 0x47, 0x33, 0x55, 0x99, 0x62, 0x8f, 0x84, - 0xd4, 0xd9, 0xf7, 0x2c, 0x36, 0x0d, 0x5b, 0x24, 0xe0, 0x9b, 0x05, 0x15, - 0xa2, 0x08, 0x7e, 0xf7 + 0xf0, 0x8d, 0xc9, 0x4c, 0x3c, 0x1a, 0x12, 0x40, 0xcb, 0x37, 0xe9, 0xac, + 0x46, 0x67, 0xbb, 0xf1, 0x6b, 0x8c, 0xb2, 0xff, 0x79, 0xeb, 0xd2, 0x0c, + 0xe7, 0x29, 0x9d, 0xd8, 0x66, 0x57, 0x63, 0x13, 0x38, 0xfd, 0x95, 0xdd, + 0x7e, 0x8a, 0xc3, 0xe2, 0xd1, 0x41, 0x6d, 0x13, 0xae, 0x80, 0x1d, 0x65, + 0xd0, 0xd3, 0x09, 0x66, 0xe7, 0x81, 0x80, 0x52, 0xb6, 0x2a, 0x2e, 0x98, + 0xa8, 0x15, 0xbf, 0x43, 0x2e, 0x4f, 0xf3, 0x10, 0x9e, 0x9c, 0xd9, 0x2d, + 0xfa, 0xfd, 0xcc, 0x29, 0xe0, 0x48, 0x91, 0xe4, 0x6e, 0xc0, 0x18, 0x14, + 0x8a, 0x6b, 0xf0, 0x11, 0xfb, 0x20, 0x4e, 0xc1, 0x01, 0x49, 0xf0, 0x9e, + 0xd7, 0x1c, 0xfd, 0x95, 0xa5, 0x17, 0x70, 0xac, 0x57, 0x75, 0x96, 0xaa, + 0x2e, 0xfa, 0xba, 0x38, 0x52, 0xca, 0x68, 0x43, 0xf4, 0xcc, 0x70, 0xcb, + 0x84, 0x4c, 0xf6, 0xe8, 0x33, 0xfe, 0x4f, 0x09, 0x07, 0x6a, 0x8f, 0xf5, + 0xc4, 0x52, 0x28, 0x18, 0xde, 0xe0, 0x89, 0x3b, 0x15, 0x06, 0xcf, 0x35, + 0x74, 0xb5, 0x28, 0x6c, 0xf6, 0xed, 0x31, 0xf7, 0x06, 0x81, 0xc5, 0xcf, + 0x2a, 0x19, 0x44, 0x3f, 0xcc, 0x80, 0x35, 0xb0, 0xc2, 0xe4, 0x27, 0x2a, + 0x87, 0xee, 0x66, 0xeb, 0xab, 0x3b, 0xe0, 0xaa, 0x1f, 0xb0, 0xe4, 0xb6, + 0xdd, 0x33, 0xfc, 0x31, 0x4d, 0x53, 0xfd, 0xd1, 0xff, 0x1b, 0x25, 0xbf, + 0x4e, 0x94, 0x58, 0xab, 0xa8, 0x56, 0x2a, 0x7a, 0x53, 0x57, 0x13, 0x09, + 0xc5, 0x63, 0x24, 0x88, 0xb0, 0xe0, 0x5c, 0xb3, 0x28, 0xd4, 0x69, 0x02, + 0x91, 0x20, 0x66, 0x8d, 0x5a, 0xb5, 0xb1, 0x86, 0x79, 0xa7, 0x52, 0x92, + 0x89, 0xc0, 0x03, 0x22, 0xe1, 0x7b, 0x4e, 0xac, 0x4a, 0xdc, 0x06, 0xf6, + 0xa6, 0x9f, 0xe3, 0xbf, 0x73, 0x3f, 0x86, 0x8c, 0x8a, 0x5d, 0xc0, 0x5d, + 0x11, 0x55, 0x6c, 0x77 }; static unsigned char dhg_2048[] = { 0x02 @@ -47,4 +47,4 @@ DH *get_dh2048(void) { return dh; } #endif /* OPENSSL_NO_DH */ -/* built for stunnel 5.70 */ +/* built for stunnel 5.71 */ diff --git a/src/evc.mak b/src/evc.mak index 55bfc743..89c99dc6 100644 --- a/src/evc.mak +++ b/src/evc.mak @@ -116,7 +116,7 @@ OBJS=$(OBJ)\stunnel.obj $(OBJ)\ssl.obj $(OBJ)\ctx.obj $(OBJ)\verify.obj \ $(OBJ)\file.obj $(OBJ)\client.obj $(OBJ)\protocol.obj $(OBJ)\sthreads.obj \ $(OBJ)\log.obj $(OBJ)\options.obj $(OBJ)\network.obj $(OBJ)\resolver.obj \ $(OBJ)\str.obj $(OBJ)\tls.obj $(OBJ)\fd.obj $(OBJ)\dhparam.obj \ - $(OBJ)\cron.obj + $(OBJ)\ocsp.obj $(OBJ)\cron.obj GUIOBJS=$(OBJ)\ui_win_gui.obj $(OBJ)\resources.res CLIOBJS=$(OBJ)\ui_win_cli.obj diff --git a/src/mingw.mak b/src/mingw.mak index 59321c35..27c751c9 100644 --- a/src/mingw.mak +++ b/src/mingw.mak @@ -73,13 +73,13 @@ OBJS=$(OBJ)/stunnel.o $(OBJ)/ssl.o $(OBJ)/ctx.o $(OBJ)/verify.o \ $(OBJ)/file.o $(OBJ)/client.o $(OBJ)/protocol.o $(OBJ)/sthreads.o \ $(OBJ)/log.o $(OBJ)/options.o $(OBJ)/network.o $(OBJ)/resolver.o \ $(OBJ)/ui_win_gui.o $(OBJ)/resources.o $(OBJ)/str.o $(OBJ)/tls.o \ - $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/cron.o + $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/ocsp.o $(OBJ)/cron.o TOBJS=$(OBJ)/stunnel.o $(OBJ)/ssl.o $(OBJ)/ctx.o $(OBJ)/verify.o \ $(OBJ)/file.o $(OBJ)/client.o $(OBJ)/protocol.o $(OBJ)/sthreads.o \ $(OBJ)/log.o $(OBJ)/options.o $(OBJ)/network.o $(OBJ)/resolver.o \ $(OBJ)/ui_win_cli.o $(OBJ)/str.o $(OBJ)/tls.o \ - $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/cron.o + $(OBJ)/fd.o $(OBJ)/dhparam.o $(OBJ)/ocsp.o $(OBJ)/cron.o CC=gcc RC=windres diff --git a/src/mingw.mk b/src/mingw.mk index 9005fc34..cf15bee0 100644 --- a/src/mingw.mk +++ b/src/mingw.mk @@ -50,7 +50,7 @@ win32_cli_libs = $(win32_common_libs) $(win32_ssl_libs) common_headers = common.h prototypes.h version.h win32_common = tls str file client log options protocol network resolver -win32_common += ssl ctx verify sthreads fd dhparam cron stunnel +win32_common += ssl ctx verify ocsp sthreads fd dhparam cron stunnel win32_gui = ui_win_gui resources win32_cli = ui_win_cli win32_common_objs = $(addsuffix .o, $(addprefix $(objdir)/, $(win32_common))) diff --git a/src/network.c b/src/network.c index 9d6dfefa..f737f2dc 100644 --- a/src/network.c +++ b/src/network.c @@ -597,7 +597,7 @@ int get_socket_error(const SOCKET fd) { /**************************************** simulate blocking I/O */ -int s_connect(CLI *c, SOCKADDR_UNION *addr, socklen_t addrlen) { +int s_connect(CLI *c, SOCKADDR_UNION *addr, socklen_t addrlen, int timeout) { int error; char *dst; @@ -618,11 +618,11 @@ int s_connect(CLI *c, SOCKADDR_UNION *addr, socklen_t addrlen) { } s_log(LOG_DEBUG, "s_connect: s_poll_wait %s: waiting %d seconds", - dst, c->opt->timeout_connect); + dst, timeout); s_poll_init(c->fds, 0); s_poll_add(c->fds, c->fd, 1, 1); s_poll_dump(c->fds, LOG_DEBUG); - switch(s_poll_wait(c->fds, c->opt->timeout_connect, 0)) { + switch(s_poll_wait(c->fds, timeout, 0)) { case -1: error=get_last_socket_error(); s_log(LOG_ERR, "s_connect: s_poll_wait %s: %s (%d)", diff --git a/src/ocsp.c b/src/ocsp.c new file mode 100644 index 00000000..5073dedf --- /dev/null +++ b/src/ocsp.c @@ -0,0 +1,909 @@ +/* + * stunnel TLS offloading and load-balancing proxy + * Copyright (C) 1998-2023 Michal Trojnara + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Linking stunnel statically or dynamically with other modules is making + * a combined work based on stunnel. Thus, the terms and conditions of + * the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holder of stunnel + * gives you permission to combine stunnel with free software programs or + * libraries that are released under the GNU LGPL and with code included + * in the standard release of OpenSSL under the OpenSSL License (or + * modified versions of such code, with unchanged license). You may copy + * and distribute such a system following the terms of the GNU GPL for + * stunnel and the licenses of the other code concerned. + * + * Note that people who make modified versions of stunnel are not obligated + * to grant this special exception for their modified versions; it is their + * choice whether to do so. The GNU General Public License gives permission + * to release a modified version without this exception; this exception + * also makes it possible to release a modified version which carries + * forward this exception. + */ + +#include "prototypes.h" + +#ifndef OPENSSL_NO_OCSP + +#define INVALID_TIME ((time_t)-1) +#ifdef DEFINE_STACK_OF +/* defined in openssl/safestack.h: + * DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) */ +#else /* DEFINE_STACK_OF */ +#ifndef sk_OPENSSL_STRING_num +#define sk_OPENSSL_STRING_num(st) sk_num(st) +#endif /* sk_OPENSSL_STRING_num */ +#ifndef sk_OPENSSL_STRING_value +#define sk_OPENSSL_STRING_value(st, i) sk_value((st),(i)) +#endif /* sk_OPENSSL_STRING_value */ +#endif /* DEFINE_STACK_OF */ + +typedef struct { + /* OCSP request and validation parameters */ + int depth; + int nonce; + int aia; + long leeway; + unsigned long flags; + char *url; + STACK_OF(X509) *chain_to_verify; + X509 *root_ca; + OCSP_CERTID *cert_id; + + /* OCSP validation results */ + int requested; + int callback_ctx_error; + + /* OCSP single request and result */ + OCSP_REQUEST *request; + OCSP_RESPONSE *response; + ASN1_GENERALIZEDTIME *revoked_at, *this_update, *next_update; +} OCSP_PARAMS; + +/**************************************** OCSP stapling callbacks */ + +NOEXPORT int ocsp_client_cb(SSL *, void *); +#if OPENSSL_VERSION_NUMBER>=0x10002000L +NOEXPORT int ocsp_server_cb(SSL *, void *); +#endif /* OpenSSL version 1.0.2 or later */ + +/**************************************** OCSP utility functions */ + +NOEXPORT void ocsp_params_free(OCSP_PARAMS *); +NOEXPORT void ocsp_params_cleanup(OCSP_PARAMS *); +NOEXPORT int ocsp_verify(CLI *, OCSP_PARAMS *); +NOEXPORT int check_aia(CLI *, OCSP_PARAMS *); +NOEXPORT int ocsp_request(CLI *, OCSP_PARAMS *); +NOEXPORT int ocsp_get_response(CLI *, OCSP_PARAMS *); +NOEXPORT int ocsp_response_validate(CLI *, OCSP_PARAMS *); +NOEXPORT void ocsp_params_setup_cert_id(OCSP_PARAMS *); +NOEXPORT int ocsp_params_append_root_ca(CLI *, OCSP_PARAMS *); +NOEXPORT void log_time(const int, const char *, ASN1_GENERALIZEDTIME *); +#if OPENSSL_VERSION_NUMBER>=0x10101000L +NOEXPORT time_t time_t_get_asn1_time(const ASN1_TIME *); +#endif /* OpenSSL version 1.1.1 or later */ + +/**************************************** OCSP initialization */ + +int ocsp_init(SERVICE_OPTIONS *section) { + section->ocsp_response_lock=CRYPTO_THREAD_lock_new(); + if(section->option.client) { + if(!SSL_CTX_set_tlsext_status_cb(section->ctx, ocsp_client_cb)) { + sslerror("OCSP: SSL_CTX_set_tlsext_status_cb"); + return 1; /* FAILED */ + } + s_log(LOG_DEBUG, "OCSP: Client OCSP stapling enabled"); + } else { +#if OPENSSL_VERSION_NUMBER>=0x10002000L + if(!section->psk_keys) { + if(SSL_CTX_set_tlsext_status_cb(section->ctx, ocsp_server_cb)==TLSEXT_STATUSTYPE_ocsp) + s_log(LOG_DEBUG, "OCSP: Server OCSP stapling enabled"); + } else { + s_log(LOG_NOTICE, "OCSP: Server OCSP stapling is incompatible with PSK"); + } +#else /* OpenSSL version 1.0.2 or later */ + s_log(LOG_NOTICE, "OCSP: Server OCSP stapling not supported"); +#endif /* OpenSSL version 1.0.2 or later */ + } + + return 0; /* OK */ +} + +/* free all of the OCSP_PARAMS values */ +NOEXPORT void ocsp_params_free(OCSP_PARAMS *params) { + ocsp_params_cleanup(params); + if(params->chain_to_verify) { + sk_X509_free(params->chain_to_verify); + params->chain_to_verify=NULL; + } + if(params->root_ca) { + X509_free(params->root_ca); + params->root_ca=NULL; + } + if(params->cert_id) { + OCSP_CERTID_free(params->cert_id); + params->cert_id=NULL; + } +} + +/* free the OCSP_PARAMS values required to reuse it for a next request */ +NOEXPORT void ocsp_params_cleanup(OCSP_PARAMS *params) { + if(params->response) { + OCSP_RESPONSE_free(params->response); + params->response=NULL; + } + if(params->request) { + OCSP_REQUEST_free(params->request); + params->request=NULL; + } + params->revoked_at=NULL; + params->this_update=NULL; + params->next_update=NULL; +} + +/**************************************** OCSP cleanup */ + +void ocsp_cleanup(SERVICE_OPTIONS *section) { + if(section->ocsp_response_len) { + OPENSSL_free(section->ocsp_response_der); + section->ocsp_response_len=0; + } + if(section->ocsp_response_lock) + CRYPTO_THREAD_lock_free(section->ocsp_response_lock); +} + +/**************************************** OCSP verify.c callback */ + +int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) { + OCSP_PARAMS params; + int ret=0; /* failed */ + + /* initial checks */ + if(!c->opt->option.verify_chain) { + s_log(LOG_INFO, "OCSP: Certificate chain verification disabled"); + return 1; /* accept */ + } + if(c->opt->option.client && + !X509_STORE_CTX_get_error_depth(callback_ctx) && + !c->opt->stapling_cb_flag) { + /* for client peer certificate verification, + * tlsext_status_ocsp_resp is needed for oscp_verify_ssl() */ + c->opt->verify_cb_flag=1; + /* ocsp_verify() will be invoked from ocsp_client_cb() */ + s_log(LOG_DEBUG, "OCSP: Waiting for OCSP stapling response"); + return 1; /* accept */ + } + + /* initialize the OCSP_PARAMS structure */ + memset(¶ms, 0, sizeof(OCSP_PARAMS)); + params.depth=X509_STORE_CTX_get_error_depth(callback_ctx); + params.nonce=c->opt->option.nonce; + params.aia=c->opt->option.aia; + params.leeway=60; /* allow for one minute leeway */ + params.flags=c->opt->ocsp_flags; + params.url=c->opt->ocsp_url; + params.callback_ctx_error=X509_V_ERR_APPLICATION_VERIFICATION; + + /* get the client certificate chain */ + params.chain_to_verify=sk_X509_dup(X509_STORE_CTX_get0_chain(callback_ctx)); + if(!params.chain_to_verify) { + s_log(LOG_ERR, "OCSP: sk_X509_dup"); + goto cleanup; + } + ocsp_params_append_root_ca(c, ¶ms); /* ignore failures */ + + ret=ocsp_verify(c, ¶ms); + +cleanup: + if(!ret) + X509_STORE_CTX_set_error(callback_ctx, params.callback_ctx_error); + ocsp_params_free(¶ms); + return ret; +} + +/**************************************** OCSP stapling client callback */ + +/* + * Returns 0 if the response is not acceptable (the handshake will fail) + * or 1 if it is acceptable. + */ +NOEXPORT int ocsp_client_cb(SSL *ssl, void *arg) { + CLI *c; + OCSP_PARAMS params; + int ret=0; /* failed */ + + (void)arg; /* squash the unused parameter warning */ + s_log(LOG_DEBUG, "OCSP stapling: Client callback called"); + + c=SSL_get_ex_data(ssl, index_ssl_cli); + + /* initial checks */ + if(!c->opt->option.verify_chain) { + s_log(LOG_INFO, "OCSP: Certificate chain verification disabled"); + return 1; /* accept */ + } + if(SSL_session_reused(ssl)) { + s_log(LOG_DEBUG, "OCSP: Skipped OCSP stapling (previous session reused)"); + return 1; /* accept: there is nothing we can do at session resumption */ + } + if(!c->opt->option.client) { /* just in case */ + s_log(LOG_DEBUG, "OCSP: Client callback ignored on a server"); + return 1; /* accept */ + } + if(!c->opt->verify_cb_flag) { + /* for client peer certificate verification, + * peer certificates are needed for oscp_verify_ssl() */ + c->opt->stapling_cb_flag=1; + /* ocsp_verify() will be invoked from ocsp_check() */ + s_log(LOG_DEBUG, "OCSP: Waiting for OCSP peer certificates"); + return 1; /* accept */ + } + + /* initialize the OCSP_PARAMS structure */ + memset(¶ms, 0, sizeof(OCSP_PARAMS)); + params.depth=0; /* peer (leaf) certificate */ + params.nonce=c->opt->option.nonce; + params.aia=c->opt->option.aia; + params.leeway=60; /* allow for one minute leeway */ + params.flags=c->opt->ocsp_flags; + params.url=c->opt->ocsp_url; + + /* get the client certificate chain */ + params.chain_to_verify=sk_X509_dup(SSL_get_peer_cert_chain(ssl)); + if(!params.chain_to_verify) { + s_log(LOG_ERR, "OCSP: sk_X509_dup"); + goto cleanup; + } + ocsp_params_append_root_ca(c, ¶ms); /* ignore failures */ + + ret=ocsp_verify(c, ¶ms); + +cleanup: + ocsp_params_free(¶ms); + return ret; +} + +/**************************************** OCSP stapling server callback */ + +#if OPENSSL_VERSION_NUMBER>=0x10002000L +/* + * This is called when a client includes a certificate status request extension. + * The response is either obtained from a cache, or from an OCSP responder. + * Returns one of: + * SSL_TLSEXT_ERR_OK - the OCSP response that has been set should be returned + * SSL_TLSEXT_ERR_NOACK - the OCSP response should not be returned + * SSL_TLSEXT_ERR_ALERT_FATAL - a fatal error has occurred + */ +NOEXPORT int ocsp_server_cb(SSL *ssl, void *arg) { + CLI *c; + OCSP_PARAMS params; + X509 *cert; + STACK_OF(X509) *chain=NULL; + unsigned char *response_der=NULL; + const unsigned char *response_tmp; + int response_len=0, ret=SSL_TLSEXT_ERR_ALERT_FATAL; + int ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; + + (void)arg; /* squash the unused parameter warning */ + s_log(LOG_DEBUG, "OCSP stapling: Server callback called"); + + c=SSL_get_ex_data(ssl, index_ssl_cli); + + /* initialize the OCSP_PARAMS structure */ + memset(¶ms, 0, sizeof(OCSP_PARAMS)); + params.depth=0; /* peer (leaf) certificate */ + params.nonce=0; /* disable nonce */ + params.aia=1; /* enable AIA */ + params.leeway=30; /* allow for 30 second leeway */ + /* OCSP_basic_verify() returns success if the signer certificate + * was found in a set of untrusted intermediate certificates */ + params.flags=OCSP_TRUSTOTHER; + params.url=NULL; /* to be set in check_aia() */ + + /* get the server certificate chain */ + cert=SSL_get_certificate(ssl); + if(!cert) { + s_log(LOG_ERR, "OCSP: SSL_get_certificate"); + goto cleanup; + } + if(!SSL_CTX_get0_chain_certs(c->opt->ctx, &chain)) { + s_log(LOG_ERR, "OCSP: SSL_CTX_get0_chain_certs"); + goto cleanup; + } + if(chain) { + params.chain_to_verify=sk_X509_dup(chain); + if(!params.chain_to_verify) { + s_log(LOG_ERR, "OCSP: sk_X509_dup"); + goto cleanup; + } + } else { + params.chain_to_verify=sk_X509_new_null(); + if(!params.chain_to_verify) { + s_log(LOG_ERR, "OCSP: sk_X509_new_null"); + goto cleanup; + } + } + /* insert the server certificate into the chain */ + if (!sk_X509_unshift(params.chain_to_verify, cert)) { + s_log(LOG_ERR, "OCSP: sk_X509_unshift"); + goto cleanup; + } + ocsp_params_append_root_ca(c, ¶ms); /* ignore failures */ + + /* retrieve the cached response */ + CRYPTO_THREAD_read_lock(c->opt->ocsp_response_lock); + if(c->opt->ocsp_response_len) { + response_len=c->opt->ocsp_response_len; + response_der=OPENSSL_malloc((size_t)response_len); + memcpy(response_der, c->opt->ocsp_response_der, (size_t)response_len); + } + CRYPTO_THREAD_unlock(c->opt->ocsp_response_lock); + + if(response_len) { /* found a cached response */ + /* decode */ + response_tmp=response_der; + params.response=d2i_OCSP_RESPONSE(NULL, &response_tmp, response_len); + + /* validate */ + ocsp_status=ocsp_response_validate(c, ¶ms); + if(ocsp_status!=V_OCSP_CERTSTATUS_UNKNOWN) { + s_log(LOG_DEBUG, "OCSP: Use the cached OCSP response"); + goto success; + } + + /* cleanup */ + ERR_clear_error(); /* silence any cached errors */ + if(response_der) { + OPENSSL_free(response_der); + response_der=NULL; + } + response_len=0; + } + + /* try fetching response from the OCSP responder */ + ocsp_status=check_aia(c, ¶ms); + if(ocsp_status==V_OCSP_CERTSTATUS_UNKNOWN) { /* no useful response */ + s_log(LOG_INFO, "OCSP: No OCSP stapling response to send"); + ret=SSL_TLSEXT_ERR_NOACK; + goto cleanup; + } + + /* encode */ + response_len=i2d_OCSP_RESPONSE(params.response, &response_der); + + if(params.next_update) { + /* cache the newly fetched OCSP response */ + CRYPTO_THREAD_write_lock(c->opt->ocsp_response_lock); + if(c->opt->ocsp_response_len) + OPENSSL_free(c->opt->ocsp_response_der); + c->opt->ocsp_response_len=response_len; + c->opt->ocsp_response_der=OPENSSL_malloc((size_t)response_len); + memcpy(c->opt->ocsp_response_der, response_der, (size_t)response_len); + CRYPTO_THREAD_unlock(c->opt->ocsp_response_lock); + s_log(LOG_DEBUG, "OCSP: Response cached"); + } + +success: + SSL_set_tlsext_status_ocsp_resp(ssl, response_der, response_len); + s_log(LOG_DEBUG, "OCSP stapling: OCSP response sent back"); + ret=SSL_TLSEXT_ERR_OK; + +cleanup: + ocsp_params_free(¶ms); + return ret; +} +#endif /* OpenSSL version 1.0.2 or later */ + +/**************************************** OCSP utility functions */ + +/* + * Issue an OCSP client-driven request and the validate reponse. + * Returns the error code of X509_STORE_CTX. + * Returns 0 if the response is not acceptable (the handshake will fail) + * or 1 if it is acceptable. + */ +NOEXPORT int ocsp_verify(CLI *c, OCSP_PARAMS *params) { + int ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; + + /* ignoring the root certificate */ + if(params->depth==sk_X509_num(params->chain_to_verify)-1) { + s_log(LOG_DEBUG, "OCSP: Ignoring the root certificate"); + return 1; /* accept */ + } + + if(!params->depth) { /* peer (leaf) certificate */ + const unsigned char *resp_der; + long resp_der_len; + + if(c->opt->option.client) { /* no stapling on the server */ + /* process the stapling response if available */ + resp_der_len=SSL_get_tlsext_status_ocsp_resp(c->ssl, &resp_der); + if(resp_der_len>0 && resp_der) { + s_log(LOG_INFO, "OCSP: OCSP stapling response received"); + params->response=d2i_OCSP_RESPONSE(NULL, &resp_der, resp_der_len); + + /* validate */ + ocsp_status=ocsp_response_validate(c, params); + if(ocsp_status!=V_OCSP_CERTSTATUS_UNKNOWN) { + params->requested=1; + goto cleanup; + } + } else { + s_log(LOG_ERR, "OCSP: No OCSP stapling response received"); + } + } + + if(params->url) { /* a responder URL was configured */ + s_log(LOG_NOTICE, "OCSP: Connecting the configured responder \"%s\"", + params->url); + ocsp_status=ocsp_request(c, params); + if(ocsp_status!=V_OCSP_CERTSTATUS_UNKNOWN) + goto cleanup; + } + } + + /* client-driven checks (configured url, aia) */ + ocsp_status=check_aia(c, params); + +cleanup: + if(!params->requested) /* neither url or aia verification was needed */ + return 1; /* accept */ + switch(ocsp_status) { + case V_OCSP_CERTSTATUS_GOOD: + s_log(LOG_NOTICE, "OCSP: Accepted (good)"); + return 1; /* accept */ + case V_OCSP_CERTSTATUS_REVOKED: + s_log(LOG_ERR, "OCSP: Rejected (revoked)"); + return 0; /* reject */ + default: /* V_OCSP_CERTSTATUS_UNKNOWN */ + if(c->opt->option.ocsp_require) { + s_log(LOG_ERR, "OCSP: Rejected (OCSPrequire = yes)"); + return 0; /* reject */ + } else { + s_log(LOG_NOTICE, "OCSP: Accepted (OCSPrequire = no)"); + return 1; /* accept */ + } + } +} + +/* + * OCSP AIA checks + * Returns one of: + * - V_OCSP_CERTSTATUS_GOOD + * - V_OCSP_CERTSTATUS_REVOKED + * - V_OCSP_CERTSTATUS_UNKNOWN + */ +NOEXPORT int check_aia(CLI *c, OCSP_PARAMS *params) { + int ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; + STACK_OF(OPENSSL_STRING) *aia; + int i, num; + + if(!params->aia) + goto cleanup; + aia=X509_get1_ocsp(sk_X509_value(params->chain_to_verify, params->depth)); + if(!aia) { + s_log(LOG_INFO, "OCSP: No AIA responder URL"); + goto cleanup; + } + num=sk_OPENSSL_STRING_num(aia); + if(!num) { + s_log(LOG_INFO, "OCSP: Empty AIA responder URL list"); + goto cleanup; + } + for(i=0; iurl=sk_OPENSSL_STRING_value(aia, i); + s_log(LOG_NOTICE, "OCSP: Connecting the AIA responder \"%s\"", params->url); + ocsp_status=ocsp_request(c, params); + if(ocsp_status!=V_OCSP_CERTSTATUS_UNKNOWN) + break; /* we received a definitive response */ + } + X509_email_free(aia); + +cleanup: + return ocsp_status; +} + +/* + * OCSP request handling. + * Returns one of: + * - V_OCSP_CERTSTATUS_GOOD + * - V_OCSP_CERTSTATUS_REVOKED + * - V_OCSP_CERTSTATUS_UNKNOWN + */ +NOEXPORT int ocsp_request(CLI *c, OCSP_PARAMS *params) { + int ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; + + /* prepare params for reuse */ + ocsp_params_cleanup(params); + + /* build request */ + params->requested=1; + params->request=OCSP_REQUEST_new(); + if(!params->request) { + sslerror("OCSP: OCSP_REQUEST_new"); + goto cleanup; + } + ocsp_params_setup_cert_id(params); + if(!params->cert_id) + goto cleanup; + if(!OCSP_request_add0_id(params->request, + OCSP_CERTID_dup(params->cert_id))) { + sslerror("OCSP: OCSP_request_add0_id"); + goto cleanup; + } + if(params->nonce) { + OCSP_request_add1_nonce(params->request, NULL, -1); + } + + /* send the request and get a response */ + if(!ocsp_get_response(c, params)) { + goto cleanup; + } + + /* validate */ + ocsp_status=ocsp_response_validate(c, params); + if(ocsp_status==V_OCSP_CERTSTATUS_REVOKED) + params->callback_ctx_error=X509_V_ERR_CERT_REVOKED; + +cleanup: + return ocsp_status; +} + +/* + * Sends the OCSP request to the specified URL and retrieves the OCSP response. + * Returns 0 on error or 1 if response received. + */ +NOEXPORT int ocsp_get_response(CLI *c, OCSP_PARAMS *params) { + BIO *bio=NULL; + OCSP_REQ_CTX *req_ctx=NULL; + char *host=NULL, *port=NULL, *path=NULL; + SOCKADDR_UNION addr; + int ssl, ret=0; + + /* parse the OCSP URL */ + if(!OCSP_parse_url(params->url, &host, &port, &path, &ssl)) { + s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL"); + goto cleanup; + } + if(ssl) { + s_log(LOG_ERR, "OCSP: TLS not supported for OCSP" + " - an additional stunnel service needs to be defined"); + goto cleanup; + } + if(!hostport2addr(&addr, host, port, 0)) { + s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP responder address"); + goto cleanup; + } + + /* connect specified OCSP responder */ + c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket"); + if(c->fd==INVALID_SOCKET) + goto cleanup; + if(s_connect(c, &addr, addr_len(&addr), c->opt->timeout_ocsp)) + goto cleanup; + bio=BIO_new_socket((int)c->fd, BIO_NOCLOSE); + if(!bio) { + sslerror("OCSP: BIO_new_socket"); + goto cleanup; + } + s_log(LOG_DEBUG, "OCSP: Connected %s:%s", host, port); + + /* initialize an HTTP request with the POST method */ +#if OPENSSL_VERSION_NUMBER>=0x10000000L + req_ctx=OCSP_sendreq_new(bio, path, NULL, -1); +#else /* OpenSSL version >= 1.0.0 */ + /* there is no way to send the Host header with older OpenSSL versions */ + req_ctx=OCSP_sendreq_new(bio, path, params->request, -1); +#endif /* OpenSSL version 1.0.0 or later */ + if(!req_ctx) { + sslerror("OCSP: OCSP_sendreq_new"); + goto cleanup; + } +#if OPENSSL_VERSION_NUMBER>=0x10000000L + /* add the HTTP headers */ + if(!OCSP_REQ_CTX_add1_header(req_ctx, "Host", host)) { + sslerror("OCSP: OCSP_REQ_CTX_add1_header"); + goto cleanup; + } + if(!OCSP_REQ_CTX_add1_header(req_ctx, "User-Agent", "stunnel")) { + sslerror("OCSP: OCSP_REQ_CTX_add1_header"); + goto cleanup; + } + /* add the remaining HTTP headers and the OCSP request body */ + if(!OCSP_REQ_CTX_set1_req(req_ctx, params->request)) { + sslerror("OCSP: OCSP_REQ_CTX_set1_req"); + goto cleanup; + } +#endif /* OpenSSL version 1.0.0 or later */ + + /* OCSP protocol communication loop */ + while(OCSP_sendreq_nbio(¶ms->response, req_ctx)==-1) { + s_poll_init(c->fds, 0); + s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio)); + switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { + case -1: + sockerror("OCSP: s_poll_wait"); + goto cleanup; + case 0: + s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded"); + goto cleanup; + } + } +#if 0 + s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); +#endif + /* http://www.mail-archive.com/openssl-users@openssl.org/msg61691.html */ + if(params->response) { + s_log(LOG_DEBUG, "OCSP: Response received"); + ret=1; + } else { + if(ERR_peek_error()) + sslerror("OCSP: OCSP_sendreq_nbio"); + else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */ + s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error"); + } + +cleanup: + if(req_ctx) + OCSP_REQ_CTX_free(req_ctx); + if(bio) + BIO_free_all(bio); + if(c->fd!=INVALID_SOCKET) { + closesocket(c->fd); + c->fd=INVALID_SOCKET; /* avoid double close on cleanup */ + } + if(host) + OPENSSL_free(host); + if(port) + OPENSSL_free(port); + if(path) + OPENSSL_free(path); + return ret; +} + +/* + * Validates the cached or fetched OCSP response. + * Returns one of: + * - V_OCSP_CERTSTATUS_GOOD + * - V_OCSP_CERTSTATUS_REVOKED + * - V_OCSP_CERTSTATUS_UNKNOWN + */ +NOEXPORT int ocsp_response_validate(CLI *c, OCSP_PARAMS *params) { + int response_status, reason; + OCSP_BASICRESP *basic_response=NULL; + int ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; + + s_log(LOG_DEBUG, "OCSP: Validate the OCSP response"); + if(!params->response) { + s_log(LOG_ERR, "OCSP: No OCSP response"); + goto cleanup; + } + response_status=OCSP_response_status(params->response); + if(response_status!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { + s_log(LOG_ERR, "OCSP: OCSP responder error: %d: %s", + response_status, OCSP_response_status_str(response_status)); + goto cleanup; + } + basic_response=OCSP_response_get1_basic(params->response); + if(!basic_response) { + s_log(LOG_WARNING, "OCSP: OCSP_response_get1_basic"); + goto cleanup; + } + if(params->request && params->nonce && + OCSP_check_nonce(params->request, basic_response)<=0) { + s_log(LOG_ERR, "OCSP: Invalid or unsupported nonce"); + goto cleanup; + } + if(OCSP_basic_verify(basic_response, params->chain_to_verify, + SSL_CTX_get_cert_store(c->opt->ctx), params->flags)<=0) { + sslerror("OCSP: OCSP_basic_verify"); + goto cleanup; + } + ocsp_params_setup_cert_id(params); + if(!params->cert_id) + goto cleanup; + if(!OCSP_resp_find_status(basic_response, params->cert_id, &ocsp_status, &reason, + ¶ms->revoked_at, ¶ms->this_update, ¶ms->next_update)) { + s_log(LOG_WARNING, "OCSP: OCSP_resp_find_status"); + goto cleanup; + } + s_log(LOG_INFO, "OCSP: Status: %s", OCSP_cert_status_str(ocsp_status)); + log_time(LOG_INFO, "OCSP: This update", params->this_update); + if(params->next_update) + log_time(LOG_INFO, "OCSP: Next update", params->next_update); + if(!OCSP_check_validity(params->this_update, params->next_update, params->leeway, -1)) { + sslerror("OCSP: OCSP_check_validity"); + ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; /* override an invalid response */ + } + switch(ocsp_status) { + case V_OCSP_CERTSTATUS_GOOD: + s_log(LOG_NOTICE, "OCSP: Certificate accepted"); + break; + case V_OCSP_CERTSTATUS_REVOKED: + if(reason==-1) + s_log(LOG_ERR, "OCSP: Certificate revoked"); + else + s_log(LOG_ERR, "OCSP: Certificate revoked: %d: %s", + reason, OCSP_crl_reason_str(reason)); + log_time(LOG_NOTICE, "OCSP: Revoked at", params->revoked_at); + break; + case V_OCSP_CERTSTATUS_UNKNOWN: + s_log(LOG_WARNING, "OCSP: Unknown verification status"); + } + +cleanup: + if(basic_response) + OCSP_BASICRESP_free(basic_response); + return ocsp_status; +} + +/* + * Create an OCSP_CERTID object from params->chain_to_verify at params->depth. + */ +NOEXPORT void ocsp_params_setup_cert_id(OCSP_PARAMS *params) { + X509 *subject, *issuer=NULL; + int chain_len; + + if(params->cert_id) /* already set */ + return; /* nothing to do */ + chain_len=sk_X509_num(params->chain_to_verify); + if(params->depth<0 || params->depth>chain_len-1) { /* sanity check */ + s_log(LOG_ERR, "OCSP: INTERNAL ERROR: Invalid verification depth"); + return; + } + subject=sk_X509_value(params->chain_to_verify, params->depth); + issuer=params->depth==chain_len-1 ? subject /* root CA certificate */ : + sk_X509_value(params->chain_to_verify, params->depth+1); + /* if dgst is NULL then SHA1 is used */ + params->cert_id=OCSP_cert_to_id(NULL, subject, issuer); + if(!params->cert_id) + s_log(LOG_ERR, "OCSP: Can't create an OCSP_CERTID object"); +} + +#if OPENSSL_VERSION_NUMBER<0x10100000L +#define X509_OBJECT_new() str_alloc(sizeof(X509_OBJECT)) +#define X509_OBJECT_free(x) X509_OBJECT_free_contents(x); str_free(x) +#define X509_OBJECT_get0_X509(x) ((x)->data.x509) +#endif /* OpenSSL older than 1.1.0 */ + +NOEXPORT int ocsp_params_append_root_ca(CLI *c, OCSP_PARAMS *params) { + int chain_len; + X509 *cert; + X509_STORE_CTX *store_ctx=NULL; + X509_OBJECT *obj=NULL; + int ret=0; /* failure */ + + chain_len=sk_X509_num(params->chain_to_verify); + if(!chain_len) { /* empty chain */ + s_log(LOG_ERR, "OCSP: Empty verification chain"); + goto cleanup; + } + cert=sk_X509_value(params->chain_to_verify, chain_len-1); + store_ctx=X509_STORE_CTX_new(); + if(!store_ctx) { + s_log(LOG_ERR, "OCSP: X509_STORE_CTX_new"); + goto cleanup; + } + if(!X509_STORE_CTX_init(store_ctx, + SSL_CTX_get_cert_store(c->opt->ctx), NULL, NULL)) { + s_log(LOG_ERR, "OCSP: X509_STORE_CTX_init"); + goto cleanup; + } + obj=X509_OBJECT_new(); + if(X509_STORE_get_by_subject(store_ctx, + X509_LU_X509, X509_get_subject_name(cert), obj)>0) { + goto success; /* the certificate is already trusted */ + } + if(X509_STORE_get_by_subject(store_ctx, + X509_LU_X509, X509_get_issuer_name(cert), obj)<=0) { + s_log(LOG_INFO, "OCSP: The root CA certificate was not found"); + goto cleanup; + } + /* append the root CA certificate into the verified chain */ + params->root_ca=X509_dup(X509_OBJECT_get0_X509(obj)); + if(!params->root_ca) { + s_log(LOG_ERR, "OCSP: X509_dup"); + goto cleanup; + } + if(!sk_X509_push(params->chain_to_verify, params->root_ca)) { + s_log(LOG_ERR, "OCSP: sk_X509_push"); + goto cleanup; + } + +success: + ret=1; /* success: a trusted root CA certificate appended to the chain */ + +cleanup: + if(obj) + X509_OBJECT_free(obj); + if(store_ctx) + X509_STORE_CTX_free(store_ctx); + return ret; +} + +/* Logs the time structure in a human-readable format */ +NOEXPORT void log_time(const int level, const char *txt, ASN1_GENERALIZEDTIME *t) { + char *cp; + BIO *bio; + int n; +#if OPENSSL_VERSION_NUMBER>=0x10101000L + time_t posix_time; + struct tm *timeptr; +#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) + struct tm timestruct; +#endif /* defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) */ +#endif /* OpenSSL version 1.1.1 or later */ + + if(!t) + return; + bio=BIO_new(BIO_s_mem()); + if(!bio) + return; +#if OPENSSL_VERSION_NUMBER>=0x10101000L + posix_time = time_t_get_asn1_time(t); + if(posix_time==INVALID_TIME) { + BIO_free(bio); + return; + } +#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) + timeptr=localtime_r(&posix_time, ×truct); +#else /* defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) */ + timeptr=localtime(&posix_time); +#endif /* defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) */ + BIO_printf(bio, "%04d.%02d.%02d %02d:%02d:%02d", + timeptr->tm_year + 1900, timeptr->tm_mon + 1, timeptr->tm_mday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); +#else /* OpenSSL version 1.1.1 or later */ + ASN1_TIME_print(bio, t); +#endif /* OpenSSL version 1.1.1 or later */ + + n=BIO_pending(bio); + cp=str_alloc((size_t)n+1); + n=BIO_read(bio, cp, n); + if(n<0) { + BIO_free(bio); + str_free(cp); + return; + } + cp[n]='\0'; + BIO_free(bio); + s_log(level, "%s: %s", txt, cp); + str_free(cp); +} + +#if OPENSSL_VERSION_NUMBER>=0x10101000L +/* Converts ASN1_TIME structure to time_t */ +NOEXPORT time_t time_t_get_asn1_time(const ASN1_TIME *s) { + struct tm tm; + + if ((!s) || (!ASN1_TIME_check(s))) { + return INVALID_TIME; + } + /* The ASN1_TIME_to_tm() function was added in OpenSSL 1.1.1 */ + if (ASN1_TIME_to_tm(s, &tm)) { +#ifdef _WIN32 + return _mkgmtime(&tm); +#else /* defined _WIN32 */ + return timegm(&tm); +#endif /* defined _WIN32 */ + } else { + return INVALID_TIME; + } +} +#endif /* OpenSSL version 1.1.0 or later */ + +#endif /* !defined(OPENSSL_NO_OCSP) */ diff --git a/src/options.c b/src/options.c index b4bf34c6..1a88139e 100644 --- a/src/options.c +++ b/src/options.c @@ -39,8 +39,14 @@ #if OPENSSL_VERSION_NUMBER >= 0x10101000L #define DEFAULT_CURVES "X25519:P-256:X448:P-521:P-384" +#ifdef SSL_SYSTEM_DEFAULT_CIPHER_LIST /* Red Hat OpenSSL */ +#define DEFAULT_CURVES_FIPS "P-256:P-521:P-384" +#else /* standard OpenSSL */ +#define DEFAULT_CURVES_FIPS DEFAULT_CURVES +#endif /* Red Hat OpenSSL */ #else /* OpenSSL version < 1.1.1 */ #define DEFAULT_CURVES "prime256v1" +#define DEFAULT_CURVES_FIPS DEFAULT_CURVES #endif /* OpenSSL version >= 1.1.1 */ #if defined(_WIN32_WCE) && !defined(CONFDIR) @@ -696,8 +702,9 @@ void service_free(SERVICE_OPTIONS *section) { #endif if(ref<0) fatal("Negative section reference counter"); - if(ref==0) + if(ref==0) { parse_service_option(CMD_FREE, §ion, NULL, NULL); + } } /**************************************** global options */ @@ -1929,7 +1936,7 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr /* curves */ switch(cmd) { case CMD_SET_DEFAULTS: - section->curves=str_dup_detached(DEFAULT_CURVES); + section->curves = NULL; break; case CMD_SET_COPY: section->curves=str_dup_detached(new_service_options.curves); @@ -1944,9 +1951,26 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr section->curves=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: + if(!section->curves) { + /* this is only executed for global options, because + * section->curves is no longer NULL in sections */ +#ifdef USE_FIPS + if(new_global_options.option.fips) + section->curves=str_dup_detached(DEFAULT_CURVES_FIPS); + else +#endif /* USE_FIPS */ + section->curves=str_dup_detached(DEFAULT_CURVES); + } break; case CMD_PRINT_DEFAULTS: - s_log(LOG_NOTICE, "%-22s = %s", "curves", DEFAULT_CURVES); + if(fips_available()) { + s_log(LOG_NOTICE, "%-22s = %s %s", "curves", + DEFAULT_CURVES_FIPS, "(with \"fips = yes\")"); + s_log(LOG_NOTICE, "%-22s = %s %s", "curves", + DEFAULT_CURVES, "(with \"fips = no\")"); + } else { + s_log(LOG_NOTICE, "%-22s = %s", "curves", DEFAULT_CURVES); + } break; case CMD_PRINT_HELP: s_log(LOG_NOTICE, "%-22s = ECDH curve names", "curves"); @@ -2387,6 +2411,9 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr section->ocsp_url=str_dup_detached(arg); return NULL; /* OK */ case CMD_INITIALIZE: + if((section->ocsp_url || section->option.aia) && + !section->option.verify_chain) + return "\"verifyChain\" has to be enabled for OCSP support"; break; case CMD_PRINT_DEFAULTS: break; @@ -2486,6 +2513,37 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr break; } + /* OCSPrequire */ + switch(cmd) { + case CMD_SET_DEFAULTS: + section->option.ocsp_require=1; /* enabled by default */ + break; + case CMD_SET_COPY: + section->option.ocsp_require=new_service_options.option.ocsp_require; + break; + case CMD_FREE: + break; + case CMD_SET_VALUE: + if(strcasecmp(opt, "OCSPrequire")) + break; + if(!strcasecmp(arg, "yes")) + section->option.ocsp_require=1; + else if(!strcasecmp(arg, "no")) + section->option.ocsp_require=0; + else + return "The argument needs to be either 'yes' or 'no'"; + return NULL; /* OK */ + case CMD_INITIALIZE: + break; + case CMD_PRINT_DEFAULTS: + break; + case CMD_PRINT_HELP: + s_log(LOG_NOTICE, + "%-22s = yes|no require a conclusive OCSP response", + "OCSPrequire"); + break; + } + #endif /* !defined(OPENSSL_NO_OCSP) */ /* options */ @@ -3718,6 +3776,36 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr break; } + /* TIMEOUTocsp */ + switch(cmd) { + case CMD_SET_DEFAULTS: + section->timeout_ocsp=5; /* 5 seconds */ + break; + case CMD_SET_COPY: + section->timeout_ocsp=new_service_options.timeout_ocsp; + break; + case CMD_FREE: + break; + case CMD_SET_VALUE: + if(strcasecmp(opt, "TIMEOUTocsp")) + break; + { + char *tmp_str; + section->timeout_ocsp=(int)strtol(arg, &tmp_str, 5); + if(tmp_str==arg || *tmp_str) /* not a number */ + return "Illegal OCSP connect timeout"; + } + return NULL; /* OK */ + case CMD_INITIALIZE: + break; + case CMD_PRINT_DEFAULTS: + s_log(LOG_NOTICE, "%-22s = %d seconds", "TIMEOUTocsp", 5); + break; + case CMD_PRINT_HELP: + s_log(LOG_NOTICE, "%-22s = seconds to connect OCSP responder", "TIMEOUTocsp"); + break; + } + /* transparent */ #ifndef USE_WIN32 switch(cmd) { @@ -3880,11 +3968,7 @@ NOEXPORT const char *parse_service_option(CMD cmd, SERVICE_OPTIONS **section_ptr case CMD_SET_COPY: break; case CMD_FREE: - str_free(section->chain); - if(section->session) - SSL_SESSION_free(section->session); - if(section->ctx) - SSL_CTX_free(section->ctx); + context_cleanup(section); str_free(section->servname); if(section==&service_options || section==&new_service_options) memset(section, 0, sizeof(SERVICE_OPTIONS)); diff --git a/src/os2.mak b/src/os2.mak index 5e2b0c68..76a99e39 100644 --- a/src/os2.mak +++ b/src/os2.mak @@ -1,11 +1,11 @@ prefix=. DEFS = -DPACKAGE_NAME=\"stunnel\" \ -DPACKAGE_TARNAME=\"stunnel\" \ - -DPACKAGE_VERSION=\"5.70\" \ - -DPACKAGE_STRING=\"stunnel\ 5.70\" \ + -DPACKAGE_VERSION=\"5.71\" \ + -DPACKAGE_STRING=\"stunnel\ 5.71\" \ -DPACKAGE_BUGREPORT=\"\" \ -DPACKAGE=\"stunnel\" \ - -DVERSION=\"5.70\" \ + -DVERSION=\"5.71\" \ -DSTDC_HEADERS=1 \ -DHAVE_SYS_TYPES_H=1 \ -DHAVE_SYS_STAT_H=1 \ @@ -41,7 +41,7 @@ OPENSSLDIR = u:/extras #SYSLOGDIR = /unixos2/workdir/syslog INCLUDES = -I$(OPENSSLDIR)/outinc LIBS = -lsocket -L$(OPENSSLDIR)/out -lssl -lcrypto -lz -lsyslog -OBJS = file.o client.o log.o options.o protocol.o network.o ssl.o ctx.o verify.o sthreads.o stunnel.o pty.o resolver.o str.o tls.o fd.o dhparam.o cron.o +OBJS = file.o client.o log.o options.o protocol.o network.o ssl.o ctx.o verify.o ocsp.o sthreads.o stunnel.o pty.o resolver.o str.o tls.o fd.o dhparam.o cron.o LIBDIR = . CFLAGS = -O2 -Wall -Wshadow -Wcast-align -Wpointer-arith @@ -64,6 +64,7 @@ pty.o: pty.c common.h prototypes.h ssl.o: ssl.c common.h prototypes.h ctx.o: ctx.c common.h prototypes.h verify.o: verify.c common.h prototypes.h +ocsp.o: ocsp.c common.h prototypes.h sthreads.o: sthreads.c common.h prototypes.h stunnel.o: stunnel.c common.h prototypes.h resolver.o: resolver.c common.h prototypes.h diff --git a/src/os2.mak.in b/src/os2.mak.in new file mode 100644 index 00000000..3eceb73c --- /dev/null +++ b/src/os2.mak.in @@ -0,0 +1,78 @@ +prefix=. +DEFS = -DPACKAGE_NAME=\"stunnel\" \ + -DPACKAGE_TARNAME=\"stunnel\" \ + -DPACKAGE_VERSION=\"@PACKAGE_VERSION@\" \ + -DPACKAGE_STRING=\"stunnel\ @PACKAGE_VERSION@\" \ + -DPACKAGE_BUGREPORT=\"\" \ + -DPACKAGE=\"stunnel\" \ + -DVERSION=\"@PACKAGE_VERSION@\" \ + -DSTDC_HEADERS=1 \ + -DHAVE_SYS_TYPES_H=1 \ + -DHAVE_SYS_STAT_H=1 \ + -DHAVE_STDLIB_H=1 \ + -DHAVE_STRING_H=1 \ + -DHAVE_MEMORY_H=1 \ + -DHAVE_STRINGS_H=1 \ + -DHAVE_UNISTD_H=1 \ + -DSSLDIR=\"/usr\" \ + -DHOST=\"i386-pc-os2-emx\" \ + -DHAVE_LIBSOCKET=1 \ + -DHAVE_GRP_H=1 \ + -DHAVE_UNISTD_H=1 \ + -DHAVE_SYS_SELECT_H=1 \ + -DHAVE_SYS_IOCTL_H=1 \ + -DHAVE_SYS_RESOURCE_H=1 \ + -DHAVE_SNPRINTF=1 \ + -DHAVE_VSNPRINTF=1 \ + -DHAVE_WAITPID=1 \ + -DHAVE_SYSCONF=1 \ + -DHAVE_ENDHOSTENT=1 \ + -DUSE_OS2=1 \ + -DSIZEOF_UNSIGNED_CHAR=1 \ + -DSIZEOF_UNSIGNED_SHORT=2 \ + -DSIZEOF_UNSIGNED_INT=4 \ + -DSIZEOF_UNSIGNED_LONG=4 \ + -DLIBDIR=\"$(prefix)/lib\" \ + -DCONFDIR=\"$(prefix)/etc\" + +CC = gcc +.SUFFIXES = .c .o +OPENSSLDIR = u:/extras +#SYSLOGDIR = /unixos2/workdir/syslog +INCLUDES = -I$(OPENSSLDIR)/outinc +LIBS = -lsocket -L$(OPENSSLDIR)/out -lssl -lcrypto -lz -lsyslog +OBJS = file.o client.o log.o options.o protocol.o network.o ssl.o ctx.o verify.o ocsp.o sthreads.o stunnel.o pty.o resolver.o str.o tls.o fd.o dhparam.o cron.o +LIBDIR = . +CFLAGS = -O2 -Wall -Wshadow -Wcast-align -Wpointer-arith + +all: stunnel.exe + +stunnel.exe: $(OBJS) + $(CC) -Zmap $(CFLAGS) -o $@ $(OBJS) $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ -c $< + +client.o: client.c common.h prototypes.h +#env.o: env.c common.h prototypes.h +#gui.o: gui.c common.h prototypes.h +file.o: file.c common.h prototypes.h +network.o: network.c common.h prototypes.h +options.o: options.c common.h prototypes.h +protocol.o: protocol.c common.h prototypes.h +pty.o: pty.c common.h prototypes.h +ssl.o: ssl.c common.h prototypes.h +ctx.o: ctx.c common.h prototypes.h +verify.o: verify.c common.h prototypes.h +ocsp.o: ocsp.c common.h prototypes.h +sthreads.o: sthreads.c common.h prototypes.h +stunnel.o: stunnel.c common.h prototypes.h +resolver.o: resolver.c common.h prototypes.h +str.o: str.c common.h prototypes.h +tls.o: tls.c common.h prototypes.h +fd.o: fd.c common.h prototypes.h +dhparam.o: dhparam.c common.h prototypes.h +cron.o: cron.c common.h prototypes.h + +clean: + rm -f *.o *.exe diff --git a/src/protocol.c b/src/protocol.c index f73951bc..d85a8cb7 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -154,8 +154,9 @@ const char *protocol_init(SERVICE_OPTIONS *opt) { {.name=NULL} }, *p; - /* the default value to be overridden in protocol initialization */ + /* the default values to be overridden in protocol initialization */ opt->option.connect_before_ssl=opt->option.client; + opt->option.protocol_endpoint=0; if(!opt->protocol) { /* no protocol specified */ opt->protocol_early=NULL; @@ -1779,7 +1780,7 @@ NOEXPORT int ldap_auth(CLI *c, const char *dn, const char *pass) { if(c->fd==INVALID_SOCKET) return 1; /* FAILED */ s_log(LOG_DEBUG, "LDAP: Connecting the server"); - if(s_connect(c, &addr, addr_len(&addr))) { + if(s_connect(c, &addr, addr_len(&addr), c->opt->timeout_connect)) { closesocket(c->fd); c->fd=INVALID_SOCKET; /* avoid double close on cleanup */ return 1; /* FAILED */ diff --git a/src/prototypes.h b/src/prototypes.h index a32a38a7..40bbc859 100644 --- a/src/prototypes.h +++ b/src/prototypes.h @@ -72,6 +72,55 @@ typedef struct servername_list_struct SERVERNAME_LIST; typedef HANDLE THREAD_ID; #endif +#if OPENSSL_VERSION_NUMBER<0x10100004L + +#ifdef USE_OS_THREADS + +struct CRYPTO_dynlock_value { +#ifdef USE_PTHREAD + pthread_rwlock_t rwlock; +#endif +#ifdef USE_WIN32 + CRITICAL_SECTION critical_section; +#endif +#ifdef DEBUG_LOCKS + const char *init_file, *read_lock_file, *write_lock_file, + *unlock_file, *destroy_file; + int init_line, read_lock_line, write_lock_line, unlock_line, destroy_line; +#endif +}; + +typedef struct CRYPTO_dynlock_value CRYPTO_RWLOCK; + +#else /* USE_OS_THREADS */ + +typedef void CRYPTO_RWLOCK; + +#endif /* USE_OS_THREADS */ + +#endif /* OPENSSL_VERSION_NUMBER<0x10100004L */ + +typedef enum { + LOCK_THREAD_LIST, /* sthreads.c */ + LOCK_SESSION, LOCK_ADDR, + LOCK_CLIENTS, LOCK_SSL, /* client.c */ + LOCK_REF, /* options.c */ + LOCK_INET, /* resolver.c */ +#ifndef USE_WIN32 + LOCK_LIBWRAP, /* libwrap.c */ +#endif + LOCK_LOG_BUFFER, LOCK_LOG_MODE, /* log.c */ + LOCK_LEAK_HASH, LOCK_LEAK_RESULTS, /* str.c */ +#ifndef OPENSSL_NO_DH + LOCK_DH, /* ctx.c */ +#endif /* OPENSSL_NO_DH */ +#ifdef USE_WIN32 + LOCK_WIN_LOG, /* ui_win_gui.c */ +#endif + LOCK_SECTIONS, /* traversing section list */ + STUNNEL_LOCKS /* number of locks */ +} LOCK_TYPE; + #if defined (USE_WIN32) #define ICON_IMAGE HICON #elif defined(__APPLE__) @@ -130,6 +179,7 @@ typedef struct sockaddr_list { /* list of addresses */ NAME_LIST *names; /* a list of unresolved names */ } SOCKADDR_LIST; +extern GLOBAL_OPTIONS global_options; #ifndef OPENSSL_NO_COMP typedef enum { COMP_NONE, /* empty compression algorithms set */ @@ -184,8 +234,6 @@ struct global_options_struct { } option; }; -extern GLOBAL_OPTIONS global_options; - #ifndef OPENSSL_NO_PSK typedef struct psk_keys_struct { const char *identity; /* the OpenSSL API requires const */ @@ -242,6 +290,11 @@ struct service_options_struct { #ifndef OPENSSL_NO_OCSP char *ocsp_url; unsigned long ocsp_flags; + CRYPTO_RWLOCK *ocsp_response_lock; /* protect the OCSP response cache */ + unsigned char *ocsp_response_der; /* OCSP response data */ + int ocsp_response_len; /* OCSP response length */ + unsigned stapling_cb_flag:1; /* OCSP stapling callback executed */ + unsigned verify_cb_flag:1; /* verify callback executed at depth 0 */ #endif /* !defined(OPENSSL_NO_OCSP) */ #if OPENSSL_VERSION_NUMBER>=0x10002000L NAME_LIST *check_host, *check_email, *check_ip; /* cert subject checks */ @@ -303,8 +356,9 @@ struct service_options_struct { SSL_SESSION *session; /* previous client session for delayed resolver */ int timeout_busy; /* maximum waiting for data time */ int timeout_close; /* maximum close_notify time */ - int timeout_connect; /* maximum connect() time */ + int timeout_connect; /* maximum s_connect() time */ int timeout_idle; /* maximum idle connection time */ + int timeout_ocsp; /* maximum s_connect() time for OCSP */ enum {FAILOVER_RR, FAILOVER_PRIO} failover; /* failover strategy */ unsigned rr; /* per-service sequential number for round-robin failover */ char *username; /* ident client username */ @@ -356,6 +410,7 @@ struct service_options_struct { #ifndef OPENSSL_NO_OCSP unsigned aia:1; /* Authority Information Access */ unsigned nonce:1; /* send and verify OCSP nonce */ + unsigned ocsp_require:1; /* require a conclusive OCSP response */ #endif /* !defined(OPENSSL_NO_OCSP) */ #ifndef OPENSSL_NO_DH unsigned dh_temp_params:1; @@ -585,6 +640,7 @@ extern int dh_temp_params; #endif /* OPENSSL_NO_DH */ int context_init(SERVICE_OPTIONS *); +void context_cleanup(SERVICE_OPTIONS *); #ifndef OPENSSL_NO_PSK void psk_sort(PSK_TABLE *, PSK_KEYS *); PSK_KEYS *psk_find(const PSK_TABLE *, const char *); @@ -604,6 +660,14 @@ X509 *engine_get_cert(ENGINE *, const char *); void print_CA_list(const char *, const STACK_OF(X509_NAME) *); char *X509_NAME2text(X509_NAME *); +/**************************************** prototypes for ocsp.c */ + +#ifndef OPENSSL_NO_OCSP +int ocsp_check(CLI *, X509_STORE_CTX *); /* OCSP client-driven checking */ +int ocsp_init(SERVICE_OPTIONS *); /* OCSP stapling initialization */ +void ocsp_cleanup(SERVICE_OPTIONS *); +#endif /* !defined(OPENSSL_NO_OCSP) */ + /**************************************** prototypes for network.c */ s_poll_set *s_poll_alloc(void); @@ -653,7 +717,7 @@ void throw_exception(CLI *, int) NORETURN; /**************************************** prototypes for network.c */ int get_socket_error(const SOCKET); -int s_connect(CLI *, SOCKADDR_UNION *, socklen_t); +int s_connect(CLI *, SOCKADDR_UNION *, socklen_t, int); void s_write(CLI *, SOCKET fd, const void *, size_t); size_t s_read_eof(CLI *, SOCKET fd, void *, size_t); void s_read(CLI *, SOCKET fd, void *, size_t); @@ -732,55 +796,6 @@ int getnameinfo(const struct sockaddr *, socklen_t, extern CLI *thread_head; #endif -#if OPENSSL_VERSION_NUMBER<0x10100004L - -#ifdef USE_OS_THREADS - -struct CRYPTO_dynlock_value { -#ifdef USE_PTHREAD - pthread_rwlock_t rwlock; -#endif -#ifdef USE_WIN32 - CRITICAL_SECTION critical_section; -#endif -#ifdef DEBUG_LOCKS - const char *init_file, *read_lock_file, *write_lock_file, - *unlock_file, *destroy_file; - int init_line, read_lock_line, write_lock_line, unlock_line, destroy_line; -#endif -}; - -typedef struct CRYPTO_dynlock_value CRYPTO_RWLOCK; - -#else /* USE_OS_THREADS */ - -typedef void CRYPTO_RWLOCK; - -#endif /* USE_OS_THREADS */ - -#endif /* OPENSSL_VERSION_NUMBER<0x10100004L */ - -typedef enum { - LOCK_THREAD_LIST, /* sthreads.c */ - LOCK_SESSION, LOCK_ADDR, - LOCK_CLIENTS, LOCK_SSL, /* client.c */ - LOCK_REF, /* options.c */ - LOCK_INET, /* resolver.c */ -#ifndef USE_WIN32 - LOCK_LIBWRAP, /* libwrap.c */ -#endif - LOCK_LOG_BUFFER, LOCK_LOG_MODE, /* log.c */ - LOCK_LEAK_HASH, LOCK_LEAK_RESULTS, /* str.c */ -#ifndef OPENSSL_NO_DH - LOCK_DH, /* ctx.c */ -#endif /* OPENSSL_NO_DH */ -#ifdef USE_WIN32 - LOCK_WIN_LOG, /* ui_win_gui.c */ -#endif - LOCK_SECTIONS, /* traversing section list */ - STUNNEL_LOCKS /* number of locks */ -} LOCK_TYPE; - extern CRYPTO_RWLOCK *stunnel_locks[STUNNEL_LOCKS]; #if OPENSSL_VERSION_NUMBER<0x10100004L diff --git a/src/str.c b/src/str.c index 9f05693b..0e45ad78 100644 --- a/src/str.c +++ b/src/str.c @@ -165,6 +165,7 @@ char *str_vprintf(const char *format, va_list start_ap) { for(;;) { va_copy(ap, start_ap); n=vsnprintf(p, size, format, ap); + va_end(ap); if(n>-1 && n<(int)size) return p; if(n>-1) /* glibc 2.1 */ diff --git a/src/stunnel.c b/src/stunnel.c index 18881da7..e25d5a21 100644 --- a/src/stunnel.c +++ b/src/stunnel.c @@ -450,7 +450,6 @@ NOEXPORT int accept_connection(SERVICE_OPTIONS *opt, unsigned i) { #endif if(create_client(fd, s, alloc_client_session(opt, s, s))) { s_log(LOG_ERR, "Connection rejected: create_client failed"); - closesocket(s); #ifndef USE_FORK service_free(opt); #endif diff --git a/src/ui_win_cli.c b/src/ui_win_cli.c index 295e9fb5..8824c858 100644 --- a/src/ui_win_cli.c +++ b/src/ui_win_cli.c @@ -93,8 +93,8 @@ void ui_new_log(const char *line) { RETAILMSG(TRUE, (TEXT("%s\r\n"), tstr)); #else /* use UTF-16 or native codepage rather than UTF-8 */ - _ftprintf(stderr, TEXT("%s\r\n"), tstr); - fflush(stderr); + _putts(tstr); + fflush(stdout); #endif str_free(tstr); } diff --git a/src/vc.mak b/src/vc.mak index 1804a226..b4aa60af 100644 --- a/src/vc.mak +++ b/src/vc.mak @@ -43,7 +43,7 @@ SHAREDOBJS=$(OBJ)\stunnel.obj $(OBJ)\ssl.obj $(OBJ)\ctx.obj \ $(OBJ)\protocol.obj $(OBJ)\sthreads.obj $(OBJ)\log.obj \ $(OBJ)\options.obj $(OBJ)\network.obj $(OBJ)\resolver.obj \ $(OBJ)\str.obj $(OBJ)\tls.obj $(OBJ)\fd.obj $(OBJ)\dhparam.obj \ - $(OBJ)\cron.obj + $(OBJ)\cron.obj $(OBJ)\ocsp.obj GUIOBJS=$(OBJ)\ui_win_gui.obj $(OBJ)\resources.res CLIOBJS=$(OBJ)\ui_win_cli.obj diff --git a/src/verify.c b/src/verify.c index 83079afa..e59ac49a 100644 --- a/src/verify.c +++ b/src/verify.c @@ -55,17 +55,6 @@ NOEXPORT int cert_check_subject(CLI *, X509_STORE_CTX *); #endif /* OPENSSL_VERSION_NUMBER>=0x10002000L */ NOEXPORT int cert_check_local(X509_STORE_CTX *); NOEXPORT int compare_pubkeys(X509 *, X509 *); -#ifndef OPENSSL_NO_OCSP -NOEXPORT int ocsp_check(CLI *, X509_STORE_CTX *); -NOEXPORT int ocsp_request(CLI *, X509_STORE_CTX *, OCSP_CERTID *, char *); -NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *, OCSP_REQUEST *, char *); -#endif - -/* utility functions */ -#ifndef OPENSSL_NO_OCSP -NOEXPORT X509 *get_current_issuer(X509_STORE_CTX *); -NOEXPORT void log_time(const int, const char *, ASN1_TIME *); -#endif /**************************************** verify initialization */ @@ -251,7 +240,7 @@ NOEXPORT int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) { c=SSL_get_ex_data(ssl, index_ssl_cli); if(!c->opt->option.verify_chain && !c->opt->option.verify_peer) { - s_log(LOG_INFO, "Certificate verification disabled"); + s_log(LOG_INFO, "CERT: Certificate verification disabled"); return 1; /* accept */ } if(verify_checks(c, preverify_ok, callback_ctx)) @@ -292,8 +281,7 @@ NOEXPORT int verify_checks(CLI *c, return 0; /* reject */ } #ifndef OPENSSL_NO_OCSP - if((c->opt->ocsp_url || c->opt->option.aia) && - !ocsp_check(c, callback_ctx)) { + if(!ocsp_check(c, callback_ctx)) { s_log(LOG_WARNING, "Rejected by OCSP at depth=%d: %s", depth, subject); str_free(subject); return 0; /* reject */ @@ -452,331 +440,6 @@ NOEXPORT int compare_pubkeys(X509 *c1, X509 *c2) { return 1; /* accept */ } -/**************************************** OCSP checking */ - -#ifndef OPENSSL_NO_OCSP - -#ifdef DEFINE_STACK_OF -/* defined in openssl/safestack.h: - * DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) */ -#else /* DEFINE_STACK_OF */ -#ifndef sk_OPENSSL_STRING_num -#define sk_OPENSSL_STRING_num(st) sk_num(st) -#endif /* sk_OPENSSL_STRING_num */ -#ifndef sk_OPENSSL_STRING_value -#define sk_OPENSSL_STRING_value(st, i) sk_value((st),(i)) -#endif /* sk_OPENSSL_STRING_value */ -#endif /* DEFINE_STACK_OF */ - -NOEXPORT int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) { - X509 *cert; - OCSP_CERTID *cert_id; - STACK_OF(OPENSSL_STRING) *aia; - int i, ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN, saved_error; - char *url; - - /* the original error code is restored unless we report our own error */ - saved_error=X509_STORE_CTX_get_error(callback_ctx); - - /* get the current certificate ID */ - cert=X509_STORE_CTX_get_current_cert(callback_ctx); - if(!cert) { - s_log(LOG_ERR, "OCSP: Failed to get the current certificate"); - X509_STORE_CTX_set_error(callback_ctx, - X509_V_ERR_APPLICATION_VERIFICATION); - return 0; /* reject */ - } - if(!X509_NAME_cmp(X509_get_subject_name(cert), - X509_get_issuer_name(cert))) { - s_log(LOG_DEBUG, "OCSP: Ignoring root certificate"); - return 1; /* accept */ - } - cert_id=OCSP_cert_to_id(NULL, cert, get_current_issuer(callback_ctx)); - if(!cert_id) { - sslerror("OCSP: OCSP_cert_to_id"); - X509_STORE_CTX_set_error(callback_ctx, - X509_V_ERR_APPLICATION_VERIFICATION); - return 0; /* reject */ - } - - /* use the responder specified in the configuration file */ - if(c->opt->ocsp_url) { - s_log(LOG_NOTICE, "OCSP: Connecting the configured responder \"%s\"", - c->opt->ocsp_url); - if(ocsp_request(c, callback_ctx, cert_id, c->opt->ocsp_url)!= - V_OCSP_CERTSTATUS_GOOD) { - OCSP_CERTID_free(cert_id); - return 0; /* reject */ - } - } - - /* use the responder from AIA (Authority Information Access) */ - if(c->opt->option.aia && (aia=X509_get1_ocsp(cert))!=NULL) { - for(i=0; iopt->option.nonce) - OCSP_request_add1_nonce(request, NULL, -1); - - /* send the request and get a response */ - response=ocsp_get_response(c, request, url); - if(!response) - goto cleanup; - response_status=OCSP_response_status(response); - if(response_status!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { - s_log(LOG_ERR, "OCSP: Responder error: %d: %s", - response_status, OCSP_response_status_str(response_status)); - goto cleanup; - } - - /* verify the response */ - basic_response=OCSP_response_get1_basic(response); - if(!basic_response) { - sslerror("OCSP: OCSP_response_get1_basic"); - goto cleanup; - } - if(c->opt->option.nonce && OCSP_check_nonce(request, basic_response)<=0) { - s_log(LOG_ERR, "OCSP: Invalid or unsupported nonce"); - goto cleanup; - } - if(OCSP_basic_verify(basic_response, - X509_STORE_CTX_get0_chain(callback_ctx), - SSL_CTX_get_cert_store(c->opt->ctx), c->opt->ocsp_flags)<=0) { - sslerror("OCSP: OCSP_basic_verify"); - goto cleanup; - } - if(!OCSP_resp_find_status(basic_response, cert_id, &ocsp_status, &reason, - &revoked_at, &this_update, &next_update)) { - sslerror("OCSP: OCSP_resp_find_status"); - goto cleanup; - } - s_log(LOG_INFO, "OCSP: Status: %s", OCSP_cert_status_str(ocsp_status)); - log_time(LOG_INFO, "OCSP: This update", this_update); - log_time(LOG_INFO, "OCSP: Next update", next_update); - /* check if the response is valid for at least one minute */ - if(!OCSP_check_validity(this_update, next_update, 60, -1)) { - sslerror("OCSP: OCSP_check_validity"); - ocsp_status=V_OCSP_CERTSTATUS_UNKNOWN; - goto cleanup; - } - switch(ocsp_status) { - case V_OCSP_CERTSTATUS_GOOD: - s_log(LOG_NOTICE, "OCSP: Certificate accepted"); - break; - case V_OCSP_CERTSTATUS_REVOKED: - if(reason==-1) - s_log(LOG_ERR, "OCSP: Certificate revoked"); - else - s_log(LOG_ERR, "OCSP: Certificate revoked: %d: %s", - reason, OCSP_crl_reason_str(reason)); - log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at); - ctx_err=X509_V_ERR_CERT_REVOKED; - break; - case V_OCSP_CERTSTATUS_UNKNOWN: - s_log(LOG_WARNING, "OCSP: Unknown verification status"); - } -cleanup: - if(request) - OCSP_REQUEST_free(request); - if(response) - OCSP_RESPONSE_free(response); - if(basic_response) - OCSP_BASICRESP_free(basic_response); - if(ocsp_status!=V_OCSP_CERTSTATUS_GOOD) - X509_STORE_CTX_set_error(callback_ctx, ctx_err); - return ocsp_status; -} - -NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c, - OCSP_REQUEST *req, char *url) { - BIO *bio=NULL; - OCSP_REQ_CTX *req_ctx=NULL; - OCSP_RESPONSE *resp=NULL; - char *host=NULL, *port=NULL, *path=NULL; - SOCKADDR_UNION addr; - int ssl; - - /* parse the OCSP URL */ - if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) { - s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL"); - goto cleanup; - } - if(ssl) { - s_log(LOG_ERR, "OCSP: TLS not supported for OCSP" - " - an additional stunnel service needs to be defined"); - goto cleanup; - } - if(!hostport2addr(&addr, host, port, 0)) { - s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP responder address"); - goto cleanup; - } - - /* connect specified OCSP responder */ - c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket"); - if(c->fd==INVALID_SOCKET) - goto cleanup; - if(s_connect(c, &addr, addr_len(&addr))) - goto cleanup; - bio=BIO_new_socket((int)c->fd, BIO_NOCLOSE); - if(!bio) { - sslerror("OCSP: BIO_new_socket"); - goto cleanup; - } - s_log(LOG_DEBUG, "OCSP: Connected %s:%s", host, port); - - /* initialize an HTTP request with the POST method */ -#if OPENSSL_VERSION_NUMBER>=0x10000000L - req_ctx=OCSP_sendreq_new(bio, path, NULL, -1); -#else - /* there is no way to send the Host header with older OpenSSL versions */ - req_ctx=OCSP_sendreq_new(bio, path, req, -1); -#endif - if(!req_ctx) { - sslerror("OCSP: OCSP_sendreq_new"); - goto cleanup; - } -#if OPENSSL_VERSION_NUMBER>=0x10000000L - /* add the HTTP headers */ - if(!OCSP_REQ_CTX_add1_header(req_ctx, "Host", host)) { - sslerror("OCSP: OCSP_REQ_CTX_add1_header"); - goto cleanup; - } - if(!OCSP_REQ_CTX_add1_header(req_ctx, "User-Agent", "stunnel")) { - sslerror("OCSP: OCSP_REQ_CTX_add1_header"); - goto cleanup; - } - /* add the remaining HTTP headers and the OCSP request body */ - if(!OCSP_REQ_CTX_set1_req(req_ctx, req)) { - sslerror("OCSP: OCSP_REQ_CTX_set1_req"); - goto cleanup; - } -#endif - - /* OCSP protocol communication loop */ - while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) { - s_poll_init(c->fds, 0); - s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio)); - switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) { - case -1: - sockerror("OCSP: s_poll_wait"); - goto cleanup; - case 0: - s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded"); - goto cleanup; - } - } -#if 0 - s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); -#endif - /* http://www.mail-archive.com/openssl-users@openssl.org/msg61691.html */ - if(resp) { - s_log(LOG_DEBUG, "OCSP: Response received"); - } else { - if(ERR_peek_error()) - sslerror("OCSP: OCSP_sendreq_nbio"); - else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */ - s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error"); - } - -cleanup: - if(req_ctx) - OCSP_REQ_CTX_free(req_ctx); - if(bio) - BIO_free_all(bio); - if(c->fd!=INVALID_SOCKET) { - closesocket(c->fd); - c->fd=INVALID_SOCKET; /* avoid double close on cleanup */ - } - if(host) - OPENSSL_free(host); - if(port) - OPENSSL_free(port); - if(path) - OPENSSL_free(path); - return resp; -} - -/* find the issuer certificate without lookups */ -NOEXPORT X509 *get_current_issuer(X509_STORE_CTX *callback_ctx) { - STACK_OF(X509) *chain; - int depth; - - chain=X509_STORE_CTX_get0_chain(callback_ctx); - depth=X509_STORE_CTX_get_error_depth(callback_ctx); - if(depth> "maketestcert.log" | head -c 50 > tmp/psk.txt if [ -s tmp/psk.txt ] @@ -21,84 +20,195 @@ gen_psk () { rm -f tmp/psk.txt } + +################################################################################ +# OpenSSL settings +################################################################################ +TEMP_LD_LIBRARY_PATH=$LD_LIBRARY_PATH +LD_LIBRARY_PATH="" +OPENSSL=openssl + +mkdir "tmp/" export LC_ALL=C +mkdir "CA/" 2>> "maketestcert.log" 1>&2 +touch "CA/index.txt" +echo -n "unique_subject = no" > "CA/index.txt.attr" +"$OPENSSL" rand -hex 16 > "CA/serial" +echo 1001 > "CA/crlnumber" +date > "maketestcert.log" +"$OPENSSL" version 2>> "maketestcert.log" 1>&2 + + +################################################################################ +# Create new psk secrets +################################################################################ gen_psk 1 cat tmp/psk1.txt > tmp/secrets.txt 2>> "maketestcert.log" gen_psk 2 cat tmp/psk2.txt >> tmp/secrets.txt 2>> "maketestcert.log" gen_psk 2 -# OpenSSL settings -TEMP_LD_LIBRARY_PATH=$LD_LIBRARY_PATH -LD_LIBRARY_PATH="" -OPENSSL=openssl -CONF="${script_path}/openssltest.cnf" - -mkdir "demoCA/" -touch "demoCA/index.txt" -touch "demoCA/index.txt.attr" -echo 1000 > "demoCA/serial" -# generate a self-signed certificate -$OPENSSL req -config $CONF -new -x509 -days $ddays -keyout tmp/stunnel.pem -out tmp/stunnel.pem \ +################################################################################ +# self-signed certificate +################################################################################ +CONF="${script_path}/openssl_root.cnf" +"$OPENSSL" req -config $CONF -new -x509 -keyout tmp/stunnel.pem -out tmp/stunnel.pem \ -subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=Stunnel Developers/OU=Provisional CA/CN=localhost/emailAddress=stunnel@example.com" \ - 1>&2 2>> "maketestcert.log" + 2>> "maketestcert.log" 1>&2 -# generate root CA certificate -$OPENSSL genrsa -out demoCA/CA.key 1>&2 2>> "maketestcert.log" -$OPENSSL req -config $CONF -new -x509 -days $ddays -key demoCA/CA.key -out tmp/CACert.pem \ - -subj "/C=PL/O=Stunnel Developers/OU=Root CA/CN=CA/emailAddress=CA@example.com" \ - 1>&2 2>> "maketestcert.log" -# generate a certificate to revoke -$OPENSSL genrsa -out demoCA/revoked.key 1>&2 2>> "maketestcert.log" -$OPENSSL req -config $CONF -new -key demoCA/revoked.key -out demoCA/revoked.csr \ +################################################################################ +# Root CA certificate +################################################################################ +"$OPENSSL" genrsa -out CA/CA.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -x509 -days 3600 -key CA/CA.key -out tmp/CACert.pem \ + -subj "/C=PL/O=Stunnel Developers/OU=Root CA/CN=CA/emailAddress=CA@example.com" \ + 2>> "maketestcert.log" 1>&2 + + +################################################################################ +# Intermediate CA certificate +################################################################################ +CONF="${script_path}/openssl_intermediate.cnf" +"$OPENSSL" genrsa -out CA/intermediateCA.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config "$CONF" -new -key CA/intermediateCA.key -out CA/intermediateCA.csr \ + -subj "/C=PL/O=Stunnel Developers/OU=Intermediate CA/CN=Intermediate CA" \ + 2>> "maketestcert.log" 1>&2 + +CONF="${script_path}/openssl_root.cnf" +"$OPENSSL" ca -config "$CONF" -batch -in CA/intermediateCA.csr -out CA/intermediateCA.cer \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/intermediateCA.cer -out tmp/intermediateCA.pem \ + 2>> "maketestcert.log" 1>&2 + + +################################################################################ +# Revoked certificate chain +################################################################################ +CONF="${script_path}/openssl_intermediate.cnf" +"$OPENSSL" genrsa -out CA/revoked.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -key CA/revoked.key -out CA/revoked.csr \ -subj "/C=PL/O=Stunnel Developers/OU=revoked/CN=revoked/emailAddress=revoked@example.com" \ - 1>&2 2>> "maketestcert.log" - -$OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/revoked.csr -out demoCA/revoked.cer 1>&2 2>> "maketestcert.log" - -$OPENSSL x509 -in demoCA/revoked.cer -out tmp/revoked_cert.pem 1>&2 2>> "maketestcert.log" -cat demoCA/revoked.key >> tmp/revoked_cert.pem 2>> "maketestcert.log" + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -batch -in CA/revoked.csr -out CA/revoked.cer \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/revoked.cer -out tmp/revoked_cert.pem \ + 2>> "maketestcert.log" 1>&2 +cat CA/revoked.key >> tmp/revoked_cert.pem 2>> "maketestcert.log" +cat tmp/intermediateCA.pem >> tmp/revoked_cert.pem 2>> "maketestcert.log" # revoke above certificate and generate CRL file -$OPENSSL ca -config $CONF -revoke demoCA/1000.pem 1>&2 2>> "maketestcert.log" -$OPENSSL ca -config $CONF -gencrl -crldays $ddays -out tmp/CACertCRL.pem 1>&2 2>> "maketestcert.log" - -# generate a client certificate -$OPENSSL genrsa -out demoCA/client.key 1>&2 2>> "maketestcert.log" -$OPENSSL req -config $CONF -new -key demoCA/client.key -out demoCA/client.csr \ - -subj "/C=PL/O=Stunnel Developers/OU=client/CN=client/emailAddress=client@example.com" \ - 1>&2 2>> "maketestcert.log" - -$OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/client.csr -out demoCA/client.cer 1>&2 2>> "maketestcert.log" - -$OPENSSL x509 -in demoCA/client.cer -out tmp/client_cert.pem 1>&2 2>> "maketestcert.log" -cat tmp/client_cert.pem > tmp/PeerCerts.pem 2>> "maketestcert.log" -cat demoCA/client.key >> tmp/client_cert.pem 2>> "maketestcert.log" - -# generate a server certificate -$OPENSSL genrsa -out demoCA/server.key 1>&2 2>> "maketestcert.log" -$OPENSSL req -config $CONF -new -key demoCA/server.key -out demoCA/server.csr \ +"$OPENSSL" ca -config $CONF -revoke CA/revoked.cer \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -gencrl -crldays 1461 -out tmp/CACertCRL.pem \ + 2>> "maketestcert.log" 1>&2 + + +################################################################################ +# Server certificate chain +################################################################################ +"$OPENSSL" genrsa -out CA/server.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -key CA/server.key -out CA/server.csr \ -subj "/C=PL/O=Stunnel Developers/OU=server/CN=server/emailAddress=server@example.com" \ - 1>&2 2>> "maketestcert.log" - -$OPENSSL ca -config $CONF -batch -days $ddays -in demoCA/server.csr -out demoCA/server.cer 1>&2 2>> "maketestcert.log" - -$OPENSSL x509 -in demoCA/server.cer -out tmp/server_cert.pem 1>&2 2>> "maketestcert.log" + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -batch -in CA/server.csr -out CA/server.cer \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/server.cer -out tmp/server_cert.pem \ + 2>> "maketestcert.log" 1>&2 cat tmp/server_cert.pem >> tmp/PeerCerts.pem 2>> "maketestcert.log" -cat demoCA/server.key >> tmp/server_cert.pem 2>> "maketestcert.log" +cat CA/server.key >> tmp/server_cert.pem 2>> "maketestcert.log" +cat tmp/intermediateCA.pem >> tmp/server_cert.pem 2>> "maketestcert.log" -# create a PKCS#12 file with a server certificate -$OPENSSL pkcs12 -export -certpbe pbeWithSHA1And3-KeyTripleDES-CBC -in tmp/server_cert.pem -out tmp/server_cert.p12 -passout pass: 1>&2 2>> "maketestcert.log" +# create a PKCS#12 file with a server certificate chain +"$OPENSSL" pkcs12 -export -certpbe pbeWithSHA1And3-KeyTripleDES-CBC \ + -in tmp/server_cert.pem -out tmp/server_cert.p12 -passout pass: \ + 2>> "maketestcert.log" 1>&2 -# copy new files -if [ -s tmp/stunnel.pem ] && [ -s tmp/CACert.pem ] && [ -s tmp/CACertCRL.pem ] && \ - [ -s tmp/revoked_cert.pem ] && [ -s tmp/client_cert.pem ] && [ -s tmp/server_cert.pem ] && \ - [ -s tmp/PeerCerts.pem ] && [ -s tmp/server_cert.p12 ] && \ - [ -s tmp/psk1.txt ] && [ -s tmp/psk2.txt ] && [ -s tmp/secrets.txt ] + +################################################################################ +# Client certificate chain +################################################################################ +"$OPENSSL" genrsa -out CA/client.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -key CA/client.key -out CA/client.csr \ + -subj "/C=PL/O=Stunnel Developers/OU=client/CN=client/emailAddress=client@example.com" \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -batch -in CA/client.csr -out CA/client.cer \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/client.cer -out tmp/client_cert.pem \ + 2>> "maketestcert.log" 1>&2 +cat tmp/client_cert.pem > tmp/PeerCerts.pem 2>> "maketestcert.log" +cat CA/client.key >> tmp/client_cert.pem 2>> "maketestcert.log" +cat tmp/intermediateCA.pem >> tmp/client_cert.pem 2>> "maketestcert.log" + + +################################################################################ +# OCSP certificates with XKU_OCSP_SIGN +# openssl ocsp -port 19253 -index index.txt -rsigner inter_ocsp.pem -CA CACert.pem -nmin 1 +# openssl ocsp -port 19254 -index index.txt -rsigner leaf_ocsp.pem -CA intermediateCA.pem -nmin 1 +################################################################################ +CONF="${script_path}/openssl_root.cnf" +"$OPENSSL" genrsa -out CA/inter_ocsp.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -key CA/inter_ocsp.key -out CA/inter_ocsp.csr \ + -extensions v3_OCSP \ + -subj "/C=PL/O=Stunnel Developers/OU=Intermediate OCSP/CN=inter_ocsp/emailAddress=inter_ocsp@example.com" \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -batch -in CA/inter_ocsp.csr -out CA/inter_ocsp.cer \ + -extensions v3_OCSP \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/inter_ocsp.cer -out tmp/inter_ocsp.pem \ + 2>> "maketestcert.log" 1>&2 +cat CA/inter_ocsp.key >> tmp/inter_ocsp.pem 2>> "maketestcert.log" + +CONF="${script_path}/openssl_intermediate.cnf" +"$OPENSSL" genrsa -out CA/leaf_ocsp.key \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" req -config $CONF -new -key CA/leaf_ocsp.key -out CA/leaf_ocsp.csr \ + -extensions v3_OCSP \ + -subj "/C=PL/O=Stunnel Developers/OU=Leaf OCSP/CN=leaf_ocsp/emailAddress=leaf_ocsp@example.com" \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" ca -config $CONF -batch -in CA/leaf_ocsp.csr -out CA/leaf_ocsp.cer \ + -extensions v3_OCSP \ + 2>> "maketestcert.log" 1>&2 +"$OPENSSL" x509 -in CA/leaf_ocsp.cer -out tmp/leaf_ocsp.pem \ + 2>> "maketestcert.log" 1>&2 +cat CA/leaf_ocsp.key >> tmp/leaf_ocsp.pem 2>> "maketestcert.log" + + +################################################################################ +# OCSP certificates without XKU_OCSP_SIGN +# Don't include any certificates in the OCSP response +# openssl ocsp -port 19253 -index index.txt -rsigner CA_ocsp.pem -CA CACert.pem -nmin 1 -resp_no_certs +# openssl ocsp -port 19254 -index index.txt -rsigner interCA_ocsp.pem -CA intermediateCA.pem -nmin 1 -resp_no_certs +################################################################################ +cat tmp/CACert.pem >> tmp/CA_ocsp.pem 2>> "makecerts.log" +cat CA/CA.key >> tmp/CA_ocsp.pem 2>> "makecerts.log" +cat tmp/intermediateCA.pem >> tmp/interCA_ocsp.pem 2>> "makecerts.log" +cat CA/intermediateCA.key >> tmp/interCA_ocsp.pem 2>> "makecerts.log" + + +################################################################################ +# Copy new files +################################################################################ +if test -s tmp/CACert.pem -a -s tmp/CACertCRL.pem \ + -a -s tmp/intermediateCA.pem \ + -a -s tmp/stunnel.pem -a -s tmp/revoked_cert.pem \ + -a -s tmp/client_cert.pem -a -s tmp/server_cert.pem \ + -a -s tmp/server_cert.p12 \ + -a -s tmp/inter_ocsp.pem -a -s tmp/leaf_ocsp.pem \ + -a -s tmp/CA_ocsp.pem -a -s tmp/interCA_ocsp.pem \ + -a -s tmp/PeerCerts.pem -a -s tmp/secrets.txt \ + -a -s tmp/psk1.txt -a -s tmp/psk2.txt \ + -a -s CA/index.txt then - cp tmp/* ./ + cp tmp/* ../certs + cp CA/index.txt ../certs printf "%s\n" "keys & certificates successfully generated" printf "%s\n" "./maketestcert.sh finished" rm -f "maketestcert.log" @@ -107,8 +217,11 @@ if [ -s tmp/stunnel.pem ] && [ -s tmp/CACert.pem ] && [ -s tmp/CACertCRL.pem ] & printf "%s\n" "error logs ${result_path}/maketestcert.log" fi -# remove the working directory -rm -rf "demoCA/" + +################################################################################ +# Remove the working directory +################################################################################ +rm -rf "CA/" rm -rf "tmp/" # restore settings diff --git a/tests/certs/openssl_intermediate.cnf b/tests/certs/openssl_intermediate.cnf new file mode 100644 index 00000000..25bbdc84 --- /dev/null +++ b/tests/certs/openssl_intermediate.cnf @@ -0,0 +1,74 @@ +# OpenSSL intermediate CA configuration file + +[ default ] +name = intermediateCA +default_ca = CA_default + +[ CA_default ] +# Directory and file locations. +dir = . +certs = $dir/CA +crl_dir = $dir/CA +new_certs_dir = $dir/CA +database = $dir/CA/index.txt +serial = $dir/CA/serial +rand_serial = yes +private_key = $dir/CA/$name.key +certificate = $dir/tmp/$name.pem +crlnumber = $dir/CA/crlnumber +crl_extensions = crl_ext +default_md = sha256 +preserve = no +policy = policy_loose +default_days = 2200 +x509_extensions = usr_cert + +[ crl_ext ] +authorityKeyIdentifier = keyid:always + +[ v3_OCSP ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning + +[ req ] +# Options for the `req` tool +encrypt_key = no +default_bits = 2048 +default_md = sha256 +string_mask = utf8only +x509_extensions = usr_extensions +distinguished_name = req_distinguished_name + +[ usr_cert ] +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid, issuer +authorityInfoAccess = OCSP;URI:http://127.0.0.1:19254/ocsp + +[ usr_extensions ] +# Extension to add when the -x509 option is used +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +keyUsage = critical, digitalSignature, keyCertSign + +[ policy_loose ] +# Allow the intermediate CA to sign a more diverse range of certificates. +# See the POLICY FORMAT section of the `ca` man page. +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +stateOrProvinceName = State or Province Name +localityName = Locality Name +0.organizationName = Organization Name +organizationalUnitName = Organizational Unit Name +commonName = Common Name +emailAddress = Email Address diff --git a/tests/certs/openssltest.cnf b/tests/certs/openssl_root.cnf similarity index 61% rename from tests/certs/openssltest.cnf rename to tests/certs/openssl_root.cnf index f95c9c6a..c3438458 100644 --- a/tests/certs/openssltest.cnf +++ b/tests/certs/openssl_root.cnf @@ -6,20 +6,31 @@ default_ca = CA_default [ CA_default ] # Directory and file locations. dir = . -certs = $dir/demoCA -crl_dir = $dir/demoCA -new_certs_dir = $dir/demoCA -database = $dir/demoCA/index.txt -serial = $dir/demoCA/serial +certs = $dir/CA +crl_dir = $dir/CA +new_certs_dir = $dir/CA +database = $dir/CA/index.txt +serial = $dir/CA/serial +rand_serial = yes +private_key = $dir/CA/CA.key +certificate = $dir/tmp/CACert.pem crl_extensions = crl_ext default_md = sha256 preserve = no policy = policy_match -x509_extensions = usr_cert -private_key = $dir/demoCA/CA.key -certificate = $dir/tmp/CACert.pem +default_days = 3000 +x509_extensions = v3_intermediate_ca + +[ crl_ext ] +authorityKeyIdentifier = keyid:always + +[ v3_OCSP ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning [ req ] +# Options for the `req` tool encrypt_key = no default_bits = 2048 default_md = sha256 @@ -27,20 +38,21 @@ string_mask = utf8only x509_extensions = ca_extensions distinguished_name = req_distinguished_name -[ crl_ext ] -authorityKeyIdentifier = keyid:always - -[ usr_cert ] -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid, issuer - [ ca_extensions ] +# Extension to add when the -x509 option is used basicConstraints = critical, CA:true subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer keyUsage = critical, digitalSignature, cRLSign, keyCertSign +[ v3_intermediate_ca ] +# Extensions for a typical intermediate CA (`man x509v3_config`) +basicConstraints = critical, CA:true, pathlen:0 +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +keyUsage = critical, digitalSignature, cRLSign, keyCertSign +authorityInfoAccess = OCSP;URI:http://127.0.0.1:19254/ocsp + [ policy_match ] countryName = match organizationName = match diff --git a/tests/maketest.py b/tests/maketest.py index 43253774..e48ac02f 100644 --- a/tests/maketest.py +++ b/tests/maketest.py @@ -7,6 +7,7 @@ import asyncio import contextlib import dataclasses +import http.client import logging import os import pathlib @@ -17,6 +18,7 @@ import subprocess import sys import tempfile +import threading from typing import ( Any, @@ -28,7 +30,13 @@ Optional, TypeVar ) - +from datetime import datetime, timedelta, timezone +from functools import partial +from urllib.parse import urlparse +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.x509 import load_pem_x509_certificate, ocsp, ReasonFlags +from cryptography.x509 import SubjectKeyIdentifier, ExtensionNotFound, OCSPNonce from plugin_collection import PluginCollection EXIT_SUCCESS = 0 @@ -39,6 +47,8 @@ DEFAULT_CERTS = os.path.join(RESULT_PATH, "certs") DEFAULT_LOGS = os.path.join(RESULT_PATH, "logs") DEFAULT_LEVEL = logging.INFO +DEFAULT_PORT = 19254 +OCSP_INDEX=os.path.join(DEFAULT_CERTS, "index.txt") RE_STUNNEL_VERSION = re.compile( r""" ^ @@ -61,8 +71,18 @@ RE_LINE_IDX = re.compile(r" ^ Hello \s+ (?P 0 | [1-9][0-9]* ) $ ", re.X) -class UnsupportedOpenSSL(Exception): - """Unsupported version of OpenSSL""" +class UnsupportedVersion(Exception): + """Unsupported version""" + + +class OutputError(Exception): + """Output error + Logging: Something went wrong + """ + + +class UnexpectedWarning(Exception): + """Unexpected warning""" @dataclasses.dataclass(frozen=True) @@ -73,7 +93,7 @@ class LogEvent(): log: str -TLogEvent = TypeVar("TEvent", bound=LogEvent) +TypeLogEvent = TypeVar("TypeLogEvent", bound=LogEvent) @dataclasses.dataclass(frozen=True) @@ -175,6 +195,7 @@ class Config(NamedTuple): results: pathlib.Path summary: pathlib.Path debug: int + port: int class TestConnections(NamedTuple): @@ -245,17 +266,17 @@ async def process_client(self, evt: ListenerClientEvent) -> None: if evt.etype == "client_send_data": conn = conns.by_id.get(evt.idx) if conn is None: - raise Exception("Listener reported unknown connection") + raise OutputError("Listener reported unknown connection") if conn.peer is not None: - raise Exception(f"Listener reported bad conn {conn!r}") + raise OutputError(f"Listener reported bad conn {conn!r}") conn.peer = peer return if evt.etype != "client_connected": - raise Exception(f"Expected 'client connected' first, got {evt.etype}") + raise OutputError(f"Expected 'client connected' first, got {evt.etype}") conns.pending[peer] = [evt] - except Exception as err: # pylint: disable=broad-except + except OutputError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", @@ -272,7 +293,7 @@ async def remove_connection(self, evt: ConnectionDoneEvent, num: int) -> None: conns = evt.conns conn = conns.by_id.get(evt.idx) if conn is None: - raise Exception("No connection") + raise OutputError("No connection") del conns.by_id[evt.idx] if conn.peer is None: await self.cfg.mainq.put( @@ -305,7 +326,7 @@ async def remove_connection(self, evt: ConnectionDoneEvent, num: int) -> None: ) return num - except Exception as err: # pylint: disable=broad-except + except OutputError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", @@ -326,14 +347,11 @@ async def process_events(self, logger: logging.Logger) -> None: while True: evt = await self.cfg.mainq.get() self.log_event(evt, logger) - if evt.etype == "cleanup_event" or evt.etype == "output_event" \ - or evt.etype == "fatal_event": + if evt.etype in ["cleanup_event", "output_event", "fatal_event"]: await self.cfg.resq.put(evt) - elif evt.etype == "stunnel_event" or evt.etype == "result_event" \ - or evt.etype == "all_connections_event": + elif evt.etype in ["stunnel_event", "result_event", "all_connections_event"]: await self.cfg.logsq.put(evt) - elif evt.etype == "client_connected" or evt.etype == "client_send_data" \ - or evt.etype == "client_done": + elif evt.etype in ["client_connected", "client_send_data", "client_done"]: await self.process_client(evt) elif evt.etype == "connection_done_event": await self.cfg.logsq.put(evt) @@ -353,7 +371,7 @@ async def check_version(self, cmd_str: str, p_err: str) -> None: tag = "check_version" lines = p_err.splitlines() if not lines: - raise Exception(f"Expected at least one line of output from `{cmd_str}`") + raise OutputError(f"Expected at least one line of output from `{cmd_str}`") openssl_version = None stunnel_version = None for line in lines: @@ -364,15 +382,16 @@ async def check_version(self, cmd_str: str, p_err: str) -> None: if match: openssl_version = match.group("version") if not openssl_version: - raise Exception("Stunnel was compiled and run with different OpenSSL versions") - """TLSv1.1 and TLSv1.2 available only with OpenSSL version 1.0.1 and later""" + raise UnsupportedVersion("Stunnel was compiled and run with different OpenSSL versions") + #TLSv1.1 and TLSv1.2 available only with OpenSSL version 1.0.1 and later if openssl_version < "1.0.1": - raise UnsupportedOpenSSL(f"OpenSSL version {openssl_version} is deprecated and not supported") + raise UnsupportedVersion( + f"OpenSSL version {openssl_version} is deprecated and not supported") if not (sys.version_info.major == 3 and sys.version_info.minor >= 7): - raise Exception("Python 3.7 or higher is required.\n" - + "You are using Python {}.{}.".format(sys.version_info.major, sys.version_info.minor)) + raise UnsupportedVersion("Python 3.7 or higher is required.\n" + + "You are using Python {sys.version_info.major}.{sys.version_info.minor}.") if not stunnel_version: - raise Exception( + raise UnsupportedVersion( f"Could not find the version line in the `{cmd_str}` output:\n" + "\n".join(lines) ) @@ -422,16 +441,16 @@ async def get_version(self, logger:logging.Logger) -> str: ) b_out, b_err = await proc.communicate() if b_out is None or b_err is None: - raise Exception("proc.communicate() failed") + raise OutputError("proc.communicate() failed") p_out, p_err = b_out.decode("UTF-8"), b_err.decode("UTF-8") logger.info(p_err) rcode = await proc.wait() if rcode != 0: print(b_out.decode("UTF-8")) print(b_err.decode("UTF-8"), file=sys.stderr) - raise Exception(f"`{cmd_str}` exited with code {rcode}") + raise OutputError(f"`{cmd_str}` exited with code {rcode}") if p_out: - raise Exception(f"`{cmd_str}` produced output on its stdout stream:\n{p_out}") + raise OutputError(f"`{cmd_str}` produced output on its stdout stream:\n{p_out}") await self.check_version(cmd_str, p_err) await self.cfg.mainq.put( LogEvent( @@ -479,7 +498,7 @@ async def set_result(self) -> str: result = "UNKNOWN" while True: evt = await self.cfg.resq.get() - if evt.etype == "output_event" or evt.etype == "fatal_event": + if evt.etype in ["output_event", "fatal_event"]: if result != "skipped": parsed = await self.parse_event(evt) if result == "UNKNOWN": @@ -523,11 +542,11 @@ def __init__(self, cfg: Config, logger: logging.Logger): ) - async def expect_event(self, msgq: asyncio.Queue[LogEvent], pattern: str) -> TLogEvent: + async def expect_event(self, msgq: asyncio.Queue[LogEvent], pattern: str) -> TypeLogEvent: """Make sure the next event in the logsq queue is of that etype.""" evt = await msgq.get() if evt.etype != pattern: - raise Exception(f"Expected {pattern}, got {evt.etype}") + raise OutputError(f"Expected {pattern}, got {evt.etype}") return evt @@ -559,8 +578,9 @@ async def start_connections(self, cfgfile: pathlib.Path, port: int) -> None: async def test_stunnel(self, cfg: Config) -> None: """Make a single test of the given stunnel configuration""" + tag = "test_stunnel" + task = None try: - tag = "test_stunnel" self.logger.info(self.params.description) await self.cfg.mainq.put(LogEvent(etype="log", level=30, log="")) await self.cfg.mainq.put( @@ -585,12 +605,12 @@ async def test_stunnel(self, cfg: Config) -> None: if cfgnew is not os.devnull: port = await self.reload_stunnel(cfgfile, cfgnew) else: - raise Exception(f"Unknown '{service}' service") + raise OutputError(f"Unknown '{service}' service") cfgfile = await self.prepare_additional_server_cfgfile(cfg, ports, lport) await self.start_connections(cfgfile, port) - except Exception as err: # pylint: disable=broad-except + except OutputError as err: await cfg.mainq.put( LogEvent( etype="fatal_event", @@ -598,6 +618,14 @@ async def test_stunnel(self, cfg: Config) -> None: log=f"[{tag}] Something went wrong: {err}" ) ) + except asyncio.CancelledError: + await cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=50, + log=f"[{tag}] Something went wrong: Cancelled task" + ) + ) finally: await self.cleanup_stunnels() await self.cleanup_tasks() @@ -625,12 +653,12 @@ async def stunnel_output(self, p_out: asyncio.StreamReader, service: str) -> Non LogEvent( etype="log", level=20, - log=f"[{tag}] Waiting for an EOF on the '{service}_output' reader socket" + log=f"[{tag}] Waiting for an EOF on the '{service}_output' reader" ) ) line = await p_out.read(1) if line: - raise Exception(f"Did not expect to read {line!r}") + raise OutputError(f"Did not expect to read {line!r}") return line = data.decode("UTF-8").rstrip("\r\n") @@ -694,7 +722,15 @@ async def stunnel_output(self, p_out: asyncio.StreamReader, service: str) -> Non ) ) - except Exception as err: # pylint: disable=broad-except + except OutputError as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=50, + log=f"[{tag}] Something went wrong: {err}" + ) + ) + except OSError as err: await self.cfg.mainq.put( StunnelEvent( etype="stunnel_event", @@ -726,14 +762,15 @@ async def run_stunnel(self, cfgfile: pathlib.Path, service: str) -> int: ) ) self.cfg.children[Keys(pid=proc.pid, service=service)] = proc - self.cfg.tasks[f"{service}_output"] = asyncio.create_task(self.stunnel_output(proc.stderr, service)) + self.cfg.tasks[f"{service}_output"] = asyncio.create_task( + self.stunnel_output(proc.stderr, service)) async def check_listening_port(self, port:int, service: str) -> int: """Raise exception if configuration failed.""" tag = "check_listening_port" if port == -1: - raise Exception(f"stunnel \'{service}\' failed") + raise OutputError(f"stunnel \'{service}\' failed") await self.cfg.mainq.put( LogEvent( etype="log", @@ -944,7 +981,7 @@ async def client_connected_cb( try: match = RE_LINE_IDX.match(line.decode("UTF-8")) if not match: - raise Exception(f"Server received unexpected message: {line!r}") + raise OutputError(f"Server received unexpected message: {line!r}") idx = int(match.group("idx")) await self.cfg.mainq.put( ClientSendDataEvent( @@ -966,7 +1003,15 @@ async def client_connected_cb( log=f"[{tag}] The server sent data to the client #{idx}: {line!r}", ) ) - except Exception as err: # pylint: disable=broad-except + except OutputError as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=50, + log=f"[{tag}] Something went wrong: {err}" + ) + ) + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", @@ -998,7 +1043,7 @@ async def client_connected_cb( ListenerClientEvent( etype="client_done", level=10, - log=f"[{tag}] The 'listener' task closed a connection to the client", + log=f"[{tag}] The 'listener' task closed a connection", peer=peer, conns=self.conns ) @@ -1020,9 +1065,9 @@ async def start_listener(self) -> int: ) srv = await self.start_socket_server(self.client_connected_cb) if not srv: - raise Exception(f"The listening {protocol} socket server failed") + raise OutputError(f"The listening {protocol} socket server failed") if not srv.sockets: - raise Exception(f"Expected a listening socket, got {srv.sockets!r}") + raise OutputError(f"Expected a listening socket, got {srv.sockets!r}") hostname, port = srv.sockets[0].getsockname()[:2] await self.cfg.mainq.put( LogEvent( @@ -1077,12 +1122,12 @@ async def cleanup_tasks(self) -> None: ) ) - except Exception as err: # pylint: disable=broad-except + except asyncio.CancelledError: await self.cfg.mainq.put( LogEvent( etype="cleanup_event", level=20, - log=f"[{tag}] Cleanup '{name}' task failed: {err}" + log=f"[{tag}] Cleanup '{name}' task failed: Cancelled task" ) ) @@ -1122,7 +1167,7 @@ async def cleanup_stunnels(self) -> None: log=f"[{tag}] PID {key.pid} already finished" ) ) - except Exception as err: # pylint: disable=broad-except + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="log", @@ -1142,7 +1187,7 @@ async def cleanup_stunnels(self) -> None: ) ) - except Exception as err: # pylint: disable=broad-except + except asyncio.CancelledError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", @@ -1177,7 +1222,7 @@ async def cleanup_stunnel(self, service: str) -> None: log=f"[{tag}] - already finished, it seems" ) ) - except Exception as err: # pylint: disable=broad-except + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="log", @@ -1196,7 +1241,7 @@ async def cleanup_stunnel(self, service: str) -> None: for key in children: self.cfg.children.pop(key) - except Exception as err: # pylint: disable=broad-except + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", @@ -1328,7 +1373,7 @@ async def establish_connection( return await asyncio.open_connection('127.0.0.1', conn.port, ssl=ctx) - except OSError as err: # pylint: disable=broad-except + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="log", @@ -1345,7 +1390,7 @@ async def get_io_stream( """Start a network connection and return a pair of (reader, writer) objects.""" client_reader, client_writer = await self.establish_connection(conn) if not client_reader or not client_writer: - raise Exception("Establish connection failed") + raise OutputError("Establish connection failed") return client_reader, client_writer @@ -1364,7 +1409,7 @@ async def test_connect(self, conn: TestConnection) -> None: ) client_reader, client_writer = await self.get_io_stream(conn) if client_writer.is_closing(): - raise Exception("Client writer is closing") + raise UnexpectedWarning("Client writer is closing") line = f"Hello {conn.idx}\n".encode("UTF-8") await self.cfg.mainq.put( @@ -1386,7 +1431,7 @@ async def test_connect(self, conn: TestConnection) -> None: ) ) if line != "There!\n".encode("UTF-8"): - raise Exception(f"Client received unexpected message: {line!r}") + raise UnexpectedWarning(f"Client received unexpected message: {line!r}") await self.cfg.mainq.put( LogEvent( @@ -1406,14 +1451,22 @@ async def test_connect(self, conn: TestConnection) -> None: ) line = await client_reader.read(1) if line: - raise Exception(f"Did not expect to read {line!r}") + raise UnexpectedWarning(f"Did not expect to read {line!r}") - except Exception as err: # pylint: disable=broad-except + except UnexpectedWarning as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=30, + log=f"[{tag}] Warning: {err}" + ) + ) + except OSError as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", level=30, - log=f"[{tag}] {err}", + log=f"[{tag}] Warning: {err}", ) ) finally: @@ -1486,7 +1539,8 @@ async def run_stunnel(self, cfgfile: pathlib.Path, service: str) -> int: ) ) self.cfg.children[Keys(pid=proc.pid, service=service)] = proc - self.cfg.tasks[f"{service}_output"] = asyncio.create_task(self.stunnel_output(proc.stderr, service)) + self.cfg.tasks[f"{service}_output"] = asyncio.create_task( + self.stunnel_output(proc.stderr, service)) async def get_io_stream( @@ -1511,7 +1565,7 @@ def __init__(self, cfg: Config, logger: logging.Logger, path:pathlib.Path): async def check_listening_port(self, port:int, service: str) -> int: """Raise exception if configuration failed.""" if port == -1: - raise Exception(f"stunnel \'{service}\' failed") + raise OutputError(f"stunnel \'{service}\' failed") async def accepting_connections(self, port:int, service: str) -> int: @@ -1559,7 +1613,7 @@ async def socket_connected_cb( ) ) if line != "There!\n".encode("UTF-8"): - raise Exception(f"Client received unexpected message: {line!r}") + raise UnexpectedWarning(f"Client received unexpected message: {line!r}") await self.cfg.mainq.put( LogEvent( etype="log", @@ -1578,14 +1632,22 @@ async def socket_connected_cb( ) line = await reader.read(1) if line: - raise Exception(f"Did not expect to read {line!r}") + raise UnexpectedWarning(f"Did not expect to read {line!r}") - except Exception as err: # pylint: disable=broad-except + except UnexpectedWarning as err: await self.cfg.mainq.put( LogEvent( etype="fatal_event", - level=20, - log=f"[{tag}] {err}", + level=30, + log=f"[{tag}] Warning: {err}" + ) + ) + except IOError as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=30, + log=f"[{tag}] Warning: {err}" ) ) finally: @@ -1640,6 +1702,237 @@ async def reopen_stunnel(self, cfgfile: pathlib.Path, idx: int, service: str) -> await self.start_stunnel(cfgfile, service) +class OcspResponder(): + """Base class for OCSP responder""" + + def __init__(self, cfg: Config): + self.cfg = cfg + + + async def start_responder(self): + """Start OCSP responder""" + tag = "start_responder" + try: + server=HttpServerThread(self.cfg) + await server.start_server() + except OSError as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=50, + log=f"[{tag}] Something went wrong: {err}" + ) + ) + + + async def stop_responder(self): + """Stop OCSP responder""" + tag = "stop_responder" + conn = http.client.HTTPConnection('localhost', self.cfg.port) + conn.request('POST', '/kill_server') + response = conn.getresponse() + await self.cfg.mainq.put( + LogEvent( + etype="log", + level=10, + log=f"[{tag}] HTTP status code: '{response.getcode()}'" + ) + ) + try: + text = response.read().decode('UTF-8') + await self.cfg.mainq.put( + LogEvent( + etype="log", + level=10, + log=f"[{tag}] HTTP status code: '{text}'" + ) + ) + except OSError as err: + await self.cfg.mainq.put( + LogEvent( + etype="fatal_event", + level=50, + log=f"[{tag}] Something went wrong: {err}" + ) + ) + conn.close() + + +class OCSPHandler(SimpleHTTPRequestHandler): + """Handle the HTTP POST request that arrive at the server""" + + def __init__(self, cfg, database, request, client_address, server): + #pylint: disable=too-many-arguments + self.cfg=cfg + self.database = database + self.server=server + SimpleHTTPRequestHandler.__init__(self, request, client_address, server) + + + def log_message(self, format, *args): + """"Override log_message method to log to a file rather than to sys.stderr""" + # pylint: disable=redefined-builtin + with open(self.cfg.results, mode="a", encoding="utf-8", buffering=1) as file: + file.write(f"do_POST: {self.log_date_time_string()}:" + +f"{self.client_address[0]}: {format%args}\n") + + + def do_POST(self): # pylint: disable=invalid-name + """"Serves the POST request type""" + try: + url=urlparse(self.path) + if url.path == "/kill_server": + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write(bytes('Shutting down HTTP server', 'utf-8')) + self.server.shutdown() + elif url.path == "/ocsp": + content_length=int(self.headers['Content-Length']) + request_data=self.rfile.read(content_length) + request=ocsp.load_der_ocsp_request(request_data) + self.process_ocsp_request(request) + + except Exception as err: # pylint: disable=broad-except + self.send_error(404, f"{err}") + + + def process_ocsp_request(self, request: ocsp.OCSPRequest): + """Process OCSP request data""" + response=None + this_update=datetime.now(timezone.utc) + try: + issuer = self.database.get(request.issuer_key_hash) + if issuer is None: + response=ocsp.OCSPResponseBuilder.build_unsuccessful( + ocsp.OCSPResponseStatus.UNAUTHORIZED) + else: + serial=request.serial_number + subject_cert = issuer.get('certificates').get(serial) + if subject_cert is None: + response=ocsp.OCSPResponseBuilder.build_unsuccessful( + ocsp.OCSPResponseStatus.UNAUTHORIZED) + else: + ocsp_cert=issuer.get('ocsp_cert') + cert_info=issuer.get('revocations').get(serial) + revoked=cert_info is not None + if revoked: + cert_status=ocsp.OCSPCertStatus.REVOKED + else: + cert_status=ocsp.OCSPCertStatus.GOOD + + # create a OCSPResponse object + builder=ocsp.OCSPResponseBuilder() + + # add status information about the certificate that was requested + builder=builder.add_response( + cert=subject_cert, + issuer=ocsp_cert, + algorithm=request.hash_algorithm, + cert_status=cert_status, + this_update=this_update, + next_update=this_update + timedelta(seconds=60), + revocation_time=cert_info['revocation_time'] if revoked else None, + revocation_reason=ReasonFlags.unspecified if revoked else None) + + # set the responderID on the OCSP response + # encode the X.509 NAME of the certificate or HASH of the public key + builder=builder.responder_id(ocsp.OCSPResponderEncoding.NAME, ocsp_cert) + + # add OCSP nonce if present + try: + nonce = request.extensions.get_extension_for_class(OCSPNonce) + builder = builder.add_extension(nonce.value, critical=nonce.critical) + except ExtensionNotFound: + pass + + # create the SUCCESSFUL response that can then be serialized and sent + response=builder.sign(issuer.get('ocsp_key'), hashes.SHA256()) + + except Exception: # pylint: disable=broad-except + response=ocsp.OCSPResponseBuilder.build_unsuccessful( + ocsp.OCSPResponseStatus.INTERNAL_ERROR) + + self.send_response(200) + self.end_headers() + # only DER encoding is supported + self.wfile.write(response.public_bytes(serialization.Encoding.DER)) + + +class HttpServerThread(): + """HTTP server thread handler""" + + def __init__(self, cfg: Config): + self.cfg = cfg + self.server=None + self.server_thread=None + + async def start_server(self) -> (int): + """Starting HTTP server on localhost and a given port""" + tag = "start_server" + database=self.load_database() + ocsp_handler = partial(OCSPHandler, self.cfg, database) + self.server=ThreadingHTTPServer(('localhost', self.cfg.port), ocsp_handler) + self.server_thread=threading.Thread(target=self.server.serve_forever) + self.server_thread.start() + hostname, port=self.server.server_address[:2] + await self.cfg.mainq.put( + LogEvent( + etype="log", + level=10, + log=f"[{tag}] OCSP responder started, URL http://'{hostname}':'{port}'" + ) + ) + return port + + + def load_database(self): + """Create an in memory database of issuer/certificates and issuer/revocations""" + database = {} + for ca_cert, certs in [("CA_ocsp.pem", ["intermediateCA.pem"]), + ("interCA_ocsp.pem", ["server_cert.pem", "client_cert.pem", "revoked_cert.pem"])]: + path = os.path.join(DEFAULT_CERTS, ca_cert) + ocsp_cert = self.load_certificate(path) + ocsp_sha1 = ocsp_cert.extensions.get_extension_for_class( + SubjectKeyIdentifier).value.digest + database[ocsp_sha1] = {} + database[ocsp_sha1]['ocsp_cert'] = ocsp_cert + database[ocsp_sha1]['ocsp_key'] = self.load_private_key(path) + + certificates = {} + for filename in certs: + path = os.path.join(DEFAULT_CERTS, filename) + cert = self.load_certificate(path) + certificates[cert.serial_number] = cert + database[ocsp_sha1]['certificates'] = certificates + + with open(OCSP_INDEX, mode="r", encoding="utf-8") as index: + revocations = {} + for line in index.readlines(): + tokens = line.split('\t') + if tokens[0] == 'R': + certinfo = { + "revocation_time": datetime.strptime(tokens[2], "%y%m%d%H%M%S%z"), + "serial_number": int(tokens[3], 16), + } + revocations[certinfo["serial_number"]] = certinfo + database[ocsp_sha1]['revocations'] = revocations + + return database + + + def load_certificate(self, path): + """Deserialize a certificate from PEM encoded data""" + with open(path, mode="rb") as file: + return load_pem_x509_certificate(file.read()) + + + def load_private_key(self, path, password=None): + """Deserialize a private key from PEM encoded data""" + with open(path, mode="rb") as file: + return serialization.load_pem_private_key(file.read(), password) + + @contextlib.contextmanager def parse_args() -> Config: """Parse the command-line arguments.""" @@ -1683,6 +1976,14 @@ def parse_args() -> Config: help="the logging level " "(default: INFO)", ) + parser.add_argument( + "--port", + type=int, + default=DEFAULT_PORT, + metavar="PORT", + help="OCSP responder port number" + f"(default: {DEFAULT_PORT})" + ) args = parser.parse_args() utf8_env = dict(os.environ) # environment can only contain strings @@ -1711,7 +2012,8 @@ def parse_args() -> Config: utf8_env=utf8_env, results=os.path.join(args.logs, "results.log"), summary=os.path.join(args.logs, "summary.log"), - debug=args.debug + debug=args.debug, + port=args.port ) @@ -1730,7 +2032,7 @@ async def main() -> None: slogs = TestLogs(cfg) formats = "%(message)s" slogger = slogs.setup_logger("summary", formats, cfg.summary, DEFAULT_LEVEL) - except Exception as err: # pylint: disable=broad-except + except asyncio.CancelledError as err: # Logging is not available at this point. print(err) print("Framework initalization failed") @@ -1741,7 +2043,15 @@ async def main() -> None: await slogs.get_version(slogger) slogs.transcript_logs("summary", formats) + # Start OCSP responder. + responder = OcspResponder(cfg) + await responder.start_responder() + + # Check plugins. await PluginCollection(cfg, slogger, 'plugins') + + # Stop OCSP responder. + await responder.stop_responder() await cfg.mainq.put( LogEvent( etype="finish_event", @@ -1749,16 +2059,26 @@ async def main() -> None: log=f"[{tag}] Stunnel tests completed" ) ) - except UnsupportedOpenSSL as err: + + except UnsupportedVersion as err: await cfg.mainq.put( LogEvent( etype="finish_event", level=30, - log=f"[{tag}] Unsupported OpenSSL: {err}" + log=f"[{tag}] Unsupported version: {err}" ) ) print(err) - except Exception as err: # pylint: disable=broad-except + except OutputError as err: + await cfg.mainq.put( + LogEvent( + etype="finish_event", + level=50, + log=f"[{tag}] Something went wrong: {err}" + ) + ) + print(err) + except OSError as err: await cfg.mainq.put( LogEvent( etype="finish_event", diff --git a/tests/plugins/p27_ocsp.py b/tests/plugins/p27_ocsp.py new file mode 100644 index 00000000..cf5e465f --- /dev/null +++ b/tests/plugins/p27_ocsp.py @@ -0,0 +1,331 @@ +"""stunnel client-server tests""" + +import logging +import os +import pathlib +from plugin_collection import Plugin, ERR_CONN_RESET +from maketest import ( + Config, + StunnelAcceptConnect +) + + +class StunnelTest(StunnelAcceptConnect): + """Base class for stunnel client-server tests.""" + # pylint: disable=too-few-public-methods + + def __init__(self, cfg: Config, logger: logging.Logger): + super().__init__(cfg, logger) + self.params.services = ['server', 'client'] + + +class VerifyOCSPStapling(StunnelTest): + """ Checking OCSP stapling certificate verification. + OCSP stapling is always available in the server mode. + Using "verifyChain" automatically enables OCSP stapling in the client mode. + The success is expected because the server presents a valid certificate. + """ + + def __init__(self, cfg: Config, logger: logging.Logger): + super().__init__(cfg, logger) + self.params.description = '271. Test OCSP stapling' + self.events.count = 1 + self.events.success = [ + r"OCSP: Accepted \(good\)" + ] + self.events.failure = [ + "peer did not return a certificate", + "bad certificate", + "certificate verify failed", + "unsupported protocol", + "TLS accepted: previous session reused", + "Redirecting connection", + ERR_CONN_RESET, + "Connection lost", + "Client received unexpected message", + "Server received unexpected message", + "Something went wrong", + "INTERNAL ERROR" + ] + + + async def prepare_client_cfgfile( + self, cfg: Config, ports: list, service: str + ) -> (pathlib.Path, pathlib.Path): + """Create a configuration file for a stunnel client.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + client = yes + accept = 127.0.0.1:0 + connect = 127.0.0.1:{ports[1]} + CAfile = {cfg.certdir}/CACert.pem + verifyChain = yes + """ + cfgfile = cfg.tempd / "stunnel_client.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile, os.devnull + + + async def prepare_server_cfgfile( + self, cfg: Config, port: int, service: str + ) -> pathlib.Path: + """Create a configuration file for a stunnel server.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + accept = 127.0.0.1:0 + connect = 127.0.0.1:{port} + cert = {cfg.certdir}/server_cert.pem + """ + cfgfile = cfg.tempd / "stunnel_server.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile + + +class VerifyOCSPClientDriven(StunnelTest): + """ Checking OCSP stapling certificate verification. + Using "OCSPaia" enables stunnel to validate certificates with the list of OCSP + responder URLs retrieved from their AIA (Authority Information Access) extension. + The success is expected because the client presents a valid certificate. + """ + + def __init__(self, cfg: Config, logger: logging.Logger): + super().__init__(cfg, logger) + self.params.description = '272. Test OCSP client-driven' + self.events.count = 1 + self.events.success = [ + r"OCSP: Accepted \(good\)" + ] + self.events.failure = [ + "peer did not return a certificate", + "bad certificate", + "certificate verify failed", + "unsupported protocol", + "TLS accepted: previous session reused", + "Redirecting connection", + ERR_CONN_RESET, + "Connection lost", + "Client received unexpected message", + "Server received unexpected message", + "Something went wrong", + "INTERNAL ERROR" + ] + + + async def prepare_client_cfgfile( + self, cfg: Config, ports: list, service: str + ) -> (pathlib.Path, pathlib.Path): + """Create a configuration file for a stunnel client.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + client = yes + accept = 127.0.0.1:0 + connect = 127.0.0.1:{ports[1]} + cert = {cfg.certdir}/client_cert.pem + """ + cfgfile = cfg.tempd / "stunnel_client.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile, os.devnull + + + async def prepare_server_cfgfile( + self, cfg: Config, port: int, service: str + ) -> pathlib.Path: + """Create a configuration file for a stunnel server.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + accept = 127.0.0.1:0 + connect = 127.0.0.1:{port} + cert = {cfg.certdir}/server_cert.pem + CAfile = {cfg.certdir}/CACert.pem + verifyChain = yes + OCSPaia = yes + """ + cfgfile = cfg.tempd / "stunnel_server.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile + + +class FailureVerifyOCSPStapling(StunnelTest): + """ Checking OCSP stapling certificate verification. + OCSP stapling is always available in the server mode. + Using "verifyChain" automatically enables OCSP stapling in the client mode. + The failure is expected because the server presents a revoked certificate. + """ + + def __init__(self, cfg: Config, logger: logging.Logger): + super().__init__(cfg, logger) + self.params.description = '273. Failure test OCSP stapling' + self.events.count = 1 + self.events.success = [ + r"OCSP: Rejected \(revoked\)" + ] + self.events.failure = [ + "peer did not return a certificate", + #"bad certificate", + "certificate verify failed", + "unsupported protocol", + "TLS accepted: previous session reused", + "Redirecting connection", + #ERR_CONN_RESET, + "Connection lost", + "Client received unexpected message", + "Server received unexpected message", + "Something went wrong", + "INTERNAL ERROR" + ] + + + async def prepare_client_cfgfile( + self, cfg: Config, ports: list, service: str + ) -> (pathlib.Path, pathlib.Path): + """Create a configuration file for a stunnel client.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + client = yes + accept = 127.0.0.1:0 + connect = 127.0.0.1:{ports[1]} + CAfile = {cfg.certdir}/CACert.pem + verifyChain = yes + """ + cfgfile = cfg.tempd / "stunnel_client.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile, os.devnull + + + async def prepare_server_cfgfile( + self, cfg: Config, port: int, service: str + ) -> pathlib.Path: + """Create a configuration file for a stunnel server.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + + [{service}] + accept = 127.0.0.1:0 + connect = 127.0.0.1:{port} + cert = {cfg.certdir}/revoked_cert.pem + """ + cfgfile = cfg.tempd / "stunnel_server.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile + + +class FailureVerifyOCSPClientDriven(StunnelTest): + """ Checking OCSP stapling certificate verification. + Using "OCSPaia" enables stunnel to validate certificates with the list of OCSP + responder URLs retrieved from their AIA (Authority Information Access) extension. + The failure is expected because client presents a revoked certificate. + """ + + def __init__(self, cfg: Config, logger: logging.Logger): + super().__init__(cfg, logger) + self.params.description = '274. Failure test OCSP client-driven' + self.events.count = 1 + self.events.success = [ + "Rejected by OCSP at depth=0" + ] + self.events.failure = [ + "peer did not return a certificate", + "bad certificate", + #"certificate verify failed", + "unsupported protocol", + "TLS accepted: previous session reused", + "Redirecting connection", + #ERR_CONN_RESET, + "Connection lost", + "Client received unexpected message", + "Server received unexpected message", + "Something went wrong", + "INTERNAL ERROR" + ] + + + async def prepare_client_cfgfile( + self, cfg: Config, ports: list, service: str + ) -> (pathlib.Path, pathlib.Path): + """Create a configuration file for a stunnel client.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + [{service}] + client = yes + accept = 127.0.0.1:0 + connect = 127.0.0.1:{ports[1]} + cert = {cfg.certdir}/revoked_cert.pem + """ + cfgfile = cfg.tempd / "stunnel_client.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile, os.devnull + + + async def prepare_server_cfgfile( + self, cfg: Config, port: int, service: str + ) -> pathlib.Path: + """Create a configuration file for a stunnel server.""" + contents = f""" + foreground = yes + debug = debug + syslog = no + + + [{service}] + accept = 127.0.0.1:0 + connect = 127.0.0.1:{port} + cert = {cfg.certdir}/server_cert.pem + CAfile = {cfg.certdir}/CACert.pem + verifyChain = yes + OCSPaia = yes + """ + cfgfile = cfg.tempd / "stunnel_server.conf" + cfgfile.write_text(contents, encoding="UTF-8") + return cfgfile + + +class StunnelClientServerTest(Plugin): + """Stunnel client-server tests + HTTP client --> stunnel client --> stunnel server --> HTTP server + """ + # pylint: disable=too-few-public-methods + + def __init__(self): + super().__init__() + self.description = 'OCSP certificate verification' + + + async def perform_operation(self, cfg: Config, logger: logging.Logger) -> None: + """Run tests""" + stunnel = VerifyOCSPStapling(cfg, logger) + await stunnel.test_stunnel(cfg) + + stunnel = VerifyOCSPClientDriven(cfg, logger) + await stunnel.test_stunnel(cfg) + + stunnel = FailureVerifyOCSPStapling(cfg, logger) + await stunnel.test_stunnel(cfg) + + stunnel = FailureVerifyOCSPClientDriven(cfg, logger) + await stunnel.test_stunnel(cfg) diff --git a/tools/Makefile.am b/tools/Makefile.am index 8de355a1..c38c8ee2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,7 +4,7 @@ EXTRA_DIST = ca.html ca.pl importCA.html importCA.sh script.sh makecert.sh EXTRA_DIST += openssl.cnf stunnel.nsi ReplaceInFile3.nsh stunnel.license stunnel.conf EXTRA_DIST += stunnel.conf-sample.in stunnel.init.in stunnel.service.in -EXTRA_DIST += stunnel.logrotate stunnel.rh.init stunnel.spec +EXTRA_DIST += stunnel.logrotate stunnel.rh.init stunnel.spec.in EXTRA_DIST += ca-certs.pem confdir = $(sysconfdir)/stunnel @@ -20,7 +20,7 @@ examples_DATA += ca.html ca.pl importCA.html importCA.sh script.sh bashcompdir = @bashcompdir@ dist_bashcomp_DATA = stunnel.bash -CLEANFILES = stunnel.conf-sample stunnel.init stunnel.service +CLEANFILES = stunnel.conf-sample stunnel.init stunnel.service stunnel.spec install-data-local: ${INSTALL} -d -m 1770 $(DESTDIR)$(localstatedir)/lib/stunnel @@ -36,11 +36,13 @@ edit = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ - -e 's|@DEFAULT_GROUP[@]|$(DEFAULT_GROUP)|g' + -e 's|@DEFAULT_GROUP[@]|$(DEFAULT_GROUP)|g' \ + -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' -stunnel.conf-sample stunnel.init stunnel.service: Makefile +stunnel.conf-sample stunnel.init stunnel.service stunnel.spec: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel.conf-sample: $(srcdir)/stunnel.conf-sample.in stunnel.init: $(srcdir)/stunnel.init.in stunnel.service: $(srcdir)/stunnel.service.in +stunnel.spec: $(srcdir)/stunnel.spec.in diff --git a/tools/Makefile.in b/tools/Makefile.in index dc5c60dc..113ddda6 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -291,7 +291,7 @@ EXTRA_DIST = ca.html ca.pl importCA.html importCA.sh script.sh \ makecert.sh openssl.cnf stunnel.nsi ReplaceInFile3.nsh \ stunnel.license stunnel.conf stunnel.conf-sample.in \ stunnel.init.in stunnel.service.in stunnel.logrotate \ - stunnel.rh.init stunnel.spec ca-certs.pem + stunnel.rh.init stunnel.spec.in ca-certs.pem confdir = $(sysconfdir)/stunnel conf_DATA = stunnel.conf-sample examplesdir = $(docdir)/examples @@ -299,13 +299,14 @@ examples_DATA = stunnel.init stunnel.service stunnel.logrotate \ stunnel.rh.init stunnel.spec ca.html ca.pl importCA.html \ importCA.sh script.sh dist_bashcomp_DATA = stunnel.bash -CLEANFILES = stunnel.conf-sample stunnel.init stunnel.service +CLEANFILES = stunnel.conf-sample stunnel.init stunnel.service stunnel.spec edit = sed \ -e 's|@prefix[@]|$(prefix)|g' \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ - -e 's|@DEFAULT_GROUP[@]|$(DEFAULT_GROUP)|g' + -e 's|@DEFAULT_GROUP[@]|$(DEFAULT_GROUP)|g' \ + -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' all: all-am @@ -582,12 +583,13 @@ cert: ${INSTALL} -b -m 600 stunnel.pem $(DESTDIR)$(confdir)/stunnel.pem rm -f stunnel.pem -stunnel.conf-sample stunnel.init stunnel.service: Makefile +stunnel.conf-sample stunnel.init stunnel.service stunnel.spec: Makefile $(edit) '$(srcdir)/$@.in' >$@ stunnel.conf-sample: $(srcdir)/stunnel.conf-sample.in stunnel.init: $(srcdir)/stunnel.init.in stunnel.service: $(srcdir)/stunnel.service.in +stunnel.spec: $(srcdir)/stunnel.spec.in # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/tools/ca-certs.pem b/tools/ca-certs.pem index b8e579c8..73fadfae 100644 --- a/tools/ca-certs.pem +++ b/tools/ca-certs.pem @@ -1,4 +1,109 @@ -----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM +MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx +MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 +MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD +QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z +4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv +Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ +kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs +GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln +nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh +3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD +0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy +geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 +ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB +c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI +pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs +o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ +qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw +xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM +rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 +AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR +0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY +o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 +dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE +oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w +LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w +CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 +MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF +Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X +tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 +AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 +KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD +aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu +CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo +9H1/IISpQuQo +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN +MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG +A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC +WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ +6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B +Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa +qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q +4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg @@ -711,42 +816,6 @@ W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV -BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC -aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV -BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 -Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz -MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ -BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp -em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN -ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY -B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH -D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF -Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo -q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D -k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH -fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut -dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM -ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 -zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn -rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX -U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 -Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 -XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF -Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR -HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY -GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c -77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 -+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK -vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 -FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl -yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P -AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD -y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d -NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG @@ -931,26 +1000,6 @@ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx -FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg -Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG -A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr -b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ -jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn -PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh -ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 -nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h -q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED -MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC -mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 -7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB -oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs -EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO -fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi -AmvZWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G @@ -1091,57 +1140,6 @@ DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQEL -BQAwgYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUt -VHVncmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYw -JAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIFJTQSB2MzAeFw0yMDAzMTgw -OTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMG -QW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1 -Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBD -QSBSU0EgdjMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J7 -7gnJY9LTQ91ew6aEOErxjYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscx -uj7X/iWpKo429NEvx7epXTPcMHD4QGxLsqYxYdE0PD0xesevxKenhOGXpOhL9hd8 -7jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF/YP9f4RtNGx/ardLAQO/ -rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8qQedmCeFL -l+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bG -wzrwbMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4 -znKS4iicvObpCdg604nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBO -M/J+JjKsBY04pOZ2PJ8QaQ5tndLBeSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK -5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiMbIedBi3x7+PmBvrFZhNb/FAH -nnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbgh3cXTJ2w2Amo -DVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSy -tK7mLfcm1ap1LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEL -BQADggIBAImocn+M684uGMQQgC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ -6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN438o2Fi+CiJ+8EUdPdk3ILY7r3y18 -Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/qln0F7psTpURs+APQ -3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3sSdPk -vmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn9 -9t2HVhjYsCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQ -mhty3QUBjYZgv6Rn7rWlDdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YA -VSgU7NbHEqIbZULpkejLPoeJVF3Zr52XnGnnCv8PWniLYypMfUeUP95L6VPQMPHF -9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFHIK+WEj5jlB0E5y67hscM -moi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiXYY60MGo8 -bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMw -gYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVn -cmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYD -VQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIEVDQyB2MzAeFw0yMDAzMTgwOTQ2 -NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMGQW5r -YXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1Z3Jh -IFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBF -Q0MgdjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQ -KczLWYHMjLiSF4mDKpL2w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YK -fWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMB -Af8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQzPUwHQYDVR0OBBYEFP+C -MXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNp -ADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/6 -7W4WAie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFx -vmjkI6TZraE3 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 @@ -3561,3 +3559,35 @@ BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 DXZDjC5Ty3zfDBeWUA== -----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- diff --git a/tools/stunnel.spec b/tools/stunnel.spec.in similarity index 99% rename from tools/stunnel.spec rename to tools/stunnel.spec.in index e6f65572..56db208e 100644 --- a/tools/stunnel.spec +++ b/tools/stunnel.spec.in @@ -1,5 +1,5 @@ Name: stunnel -Version: 5.70 +Version: @PACKAGE_VERSION@ Release: 1%{?dist} Summary: An TLS-encrypting socket wrapper Group: Applications/Internet