diff --git a/04_workaround_as_needed_bug.patch b/04_workaround_as_needed_bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..00fa7f7648e88c9947323a409b8547e7339557bc --- /dev/null +++ b/04_workaround_as_needed_bug.patch @@ -0,0 +1,38 @@ +Description: Work around libtool --as-needed reordering bug +Origin: vendor +Bug-Debian: http://bugs.debian.org/347650 +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2016-08-03 + +--- a/ltmain.sh ++++ b/ltmain.sh +@@ -7312,6 +7312,11 @@ + arg=$func_stripname_result + ;; + ++ -Wl,--as-needed|-Wl,--no-as-needed) ++ deplibs="$arg $deplibs" ++ continue ++ ;; ++ + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result +@@ -7703,6 +7708,15 @@ + lib= + found=false + case $deplib in ++ -Wl,--as-needed|-Wl,--no-as-needed) ++ if test "$linkmode,$pass" = "prog,link"; then ++ compile_deplibs="$deplib $compile_deplibs" ++ finalize_deplibs="$deplib $finalize_deplibs" ++ else ++ deplibs="$deplib $deplibs" ++ fi ++ continue ++ ;; + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then diff --git a/06_always-disable-valgrind.patch b/06_always-disable-valgrind.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b8dbca3cbb23767a8b0aadd25c5f83301bc27c8 --- /dev/null +++ b/06_always-disable-valgrind.patch @@ -0,0 +1,17 @@ +Description: Always disable valgrind tests +Origin: vendor +Bug-Debian: http://bugs.debian.org/690968 +Forwarded: not-needed +Last-Update: 2012-10-22 + +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -68,7 +68,7 @@ + if CROSSCOMPILING + TEST = @echo "NOTICE: we can't run the tests when cross-compiling!" + else # if not cross-compiling: +-TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl ++TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -n + TEST_Q = -a -s + TEST_AM = -a -am + TEST_F = -a -p -r diff --git a/07_do-not-disable-debug-symbols.patch b/07_do-not-disable-debug-symbols.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3b179c45ff74f1b7dea893e604d1f43c332c764 --- /dev/null +++ b/07_do-not-disable-debug-symbols.patch @@ -0,0 +1,98 @@ +Description: Do not disable debug symbols without --enable-debug +Origin: vendor +Bug-Debian: http://bugs.debian.org/693110 +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2012-11-16 + +--- a/m4/curl-compilers.m4 ++++ b/m4/curl-compilers.m4 +@@ -115,7 +115,6 @@ + flags_dbg_all="$flags_dbg_all -gdwarf-2" + flags_dbg_all="$flags_dbg_all -gvms" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -Os -O3 -O4" + flags_opt_yes="-Os" + flags_opt_off="-O0" +@@ -139,7 +138,6 @@ + compiler_id="DEC_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g2" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4" + flags_opt_yes="-O1" + flags_opt_off="-O0" +@@ -175,7 +173,6 @@ + flags_dbg_all="$flags_dbg_all -gdwarf-2" + flags_dbg_all="$flags_dbg_all -gvms" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os -Og -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -220,7 +217,6 @@ + compiler_id="IBM_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4 -O5" + flags_opt_all="$flags_opt_all -qnooptimize" + flags_opt_all="$flags_opt_all -qoptimize=0" +@@ -254,7 +250,6 @@ + compiler_id="INTEL_UNIX_C" + flags_dbg_all="-g -g0" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -292,7 +287,6 @@ + compiler_id="LCC" + flags_dbg_all="-g" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" +@@ -318,7 +312,6 @@ + compiler_id="SGI_MIPS_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -345,7 +338,6 @@ + compiler_id="SGI_MIPSPRO_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -389,7 +381,6 @@ + compiler_id="TINY_C" + flags_dbg_all="-g -b" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" +@@ -413,7 +404,6 @@ + compiler_id="WATCOM_UNIX_C" + flags_dbg_all="-g1 -g1+ -g2 -g3" + flags_dbg_yes="-g2" +- flags_dbg_off="" + flags_opt_all="-O0 -O1 -O2 -O3" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -421,7 +411,6 @@ + compiler_id="WATCOM_WINDOWS_C" + flags_dbg_all="" + flags_dbg_yes="" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" diff --git a/08_enable-zsh.patch b/08_enable-zsh.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a85e380afe316783857ebd576d1bf25b5718867 --- /dev/null +++ b/08_enable-zsh.patch @@ -0,0 +1,20 @@ +Description: Enable zsh completion generation +Origin: vendor +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2016-08-03 + +--- a/Makefile.am ++++ b/Makefile.am +@@ -178,8 +178,8 @@ + + bin_SCRIPTS = curl-config + +-SUBDIRS = lib src +-DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs ++SUBDIRS = lib src scripts ++DIST_SUBDIRS = $(SUBDIRS) tests packages include docs + + pkgconfigdir = $(libdir)/pkgconfig + pkgconfig_DATA = libcurl.pc diff --git a/11_omit-directories-from-config.patch b/11_omit-directories-from-config.patch new file mode 100644 index 0000000000000000000000000000000000000000..59940faea80cefbe6c36271563044ab325b09797 --- /dev/null +++ b/11_omit-directories-from-config.patch @@ -0,0 +1,53 @@ +Description: In order to (partially) multi-arch-ify curl-config, remove all + mention of @includedir@ and @libdir@ from the script. On Debian, the actual + header and library directories are architecture-dependent, but will always be + in the C compiler's default search path, so -I and -L options are not + necessary (and may be harmful in multi-arch environments.) +Origin: vendor +Bug-Debian: http://bugs.debian.org/731998 +Forwarded: not-needed +Author: Benjamin Moody +Reviewed-by: Alessandro Ghedini +Last-Update: 2017-01-10 + +--- a/curl-config.in ++++ b/curl-config.in +@@ -23,7 +23,6 @@ + + prefix=@prefix@ + exec_prefix=@exec_prefix@ +-includedir=@includedir@ + cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@ + + usage() +@@ -147,19 +146,11 @@ + else + CPPFLAG_CURL_STATICLIB="" + fi +- if test "X@includedir@" = "X/usr/include"; then +- echo "$CPPFLAG_CURL_STATICLIB" +- else +- echo "${CPPFLAG_CURL_STATICLIB}-I@includedir@" +- fi ++ echo "$CPPFLAG_CURL_STATICLIB" + ;; + + --libs) +- if test "X@libdir@" != "X/usr/lib" -a "X@libdir@" != "X/usr/lib64"; then +- CURLLIBDIR="-L@libdir@ " +- else +- CURLLIBDIR="" +- fi ++ CURLLIBDIR="" + if test "X@REQUIRE_LIB_DEPS@" = "Xyes"; then + echo ${CURLLIBDIR}-lcurl @LIBCURL_LIBS@ + else +@@ -172,7 +163,7 @@ + + --static-libs) + if test "X@ENABLE_STATIC@" != "Xno" ; then +- echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ ++ echo -Wl,-Bstatic -lcurl -Wl,-Bdynamic @LDFLAGS@ @LIBCURL_LIBS@ + else + echo "curl was built with static libraries disabled" >&2 + exit 1 diff --git a/90_gnutls.patch b/90_gnutls.patch new file mode 100644 index 0000000000000000000000000000000000000000..372a3786df47444c4e647705191c9b188c4798ce --- /dev/null +++ b/90_gnutls.patch @@ -0,0 +1,142 @@ +Description: Build with GnuTLS. +Origin: vendor +Forwarded: not-needed +Author: Ramakrishnan Muthukrishnan +Reviewed-by: Alessandro Ghedini +Last-Update: 2018-05-23 + +--- a/docs/examples/Makefile.am ++++ b/docs/examples/Makefile.am +@@ -48,9 +48,9 @@ + + # Dependencies + if USE_EXPLICIT_LIB_DEPS +-LDADD = $(LIBDIR)/libcurl.la @LIBCURL_LIBS@ ++LDADD = $(LIBDIR)/libcurl-gnutls.la @LIBCURL_LIBS@ + else +-LDADD = $(LIBDIR)/libcurl.la ++LDADD = $(LIBDIR)/libcurl-gnutls.la + endif + + # This might hold -Werror +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -31,7 +31,7 @@ + config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ + firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl + +-lib_LTLIBRARIES = libcurl.la ++lib_LTLIBRARIES = libcurl-gnutls.la + + if BUILD_UNITTESTS + noinst_LTLIBRARIES = libcurlu.la +@@ -83,43 +83,43 @@ + AM_LDFLAGS = + AM_CFLAGS = + +-libcurl_la_CPPFLAGS_EXTRA = +-libcurl_la_LDFLAGS_EXTRA = +-libcurl_la_CFLAGS_EXTRA = ++libcurl_gnutls_la_CPPFLAGS_EXTRA = ++libcurl_gnutls_la_LDFLAGS_EXTRA = ++libcurl_gnutls_la_CFLAGS_EXTRA = + + if CURL_LT_SHLIB_USE_VERSION_INFO +-libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) ++libcurl_gnutls_la_LDFLAGS_EXTRA += $(VERSIONINFO) + endif + + if CURL_LT_SHLIB_USE_NO_UNDEFINED +-libcurl_la_LDFLAGS_EXTRA += -no-undefined ++libcurl_gnutls_la_LDFLAGS_EXTRA += -no-undefined + endif + + if CURL_LT_SHLIB_USE_MIMPURE_TEXT +-libcurl_la_LDFLAGS_EXTRA += -mimpure-text ++libcurl_gnutls_la_LDFLAGS_EXTRA += -mimpure-text + endif + + if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +-libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers ++libcurl_gnutls_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers + else + # if symbol-hiding is enabled, hide them! + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' ++libcurl_gnutls_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' + endif + endif + + if USE_CPPFLAG_CURL_STATICLIB +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB ++libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + endif + + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +-libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) ++libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS ++libcurl_gnutls_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) + endif + +-libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) +-libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) +-libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) ++libcurl_gnutls_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_gnutls_la_CPPFLAGS_EXTRA) ++libcurl_gnutls_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_gnutls_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) ++libcurl_gnutls_la_CFLAGS = $(AM_CFLAGS) $(libcurl_gnutls_la_CFLAGS_EXTRA) + + libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS + libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +@@ -128,7 +128,7 @@ + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_gnutls_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) + + CHECKSRC = $(CS_$(V)) +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -61,9 +61,9 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ + else +-curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ + endif + + curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ +--- a/tests/libtest/Makefile.am ++++ b/tests/libtest/Makefile.am +@@ -57,11 +57,11 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ + else +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + endif + + # Dependencies (may need to be overridden) +--- a/lib/libcurl.vers.in ++++ b/lib/libcurl.vers.in +@@ -6,7 +6,7 @@ + _save*; + }; + +-CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4 ++CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@3 + { + global: curl_*; + local: *; diff --git a/99_nss.patch b/99_nss.patch new file mode 100644 index 0000000000000000000000000000000000000000..b35f24666495c33887120ba69b45c86b1f8f6113 --- /dev/null +++ b/99_nss.patch @@ -0,0 +1,131 @@ +Description: Build with NSS. +Origin: vendor +Forwarded: not-needed +Author: Ramakrishnan Muthukrishnan +Reviewed-by: Alessandro Ghedini +Last-Update: 2015-08-12 + +--- a/docs/examples/Makefile.am ++++ b/docs/examples/Makefile.am +@@ -48,9 +48,9 @@ + + # Dependencies + if USE_EXPLICIT_LIB_DEPS +-LDADD = $(LIBDIR)/libcurl-gnutls.la @LIBCURL_LIBS@ ++LDADD = $(LIBDIR)/libcurl-nss.la @LIBCURL_LIBS@ + else +-LDADD = $(LIBDIR)/libcurl-gnutls.la ++LDADD = $(LIBDIR)/libcurl-nss.la + endif + + # This might hold -Werror +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -31,7 +31,7 @@ + config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ + firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl + +-lib_LTLIBRARIES = libcurl-gnutls.la ++lib_LTLIBRARIES = libcurl-nss.la + + if BUILD_UNITTESTS + noinst_LTLIBRARIES = libcurlu.la +@@ -83,43 +83,43 @@ + AM_LDFLAGS = + AM_CFLAGS = + +-libcurl_gnutls_la_CPPFLAGS_EXTRA = +-libcurl_gnutls_la_LDFLAGS_EXTRA = +-libcurl_gnutls_la_CFLAGS_EXTRA = ++libcurl_nss_la_CPPFLAGS_EXTRA = ++libcurl_nss_la_LDFLAGS_EXTRA = ++libcurl_nss_la_CFLAGS_EXTRA = + + if CURL_LT_SHLIB_USE_VERSION_INFO +-libcurl_gnutls_la_LDFLAGS_EXTRA += $(VERSIONINFO) ++libcurl_nss_la_LDFLAGS_EXTRA += $(VERSIONINFO) + endif + + if CURL_LT_SHLIB_USE_NO_UNDEFINED +-libcurl_gnutls_la_LDFLAGS_EXTRA += -no-undefined ++libcurl_nss_la_LDFLAGS_EXTRA += -no-undefined + endif + + if CURL_LT_SHLIB_USE_MIMPURE_TEXT +-libcurl_gnutls_la_LDFLAGS_EXTRA += -mimpure-text ++libcurl_nss_la_LDFLAGS_EXTRA += -mimpure-text + endif + + if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +-libcurl_gnutls_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers ++libcurl_nss_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers + else + # if symbol-hiding is enabled, hide them! + if DOING_CURL_SYMBOL_HIDING +-libcurl_gnutls_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' ++libcurl_nss_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' + endif + endif + + if USE_CPPFLAG_CURL_STATICLIB +-libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB ++libcurl_nss_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + endif + + if DOING_CURL_SYMBOL_HIDING +-libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +-libcurl_gnutls_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) ++libcurl_nss_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS ++libcurl_nss_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) + endif + +-libcurl_gnutls_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_gnutls_la_CPPFLAGS_EXTRA) +-libcurl_gnutls_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_gnutls_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) +-libcurl_gnutls_la_CFLAGS = $(AM_CFLAGS) $(libcurl_gnutls_la_CFLAGS_EXTRA) ++libcurl_nss_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_nss_la_CPPFLAGS_EXTRA) ++libcurl_nss_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_nss_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) ++libcurl_nss_la_CFLAGS = $(AM_CFLAGS) $(libcurl_nss_la_CFLAGS_EXTRA) + + libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS + libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +@@ -128,7 +128,7 @@ + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_gnutls_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_nss_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) + + CHECKSRC = $(CS_$(V)) +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -61,9 +61,9 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-nss.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ + else +-curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-nss.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ + endif + + curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ +--- a/tests/libtest/Makefile.am ++++ b/tests/libtest/Makefile.am +@@ -57,11 +57,11 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-nss.la @LIBCURL_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-nss.la @LIBCURL_LIBS@ + else +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-nss.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-nss.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + endif + + # Dependencies (may need to be overridden) diff --git a/CVE-2020-8169.patch b/CVE-2020-8169.patch new file mode 100644 index 0000000000000000000000000000000000000000..c07409b20d320473fa5d55b01b0f23e1c483dc33 --- /dev/null +++ b/CVE-2020-8169.patch @@ -0,0 +1,130 @@ +Backport of: + +From 600a8cded447cd7118ed50142c576567c0cf5158 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 14 May 2020 14:37:12 +0200 +Subject: [PATCH] url: make the updated credentials URL-encoded in the URL + +Found-by: Gregory Jefferis +Reported-by: Jeroen Ooms +Added test 1168 to verify. Bug spotted when doing a redirect. +Bug: https://github.com/jeroen/curl/issues/224 +Closes #5400 +--- + lib/url.c | 6 ++-- + tests/data/Makefile.inc | 1 + + tests/data/test1168 | 78 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 83 insertions(+), 2 deletions(-) + create mode 100644 tests/data/test1168 + +--- a/lib/url.c ++++ b/lib/url.c +@@ -2733,12 +2733,14 @@ static CURLcode override_login(struct Cu + + /* for updated strings, we update them in the URL */ + if(user_changed) { +- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0); ++ uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, ++ CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + } + if(passwd_changed) { +- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0); ++ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, ++ CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + } +--- /dev/null ++++ b/tests/data/test1168 +@@ -0,0 +1,78 @@ ++ ++ ++ ++HTTP ++HTTP GET ++followlocation ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 301 This is a weirdo text message swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Location: /data/11680002.txt ++Connection: close ++ ++This server reply is for testing a simple Location: following ++ ++ ++ ++HTTP/1.1 200 Followed here fine swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 52 ++ ++If this is received, the location following worked ++ ++ ++ ++HTTP/1.1 301 This is a weirdo text message swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Location: /data/11680002.txt ++Connection: close ++ ++HTTP/1.1 200 Followed here fine swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 52 ++ ++If this is received, the location following worked ++ ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++HTTP redirect with credentials using # in user and password ++ ++ ++http://%HOSTIP:%HTTPPORT/want/1168 -L -u "catmai#d:#DZaRJYrixKE*gFY" ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET /want/1168 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ== ++Accept: */* ++ ++GET /data/11680002.txt HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ== ++Accept: */* ++ ++ ++ ++ +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -131,7 +131,7 @@ test1128 test1129 test1130 test1131 test + test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \ + test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \ + test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \ +-test1160 test1161 test1162 test1163 test1164 test1165 test1166 \ ++test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1168 \ + test1170 test1171 test1172 test1173 test1174 test1175 \ + \ + test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ diff --git a/CVE-2020-8177.patch b/CVE-2020-8177.patch new file mode 100644 index 0000000000000000000000000000000000000000..da0895036bc29ccd64fd622fb47b3a13de01c268 --- /dev/null +++ b/CVE-2020-8177.patch @@ -0,0 +1,60 @@ +Backport of: + +From 3b884d1cc588c6cfede9d2f124d43c93e93226e8 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sun, 31 May 2020 23:09:59 +0200 +Subject: [PATCH] tool_getparam: -i is not OK if -J is used + +Reported-by: sn on hackerone +Bug: https://curl.haxx.se/docs/CVE-2020-8177.html +--- + src/tool_cb_hdr.c | 22 ++++------------------ + src/tool_getparam.c | 5 +++++ + 2 files changed, 9 insertions(+), 18 deletions(-) + +--- a/src/tool_cb_hdr.c ++++ b/src/tool_cb_hdr.c +@@ -188,25 +188,11 @@ size_t tool_header_cb(char *ptr, size_t + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { +- int rc; +- /* already opened and possibly written to */ +- if(outs->fopened) +- fclose(outs->stream); +- outs->stream = NULL; +- +- /* rename the initial file name to the new file name */ +- rc = rename(outs->filename, filename); +- if(rc != 0) { +- warnf(outs->config->global, "Failed to rename %s -> %s: %s\n", +- outs->filename, filename, strerror(errno)); +- } +- if(outs->alloc_filename) +- Curl_safefree(outs->filename); +- if(rc != 0) { +- free(filename); +- return failure; +- } ++ /* indication of problem, get out! */ ++ free(filename); ++ return failure; + } ++ + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; +--- a/src/tool_getparam.c ++++ b/src/tool_getparam.c +@@ -1800,6 +1800,11 @@ ParameterError getparameter(const char * + } + break; + case 'i': ++ if(config->content_disposition) { ++ warnf(global, ++ "--include and --remote-header-name cannot be combined.\n"); ++ return PARAM_BAD_USE; ++ } + config->show_headers = toggle; /* show the headers as well in the + general output stream */ + break; diff --git a/CVE-2020-8231.patch b/CVE-2020-8231.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff94b178dc0db113f2d03c004942d82d5008b6e --- /dev/null +++ b/CVE-2020-8231.patch @@ -0,0 +1,128 @@ +Backport of: + +From 8c899c70575126151628b1455429cdb7224894fc Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 3 Aug 2020 14:54:13 +0200 +Subject: [PATCH] Curl_easy: remember last connection by id, not by pointer + +CVE-2020-8231 + +Bug: https://curl.haxx.se/docs/CVE-2020-8231.html + +Reported-by: Marc Aldorasi +--- + lib/connect.c | 19 ++++++++++--------- + lib/easy.c | 3 +-- + lib/multi.c | 10 ++++++---- + lib/url.c | 2 +- + lib/urldata.h | 2 +- + 5 files changed, 19 insertions(+), 17 deletions(-) + +--- a/lib/connect.c ++++ b/lib/connect.c +@@ -1336,15 +1336,15 @@ CURLcode Curl_connecthost(struct connect + } + + struct connfind { +- struct connectdata *tofind; +- bool found; ++ long id_tofind; ++ struct connectdata *found; + }; + + static int conn_is_conn(struct connectdata *conn, void *param) + { + struct connfind *f = (struct connfind *)param; +- if(conn == f->tofind) { +- f->found = TRUE; ++ if(conn->connection_id == f->id_tofind) { ++ f->found = conn; + return 1; + } + return 0; +@@ -1366,21 +1366,22 @@ curl_socket_t Curl_getconnectinfo(struct + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ +- if(data->state.lastconnect && (data->multi_easy || data->multi)) { +- struct connectdata *c = data->state.lastconnect; ++ if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) { ++ struct connectdata *c; + struct connfind find; +- find.tofind = data->state.lastconnect; +- find.found = FALSE; ++ find.id_tofind = data->state.lastconnect_id; ++ find.found = NULL; + + Curl_conncache_foreach(data, data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); + + if(!find.found) { +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + return CURL_SOCKET_BAD; + } + ++ c = find.found; + if(connp) { + /* only store this if the caller cares for it */ + *connp = c; +--- a/lib/easy.c ++++ b/lib/easy.c +@@ -832,8 +832,7 @@ struct Curl_easy *curl_easy_duphandle(st + + /* the connection cache is setup on demand */ + outcurl->state.conn_cache = NULL; +- +- outcurl->state.lastconnect = NULL; ++ outcurl->state.lastconnect_id = -1; + + outcurl->progress.flags = data->progress.flags; + outcurl->progress.callback = data->progress.callback; +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -451,6 +451,7 @@ CURLMcode curl_multi_add_handle(struct C + data->state.conn_cache = &data->share->conn_cache; + else + data->state.conn_cache = &multi->conn_cache; ++ data->state.lastconnect_id = -1; + + #ifdef USE_LIBPSL + /* Do the same for PSL. */ +@@ -663,11 +664,11 @@ static CURLcode multi_done(struct Curl_e + CONN_UNLOCK(data); + if(Curl_conncache_return_conn(data, conn)) { + /* remember the most recently used connection */ +- data->state.lastconnect = conn; ++ data->state.lastconnect_id = conn->connection_id; + infof(data, "%s\n", buffer); + } + else +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + } + + Curl_free_request_state(data); +--- a/lib/url.c ++++ b/lib/url.c +@@ -618,7 +618,7 @@ CURLcode Curl_open(struct Curl_easy **cu + Curl_initinfo(data); + + /* most recent connection is not yet defined */ +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1301,7 +1301,7 @@ struct UrlState { + /* buffers to store authentication data in, as parsed from input options */ + struct curltime keeps_speed; /* for the progress meter really */ + +- struct connectdata *lastconnect; /* The last connection, NULL if undefined */ ++ long lastconnect_id; /* The last connection, -1 if undefined */ + + char *headerbuff; /* allocated buffer to store headers in */ + size_t headersize; /* size of the allocation */ diff --git a/CVE-2020-8284.patch b/CVE-2020-8284.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1627f6e60c6770d501fecc4592fc6afadeb913d --- /dev/null +++ b/CVE-2020-8284.patch @@ -0,0 +1,179 @@ +Backport of: + +From 20ceeeeb6df4ad7444d0ac6f080557954e05ec1d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 24 Nov 2020 14:56:57 +0100 +Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default + +The command line tool also independently sets --ftp-skip-pasv-ip by +default. + +Ten test cases updated to adapt the modified --libcurl output. + +Bug: https://curl.se/docs/CVE-2020-8284.html +CVE-2020-8284 + +Reported-by: Varnavas Papaioannou +--- + docs/cmdline-opts/ftp-skip-pasv-ip.d | 2 ++ + docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 | 8 +++++--- + lib/url.c | 1 + + src/tool_cfgable.c | 1 + + tests/data/test1400 | 1 + + tests/data/test1401 | 1 + + tests/data/test1402 | 1 + + tests/data/test1403 | 1 + + tests/data/test1404 | 1 + + tests/data/test1405 | 1 + + tests/data/test1406 | 1 + + tests/data/test1407 | 1 + + tests/data/test1420 | 1 + + tests/data/test1465 | Bin 2909 -> 2964 bytes + 14 files changed, 18 insertions(+), 3 deletions(-) + +--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d ++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d +@@ -9,4 +9,6 @@ to curl's PASV command when curl connect + will re-use the same IP address it already uses for the control + connection. + ++Since curl 7.74.0 this option is enabled by default. ++ + This option has no effect if PORT, EPRT or EPSV is used instead of PASV. +--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 ++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 +@@ -5,7 +5,7 @@ + .\" * | (__| |_| | _ <| |___ + .\" * \___|\___/|_| \_\_____| + .\" * +-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. ++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + .\" * + .\" * This software is licensed as described in the file COPYING, which + .\" * you should have received as part of this distribution. The terms +@@ -36,11 +36,13 @@ address it already uses for the control + number from the 227-response. + + This option thus allows libcurl to work around broken server installations +-that due to NATs, firewalls or incompetence report the wrong IP address back. ++that due to NATs, firewalls or incompetence report the wrong IP address ++back. Setting the option also reduces the risk for various sorts of client ++abuse by malicious servers. + + This option has no effect if PORT, EPRT or EPSV is used instead of PASV. + .SH DEFAULT +-0 ++1 since 7.74.0, was 0 before then. + .SH PROTOCOLS + FTP + .SH EXAMPLE +--- a/lib/url.c ++++ b/lib/url.c +@@ -456,6 +456,7 @@ CURLcode Curl_init_userdefined(struct Cu + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; ++ set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ + #endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + +--- a/src/tool_cfgable.c ++++ b/src/tool_cfgable.c +@@ -44,6 +44,7 @@ void config_init(struct OperationConfig* + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; ++ config->ftp_skip_ip = TRUE; + } + + static void free_config_fields(struct OperationConfig *config) +--- a/tests/data/test1400 ++++ b/tests/data/test1400 +@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1401 ++++ b/tests/data/test1401 +@@ -90,6 +90,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE | + (long)CURLPROTO_FTP | +--- a/tests/data/test1402 ++++ b/tests/data/test1402 +@@ -81,6 +81,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1403 ++++ b/tests/data/test1403 +@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1404 ++++ b/tests/data/test1404 +@@ -147,6 +147,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1405 ++++ b/tests/data/test1405 +@@ -89,6 +89,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2); + curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1406 ++++ b/tests/data/test1406 +@@ -79,6 +79,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406"); + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com"); + curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1); +--- a/tests/data/test1407 ++++ b/tests/data/test1407 +@@ -62,6 +62,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L); + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1420 ++++ b/tests/data/test1420 +@@ -67,6 +67,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1"); + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated diff --git a/CVE-2020-8285.patch b/CVE-2020-8285.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a68a75e229cd0426cbba6b86ec2179a084a0849 --- /dev/null +++ b/CVE-2020-8285.patch @@ -0,0 +1,249 @@ +Backport of: + +From c11171033d5eb8e6514bbabd49c710e0b9885e6f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 28 Nov 2020 00:27:21 +0100 +Subject: [PATCH] ftp: make wc_statemach loop instead of recurse + +--- + lib/ftp.c | 202 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 102 insertions(+), 100 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -3773,129 +3773,131 @@ static CURLcode init_wc_data(struct conn + return result; + } + +-/* This is called recursively */ + static CURLcode wc_statemach(struct connectdata *conn) + { + struct WildcardData * const wildcard = &(conn->data->wildcard); + CURLcode result = CURLE_OK; + +- switch(wildcard->state) { +- case CURLWC_INIT: +- result = init_wc_data(conn); +- if(wildcard->state == CURLWC_CLEAN) +- /* only listing! */ +- break; +- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; +- break; +- +- case CURLWC_MATCHING: { +- /* In this state is LIST response successfully parsed, so lets restore +- previous WRITEFUNCTION callback and WRITEDATA pointer */ +- struct ftp_wc *ftpwc = wildcard->protdata; +- conn->data->set.fwrite_func = ftpwc->backup.write_function; +- conn->data->set.out = ftpwc->backup.file_descriptor; +- ftpwc->backup.write_function = ZERO_NULL; +- ftpwc->backup.file_descriptor = NULL; +- wildcard->state = CURLWC_DOWNLOADING; +- +- if(Curl_ftp_parselist_geterror(ftpwc->parser)) { +- /* error found in LIST parsing */ +- wildcard->state = CURLWC_CLEAN; +- return wc_statemach(conn); +- } +- if(wildcard->filelist.size == 0) { +- /* no corresponding file */ +- wildcard->state = CURLWC_CLEAN; +- return CURLE_REMOTE_FILE_NOT_FOUND; ++ for(;;) { ++ switch(wildcard->state) { ++ case CURLWC_INIT: ++ result = init_wc_data(conn); ++ if(wildcard->state == CURLWC_CLEAN) ++ /* only listing! */ ++ return result; ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; ++ return result; ++ ++ case CURLWC_MATCHING: { ++ /* In this state is LIST response successfully parsed, so lets restore ++ previous WRITEFUNCTION callback and WRITEDATA pointer */ ++ struct ftp_wc *ftpwc = wildcard->protdata; ++ conn->data->set.fwrite_func = ftpwc->backup.write_function; ++ conn->data->set.out = ftpwc->backup.file_descriptor; ++ ftpwc->backup.write_function = ZERO_NULL; ++ ftpwc->backup.file_descriptor = NULL; ++ wildcard->state = CURLWC_DOWNLOADING; ++ ++ if(Curl_ftp_parselist_geterror(ftpwc->parser)) { ++ /* error found in LIST parsing */ ++ wildcard->state = CURLWC_CLEAN; ++ continue; ++ } ++ if(wildcard->filelist.size == 0) { ++ /* no corresponding file */ ++ wildcard->state = CURLWC_CLEAN; ++ return CURLE_REMOTE_FILE_NOT_FOUND; ++ } ++ continue; + } +- return wc_statemach(conn); +- } + +- case CURLWC_DOWNLOADING: { +- /* filelist has at least one file, lets get first one */ +- struct ftp_conn *ftpc = &conn->proto.ftpc; +- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; +- struct FTP *ftp = conn->data->req.protop; +- +- char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); +- if(!tmp_path) +- return CURLE_OUT_OF_MEMORY; +- +- /* switch default ftp->path and tmp_path */ +- free(ftp->pathalloc); +- ftp->pathalloc = ftp->path = tmp_path; +- +- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); +- if(conn->data->set.chunk_bgn) { +- long userresponse; +- Curl_set_in_callback(conn->data, true); +- userresponse = conn->data->set.chunk_bgn( +- finfo, wildcard->customptr, (int)wildcard->filelist.size); +- Curl_set_in_callback(conn->data, false); +- switch(userresponse) { +- case CURL_CHUNK_BGN_FUNC_SKIP: +- infof(conn->data, "Wildcard - \"%s\" skipped by user\n", +- finfo->filename); ++ case CURLWC_DOWNLOADING: { ++ /* filelist has at least one file, lets get first one */ ++ struct ftp_conn *ftpc = &conn->proto.ftpc; ++ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; ++ struct FTP *ftp = conn->data->req.protop; ++ ++ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); ++ if(!tmp_path) ++ return CURLE_OUT_OF_MEMORY; ++ ++ /* switch default ftp->path and tmp_path */ ++ free(ftp->pathalloc); ++ ftp->pathalloc = ftp->path = tmp_path; ++ ++ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); ++ if(conn->data->set.chunk_bgn) { ++ long userresponse; ++ Curl_set_in_callback(conn->data, true); ++ userresponse = conn->data->set.chunk_bgn( ++ finfo, wildcard->customptr, (int)wildcard->filelist.size); ++ Curl_set_in_callback(conn->data, false); ++ switch(userresponse) { ++ case CURL_CHUNK_BGN_FUNC_SKIP: ++ infof(conn->data, "Wildcard - \"%s\" skipped by user\n", ++ finfo->filename); ++ wildcard->state = CURLWC_SKIP; ++ continue; ++ case CURL_CHUNK_BGN_FUNC_FAIL: ++ return CURLE_CHUNK_FAILED; ++ } ++ } ++ ++ if(finfo->filetype != CURLFILETYPE_FILE) { + wildcard->state = CURLWC_SKIP; +- return wc_statemach(conn); +- case CURL_CHUNK_BGN_FUNC_FAIL: +- return CURLE_CHUNK_FAILED; ++ continue; ++ } ++ ++ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) ++ ftpc->known_filesize = finfo->size; ++ ++ result = ftp_parse_url_path(conn); ++ if(result) ++ return result; ++ ++ /* we don't need the Curl_fileinfo of first file anymore */ ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); ++ ++ if(wildcard->filelist.size == 0) { /* remains only one file to down. */ ++ wildcard->state = CURLWC_CLEAN; ++ /* after that will be ftp_do called once again and no transfer ++ will be done because of CURLWC_CLEAN state */ ++ return CURLE_OK; + } ++ return result; + } + +- if(finfo->filetype != CURLFILETYPE_FILE) { +- wildcard->state = CURLWC_SKIP; +- return wc_statemach(conn); ++ case CURLWC_SKIP: { ++ if(conn->data->set.chunk_end) { ++ Curl_set_in_callback(conn->data, true); ++ conn->data->set.chunk_end(conn->data->wildcard.customptr); ++ Curl_set_in_callback(conn->data, false); ++ } ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); ++ wildcard->state = (wildcard->filelist.size == 0) ? ++ CURLWC_CLEAN : CURLWC_DOWNLOADING; ++ continue; + } + +- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) +- ftpc->known_filesize = finfo->size; ++ case CURLWC_CLEAN: { ++ struct ftp_wc *ftpwc = wildcard->protdata; ++ result = CURLE_OK; ++ if(ftpwc) ++ result = Curl_ftp_parselist_geterror(ftpwc->parser); + +- result = ftp_parse_url_path(conn); +- if(result) ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; + return result; +- +- /* we don't need the Curl_fileinfo of first file anymore */ +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); +- +- if(wildcard->filelist.size == 0) { /* remains only one file to down. */ +- wildcard->state = CURLWC_CLEAN; +- /* after that will be ftp_do called once again and no transfer +- will be done because of CURLWC_CLEAN state */ +- return CURLE_OK; + } +- } break; + +- case CURLWC_SKIP: { +- if(conn->data->set.chunk_end) { +- Curl_set_in_callback(conn->data, true); +- conn->data->set.chunk_end(conn->data->wildcard.customptr); +- Curl_set_in_callback(conn->data, false); ++ case CURLWC_DONE: ++ case CURLWC_ERROR: ++ case CURLWC_CLEAR: ++ if(wildcard->dtor) ++ wildcard->dtor(wildcard->protdata); ++ return result; + } +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); +- wildcard->state = (wildcard->filelist.size == 0) ? +- CURLWC_CLEAN : CURLWC_DOWNLOADING; +- return wc_statemach(conn); +- } +- +- case CURLWC_CLEAN: { +- struct ftp_wc *ftpwc = wildcard->protdata; +- result = CURLE_OK; +- if(ftpwc) +- result = Curl_ftp_parselist_geterror(ftpwc->parser); +- +- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; +- } break; +- +- case CURLWC_DONE: +- case CURLWC_ERROR: +- case CURLWC_CLEAR: +- if(wildcard->dtor) +- wildcard->dtor(wildcard->protdata); +- break; + } +- +- return result; ++ /* UNREACHABLE */ + } + + /*********************************************************************** diff --git a/CVE-2020-8286.patch b/CVE-2020-8286.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e2ac5f9fa57b274c254bfd38d01f8292daf58f0 --- /dev/null +++ b/CVE-2020-8286.patch @@ -0,0 +1,128 @@ +Backport of: + +From dd5ec983ccb8106484a787713346cdcabf52af62 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Wed, 2 Dec 2020 23:01:11 +0100 +Subject: [PATCH] openssl: make the OCSP verification verify the certificate id + +CVE-2020-8286 + +Reported by anonymous + +Bug: https://curl.se/docs/CVE-2020-8286.html +--- + lib/vtls/openssl.c | 83 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 29 deletions(-) + +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct conn + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; ++ X509 *cert; ++ OCSP_CERTID *id = NULL; ++ int cert_status, crl_reason; ++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; ++ int ret; + + long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status); + +@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct conn + goto end; + } + +- for(i = 0; i < OCSP_resp_count(br); i++) { +- int cert_status, crl_reason; +- OCSP_SINGLERESP *single = NULL; +- +- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; +- +- single = OCSP_resp_get0(br, i); +- if(!single) +- continue; +- +- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, +- &thisupd, &nextupd); +- +- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { +- failf(data, "OCSP response has expired"); +- result = CURLE_SSL_INVALIDCERTSTATUS; +- goto end; ++ /* Compute the certificate's ID */ ++ cert = SSL_get_peer_certificate(BACKEND->handle); ++ if(!cert) { ++ failf(data, "Error getting peer certficate"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ for(i = 0; i < sk_X509_num(ch); i++) { ++ X509 *issuer = sk_X509_value(ch, i); ++ if(X509_check_issued(issuer, cert) == X509_V_OK) { ++ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer); ++ break; + } ++ } ++ X509_free(cert); + +- infof(data, "SSL certificate status: %s (%d)\n", +- OCSP_cert_status_str(cert_status), cert_status); ++ if(!id) { ++ failf(data, "Error computing OCSP ID"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } + +- switch(cert_status) { +- case V_OCSP_CERTSTATUS_GOOD: +- break; +- +- case V_OCSP_CERTSTATUS_REVOKED: +- result = CURLE_SSL_INVALIDCERTSTATUS; +- +- failf(data, "SSL certificate revocation reason: %s (%d)", +- OCSP_crl_reason_str(crl_reason), crl_reason); +- goto end; +- +- case V_OCSP_CERTSTATUS_UNKNOWN: +- result = CURLE_SSL_INVALIDCERTSTATUS; +- goto end; +- } ++ /* Find the single OCSP response corresponding to the certificate ID */ ++ ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev, ++ &thisupd, &nextupd); ++ OCSP_CERTID_free(id); ++ if(ret != 1) { ++ failf(data, "Could not find certificate ID in OCSP response"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ /* Validate the corresponding single OCSP response */ ++ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { ++ failf(data, "OCSP response has expired"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ infof(data, "SSL certificate status: %s (%d)\n", ++ OCSP_cert_status_str(cert_status), cert_status); ++ ++ switch(cert_status) { ++ case V_OCSP_CERTSTATUS_GOOD: ++ break; ++ ++ case V_OCSP_CERTSTATUS_REVOKED: ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ failf(data, "SSL certificate revocation reason: %s (%d)", ++ OCSP_crl_reason_str(crl_reason), crl_reason); ++ goto end; ++ ++ case V_OCSP_CERTSTATUS_UNKNOWN: ++ default: ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; + } + + end: diff --git a/CVE-2021-22876.patch b/CVE-2021-22876.patch new file mode 100644 index 0000000000000000000000000000000000000000..a0410cf0cc40ee3002aa03b00b0375cd8cf4a2fc --- /dev/null +++ b/CVE-2021-22876.patch @@ -0,0 +1,62 @@ +Backport of: + +From 3dec1183be112e587f89edc059c1c11cf8fdc0ae Mon Sep 17 00:00:00 2001 +From: Viktor Szakats +Date: Tue, 23 Feb 2021 14:54:46 +0100 +Subject: [PATCH] transfer: strip credentials from the auto-referer header + field + +Added test 2081 to verify. + +CVE-2021-22876 + +Bug: https://curl.se/docs/CVE-2021-22876.html +--- + lib/transfer.c | 25 ++++++++++++++-- + tests/data/Makefile.inc | 2 +- + tests/data/test2081 | 66 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 90 insertions(+), 3 deletions(-) + create mode 100644 tests/data/test2081 + +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1572,6 +1572,9 @@ CURLcode Curl_follow(struct Curl_easy *d + data->set.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { ++ CURLU *u; ++ char *referer; ++ + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ +@@ -1581,9 +1584,27 @@ CURLcode Curl_follow(struct Curl_easy *d + data->change.referer_alloc = FALSE; + } + +- data->change.referer = strdup(data->change.url); +- if(!data->change.referer) ++ /* Make a copy of the URL without crenditals and fragment */ ++ u = curl_url(); ++ if(!u) ++ return CURLE_OUT_OF_MEMORY; ++ ++ uc = curl_url_set(u, CURLUPART_URL, data->change.url, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_USER, NULL, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); ++ if(!uc) ++ uc = curl_url_get(u, CURLUPART_URL, &referer, 0); ++ ++ curl_url_cleanup(u); ++ ++ if(uc || referer == NULL) + return CURLE_OUT_OF_MEMORY; ++ ++ data->change.referer = referer; + data->change.referer_alloc = TRUE; /* yes, free this later */ + } + } diff --git a/CVE-2021-22890.patch b/CVE-2021-22890.patch new file mode 100644 index 0000000000000000000000000000000000000000..7322c6036c5ed097972687e2ed8a2db7459ad293 --- /dev/null +++ b/CVE-2021-22890.patch @@ -0,0 +1,443 @@ +Backport of: + +From e9c835dbd51f482f5d572e6fb33a0e8ef60c846b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 19 Mar 2021 12:38:49 +0100 +Subject: [PATCH] vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid() + +To make sure we set and extract the correct session. + +Reported-by: Mingtao Yang +Bug: https://curl.se/docs/CVE-2021-22890.html + +CVE-2021-22890 +--- + lib/vtls/bearssl.c | 8 +++++-- + lib/vtls/gtls.c | 12 ++++++---- + lib/vtls/mbedtls.c | 12 ++++++---- + lib/vtls/mesalink.c | 14 ++++++++---- + lib/vtls/openssl.c | 54 +++++++++++++++++++++++++++++++++----------- + lib/vtls/schannel.c | 10 ++++---- + lib/vtls/sectransp.c | 10 ++++---- + lib/vtls/vtls.c | 12 +++++++--- + lib/vtls/vtls.h | 2 ++ + lib/vtls/wolfssl.c | 13 +++++++---- + 10 files changed, 103 insertions(+), 44 deletions(-) + +--- a/lib/vtls/bearssl.c ++++ b/lib/vtls/bearssl.c +@@ -372,7 +372,8 @@ static CURLcode bearssl_connect_step1(st + void *session; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &session, NULL, sockindex)) { + br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); + infof(data, "BearSSL: re-using session ID\n"); + } +@@ -560,10 +561,12 @@ static CURLcode bearssl_connect_step3(st + return CURLE_OUT_OF_MEMORY; + br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); ++ incache = !(Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &oldsession, NULL, sockindex)); + if(incache) + Curl_ssl_delsessionid(conn, oldsession); +- ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); ++ ret = Curl_ssl_addsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ session, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(ret) { + free(session); +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -942,7 +942,8 @@ gtls_connect_step1(struct connectdata *c + size_t ssl_idsize; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, &ssl_idsize, sockindex)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + +@@ -1490,7 +1491,8 @@ gtls_connect_step3(struct connectdata *c + gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, + sockindex)); + if(incache) { + /* there was one before in the cache, so instead of risking that the +@@ -1499,7 +1501,8 @@ gtls_connect_step3(struct connectdata *c + } + + /* store this session id */ +- result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, ++ result = Curl_ssl_addsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ connect_sessionid, connect_idsize, + sockindex); + Curl_ssl_sessionid_unlock(conn); + if(result) { +--- a/lib/vtls/mbedtls.c ++++ b/lib/vtls/mbedtls.c +@@ -453,7 +453,8 @@ mbed_connect_step1(struct connectdata *c + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &old_session, NULL, sockindex)) { + ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(conn); +@@ -709,6 +710,7 @@ mbed_connect_step3(struct connectdata *c + int ret; + mbedtls_ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; ++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) +@@ -727,10 +729,10 @@ mbed_connect_step3(struct connectdata *c + + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) ++ if(!Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, NULL, sockindex)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + +- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); ++ retcode = Curl_ssl_addsessionid(conn, isproxy, our_ssl_sessionid, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + mbedtls_ssl_session_free(our_ssl_sessionid); +--- a/lib/vtls/mesalink.c ++++ b/lib/vtls/mesalink.c +@@ -263,7 +263,8 @@ mesalink_connect_step1(struct connectdat + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); +@@ -347,12 +348,14 @@ mesalink_connect_step3(struct connectdat + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; ++ bool inproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + our_ssl_sessionid = SSL_get_session(BACKEND->handle); + + Curl_ssl_sessionid_lock(conn); + incache = +- !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)); ++ !(Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, ++ NULL, sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); +@@ -363,7 +366,7 @@ mesalink_connect_step3(struct connectdat + + if(!incache) { + result = Curl_ssl_addsessionid( +- conn, our_ssl_sessionid, 0 /* unknown size */, sockindex); ++ conn, isproxy, our_ssl_sessionid, 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -422,12 +422,23 @@ static int ossl_get_ssl_conn_index(void) + */ + static int ossl_get_ssl_sockindex_index(void) + { +- static int ssl_ex_data_sockindex_index = -1; +- if(ssl_ex_data_sockindex_index < 0) { +- ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, +- NULL); ++ static int sockindex_index = -1; ++ if(sockindex_index < 0) { ++ sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + } +- return ssl_ex_data_sockindex_index; ++ return sockindex_index; ++} ++ ++/* Return an extra data index for proxy boolean. ++ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). ++ */ ++static int ossl_get_proxy_index(void) ++{ ++ static int proxy_index = -1; ++ if(proxy_index < 0) { ++ proxy_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ++ } ++ return proxy_index; + } + + static int passwd_callback(char *buf, int num, int encrypting, +@@ -1079,7 +1090,8 @@ static int Curl_ossl_init(void) + #endif + + /* Initialize the extra data indexes */ +- if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0) ++ if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0 || ++ ossl_get_proxy_index() < 0) + return 0; + + return 1; +@@ -2367,8 +2379,10 @@ static int ossl_new_session_cb(SSL *ssl, + curl_socket_t *sockindex_ptr; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); ++ int proxy_idx = ossl_get_proxy_index(); ++ bool isproxy; + +- if(connectdata_idx < 0 || sockindex_idx < 0) ++ if(connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0) + return 0; + + conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx); +@@ -2381,13 +2395,18 @@ static int ossl_new_session_cb(SSL *ssl, + sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx); + sockindex = (int)(sockindex_ptr - conn->sock); + ++ isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE; ++ + if(SSL_SET_OPTION(primary.sessionid)) { + bool incache; + void *old_ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, +- sockindex)); ++ if(isproxy) ++ incache = FALSE; ++ else ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, ++ &old_ssl_sessionid, NULL, sockindex)); + if(incache) { + if(old_ssl_sessionid != ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); +@@ -2397,7 +2416,7 @@ static int ossl_new_session_cb(SSL *ssl, + } + + if(!incache) { +- if(!Curl_ssl_addsessionid(conn, ssl_sessionid, ++ if(!Curl_ssl_addsessionid(conn, isproxy, ssl_sessionid, + 0 /* unknown size */, sockindex)) { + /* the session has been put into the session cache */ + res = 1; +@@ -2894,16 +2913,25 @@ static CURLcode ossl_connect_step1(struc + void *ssl_sessionid = NULL; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); ++ int proxy_idx = ossl_get_proxy_index(); + +- if(connectdata_idx >= 0 && sockindex_idx >= 0) { ++ if(connectdata_idx >= 0 && sockindex_idx >= 0 && proxy_idx >= 0) { + /* Store the data needed for the "new session" callback. + * The sockindex is stored as a pointer to an array element. */ + SSL_set_ex_data(BACKEND->handle, connectdata_idx, conn); + SSL_set_ex_data(BACKEND->handle, sockindex_idx, conn->sock + sockindex); ++#ifndef CURL_DISABLE_PROXY ++ SSL_set_ex_data(BACKEND->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1: ++ NULL); ++#else ++ SSL_set_ex_data(BACKEND->handle, proxy_idx, NULL); ++#endif ++ + } + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); +--- a/lib/vtls/schannel.c ++++ b/lib/vtls/schannel.c +@@ -497,7 +497,8 @@ schannel_connect_step1(struct connectdat + /* check for an existing re-usable credential handle */ + if(SSL_SET_OPTION(primary.sessionid)) { + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ (void **)&old_cred, NULL, sockindex)) { + BACKEND->cred = old_cred; + DEBUGF(infof(data, "schannel: re-using existing credential handle\n")); + +@@ -1203,8 +1204,9 @@ schannel_connect_step3(struct connectdat + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; ++ bool isproxy = SSL_IS_PROXY(); + #ifdef DEBUGBUILD +- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ++ const char * const hostname = isproxy ? conn->http_proxy.host.name : + conn->host.name; + #endif + #ifdef HAS_ALPN +@@ -1278,7 +1280,7 @@ schannel_connect_step3(struct connectdat + struct curl_schannel_cred *old_cred = NULL; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, (void **)&old_cred, NULL, + sockindex)); + if(incache) { + if(old_cred != BACKEND->cred) { +@@ -1290,7 +1292,7 @@ schannel_connect_step3(struct connectdat + } + } + if(!incache) { +- result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred, ++ result = Curl_ssl_addsessionid(conn, isproxy, (void *)BACKEND->cred, + sizeof(struct curl_schannel_cred), + sockindex); + if(result) { +--- a/lib/vtls/sectransp.c ++++ b/lib/vtls/sectransp.c +@@ -1376,7 +1376,8 @@ static CURLcode sectransp_connect_step1( + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + char * const ssl_cert = SSL_SET_OPTION(cert); +- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ++ bool isproxy = SSL_IS_PROXY(); ++ const char * const hostname = isproxy ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; + #ifdef ENABLE_IPV6 +@@ -1584,7 +1585,7 @@ static CURLcode sectransp_connect_step1( + + #ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && +- (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { ++ (!isproxy || !conn->bits.tunnel_proxy)) { + CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID)); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +@@ -1916,7 +1917,7 @@ static CURLcode sectransp_connect_step1( + size_t ssl_sessionid_len; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, ++ if(!Curl_ssl_getsessionid(conn, isproxy, (void **)&ssl_sessionid, + &ssl_sessionid_len, sockindex)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); +@@ -1944,7 +1945,7 @@ static CURLcode sectransp_connect_step1( + return CURLE_SSL_CONNECT_ERROR; + } + +- result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, ++ result = Curl_ssl_addsessionid(conn, isproxy, ssl_sessionid, ssl_sessionid_len, + sockindex); + Curl_ssl_sessionid_unlock(conn); + if(result) { +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -305,6 +305,7 @@ void Curl_ssl_sessionid_unlock(struct co + * there's one suitable, it is provided. Returns TRUE when no entry matched. + */ + bool Curl_ssl_getsessionid(struct connectdata *conn, ++ const bool isProxy, + void **ssl_sessionid, + size_t *idsize, /* set 0 if unknown */ + int sockindex) +@@ -315,7 +316,6 @@ bool Curl_ssl_getsessionid(struct connec + long *general_age; + bool no_match = TRUE; + +- const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; +@@ -324,6 +324,11 @@ bool Curl_ssl_getsessionid(struct connec + int port = isProxy ? (int)conn->port : conn->remote_port; + *ssl_sessionid = NULL; + ++#ifdef CURL_DISABLE_PROXY ++ if(isProxy) ++ return TRUE; ++#endif ++ + DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); + + if(!SSL_SET_OPTION(primary.sessionid)) +@@ -411,6 +416,7 @@ void Curl_ssl_delsessionid(struct connec + * later on. + */ + CURLcode Curl_ssl_addsessionid(struct connectdata *conn, ++ bool isProxy, + void *ssl_sessionid, + size_t idsize, + int sockindex) +@@ -423,7 +429,6 @@ CURLcode Curl_ssl_addsessionid(struct co + char *clone_conn_to_host; + int conn_to_port; + long *general_age; +- const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; +--- a/lib/vtls/vtls.h ++++ b/lib/vtls/vtls.h +@@ -203,6 +203,7 @@ void Curl_ssl_sessionid_unlock(struct co + * under sessionid mutex). + */ + bool Curl_ssl_getsessionid(struct connectdata *conn, ++ const bool isproxy, + void **ssl_sessionid, + size_t *idsize, /* set 0 if unknown */ + int sockindex); +@@ -212,6 +213,7 @@ bool Curl_ssl_getsessionid(struct connec + * object with cache (e.g. incrementing refcount on success) + */ + CURLcode Curl_ssl_addsessionid(struct connectdata *conn, ++ const bool isProxy, + void *ssl_sessionid, + size_t idsize, + int sockindex); +--- a/lib/vtls/wolfssl.c ++++ b/lib/vtls/wolfssl.c +@@ -392,7 +392,8 @@ wolfssl_connect_step1(struct connectdata + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; +@@ -618,9 +619,10 @@ wolfssl_connect_step3(struct connectdata + void *old_ssl_sessionid = NULL; + + our_ssl_sessionid = SSL_get_session(BACKEND->handle); ++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, NULL, + sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { +@@ -631,7 +633,7 @@ wolfssl_connect_step3(struct connectdata + } + + if(!incache) { +- result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, ++ result = Curl_ssl_addsessionid(conn, isproxy, our_ssl_sessionid, + 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); diff --git a/CVE-2021-22898.patch b/CVE-2021-22898.patch new file mode 100644 index 0000000000000000000000000000000000000000..9da5524bb1c1726b11341334384bc68e418acfbd --- /dev/null +++ b/CVE-2021-22898.patch @@ -0,0 +1,23 @@ +From 39ce47f219b09c380b81f89fe54ac586c8db6bde Mon Sep 17 00:00:00 2001 +From: Harry Sintonen +Date: Fri, 7 May 2021 13:09:57 +0200 +Subject: [PATCH] telnet: check sscanf() for correct number of matches + +CVE-2021-22898 + +Bug: https://curl.se/docs/CVE-2021-22898.html +--- + lib/telnet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -967,7 +967,7 @@ static void suboption(struct connectdata + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { +- if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { ++ if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); diff --git a/CVE-2021-22924.patch b/CVE-2021-22924.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f03402591a4a662715d85b1a6eae71494912f85 --- /dev/null +++ b/CVE-2021-22924.patch @@ -0,0 +1,215 @@ +Backport of: + +From 5ea3145850ebff1dc2b13d17440300a01ca38161 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 19 Jun 2021 00:42:28 +0200 +Subject: [PATCH] vtls: fix connection reuse checks for issuer cert and case + sensitivity + +CVE-2021-22924 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2021-22924.html +--- + lib/url.c | 10 ++++++---- + lib/urldata.h | 4 ++-- + lib/vtls/gtls.c | 10 +++++----- + lib/vtls/nss.c | 4 ++-- + lib/vtls/openssl.c | 18 +++++++++--------- + lib/vtls/vtls.c | 26 +++++++++++++++++++++----- + 6 files changed, 45 insertions(+), 27 deletions(-) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -3523,6 +3523,9 @@ static CURLcode create_conn(struct Curl_ + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; ++ data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; ++ data->set.proxy_ssl.primary.issuercert = ++ data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; +@@ -3543,8 +3546,6 @@ static CURLcode create_conn(struct Curl_ + + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; +- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; +- data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -224,6 +224,7 @@ struct ssl_primary_config { + long version_max; /* max supported version the client wants to use*/ + char *CApath; /* certificate dir (doesn't work on windows) */ + char *CAfile; /* certificate to verify peer against */ ++ char *issuercert; /* optional issuer certificate filename */ + char *clientcert; + char *random_file; /* path to file containing "random" data */ + char *egdsocket; /* path to file containing the EGD daemon socket */ +@@ -240,7 +241,6 @@ struct ssl_config_data { + struct ssl_primary_config primary; + long certverifyresult; /* result from the certificate verification */ + char *CRLfile; /* CRL to check certificate revocation */ +- char *issuercert;/* optional issuer certificate filename */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + char *cert; /* client certificate file name */ +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -1064,7 +1064,7 @@ gtls_connect_step3(struct connectdata *c + if(!chainp) { + if(SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost) || +- SSL_SET_OPTION(issuercert)) { ++ SSL_CONN_CONFIG(issuercert)) { + #ifdef USE_TLS_SRP + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL +@@ -1246,21 +1246,21 @@ gtls_connect_step3(struct connectdata *c + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + gnutls_x509_crt_init(&x509_issuer); +- issuerp = load_file(SSL_SET_OPTION(issuercert)); ++ issuerp = load_file(SSL_CONN_CONFIG(issuercert)); + gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + gnutls_x509_crt_deinit(x509_issuer); + unload_file(issuerp); + if(rc <= 0) { + failf(data, "server certificate issuer check failed (IssuerCert: %s)", +- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); ++ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_ISSUER_ERROR; + } + infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", +- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); ++ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); + } + + size = sizeof(certbuf); +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -2151,9 +2151,9 @@ static CURLcode nss_do_connect(struct co + if(result) + goto error; + +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + SECStatus ret = SECFailure; +- char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); ++ char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert)); + if(nickname) { + /* we support only nicknames in case of issuercert for now */ + ret = check_issuer_cert(BACKEND->handle, nickname); +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -3592,7 +3592,7 @@ static CURLcode servercert(struct connec + deallocating the certificate. */ + + /* e.g. match issuer name with provided issuer certificate */ +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, +@@ -3605,10 +3605,10 @@ static CURLcode servercert(struct connec + return CURLE_OUT_OF_MEMORY; + } + +- if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { ++ if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; +@@ -3619,7 +3619,7 @@ static CURLcode servercert(struct connec + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(BACKEND->server_cert); +@@ -3630,7 +3630,7 @@ static CURLcode servercert(struct connec + if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(BACKEND->server_cert); +@@ -3639,7 +3639,7 @@ static CURLcode servercert(struct connec + } + + infof(data, " SSL certificate issuer check ok (%s)\n", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + } +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -82,6 +82,16 @@ + else \ + dest->var = NULL; + ++static bool safecmp(char *a, char *b) ++{ ++ if(a && b) ++ return !strcmp(a, b); ++ else if(!a && !b) ++ return TRUE; /* match */ ++ return FALSE; /* no match */ ++} ++ ++ + bool + Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) +@@ -91,11 +101,12 @@ Curl_ssl_config_matches(struct ssl_prima + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +- Curl_safe_strcasecompare(data->CApath, needle->CApath) && +- Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && +- Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && +- Curl_safe_strcasecompare(data->random_file, needle->random_file) && +- Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && ++ safecmp(data->CApath, needle->CApath) && ++ safecmp(data->CAfile, needle->CAfile) && ++ safecmp(data->issuercert, needle->issuercert) && ++ safecmp(data->clientcert, needle->clientcert) && ++ safecmp(data->random_file, needle->random_file) && ++ safecmp(data->egdsocket, needle->egdsocket) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && + Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) +@@ -117,6 +128,7 @@ Curl_clone_primary_ssl_config(struct ssl + + CLONE_STRING(CApath); + CLONE_STRING(CAfile); ++ CLONE_STRING(issuercert); + CLONE_STRING(clientcert); + CLONE_STRING(random_file); + CLONE_STRING(egdsocket); +@@ -131,6 +143,7 @@ void Curl_free_primary_ssl_config(struct + { + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->CAfile); ++ Curl_safefree(sslc->issuercert); + Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->random_file); + Curl_safefree(sslc->egdsocket); diff --git a/CVE-2021-22925.patch b/CVE-2021-22925.patch new file mode 100644 index 0000000000000000000000000000000000000000..71926e2cfcdf3ac604fbb0ab12409b7a27ab7bc7 --- /dev/null +++ b/CVE-2021-22925.patch @@ -0,0 +1,39 @@ +From cfc17716133ad1f8b99094c9a0ad15f1cfb63525 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 12 Jun 2021 18:25:15 +0200 +Subject: [PATCH] telnet: fix option parser to not send uninitialized contents + +CVS-2021-22925 + +Reported-by: Red Hat Product Security +Bug: https://curl.se/docs/CVE-2021-22925.html +--- + lib/telnet.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -967,12 +967,17 @@ static void suboption(struct connectdata + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { +- if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { +- msnprintf((char *)&temp[len], sizeof(temp) - len, +- "%c%s%c%s", CURL_NEW_ENV_VAR, varname, +- CURL_NEW_ENV_VALUE, varval); +- len += tmplen; +- } ++ int rv; ++ char sep[2] = ""; ++ varval[0] = 0; ++ rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval); ++ if(rv == 1) ++ len += msnprintf((char *)&temp[len], sizeof(temp) - len, ++ "%c%s", CURL_NEW_ENV_VAR, varname); ++ else if(rv >= 2) ++ len += msnprintf((char *)&temp[len], sizeof(temp) - len, ++ "%c%s%c%s", CURL_NEW_ENV_VAR, varname, ++ CURL_NEW_ENV_VALUE, varval); + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, diff --git a/CVE-2021-22946-pre1.patch b/CVE-2021-22946-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..d86cfeba07e56c916b53efb0e9dcf67c4477ccee --- /dev/null +++ b/CVE-2021-22946-pre1.patch @@ -0,0 +1,81 @@ +Backport of: + +From 1397a7de6e312e019a3b339f855ba0a5cafa9127 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 21 Sep 2020 09:15:51 +0200 +Subject: [PATCH] ftp: separate FTPS from FTP over "HTTPS proxy" + +When using HTTPS proxy, SSL is used but not in the view of the FTP +protocol handler itself so separate the connection's use of SSL from the +FTP control connection's sue. + +Reported-by: Mingtao Yang +Fixes #5523 +Closes #6006 +--- + lib/ftp.c | 16 ++++++---------- + lib/urldata.h | 1 + + tests/data/test1631 | 2 -- + tests/data/test1632 | 2 -- + 4 files changed, 7 insertions(+), 14 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2497,7 +2497,7 @@ static CURLcode ftp_state_loggedin(struc + { + CURLcode result = CURLE_OK; + +- if(conn->ssl[FIRSTSOCKET].use) { ++ if(conn->bits.ftp_use_control_ssl) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: +@@ -2643,11 +2643,8 @@ static CURLcode ftp_statemach_act(struct + } + #endif + +- if(data->set.use_ssl && +- (!conn->ssl[FIRSTSOCKET].use || +- (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && +- !conn->proxy_ssl[FIRSTSOCKET].use))) { +- /* We don't have a SSL/TLS connection yet, but FTPS is ++ if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { ++ /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; +@@ -2692,6 +2689,7 @@ static CURLcode ftp_statemach_act(struct + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ ++ conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(conn); + } + } +@@ -3082,7 +3080,7 @@ static CURLcode ftp_block_statemach(stru + * + */ + static CURLcode ftp_connect(struct connectdata *conn, +- bool *done) /* see description above */ ++ bool *done) /* see description above */ + { + CURLcode result; + struct ftp_conn *ftpc = &conn->proto.ftpc; +@@ -3103,6 +3101,7 @@ static CURLcode ftp_connect(struct conne + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; ++ conn->bits.ftp_use_control_ssl = TRUE; + } + + Curl_pp_init(pp); /* init the generic pingpong data */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -453,6 +453,7 @@ struct ConnectBits { + EPRT doesn't work we disable it for the forthcoming + requests */ + BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ ++ BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */ + #endif + BIT(netrc); /* name+password provided by netrc */ + BIT(userpwd_in_url); /* name+password found in url */ diff --git a/CVE-2021-22946.patch b/CVE-2021-22946.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ff93dc94ec902b054f2938dba0cd31bded081a9 --- /dev/null +++ b/CVE-2021-22946.patch @@ -0,0 +1,310 @@ +Backport of: + +From 96d71feb27e533a8b337512841a537952916262c Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Wed, 8 Sep 2021 11:56:22 +0200 +Subject: [PATCH] ftp,imap,pop3: do not ignore --ssl-reqd + +In imap and pop3, check if TLS is required even when capabilities +request has failed. + +In ftp, ignore preauthentication (230 status of server greeting) if TLS +is required. + +Bug: https://curl.se/docs/CVE-2021-22946.html + +CVE-2021-22946 +--- + lib/ftp.c | 9 ++++--- + lib/imap.c | 24 ++++++++---------- + lib/pop3.c | 33 +++++++++++------------- + tests/data/Makefile.inc | 2 ++ + tests/data/test984 | 56 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test985 | 54 +++++++++++++++++++++++++++++++++++++++ + tests/data/test986 | 53 ++++++++++++++++++++++++++++++++++++++ + 7 files changed, 195 insertions(+), 36 deletions(-) + create mode 100644 tests/data/test984 + create mode 100644 tests/data/test985 + create mode 100644 tests/data/test986 + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2616,9 +2616,12 @@ static CURLcode ftp_statemach_act(struct + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: +- if(ftpcode == 230) +- /* 230 User logged in - already! */ +- return ftp_state_user_resp(conn, ftpcode, ftpc->state); ++ if(ftpcode == 230) { ++ /* 230 User logged in - already! Take as 220 if TLS required. */ ++ if(data->set.use_ssl <= CURLUSESSL_TRY || ++ conn->bits.ftp_use_control_ssl) ++ return ftp_state_user_resp(conn, ftpcode, ftpc->state); ++ } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -917,22 +917,18 @@ static CURLcode imap_state_capability_re + line += wordlen; + } + } +- else if(imapcode == IMAP_RESP_OK) { +- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { +- /* We don't have a SSL/TLS connection yet, but SSL is requested */ +- if(imapc->tls_supported) +- /* Switch to TLS connection now */ +- result = imap_perform_starttls(conn); +- else if(data->set.use_ssl == CURLUSESSL_TRY) +- /* Fallback and carry on with authentication */ +- result = imap_perform_authentication(conn); +- else { +- failf(data, "STARTTLS not supported."); +- result = CURLE_USE_SSL_FAILED; +- } ++ else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { ++ /* PREAUTH is not compatible with STARTTLS. */ ++ if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { ++ /* Switch to TLS connection now */ ++ result = imap_perform_starttls(conn); + } +- else ++ else if(data->set.use_ssl <= CURLUSESSL_TRY) + result = imap_perform_authentication(conn); ++ else { ++ failf(data, "STARTTLS not available."); ++ result = CURLE_USE_SSL_FAILED; ++ } + } + else + result = imap_perform_authentication(conn); +--- a/lib/pop3.c ++++ b/lib/pop3.c +@@ -721,28 +721,23 @@ static CURLcode pop3_state_capa_resp(str + } + } + } +- else if(pop3code == '+') { +- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { +- /* We don't have a SSL/TLS connection yet, but SSL is requested */ +- if(pop3c->tls_supported) +- /* Switch to TLS connection now */ +- result = pop3_perform_starttls(conn); +- else if(data->set.use_ssl == CURLUSESSL_TRY) +- /* Fallback and carry on with authentication */ +- result = pop3_perform_authentication(conn); +- else { +- failf(data, "STLS not supported."); +- result = CURLE_USE_SSL_FAILED; +- } +- } +- else +- result = pop3_perform_authentication(conn); +- } + else { + /* Clear text is supported when CAPA isn't recognised */ +- pop3c->authtypes |= POP3_TYPE_CLEARTEXT; ++ if(pop3code != '+') ++ pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + +- result = pop3_perform_authentication(conn); ++ if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use) ++ result = pop3_perform_authentication(conn); ++ else if(pop3code == '+' && pop3c->tls_supported) ++ /* Switch to TLS connection now */ ++ result = pop3_perform_starttls(conn); ++ else if(data->set.use_ssl <= CURLUSESSL_TRY) ++ /* Fallback and carry on with authentication */ ++ result = pop3_perform_authentication(conn); ++ else { ++ failf(data, "STLS not supported."); ++ result = CURLE_USE_SSL_FAILED; ++ } + } + + return result; +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -111,6 +111,8 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test984 test985 test986 \ ++\ + test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ + test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ + test1016 test1017 test1018 test1019 test1020 test1021 test1022 test1023 \ +--- /dev/null ++++ b/tests/data/test984 +@@ -0,0 +1,56 @@ ++ ++ ++ ++IMAP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY CAPABILITY A001 BAD Not implemented ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++imap ++ ++ ++IMAP require STARTTLS with failing capabilities ++ ++ ++imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl-reqd ++ ++ ++Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) ++From: Fred Foobar ++Subject: afternoon meeting ++To: joe@example.com ++Message-Id: ++MIME-Version: 1.0 ++Content-Type: TEXT/PLAIN; CHARSET=US-ASCII ++ ++Hello Joe, do you think we can meet at 3:30 tomorrow? ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++A001 CAPABILITY ++ ++ ++ +--- /dev/null ++++ b/tests/data/test985 +@@ -0,0 +1,54 @@ ++ ++ ++ ++POP3 ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY CAPA -ERR Not implemented ++ ++ ++From: me@somewhere ++To: fake@nowhere ++ ++body ++ ++-- ++ yours sincerely ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++pop3 ++ ++ ++POP3 require STARTTLS with failing capabilities ++ ++ ++pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl-reqd ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++CAPA ++ ++ ++ +--- /dev/null ++++ b/tests/data/test986 +@@ -0,0 +1,53 @@ ++ ++ ++ ++FTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY welcome 230 Welcome ++REPLY AUTH 500 unknown command ++ ++ ++ ++# Client-side ++ ++ ++SSL ++ ++ ++ftp ++ ++ ++FTP require STARTTLS while preauthenticated ++ ++ ++data ++ to ++ see ++that FTPS ++works ++ so does it? ++ ++ ++--ssl-reqd --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++AUTH SSL ++AUTH TLS ++ ++ ++ diff --git a/CVE-2021-22947.patch b/CVE-2021-22947.patch new file mode 100644 index 0000000000000000000000000000000000000000..b93339d783d8ea6fc0d6925c6ac3169c2403f9d4 --- /dev/null +++ b/CVE-2021-22947.patch @@ -0,0 +1,328 @@ +Backport of: + +From 259b4f2e1fd01fbc55e569ee0a507afeae34f77c Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Tue, 7 Sep 2021 13:26:42 +0200 +Subject: [PATCH] ftp,imap,pop3,smtp: reject STARTTLS server response + pipelining + +If a server pipelines future responses within the STARTTLS response, the +former are preserved in the pingpong cache across TLS negotiation and +used as responses to the encrypted commands. + +This fix detects pipelined STARTTLS responses and rejects them with an +error. + +CVE-2021-22947 + +Bug: https://curl.se/docs/CVE-2021-22947.html +--- + lib/ftp.c | 3 +++ + lib/imap.c | 4 +++ + lib/pop3.c | 4 +++ + lib/smtp.c | 4 +++ + tests/data/Makefile.inc | 2 ++ + tests/data/test980 | 52 ++++++++++++++++++++++++++++++++++++ + tests/data/test981 | 59 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test982 | 57 +++++++++++++++++++++++++++++++++++++++ + tests/data/test983 | 52 ++++++++++++++++++++++++++++++++++++ + 9 files changed, 237 insertions(+) + create mode 100644 tests/data/test980 + create mode 100644 tests/data/test981 + create mode 100644 tests/data/test982 + create mode 100644 tests/data/test983 + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2680,6 +2680,9 @@ static CURLcode ftp_statemach_act(struct + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + ++ if(pp->cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ ++ + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -946,6 +946,10 @@ static CURLcode imap_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.imapc.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(imapcode != IMAP_RESP_OK) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); +--- a/lib/pop3.c ++++ b/lib/pop3.c +@@ -753,6 +753,10 @@ static CURLcode pop3_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.pop3c.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); +--- a/lib/smtp.c ++++ b/lib/smtp.c +@@ -680,6 +680,10 @@ static CURLcode smtp_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.smtpc.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(smtpcode != 220) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied, code %d", smtpcode); +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -111,6 +111,8 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test980 test981 test982 test983 \ ++\ + test984 test985 test986 \ + \ + test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ +--- /dev/null ++++ b/tests/data/test980 +@@ -0,0 +1,52 @@ ++ ++ ++ ++SMTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STARTTLS ++AUTH PLAIN ++REPLY STARTTLS 454 currently unavailable\r\n235 Authenticated\r\n250 2.1.0 Sender ok\r\n250 2.1.5 Recipient ok\r\n354 Enter mail\r\n250 2.0.0 Accepted ++REPLY AUTH 535 5.7.8 Authentication credentials invalid ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++smtp ++ ++ ++SMTP STARTTLS pipelined server response ++ ++ ++mail body ++ ++ ++smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret --ssl --sasl-ir -T - ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++EHLO %TESTNUMBER ++STARTTLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test981 +@@ -0,0 +1,59 @@ ++ ++ ++ ++IMAP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STARTTLS ++REPLY STARTTLS A002 BAD currently unavailable\r\nA003 OK Authenticated\r\nA004 OK Accepted ++REPLY LOGIN A003 BAD Authentication credentials invalid ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++imap ++ ++ ++IMAP STARTTLS pipelined server response ++ ++ ++imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl ++ ++ ++Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) ++From: Fred Foobar ++Subject: afternoon meeting ++To: joe@example.com ++Message-Id: ++MIME-Version: 1.0 ++Content-Type: TEXT/PLAIN; CHARSET=US-ASCII ++ ++Hello Joe, do you think we can meet at 3:30 tomorrow? ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++A001 CAPABILITY ++A002 STARTTLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test982 +@@ -0,0 +1,57 @@ ++ ++ ++ ++POP3 ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STLS USER ++REPLY STLS -ERR currently unavailable\r\n+OK user accepted\r\n+OK authenticated ++REPLY PASS -ERR Authentication credentials invalid ++ ++ ++From: me@somewhere ++To: fake@nowhere ++ ++body ++ ++-- ++ yours sincerely ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++pop3 ++ ++ ++POP3 STARTTLS pipelined server response ++ ++ ++pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++CAPA ++STLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test983 +@@ -0,0 +1,52 @@ ++ ++ ++ ++FTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY AUTH 500 unknown command\r\n500 unknown command\r\n331 give password\r\n230 Authenticated\r\n257 "/"\r\n200 OK\r\n200 OK\r\n200 OK\r\n226 Transfer complete ++REPLY PASS 530 Login incorrect ++ ++ ++ ++# Client-side ++ ++ ++SSL ++ ++ ++ftp ++ ++ ++FTP STARTTLS pipelined server response ++ ++ ++data ++ to ++ see ++that FTPS ++works ++ so does it? ++ ++ ++--ssl --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret -P %CLIENTIP ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++AUTH SSL ++ ++ ++ diff --git a/CVE-2022-22576.patch b/CVE-2022-22576.patch new file mode 100644 index 0000000000000000000000000000000000000000..33eb58beb03f9040e93751ccefbf91a782617758 --- /dev/null +++ b/CVE-2022-22576.patch @@ -0,0 +1,73 @@ +From e193f712be95dc9e5e2b92eae6381d4572231152 Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Sun, 17 Apr 2022 23:29:46 +0200 +Subject: [PATCH] url: check sasl additional parameters for connection reuse. + +Also move static function safecmp() as non-static Curl_safecmp() since +its purpose is needed at several places. + +Bug: https://curl.se/docs/CVE-2022-22576.html + +CVE-2022-22576 +Index: curl-7.68.0/lib/strcase.c +=================================================================== +--- curl-7.68.0.orig/lib/strcase.c ++++ curl-7.68.0/lib/strcase.c +@@ -249,6 +249,16 @@ void Curl_strntolower(char *dest, const + } while(*src++ && --n); + } + ++/* Compare case-sensitive NUL-terminated strings, taking care of possible ++ * null pointers. Return true if arguments match. ++ */ ++bool Curl_safecmp(char *a, char *b) ++{ ++ if(a && b) ++ return !strcmp(a, b); ++ return !a && !b; ++} ++ + /* --- public functions --- */ + + int curl_strequal(const char *first, const char *second) +Index: curl-7.68.0/lib/strcase.h +=================================================================== +--- curl-7.68.0.orig/lib/strcase.h ++++ curl-7.68.0/lib/strcase.h +@@ -49,4 +49,6 @@ char Curl_raw_tolower(char in); + void Curl_strntoupper(char *dest, const char *src, size_t n); + void Curl_strntolower(char *dest, const char *src, size_t n); + ++bool Curl_safecmp(char *a, char *b); ++ + #endif /* HEADER_CURL_STRCASE_H */ +Index: curl-7.68.0/lib/url.c +=================================================================== +--- curl-7.68.0.orig/lib/url.c ++++ curl-7.68.0/lib/url.c +@@ -1219,7 +1219,9 @@ ConnectionExists(struct Curl_easy *data, + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ + if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd)) { ++ strcmp(needle->passwd, check->passwd) || ++ !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || ++ !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } +@@ -3353,6 +3355,14 @@ static CURLcode create_conn(struct Curl_ + result = CURLE_OUT_OF_MEMORY; + goto out; + } ++ } ++ ++ if(data->set.str[STRING_BEARER]) { ++ conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); ++ if(!conn->oauth_bearer) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + } + + #ifdef USE_UNIX_SOCKETS diff --git a/CVE-2022-27774-1.patch b/CVE-2022-27774-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..7128e9a8a0e251407bc50177637e28cf4e16f630 --- /dev/null +++ b/CVE-2022-27774-1.patch @@ -0,0 +1,35 @@ +From b92ebe53f3fc7b4a4355724a22690fdef4f1bf2f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 1/3] connect: store "conn_remote_port" in the info struct + +To make it available after the connection ended. +Index: curl-7.68.0/lib/connect.c +=================================================================== +--- curl-7.68.0.orig/lib/connect.c ++++ curl-7.68.0/lib/connect.c +@@ -624,6 +624,7 @@ void Curl_persistconninfo(struct connect + conn->data->info.conn_scheme = conn->handler->scheme; + conn->data->info.conn_protocol = conn->handler->protocol; + conn->data->info.conn_primary_port = conn->primary_port; ++ conn->data->info.conn_remote_port = conn->remote_port; + conn->data->info.conn_local_port = conn->local_port; + } + +Index: curl-7.68.0/lib/urldata.h +=================================================================== +--- curl-7.68.0.orig/lib/urldata.h ++++ curl-7.68.0/lib/urldata.h +@@ -1115,7 +1115,11 @@ struct PureInfo { + reused, in the connection cache. */ + + char conn_primary_ip[MAX_IPADR_LEN]; +- long conn_primary_port; ++ int conn_primary_port; /* this is the destination port to the connection, ++ which might have been a proxy */ ++ int conn_remote_port; /* this is the "remote port", which is the port ++ number of the used URL, independent of proxy or ++ not */ + char conn_local_ip[MAX_IPADR_LEN]; + long conn_local_port; + const char *conn_scheme; diff --git a/CVE-2022-27774-2.patch b/CVE-2022-27774-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..a64064669154cdc46b2c0e743d983b0b4c8ffe09 --- /dev/null +++ b/CVE-2022-27774-2.patch @@ -0,0 +1,69 @@ +From 2b4afd8dd2132a0edd16acbe7c8d4d5c4fd06e61 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 2/3] transfer: redirects to other protocols or ports clear + auth + +... unless explicitly permitted. + +Bug: https://curl.se/docs/CVE-2022-27774.html +Reported-by: Harry Sintonen +Index: curl-7.68.0/lib/transfer.c +=================================================================== +--- curl-7.68.0.orig/lib/transfer.c ++++ curl-7.68.0/lib/transfer.c +@@ -1629,10 +1629,53 @@ CURLcode Curl_follow(struct Curl_easy *d + return CURLE_OUT_OF_MEMORY; + } + else { +- + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); ++ ++ /* Clear auth if this redirects to a different port number or protocol, ++ unless permitted */ ++ if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { ++ char *portnum; ++ int port; ++ bool clear = FALSE; ++ ++ uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, ++ CURLU_DEFAULT_PORT); ++ if(uc) { ++ free(newurl); ++ return Curl_uc_to_curlcode(uc); ++ } ++ port = atoi(portnum); ++ free(portnum); ++ ++ if(port != data->info.conn_remote_port) { ++ infof(data, "Clear auth, redirects to port from %u to %u", ++ data->info.conn_remote_port, port); ++ clear = TRUE; ++ } ++ else { ++ char *scheme; ++ const struct Curl_handler *p; ++ uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); ++ if(uc) { ++ free(newurl); ++ return Curl_uc_to_curlcode(uc); ++ } ++ ++ p = Curl_builtin_scheme(scheme); ++ if(p && (p->protocol != data->info.conn_protocol)) { ++ infof(data, "Clear auth, redirects scheme from %s to %s", ++ data->info.conn_scheme, scheme); ++ clear = TRUE; ++ } ++ free(scheme); ++ } ++ if(clear) { ++ Curl_safefree(data->set.str[STRING_USERNAME]); ++ Curl_safefree(data->set.str[STRING_PASSWORD]); ++ } ++ } + } + + if(type == FOLLOW_FAKE) { diff --git a/CVE-2022-27774-3.patch b/CVE-2022-27774-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..d3cab2666f2531ea67b5e19e3df3acf387295a1c --- /dev/null +++ b/CVE-2022-27774-3.patch @@ -0,0 +1,393 @@ +From 2bb9658d75c846d398d490a96a58b5712e43c135 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 3/3] tests: verify the fix for CVE-2022-27774 + + - Test 973 redirects from HTTP to FTP, clear auth + - Test 974 redirects from HTTP to HTTP different port, clear auth + - Test 975 redirects from HTTP to FTP, permitted to keep auth + - Test 976 redirects from HTTP to HTTP different port, permitted to keep + auth +--- + tests/data/Makefile.inc | 2 +- + tests/data/test973 | 88 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test974 | 87 ++++++++++++++++++++++++++++++++++++++++ + tests/data/test975 | 88 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test976 | 88 +++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 352 insertions(+), 1 deletion(-) + create mode 100644 tests/data/test973 + create mode 100644 tests/data/test974 + create mode 100644 tests/data/test975 + create mode 100644 tests/data/test976 + +Index: curl-7.81.0/tests/data/test973 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test973 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++FTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP w/o auth ++ ++ ++http://%HOSTIP:%HTTPPORT/973 -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET /973 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++USER anonymous ++PASS ftp@example.com ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9730002 ++RETR 9730002 ++QUIT ++ ++ ++ +Index: curl-7.81.0/tests/data/test974 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test974 +@@ -0,0 +1,87 @@ ++ ++ ++ ++HTTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.974:9999/a/path/9740002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.974:9999/a/path/9740002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port w/o auth ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.974 -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET http://firsthost.974/ HTTP/1.1 ++Host: firsthost.974 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.974:9999/a/path/9740002 HTTP/1.1 ++Host: firsthost.974:9999 ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +Index: curl-7.81.0/tests/data/test975 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test975 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++FTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP allowing auth to continue ++ ++ ++http://%HOSTIP:%HTTPPORT/975 --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET /975 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++USER joe ++PASS secret ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9750002 ++RETR 9750002 ++QUIT ++ ++ ++ +Index: curl-7.81.0/tests/data/test976 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test976 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.976:9999/a/path/9760002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.976:9999/a/path/9760002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port --location-trusted ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.976 --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET http://firsthost.976/ HTTP/1.1 ++Host: firsthost.976 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.976:9999/a/path/9760002 HTTP/1.1 ++Host: firsthost.976:9999 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ diff --git a/CVE-2022-27774-3pre.patch b/CVE-2022-27774-3pre.patch new file mode 100644 index 0000000000000000000000000000000000000000..aa69c1aa08b7e3b689d5b23b07ddad13a161f720 --- /dev/null +++ b/CVE-2022-27774-3pre.patch @@ -0,0 +1,17 @@ +From 2bb9658d75c846d398d490a96a58b5712e43c135 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 3/3] tests: verify the fix for CVE-2022-27774 + +Index: curl-7.68.0/tests/data/Makefile.inc +=================================================================== +--- curl-7.68.0.orig/tests/data/Makefile.inc ++++ curl-7.68.0/tests/data/Makefile.inc +@@ -111,6 +111,7 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test973 test974 test975 test976 \ + test980 test981 test982 test983 \ + \ + test984 test985 test986 \ diff --git a/CVE-2022-27775.patch b/CVE-2022-27775.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff7cf0dafe15a6895cddcf02d4615316c92e4b2 --- /dev/null +++ b/CVE-2022-27775.patch @@ -0,0 +1,33 @@ +From 46091487fbdb37ffbe9c495de86c62d14634b71a Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 21 Apr 2022 12:30:34 +0200 +Subject: [PATCH] conncache: include the zone id in the "bundle" hashkey + +Make connections to two separate IPv6 zone ids create separate +connections. + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27775.html +--- + lib/conncache.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +Index: curl-7.68.0/lib/conncache.c +=================================================================== +--- curl-7.68.0.orig/lib/conncache.c ++++ curl-7.68.0/lib/conncache.c +@@ -158,8 +158,12 @@ static void hashkey(struct connectdata * + /* report back which name we used */ + *hostp = hostname; + +- /* put the number first so that the hostname gets cut off if too long */ +- msnprintf(buf, len, "%ld%s", port, hostname); ++ /* put the numbers first so that the hostname gets cut off if too long */ ++#ifdef ENABLE_IPV6 ++ msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname); ++#else ++ msnprintf(buf, len, "%ld/%s", port, hostname); ++#endif + } + + void Curl_conncache_unlock(struct Curl_easy *data) diff --git a/CVE-2022-27776.patch b/CVE-2022-27776.patch new file mode 100644 index 0000000000000000000000000000000000000000..c8a4e2e5713e4fd12bd45c218037e33cfd7ef101 --- /dev/null +++ b/CVE-2022-27776.patch @@ -0,0 +1,105 @@ +Backported of: + +From 125302094326ad5eb0ea87f2d2ece6ceab1b1e59 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 22 Apr 2022 08:19:18 +0200 +Subject: [PATCH] http: avoid auth/cookie on redirects same host diff port + +CVE-2022-27776 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27776.html +diff --git a/lib/http.c b/lib/http.c +index 837f53c..4d6626b 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -733,6 +733,21 @@ output_auth_headers(struct connectdata *conn, + return CURLE_OK; + } + ++/* ++ * allow_auth_to_host() tells if autentication, cookies or other "sensitive ++ * data" can (still) be sent to this host. ++ */ ++static bool allow_auth_to_host(struct Curl_easy *data) ++{ ++ struct connectdata *conn = data->conn; ++ return (!data->state.this_is_a_follow || ++ data->set.allow_auth_to_other_hosts || ++ (data->state.first_host && ++ strcasecompare(data->state.first_host, conn->host.name) && ++ (data->state.first_remote_port == conn->remote_port) && ++ (data->state.first_remote_protocol == conn->handler->protocol))); ++} ++ + /** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication +@@ -801,15 +816,12 @@ Curl_http_output_auth(struct connectdata *conn, + with it */ + authproxy->done = TRUE; + +- /* To prevent the user+password to get sent to other than the original +- host due to a location-follow, we do some weirdo checks here */ +- if(!data->state.this_is_a_follow || +- conn->bits.netrc || +- !data->state.first_host || +- data->set.allow_auth_to_other_hosts || +- strcasecompare(data->state.first_host, conn->host.name)) { ++ /* To prevent the user+password to get sent to other than the original host ++ due to a location-follow */ ++ if(allow_auth_to_host(data) ++ || conn->bits.netrc ++ ) + result = output_auth_headers(conn, authhost, request, path, FALSE); +- } + else + authhost->done = TRUE; + +@@ -1881,10 +1893,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Cookie:", compare)) && + /* be careful of sending this potentially sensitive header to + other hosts */ +- (data->state.this_is_a_follow && +- data->state.first_host && +- !data->set.allow_auth_to_other_hosts && +- !strcasecompare(data->state.first_host, conn->host.name))) ++ !allow_auth_to_host(data)) + ; + else { + result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); +@@ -2067,6 +2076,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) + return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; ++ data->state.first_remote_protocol = conn->handler->protocol; + } + + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && +diff --git a/lib/urldata.h b/lib/urldata.h +index 6993def..5ca0921 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1315,13 +1315,15 @@ struct UrlState { + char *ulbuf; /* allocated upload buffer or NULL */ + curl_off_t current_speed; /* the ProgressShow() function sets this, + bytes / second */ +- char *first_host; /* host name of the first (not followed) request. +- if set, this should be the host name that we will +- sent authorization to, no else. Used to make Location: +- following not keep sending user+password... This is +- strdup() data. +- */ +- int first_remote_port; /* remote port of the first (not followed) request */ ++ ++ /* host name, port number and protocol of the first (not followed) request. ++ if set, this should be the host name that we will sent authorization to, ++ no else. Used to make Location: following not keep sending user+password. ++ This is strdup()ed data. */ ++ char *first_host; ++ int first_remote_port; ++ unsigned int first_remote_protocol; ++ + struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ + long sessionage; /* number of the most recent session */ + unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ diff --git a/CVE-2022-27781.patch b/CVE-2022-27781.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc8a670743321e978138e35f2bb7225438c0319c --- /dev/null +++ b/CVE-2022-27781.patch @@ -0,0 +1,42 @@ +Backport of: + +From 625924941cbd684c2a6b10d18aa6920a27c31db3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 3 May 2022 09:24:56 +0200 +Subject: [PATCH] nss: return error if seemingly stuck in a cert loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CVE-2022-27781 + +Reported-by: Florian Kohnhäuser +Bug: https://curl.se/docs/CVE-2022-27781.html +--- + lib/vtls/nss.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -950,6 +950,9 @@ static void display_cert_info(struct Cur + PR_Free(common_name); + } + ++/* A number of certs that will never occur in a real server handshake */ ++#define TOO_MANY_CERTS 300 ++ + static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) + { + CURLcode result = CURLE_OK; +@@ -986,6 +989,11 @@ static CURLcode display_conn_info(struct + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); + while(cert2) { + i++; ++ if(i >= TOO_MANY_CERTS) { ++ CERT_DestroyCertificate(cert2); ++ failf(conn->data, "certificate loop"); ++ return CURLE_SSL_CERTPROBLEM; ++ } + if(cert2->isRoot) { + CERT_DestroyCertificate(cert2); + break; diff --git a/CVE-2022-27782.patch b/CVE-2022-27782.patch new file mode 100644 index 0000000000000000000000000000000000000000..45928b999510ea2b26cc72bbfe38abce72ffdad0 --- /dev/null +++ b/CVE-2022-27782.patch @@ -0,0 +1,445 @@ +Backport of: + +From 222b896a07ed1e183e7eacd6df10fc23264bd820 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 6 May 2022 10:48:58 +0200 +Subject: [PATCH 1/2] tls: check more TLS details for connection reuse + +CVE-2022-27782 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27782.html +--- + lib/setopt.c | 29 +++++++++++++++++------------ + lib/url.c | 23 ++++++++++++++++------- + lib/urldata.h | 13 +++++++------ + lib/vtls/gtls.c | 32 +++++++++++++++++--------------- + lib/vtls/openssl.c | 10 +++++----- + lib/vtls/vtls.c | 21 +++++++++++++++++++++ + 6 files changed, 83 insertions(+), 45 deletions(-) + +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -2130,6 +2130,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + + case CURLOPT_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.ssl.enable_beast = + (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); +@@ -2139,6 +2140,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + #ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.proxy_ssl.enable_beast = + (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); +@@ -2537,44 +2539,47 @@ CURLcode Curl_vsetopt(struct Curl_easy * + case CURLOPT_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to ++ SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + case CURLOPT_PROXY_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + #endif + #ifdef USE_ARES +--- a/lib/url.c ++++ b/lib/url.c +@@ -483,7 +483,7 @@ CURLcode Curl_init_userdefined(struct Cu + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; + #ifdef USE_TLS_SRP +- set->ssl.authtype = CURL_TLSAUTH_NONE; ++ set->ssl.primary.authtype = CURL_TLSAUTH_NONE; + #endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ +@@ -997,6 +997,12 @@ static void prune_dead_connections(struc + } + } + ++static bool ssh_config_matches(struct connectdata *one, ++ struct connectdata *two) ++{ ++ return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && ++ Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub)); ++} + /* + * Given one filled in connection struct (named needle), this function should + * detect if there already is one that has all the significant details +@@ -1227,6 +1233,11 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++ if(get_protocol_family(needle->handler->protocol) == PROTO_FAMILY_SSH) { ++ if(!ssh_config_matches(needle, check)) ++ continue; ++ } ++ + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + needle->bits.tunnel_proxy) { + /* The requested connection does not use a HTTP proxy or it uses SSL or +@@ -1608,10 +1619,16 @@ static struct connectdata *allocate_conn + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; ++ conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options; ++#ifdef USE_TLS_SRP ++#endif + conn->proxy_ssl_config.verifystatus = + data->set.proxy_ssl.primary.verifystatus; + conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; + conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; ++ conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; ++#ifdef USE_TLS_SRP ++#endif + conn->ip_version = data->set.ipver; + conn->bits.connect_only = data->set.connect_only; + conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ +@@ -3554,8 +3571,9 @@ static CURLcode create_conn(struct Curl_ + data->set.proxy_ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + +- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; +- data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; ++ data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; ++ data->set.proxy_ssl.primary.CRLfile = ++ data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; +@@ -3569,10 +3587,12 @@ static CURLcode create_conn(struct Curl_ + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + #ifdef USE_TLS_SRP +- data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; +- data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; +- data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; +- data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; ++ data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; ++ data->set.proxy_ssl.primary.username = ++ data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; ++ data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; ++ data->set.proxy_ssl.primary.password = ++ data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; + #endif + + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -231,6 +231,13 @@ struct ssl_primary_config { + char *cipher_list; /* list of ciphers to use */ + char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ + char *pinned_key; ++ char *CRLfile; /* CRL to check certificate revocation */ ++#ifdef USE_TLS_SRP ++ char *username; /* TLS username (for, e.g., SRP) */ ++ char *password; /* TLS password (for, e.g., SRP) */ ++ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ ++#endif ++ unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ + BIT(verifypeer); /* set TRUE if this is desired */ + BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ + BIT(verifystatus); /* set TRUE if certificate status must be checked */ +@@ -240,7 +247,6 @@ struct ssl_primary_config { + struct ssl_config_data { + struct ssl_primary_config primary; + long certverifyresult; /* result from the certificate verification */ +- char *CRLfile; /* CRL to check certificate revocation */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + char *cert; /* client certificate file name */ +@@ -248,11 +254,6 @@ struct ssl_config_data { + char *key; /* private key file name */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ +-#ifdef USE_TLS_SRP +- char *username; /* TLS username (for, e.g., SRP) */ +- char *password; /* TLS password (for, e.g., SRP) */ +- enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +-#endif + BIT(certinfo); /* gather lots of certificate info */ + BIT(falsestart); + BIT(enable_beast); /* allow this flaw for interoperability's sake*/ +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -581,8 +581,9 @@ gtls_connect_step1(struct connectdata *c + } + + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { +- infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { ++ infof(data, "Using TLS-SRP username: %s\n", ++ SSL_SET_OPTION(primary.username)); + + rc = gnutls_srp_allocate_client_credentials( + &BACKEND->srp_client_cred); +@@ -593,8 +594,8 @@ gtls_connect_step1(struct connectdata *c + } + + rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, +- SSL_SET_OPTION(username), +- SSL_SET_OPTION(password)); ++ SSL_SET_OPTION(primary.username), ++ SSL_SET_OPTION(primary.password)); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_set_client_cred() failed: %s", + gnutls_strerror(rc)); +@@ -648,19 +649,19 @@ gtls_connect_step1(struct connectdata *c + } + #endif + +- if(SSL_SET_OPTION(CRLfile)) { ++ if(SSL_SET_OPTION(primary.CRLfile)) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, +- SSL_SET_OPTION(CRLfile), ++ SSL_SET_OPTION(primary.CRLfile), + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)", +- SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); ++ SSL_SET_OPTION(primary.CRLfile), gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s\n", +- rc, SSL_SET_OPTION(CRLfile)); ++ rc, SSL_SET_OPTION(primary.CRLfile)); + } + + /* Initialize TLS session as a client */ +@@ -787,7 +788,7 @@ gtls_connect_step1(struct connectdata *c + #ifdef USE_TLS_SRP + /* Only add SRP to the cipher list if SRP is requested. Otherwise + * GnuTLS will disable TLS 1.3 support. */ +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { + size_t len = strlen(prioritylist); + + char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); +@@ -884,7 +885,7 @@ gtls_connect_step1(struct connectdata *c + + #ifdef USE_TLS_SRP + /* put the credentials to the current session */ +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { + rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, + BACKEND->srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { +@@ -1066,8 +1067,8 @@ gtls_connect_step3(struct connectdata *c + SSL_CONN_CONFIG(verifyhost) || + SSL_CONN_CONFIG(issuercert)) { + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP +- && SSL_SET_OPTION(username) != NULL ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP ++ && SSL_SET_OPTION(primary.username) != NULL + && !SSL_CONN_CONFIG(verifypeer) + && gnutls_cipher_get(session)) { + /* no peer cert, but auth is ok if we have SRP user and cipher and no +@@ -1121,7 +1122,8 @@ gtls_connect_step3(struct connectdata *c + failf(data, "server certificate verification failed. CAfile: %s " + "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): + "none", +- SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); ++ SSL_SET_OPTION(primary.CRLfile) ? ++ SSL_SET_OPTION(primary.CRLfile) : "none"); + return CURLE_PEER_FAILED_VERIFICATION; + } + else +@@ -1708,8 +1710,8 @@ static int Curl_gtls_shutdown(struct con + gnutls_certificate_free_credentials(BACKEND->cred); + + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP +- && SSL_SET_OPTION(username) != NULL) ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP ++ && SSL_SET_OPTION(primary.username) != NULL) + gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); + #endif + +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -2466,14 +2466,14 @@ static CURLcode ossl_connect_step1(struc + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const long int ssl_version = SSL_CONN_CONFIG(version); + #ifdef USE_TLS_SRP +- const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); ++ const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype); + #endif + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); +- const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); ++ const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile); + char error_buffer[256]; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); +@@ -2752,15 +2752,15 @@ static CURLcode ossl_connect_step1(struc + + #ifdef USE_TLS_SRP + if(ssl_authtype == CURL_TLSAUTH_SRP) { +- char * const ssl_username = SSL_SET_OPTION(username); +- ++ char * const ssl_username = SSL_SET_OPTION(primary.username); ++ char * const ssl_password = SSL_SET_OPTION(primary.password); + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +- if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { ++ if(!SSL_CTX_set_srp_password(BACKEND->ctx, ssl_password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -98,6 +98,7 @@ Curl_ssl_config_matches(struct ssl_prima + { + if((data->version == needle->version) && + (data->version_max == needle->version_max) && ++ (data->ssl_options == needle->ssl_options) && + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +@@ -107,8 +108,14 @@ Curl_ssl_config_matches(struct ssl_prima + safecmp(data->clientcert, needle->clientcert) && + safecmp(data->random_file, needle->random_file) && + safecmp(data->egdsocket, needle->egdsocket) && ++#ifdef USE_TLS_SRP ++ Curl_safecmp(data->username, needle->username) && ++ Curl_safecmp(data->password, needle->password) && ++ (data->authtype == needle->authtype) && ++#endif + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && ++ Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) && + Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) + return TRUE; + +@@ -125,6 +132,10 @@ Curl_clone_primary_ssl_config(struct ssl + dest->verifyhost = source->verifyhost; + dest->verifystatus = source->verifystatus; + dest->sessionid = source->sessionid; ++ dest->ssl_options = source->ssl_options; ++#ifdef USE_TLS_SRP ++ dest->authtype = source->authtype; ++#endif + + CLONE_STRING(CApath); + CLONE_STRING(CAfile); +@@ -135,6 +146,11 @@ Curl_clone_primary_ssl_config(struct ssl + CLONE_STRING(cipher_list); + CLONE_STRING(cipher_list13); + CLONE_STRING(pinned_key); ++ CLONE_STRING(CRLfile); ++#ifdef USE_TLS_SRP ++ CLONE_STRING(username); ++ CLONE_STRING(password); ++#endif + + return TRUE; + } +@@ -150,6 +166,11 @@ void Curl_free_primary_ssl_config(struct + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); + Curl_safefree(sslc->pinned_key); ++ Curl_safefree(sslc->CRLfile); ++#ifdef USE_TLS_SRP ++ Curl_safefree(sslc->username); ++ Curl_safefree(sslc->password); ++#endif + } + + #ifdef USE_SSL +--- a/lib/vssh/ssh.h ++++ b/lib/vssh/ssh.h +@@ -117,8 +117,8 @@ struct ssh_conn { + + /* common */ + const char *passphrase; /* pass-phrase to use */ +- char *rsa_pub; /* path name */ +- char *rsa; /* path name */ ++ char *rsa_pub; /* strdup'ed public key file */ ++ char *rsa; /* strdup'ed private key file */ + bool authed; /* the connection has been authenticated fine */ + sshstate state; /* always use ssh.c:state() to change state! */ + sshstate nextstate; /* the state to goto after stopping */ +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -1955,13 +1955,13 @@ static CURLcode nss_setup_connect(struct + } + } + +- if(SSL_SET_OPTION(CRLfile)) { +- const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); ++ if(SSL_SET_OPTION(primary.CRLfile)) { ++ const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile)); + if(rv) { + result = rv; + goto error; + } +- infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); ++ infof(data, " CRLfile: %s\n", SSL_SET_OPTION(primary.CRLfile)); + } + + if(SSL_SET_OPTION(cert)) { diff --git a/CVE-2022-32206.patch b/CVE-2022-32206.patch new file mode 100644 index 0000000000000000000000000000000000000000..815247eea649375c031df3738af94b134e1c56a5 --- /dev/null +++ b/CVE-2022-32206.patch @@ -0,0 +1,42 @@ +Backported of: + +From 7035676c3daa4f1c3766095561f12e7a0e82c736 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 16 May 2022 16:28:13 +0200 +Subject: [PATCH] content_encoding: return error on too many compression steps + +The max allowed steps is arbitrarily set to 5. +Index: curl-7.68.0/lib/content_encoding.c +=================================================================== +--- curl-7.68.0.orig/lib/content_encoding.c ++++ curl-7.68.0/lib/content_encoding.c +@@ -934,6 +934,9 @@ static const content_encoding *find_enco + return NULL; + } + ++/* allow no more than 5 "chained" compression steps */ ++#define MAX_ENCODE_STACK 5 ++ + /* Set-up the unencoding stack from the Content-Encoding header value. + * See RFC 7231 section 3.1.2.2. */ + CURLcode Curl_build_unencoding_stack(struct connectdata *conn, +@@ -941,6 +944,7 @@ CURLcode Curl_build_unencoding_stack(str + { + struct Curl_easy *data = conn->data; + struct SingleRequest *k = &data->req; ++ int counter = 0; + + do { + const char *name; +@@ -975,6 +979,11 @@ CURLcode Curl_build_unencoding_stack(str + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + ++ if(++counter >= MAX_ENCODE_STACK) { ++ failf(data, "Reject response due to %u content encodings", ++ counter); ++ return CURLE_BAD_CONTENT_ENCODING; ++ } + /* Stack the unencoding stage. */ + writer = new_unencoding_writer(conn, encoding, k->writer_stack); + if(!writer) diff --git a/CVE-2022-32208.patch b/CVE-2022-32208.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f861e7d94201123e5be52d24d5e1bb5e0517042 --- /dev/null +++ b/CVE-2022-32208.patch @@ -0,0 +1,24 @@ +Backported from: + +From 4c3f77e871820d055a5f6c4cd7a6ac47a7f3877d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Jun 2022 09:27:24 +0200 +Subject: [PATCH] krb5: return error properly on decode errors + +diff --git a/lib/krb5.c b/lib/krb5.c +index f50287a..5b77e35 100644 +--- a/lib/krb5.c ++++ b/lib/krb5.c +@@ -86,11 +86,8 @@ krb5_decode(void *app_data, void *buf, int len, + enc.value = buf; + enc.length = len; + maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); +- if(maj != GSS_S_COMPLETE) { +- if(len >= 4) +- strcpy(buf, "599 "); ++ if(maj != GSS_S_COMPLETE) + return -1; +- } + + memcpy(buf, dec.value, dec.length); + len = curlx_uztosi(dec.length); diff --git a/CVE-2022-32221.patch b/CVE-2022-32221.patch new file mode 100644 index 0000000000000000000000000000000000000000..40b9ad500dd7275e290d0df9785281f4834ee317 --- /dev/null +++ b/CVE-2022-32221.patch @@ -0,0 +1,24 @@ +Backport of: + +From a64e3e59938abd7d667e4470a18072a24d7e9de9 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 15 Sep 2022 09:22:45 +0200 +Subject: [PATCH] setopt: when POST is set, reset the 'upload' field + +Reported-by: RobBotic1 on github +Fixes #9507 +Closes #9511 +--- + lib/setopt.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -486,6 +486,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + } + else + data->set.httpreq = HTTPREQ_GET; ++ data->set.upload = FALSE; + break; + + case CURLOPT_COPYPOSTFIELDS: diff --git a/CVE-2022-35252.patch b/CVE-2022-35252.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d51a61acecbbb82e4d8cf9d3ad9a15a7fc6cd9b --- /dev/null +++ b/CVE-2022-35252.patch @@ -0,0 +1,63 @@ +From 8dfc93e573ca740544a2d79ebb0ed786592c65c3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 29 Aug 2022 00:09:17 +0200 +Subject: [PATCH] cookie: reject cookies with "control bytes" + +Rejects 0x01 - 0x1f (except 0x09) plus 0x7f + +Reported-by: Axel Chong + +Bug: https://curl.se/docs/CVE-2022-35252.html + +CVE-2022-35252 + +Closes #9381 +--- + lib/cookie.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +--- a/lib/cookie.c ++++ b/lib/cookie.c +@@ -411,6 +411,30 @@ static bool bad_domain(const char *domai + return !strchr(domain, '.') && !strcasecompare(domain, "localhost"); + } + ++/* ++ RFC 6265 section 4.1.1 says a server should accept this range: ++ ++ cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E ++ ++ But Firefox and Chrome as of June 2022 accept space, comma and double-quotes ++ fine. The prime reason for filtering out control bytes is that some HTTP ++ servers return 400 for requests that contain such. ++*/ ++static int invalid_octets(const char *p) ++{ ++ /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */ ++ static const char badoctets[] = { ++ "\x01\x02\x03\x04\x05\x06\x07\x08\x0a" ++ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" ++ "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" ++ }; ++ size_t vlen, len; ++ /* scan for all the octets that are *not* in cookie-octet */ ++ len = strcspn(p, badoctets); ++ vlen = strlen(p); ++ return (len != vlen); ++} ++ + /**************************************************************************** + * + * Curl_cookie_add() +@@ -557,6 +581,11 @@ Curl_cookie_add(struct Curl_easy *data, + badcookie = TRUE; + break; + } ++ if(invalid_octets(whatptr) || invalid_octets(name)) { ++ infof(data, "invalid octets in name/value, cookie dropped"); ++ badcookie = TRUE; ++ break; ++ } + } + else if(!len) { + /* this was a "=" with no content, and we must allow diff --git a/CVE-2022-43552.patch b/CVE-2022-43552.patch new file mode 100644 index 0000000000000000000000000000000000000000..5085cc12764b664023a7f8b20c4f14b7e5b84f28 --- /dev/null +++ b/CVE-2022-43552.patch @@ -0,0 +1,72 @@ +Backport of: + +From 4f20188ac644afe174be6005ef4f6ffba232b8b2 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 19 Dec 2022 08:38:37 +0100 +Subject: [PATCH] smb/telnet: do not free the protocol struct in *_done() + +It is managed by the generic layer. + +Reported-by: Trail of Bits + +Closes #10112 +--- + lib/smb.c | 14 ++------------ + lib/telnet.c | 3 --- + 2 files changed, 2 insertions(+), 15 deletions(-) + +--- a/lib/smb.c ++++ b/lib/smb.c +@@ -61,8 +61,6 @@ static CURLcode smb_connect(struct conne + static CURLcode smb_connection_state(struct connectdata *conn, bool *done); + static CURLcode smb_do(struct connectdata *conn, bool *done); + static CURLcode smb_request_state(struct connectdata *conn, bool *done); +-static CURLcode smb_done(struct connectdata *conn, CURLcode status, +- bool premature); + static CURLcode smb_disconnect(struct connectdata *conn, bool dead); + static int smb_getsock(struct connectdata *conn, curl_socket_t *socks); + static CURLcode smb_parse_url_path(struct connectdata *conn); +@@ -74,7 +72,7 @@ const struct Curl_handler Curl_handler_s + "SMB", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ +- smb_done, /* done */ ++ ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ +@@ -99,7 +97,7 @@ const struct Curl_handler Curl_handler_s + "SMBS", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ +- smb_done, /* done */ ++ ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ +@@ -919,14 +917,6 @@ static CURLcode smb_request_state(struct + return CURLE_OK; + } + +-static CURLcode smb_done(struct connectdata *conn, CURLcode status, +- bool premature) +-{ +- (void) premature; +- Curl_safefree(conn->data->req.protop); +- return status; +-} +- + static CURLcode smb_disconnect(struct connectdata *conn, bool dead) + { + struct smb_conn *smbc = &conn->proto.smbc; +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -1295,8 +1295,6 @@ static CURLcode telnet_done(struct conne + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + +- Curl_safefree(conn->data->req.protop); +- + return CURLE_OK; + } + diff --git a/CVE-2023-23916.patch b/CVE-2023-23916.patch new file mode 100644 index 0000000000000000000000000000000000000000..fab115a93550f4a71bff9b14f2f17fb9f753daf9 --- /dev/null +++ b/CVE-2023-23916.patch @@ -0,0 +1,221 @@ +Backport of: + +From 119fb187192a9ea13dc90d9d20c215fc82799ab9 Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Mon, 13 Feb 2023 08:33:09 +0100 +Subject: [PATCH] content_encoding: do not reset stage counter for each header + +Test 418 verifies + +Closes #10492 +--- + lib/content_encoding.c | 7 +- + lib/urldata.h | 1 + + tests/data/Makefile.inc | 2 +- + tests/data/test387 | 2 +- + tests/data/test418 | 152 ++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 158 insertions(+), 6 deletions(-) + create mode 100644 tests/data/test418 + +--- a/lib/content_encoding.c ++++ b/lib/content_encoding.c +@@ -944,7 +944,6 @@ CURLcode Curl_build_unencoding_stack(str + { + struct Curl_easy *data = conn->data; + struct SingleRequest *k = &data->req; +- int counter = 0; + + do { + const char *name; +@@ -979,9 +978,9 @@ CURLcode Curl_build_unencoding_stack(str + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + +- if(++counter >= MAX_ENCODE_STACK) { +- failf(data, "Reject response due to %u content encodings", +- counter); ++ if(k->writer_stack_depth++ >= MAX_ENCODE_STACK) { ++ failf(data, "Reject response due to more than %u content encodings", ++ MAX_ENCODE_STACK); + return CURLE_BAD_CONTENT_ENCODING; + } + /* Stack the unencoding stage. */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -643,6 +643,7 @@ struct SingleRequest { + #ifndef CURL_DISABLE_DOH + struct dohdata doh; /* DoH specific data for this request */ + #endif ++ unsigned char writer_stack_depth; /* Unencoding stack depth. */ + BIT(header); /* incoming data has HTTP header */ + BIT(content_range); /* set TRUE if Content-Range: was found */ + BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -63,7 +63,7 @@ test350 test351 test352 test353 test354 + test393 test394 test395 \ + \ + test400 test401 test402 test403 test404 test405 test406 test407 test408 \ +-test409 \ ++test409 test418 \ + \ + test490 test491 test492 \ + \ +--- /dev/null ++++ b/tests/data/test418 +@@ -0,0 +1,155 @@ ++ ++ ++ ++HTTP ++gzip ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 200 OK ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++ ++-foo- ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++Response with multiple Transfer-Encoding headers ++ ++ ++http://%HOSTIP:%HTTPPORT/418 -sS ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent: curl/.* ++ ++ ++GET /418 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++ ++ ++# CURLE_BAD_CONTENT_ENCODING is 61 ++ ++61 ++ ++ ++curl: (61) Reject response due to more than 5 content encodings ++ ++ ++ diff --git a/CVE-2023-27533.patch b/CVE-2023-27533.patch new file mode 100644 index 0000000000000000000000000000000000000000..ddd5efa46e0e0821cdf760541e85a4749c61ba50 --- /dev/null +++ b/CVE-2023-27533.patch @@ -0,0 +1,54 @@ +Backport of: + +From 538b1e79a6e7b0bb829ab4cecc828d32105d0684 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 6 Mar 2023 12:07:33 +0100 +Subject: [PATCH] telnet: only accept option arguments in ascii + +To avoid embedded telnet negotiation commands etc. + +Reported-by: Harry Sintonen +Closes #10728 +--- + lib/telnet.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -815,6 +815,17 @@ static void printsub(struct Curl_easy *d + } + } + ++static bool str_is_nonascii(const char *str) ++{ ++ size_t len = strlen(str); ++ while(len--) { ++ if(*str & 0x80) ++ return TRUE; ++ str++; ++ } ++ return FALSE; ++} ++ + static CURLcode check_telnet_options(struct connectdata *conn) + { + struct curl_slist *head; +@@ -829,6 +840,8 @@ static CURLcode check_telnet_options(str + /* Add the user name as an environment variable if it + was given on the command line */ + if(conn->bits.user_passwd) { ++ if(str_is_nonascii(data->conn->user)) ++ return CURLE_BAD_FUNCTION_ARGUMENT; + msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { +@@ -844,6 +857,9 @@ static CURLcode check_telnet_options(str + if(sscanf(head->data, "%127[^= ]%*[ =]%255s", + option_keyword, option_arg) == 2) { + ++ if(str_is_nonascii(option_arg)) ++ continue; ++ + /* Terminal type */ + if(strcasecompare(option_keyword, "TTYPE")) { + strncpy(tn->subopt_ttype, option_arg, 31); diff --git a/CVE-2023-27534-pre1.patch b/CVE-2023-27534-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..efb03f6a71a38954c44a7a9236f3cdc079848443 --- /dev/null +++ b/CVE-2023-27534-pre1.patch @@ -0,0 +1,33 @@ +From 6c51adeb71da076c5c40a45e339e06bb4394a86b Mon Sep 17 00:00:00 2001 +From: Eric Vigeant +Date: Wed, 2 Nov 2022 11:47:09 -0400 +Subject: [PATCH] cur_path: do not add '/' if homedir ends with one + +When using SFTP and a path relative to the user home, do not add a +trailing '/' to the user home dir if it already ends with one. + +Closes #9844 +--- + lib/curl_path.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/lib/curl_path.c ++++ b/lib/curl_path.c +@@ -70,10 +70,14 @@ CURLcode Curl_getworkingpath(struct conn + /* It is referenced to the home directory, so strip the + leading '/' */ + memcpy(real_path, homedir, homelen); +- real_path[homelen] = '/'; +- real_path[homelen + 1] = '\0'; ++ /* Only add a trailing '/' if homedir does not end with one */ ++ if(homelen == 0 || real_path[homelen - 1] != '/') { ++ real_path[homelen] = '/'; ++ homelen++; ++ real_path[homelen] = '\0'; ++ } + if(working_path_len > 3) { +- memcpy(real_path + homelen + 1, working_path + 3, ++ memcpy(real_path + homelen, working_path + 3, + 1 + working_path_len -3); + } + } diff --git a/CVE-2023-27534.patch b/CVE-2023-27534.patch new file mode 100644 index 0000000000000000000000000000000000000000..6eedebbfc011b6b3a0f46e8aa8900a156997e5cf --- /dev/null +++ b/CVE-2023-27534.patch @@ -0,0 +1,24 @@ +Backport of: + +From 4e2b52b5f7a3bf50a0f1494155717b02cc1df6d6 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Mar 2023 16:22:11 +0100 +Subject: [PATCH] curl_path: create the new path with dynbuf + +Closes #10729 +--- + lib/curl_path.c | 75 +++++++++++++++++++++++-------------------------- + 1 file changed, 35 insertions(+), 40 deletions(-) + + +--- a/lib/curl_path.c ++++ b/lib/curl_path.c +@@ -60,7 +60,7 @@ CURLcode Curl_getworkingpath(struct conn + memcpy(real_path, working_path, 1 + working_path_len); + } + else if(conn->handler->protocol & CURLPROTO_SFTP) { +- if((working_path_len > 1) && (working_path[1] == '~')) { ++ if((working_path_len > 2) && !memcmp(working_path, "/~/", 3)) { + size_t homelen = strlen(homedir); + real_path = malloc(homelen + working_path_len + 1); + if(real_path == NULL) { diff --git a/CVE-2023-27535-pre1.patch b/CVE-2023-27535-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..4937686ca857539e3599c602028ce6e32556a46f --- /dev/null +++ b/CVE-2023-27535-pre1.patch @@ -0,0 +1,156 @@ +Backport of: + +From ed5095ed94281989e103c72e032200b83be37878 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 6 Oct 2022 00:49:10 +0200 +Subject: [PATCH] strcase: add and use Curl_timestrcmp + +This is a strcmp() alternative function for comparing "secrets", +designed to take the same time no matter the content to not leak +match/non-match info to observers based on how fast it is. + +The time this function takes is only a function of the shortest input +string. + +Reported-by: Trail of Bits + +Closes #9658 +--- + lib/netrc.c | 6 +++--- + lib/strcase.c | 22 ++++++++++++++++++++++ + lib/strcase.h | 1 + + lib/url.c | 34 +++++++++++++--------------------- + lib/vauth/digest_sspi.c | 4 ++-- + lib/vtls/vtls.c | 4 ++-- + 6 files changed, 43 insertions(+), 28 deletions(-) + +--- a/lib/netrc.c ++++ b/lib/netrc.c +@@ -123,9 +123,9 @@ static int parsenetrc(const char *host, + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + if(specific_login) { +- state_our_login = strcasecompare(login, tok); ++ state_our_login = !Curl_timestrcmp(login, tok); + } +- else if(!login || strcmp(login, tok)) { ++ else if(!login || Curl_timestrcmp(login, tok)) { + if(login_alloc) { + free(login); + login_alloc = FALSE; +@@ -141,7 +141,7 @@ static int parsenetrc(const char *host, + } + else if(state_password) { + if((state_our_login || !specific_login) +- && (!password || strcmp(password, tok))) { ++ && (!password || Curl_timestrcmp(password, tok))) { + if(password_alloc) { + free(password); + password_alloc = FALSE; +--- a/lib/strcase.c ++++ b/lib/strcase.c +@@ -259,6 +259,28 @@ bool Curl_safecmp(char *a, char *b) + return !a && !b; + } + ++/* ++ * Curl_timestrcmp() returns 0 if the two strings are identical. The time this ++ * function spends is a function of the shortest string, not of the contents. ++ */ ++int Curl_timestrcmp(const char *a, const char *b) ++{ ++ int match = 0; ++ int i = 0; ++ ++ if(a && b) { ++ while(1) { ++ match |= a[i]^b[i]; ++ if(!a[i] || !b[i]) ++ break; ++ i++; ++ } ++ } ++ else ++ return a || b; ++ return match; ++} ++ + /* --- public functions --- */ + + int curl_strequal(const char *first, const char *second) +--- a/lib/strcase.h ++++ b/lib/strcase.h +@@ -50,5 +50,6 @@ void Curl_strntoupper(char *dest, const + void Curl_strntolower(char *dest, const char *src, size_t n); + + bool Curl_safecmp(char *a, char *b); ++int Curl_timestrcmp(const char *first, const char *second); + + #endif /* HEADER_CURL_STRCASE_H */ +--- a/lib/url.c ++++ b/lib/url.c +@@ -1224,10 +1224,10 @@ ConnectionExists(struct Curl_easy *data, + if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ +- if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd) || +- !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || +- !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd) || ++ Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) || ++ Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } +@@ -1293,8 +1293,8 @@ ConnectionExists(struct Curl_easy *data, + possible. (Especially we must not reuse the same connection if + partway through a handshake!) */ + if(wantNTLMhttp) { +- if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd)) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd)) { + + /* we prefer a credential match, but this is at least a connection + that can be reused and "upgraded" to NTLM */ +@@ -1315,8 +1315,10 @@ ConnectionExists(struct Curl_easy *data, + if(!check->http_proxy.user || !check->http_proxy.passwd) + continue; + +- if(strcmp(needle->http_proxy.user, check->http_proxy.user) || +- strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) ++ if(Curl_timestrcmp(needle->http_proxy.user, ++ check->http_proxy.user) || ++ Curl_timestrcmp(needle->http_proxy.passwd, ++ check->http_proxy.passwd)) + continue; + } + else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { +--- a/lib/vauth/digest_sspi.c ++++ b/lib/vauth/digest_sspi.c +@@ -450,8 +450,8 @@ CURLcode Curl_auth_create_digest_http_me + has changed then delete that context. */ + if((userp && !digest->user) || (!userp && digest->user) || + (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || +- (userp && digest->user && strcmp(userp, digest->user)) || +- (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { ++ (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || ++ (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -109,8 +109,8 @@ Curl_ssl_config_matches(struct ssl_prima + safecmp(data->random_file, needle->random_file) && + safecmp(data->egdsocket, needle->egdsocket) && + #ifdef USE_TLS_SRP +- Curl_safecmp(data->username, needle->username) && +- Curl_safecmp(data->password, needle->password) && ++ !Curl_timestrcmp(data->username, needle->username) && ++ !Curl_timestrcmp(data->password, needle->password) && + (data->authtype == needle->authtype) && + #endif + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && diff --git a/CVE-2023-27535.patch b/CVE-2023-27535.patch new file mode 100644 index 0000000000000000000000000000000000000000..b98337d4636b968e99906417283ce65ec3cc98a6 --- /dev/null +++ b/CVE-2023-27535.patch @@ -0,0 +1,153 @@ +Backport of: + +From 8f4608468b890dce2dad9f91d5607ee7e9c1aba1 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Mar 2023 17:47:06 +0100 +Subject: [PATCH] ftp: add more conditions for connection reuse + +Reported-by: Harry Sintonen +Closes #10730 +--- + lib/ftp.c | 28 ++++++++++++++++++++++++++-- + lib/ftp.h | 5 +++++ + lib/setopt.c | 2 +- + lib/url.c | 17 +++++++++++++++-- + lib/urldata.h | 4 ++-- + 5 files changed, 49 insertions(+), 7 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -4069,6 +4069,10 @@ static CURLcode ftp_disconnect(struct co + } + + freedirs(ftpc); ++ free(ftpc->account); ++ ftpc->account = NULL; ++ free(ftpc->alternative_to_user); ++ ftpc->alternative_to_user = NULL; + free(ftpc->prevpath); + ftpc->prevpath = NULL; + free(ftpc->server_os); +@@ -4336,11 +4340,31 @@ static CURLcode ftp_setup_connection(str + struct Curl_easy *data = conn->data; + char *type; + struct FTP *ftp; ++ struct ftp_conn *ftpc = &conn->proto.ftpc; + +- conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1); ++ ftp = calloc(sizeof(struct FTP), 1); + if(NULL == ftp) + return CURLE_OUT_OF_MEMORY; + ++ /* clone connection related data that is FTP specific */ ++ if(data->set.str[STRING_FTP_ACCOUNT]) { ++ ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]); ++ if(!ftpc->account) { ++ free(ftp); ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { ++ ftpc->alternative_to_user = ++ strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); ++ if(!ftpc->alternative_to_user) { ++ Curl_safefree(ftpc->account); ++ free(ftp); ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ conn->data->req.protop = ftp; ++ + ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=" that +@@ -4388,7 +4412,9 @@ static CURLcode ftp_setup_connection(str + if(isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + +- conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ ++ ftpc->known_filesize = -1; /* unknown size for now */ ++ ftpc->use_ssl = data->set.use_ssl; ++ ftpc->ccc = data->set.ftp_ccc; + + return CURLE_OK; + } +--- a/lib/ftp.h ++++ b/lib/ftp.h +@@ -118,6 +118,8 @@ struct FTP { + struct */ + struct ftp_conn { + struct pingpong pp; ++ char *account; ++ char *alternative_to_user; + char *entrypath; /* the PWD reply when we logged on */ + char **dirs; /* realloc()ed array for path components */ + int dirdepth; /* number of entries used in the 'dirs' array */ +@@ -143,6 +145,9 @@ struct ftp_conn { + ftpstate state; /* always use ftp.c:state() to change state! */ + ftpstate state_saved; /* transfer type saved to be reloaded after + data connection is established */ ++ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or ++ IMAP or POP3 or others! (type: curl_usessl)*/ ++ unsigned char ccc; /* ccc level for this connection */ + curl_off_t retr_size_saved; /* Size of retrieved file saved */ + char *server_os; /* The target server operating system. */ + curl_off_t known_filesize; /* file size is different from -1, if wildcard +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -2126,7 +2126,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + arg = va_arg(param, long); + if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; +- data->set.use_ssl = (curl_usessl)arg; ++ data->set.use_ssl = (unsigned char)arg; + break; + + case CURLOPT_SSL_OPTIONS: +--- a/lib/url.c ++++ b/lib/url.c +@@ -1238,10 +1238,24 @@ ConnectionExists(struct Curl_easy *data, + if(needle->gssapi_delegation != check->gssapi_delegation) + continue; + ++#ifdef USE_SSH + if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; + } ++#endif ++#ifndef CURL_DISABLE_FTP ++ else if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_FTP) { ++ /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */ ++ if(Curl_timestrcmp(needle->proto.ftpc.account, ++ check->proto.ftpc.account) || ++ Curl_timestrcmp(needle->proto.ftpc.alternative_to_user, ++ check->proto.ftpc.alternative_to_user) || ++ (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) || ++ (needle->proto.ftpc.ccc != check->proto.ftpc.ccc)) ++ continue; ++ } ++#endif + + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + needle->bits.tunnel_proxy) { +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1683,8 +1683,6 @@ struct UserDefined { + void *ssh_keyfunc_userp; /* custom pointer to callback */ + enum CURL_NETRC_OPTION + use_netrc; /* defined in include/curl.h */ +- curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or +- IMAP or POP3 or others! */ + long new_file_perms; /* Permissions to use when creating remote files */ + long new_directory_perms; /* Permissions to use when creating remote dirs */ + long ssh_auth_types; /* allowed SSH auth types */ +@@ -1802,6 +1800,8 @@ struct UserDefined { + BIT(doh); /* DNS-over-HTTPS enabled */ + BIT(doh_get); /* use GET for DoH requests, instead of POST */ + BIT(http09_allowed); /* allow HTTP/0.9 responses */ ++ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or ++ IMAP or POP3 or others! (type: curl_usessl)*/ + }; + + struct Names { diff --git a/CVE-2023-27536.patch b/CVE-2023-27536.patch new file mode 100644 index 0000000000000000000000000000000000000000..222c55b9fea5e0e636ce3c50a3823f4e745e2001 --- /dev/null +++ b/CVE-2023-27536.patch @@ -0,0 +1,46 @@ +Backport of: + +From cb49e67303dbafbab1cebf4086e3ec15b7d56ee5 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 10 Mar 2023 09:22:43 +0100 +Subject: [PATCH] url: only reuse connections with same GSS delegation + +Reported-by: Harry Sintonen +Closes #10731 +--- + lib/url.c | 6 ++++++ + lib/urldata.h | 1 + + 2 files changed, 7 insertions(+) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -1233,6 +1233,11 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++ /* GSS delegation differences do not actually affect every connection ++ and auth method, but this check takes precaution before efficiency */ ++ if(needle->gssapi_delegation != check->gssapi_delegation) ++ continue; ++ + if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; +@@ -1661,6 +1666,7 @@ static struct connectdata *allocate_conn + conn->fclosesocket = data->set.fclosesocket; + conn->closesocket_client = data->set.closesocket_client; + conn->lastused = Curl_now(); /* used now */ ++ conn->gssapi_delegation = data->set.gssapi_delegation; + + return conn; + error: +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1085,6 +1085,7 @@ struct connectdata { + handle */ + BIT(writechannel_inuse); /* whether the write channel is in use by an easy + handle */ ++ long gssapi_delegation; /* inherited from set.gssapi_delegation */ + }; + + /* The end of connectdata. */ diff --git a/CVE-2023-27538.patch b/CVE-2023-27538.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e6c7fca52640f02b062985dda5a3f1b8e05b8ef --- /dev/null +++ b/CVE-2023-27538.patch @@ -0,0 +1,24 @@ +Backport of: + +From af369db4d3833272b8ed443f7fcc2e757a0872eb Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 10 Mar 2023 08:22:51 +0100 +Subject: [PATCH] url: fix the SSH connection reuse check + +Reported-by: Harry Sintonen +Closes #10735 +--- + lib/url.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -1233,7 +1233,7 @@ ConnectionExists(struct Curl_easy *data, + } + } + +- if(get_protocol_family(needle->handler->protocol) == PROTO_FAMILY_SSH) { ++ if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; + } diff --git a/CVE-2023-28321.patch b/CVE-2023-28321.patch new file mode 100644 index 0000000000000000000000000000000000000000..84408480bdbce3a5ef3c81da1c3e6aba406d6d78 --- /dev/null +++ b/CVE-2023-28321.patch @@ -0,0 +1,269 @@ +This backport was obtained from SUSE. + +From 199f2d440d8659b42670c1b796220792b01a97bf Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 24 Apr 2023 21:07:02 +0200 +Subject: [PATCH] hostcheck: fix host name wildcard checking + +The leftmost "label" of the host name can now only match against single +'*'. Like the browsers have worked for a long time. + +- extended unit test 1397 for this +- move some SOURCE variables from unit/Makefile.am to unit/Makefile.inc + +Reported-by: Hiroki Kurosawa +Closes #11018 +--- + lib/hostcheck.c | 50 +++++++-------- + tests/data/test1397 | 10 ++- + tests/unit/Makefile.am | 94 ---------------------------- + tests/unit/Makefile.inc | 94 ++++++++++++++++++++++++++++ + tests/unit/unit1397.c | 134 ++++++++++++++++++++++++---------------- + 5 files changed, 202 insertions(+), 180 deletions(-) + +--- a/lib/hostcheck.c ++++ b/lib/hostcheck.c +@@ -58,15 +58,19 @@ + * apparent distinction between a name and an IP. We need to detect the use of + * an IP address and not wildcard match on such names. + * ++ * Only match on "*" being used for the leftmost label, not "a*", "a*b" nor ++ * "*b". ++ * ++ * @unittest: 1397 ++ * + * NOTE: hostmatch() gets called with copied buffers so that it can modify the + * contents at will. + */ + + static int hostmatch(char *hostname, char *pattern) + { +- const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; +- int wildcard_enabled; +- size_t prefixlen, suffixlen; ++ const char *pattern_label_end, *hostname_label_end; ++ size_t suffixlen; + struct in_addr ignored; + #ifdef ENABLE_IPV6 + struct sockaddr_in6 si6; +@@ -80,13 +84,12 @@ static int hostmatch(char *hostname, cha + if(pattern[len-1]=='.') + pattern[len-1] = 0; + +- pattern_wildcard = strchr(pattern, '*'); +- if(pattern_wildcard == NULL) ++ if(strncmp(pattern, "*.", 2)) + return strcasecompare(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + /* detect IP address as hostname and fail the match if so */ +- if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) ++ else if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) + return CURL_HOST_NOMATCH; + #ifdef ENABLE_IPV6 + if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) +@@ -95,14 +98,9 @@ static int hostmatch(char *hostname, cha + + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ +- wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); +- if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || +- pattern_wildcard > pattern_label_end || +- strncasecompare(pattern, "xn--", 4)) { +- wildcard_enabled = 0; +- } +- if(!wildcard_enabled) ++ if(pattern_label_end == NULL || ++ strchr(pattern_label_end + 1, '.') == NULL) + return strcasecompare(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + +@@ -117,11 +115,9 @@ static int hostmatch(char *hostname, cha + if(hostname_label_end - hostname < pattern_label_end - pattern) + return CURL_HOST_NOMATCH; + +- prefixlen = pattern_wildcard - pattern; +- suffixlen = pattern_label_end - (pattern_wildcard + 1); +- return strncasecompare(pattern, hostname, prefixlen) && +- strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, +- suffixlen) ? ++ suffixlen = pattern_label_end - (pattern + 1); ++ return strncasecompare(pattern + 1, hostname_label_end - suffixlen, ++ suffixlen) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + } + +--- a/tests/data/test1397 ++++ b/tests/data/test1397 +@@ -2,8 +2,7 @@ + + + unittest +-ssl +-wildcard ++Curl_cert_hostcheck + + + +@@ -16,12 +15,11 @@ none + + unittest + +- +-Check wildcard certificate matching function Curl_cert_hostcheck +- ++ ++Curl_cert_hostcheck unit tests ++ + + unit1397 + + +- + +--- a/tests/unit/unit1397.c ++++ b/tests/unit/unit1397.c +@@ -21,8 +21,6 @@ + ***************************************************************************/ + #include "curlcheck.h" + +-#include "hostcheck.h" /* from the lib dir */ +- + static CURLcode unit_setup(void) + { + return CURLE_OK; +@@ -30,50 +28,94 @@ static CURLcode unit_setup(void) + + static void unit_stop(void) + { +- /* done before shutting down and exiting */ + } + +-UNITTEST_START ++* only these backends define the tested functions */ ++#if defined(USE_OPENSSL) || defined(USE_GSKIT) || \ ++ defined(USE_SCHANNEL) ++#include "hostcheck.h" ++struct testcase { ++ const char *host; ++ const char *pattern; ++ bool match; ++}; ++ ++static struct testcase tests[] = { ++ {"", "", FALSE}, ++ {"a", "", FALSE}, ++ {"", "b", FALSE}, ++ {"a", "b", FALSE}, ++ {"aa", "bb", FALSE}, ++ {"\xff", "\xff", TRUE}, ++ {"aa.aa.aa", "aa.aa.bb", FALSE}, ++ {"aa.aa.aa", "aa.aa.aa", TRUE}, ++ {"aa.aa.aa", "*.aa.bb", FALSE}, ++ {"aa.aa.aa", "*.aa.aa", TRUE}, ++ {"192.168.0.1", "192.168.0.1", TRUE}, ++ {"192.168.0.1", "*.168.0.1", FALSE}, ++ {"192.168.0.1", "*.0.1", FALSE}, ++ {"h.ello", "*.ello", FALSE}, ++ {"h.ello.", "*.ello", FALSE}, ++ {"h.ello", "*.ello.", FALSE}, ++ {"h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo", " *.e.llo", FALSE}, ++ {" h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo", TRUE}, ++ {"*.e.llo.", "*.e.llo", TRUE}, ++ {"************.e.llo.", "*.e.llo", TRUE}, ++ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ++ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ++ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ++ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ++ "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" ++ ".e.llo.", "*.e.llo", TRUE}, ++ {"\xfe\xfe.e.llo.", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo.", TRUE}, ++ {"h.e.llo", "*.e.llo.", TRUE}, ++ {".h.e.llo", "*.e.llo.", FALSE}, ++ {"h.e.llo", "*.*.llo.", FALSE}, ++ {"h.e.llo", "h.*.llo", FALSE}, ++ {"h.e.llo", "h.e.*", FALSE}, ++ {"hello", "*.ello", FALSE}, ++ {"hello", "**llo", FALSE}, ++ {"bar.foo.example.com", "*.example.com", FALSE}, ++ {"foo.example.com", "*.example.com", TRUE}, ++ {"baz.example.net", "b*z.example.net", FALSE}, ++ {"foobaz.example.net", "*baz.example.net", FALSE}, ++ {"xn--l8j.example.local", "x*.example.local", FALSE}, ++ {"xn--l8j.example.net", "*.example.net", TRUE}, ++ {"xn--l8j.example.net", "*j.example.net", FALSE}, ++ {"xn--l8j.example.net", "xn--l8j.example.net", TRUE}, ++ {"xn--l8j.example.net", "xn--l8j.*.net", FALSE}, ++ {"xl8j.example.net", "*.example.net", TRUE}, ++ {"fe80::3285:a9ff:fe46:b619", "*::3285:a9ff:fe46:b619", FALSE}, ++ {"fe80::3285:a9ff:fe46:b619", "fe80::3285:a9ff:fe46:b619", TRUE}, ++ {NULL, NULL, FALSE} ++}; + +-/* only these backends define the tested functions */ +-#if defined(USE_OPENSSL) || defined(USE_GSKIT) ++UNITTEST_START ++{ ++ int i; ++ for(i = 0; tests[i].host; i++) { ++ if(tests[i].match != Curl_cert_hostcheck(tests[i].pattern, ++ tests[i].host)) { ++ fprintf(stderr, ++ "HOST: %s\n" ++ "PTRN: %s\n" ++ "did %sMATCH\n", ++ tests[i].host, ++ tests[i].pattern, ++ tests[i].match ? "NOT ": ""); ++ unitfail++; ++ } ++ } ++} + +- /* here you start doing things and checking that the results are good */ ++UNITTEST_STOP ++#else + +-fail_unless(Curl_cert_hostcheck("www.example.com", "www.example.com"), +- "good 1"); +-fail_unless(Curl_cert_hostcheck("*.example.com", "www.example.com"), +- "good 2"); +-fail_unless(Curl_cert_hostcheck("xxx*.example.com", "xxxwww.example.com"), +- "good 3"); +-fail_unless(Curl_cert_hostcheck("f*.example.com", "foo.example.com"), +- "good 4"); +-fail_unless(Curl_cert_hostcheck("192.168.0.0", "192.168.0.0"), +- "good 5"); +- +-fail_if(Curl_cert_hostcheck("xxx.example.com", "www.example.com"), "bad 1"); +-fail_if(Curl_cert_hostcheck("*", "www.example.com"), "bad 2"); +-fail_if(Curl_cert_hostcheck("*.*.com", "www.example.com"), "bad 3"); +-fail_if(Curl_cert_hostcheck("*.example.com", "baa.foo.example.com"), "bad 4"); +-fail_if(Curl_cert_hostcheck("f*.example.com", "baa.example.com"), "bad 5"); +-fail_if(Curl_cert_hostcheck("*.com", "example.com"), "bad 6"); +-fail_if(Curl_cert_hostcheck("*fail.com", "example.com"), "bad 7"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example."), "bad 8"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example"), "bad 9"); +-fail_if(Curl_cert_hostcheck("", "www"), "bad 10"); +-fail_if(Curl_cert_hostcheck("*", "www"), "bad 11"); +-fail_if(Curl_cert_hostcheck("*.168.0.0", "192.168.0.0"), "bad 12"); +-fail_if(Curl_cert_hostcheck("www.example.com", "192.168.0.0"), "bad 13"); +- +-#ifdef ENABLE_IPV6 +-fail_if(Curl_cert_hostcheck("*::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "bad 14"); +-fail_unless(Curl_cert_hostcheck("fe80::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "good 6"); +-#endif ++UNITTEST_START + ++UNITTEST_STOP + #endif + +- /* you end the test code like this: */ +- +-UNITTEST_STOP diff --git a/CVE-2023-28322.patch b/CVE-2023-28322.patch new file mode 100644 index 0000000000000000000000000000000000000000..568415e2821ab6a8d4275d103142e320c474f8c8 --- /dev/null +++ b/CVE-2023-28322.patch @@ -0,0 +1,375 @@ +Backport of: + +From 7815647d6582c0a4900be2e1de6c5e61272c496b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 25 Apr 2023 08:28:01 +0200 +Subject: [PATCH] lib: unify the upload/method handling + +By making sure we set state.upload based on the set.method value and not +independently as set.upload, we reduce confusion and mixup risks, both +internally and externally. + +Closes #11017 +--- + lib/curl_rtmp.c | 4 ++-- + lib/file.c | 4 ++-- + lib/ftp.c | 8 ++++---- + lib/http.c | 4 ++-- + lib/imap.c | 6 +++--- + lib/rtsp.c | 4 ++-- + lib/setopt.c | 6 ++---- + lib/smb.c | 6 +++--- + lib/smtp.c | 4 ++-- + lib/tftp.c | 8 ++++---- + lib/transfer.c | 4 ++-- + lib/urldata.h | 2 +- + lib/vssh/libssh.c | 6 +++--- + lib/vssh/libssh2.c | 6 +++--- + lib/vssh/wolfssh.c | 2 +- + 15 files changed, 36 insertions(+), 38 deletions(-) + +--- a/lib/curl_rtmp.c ++++ b/lib/curl_rtmp.c +@@ -213,7 +213,7 @@ static CURLcode rtmp_connect(struct conn + /* We have to know if it's a write before we send the + * connect request packet + */ +- if(conn->data->set.upload) ++ if(conn->data->state.upload) + r->Link.protocol |= RTMP_FEATURE_WRITE; + + /* For plain streams, use the buffer toggle trick to keep data flowing */ +@@ -245,7 +245,7 @@ static CURLcode rtmp_do(struct connectda + if(!RTMP_ConnectStream(r, 0)) + return CURLE_FAILED_INIT; + +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + } +--- a/lib/file.c ++++ b/lib/file.c +@@ -198,7 +198,7 @@ static CURLcode file_connect(struct conn + file->freepath = real_path; /* free this when done */ + + file->fd = fd; +- if(!data->set.upload && (fd == -1)) { ++ if(!data->state.upload && (fd == -1)) { + failf(data, "Couldn't open file %s", data->state.up.path); + file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); + return CURLE_FILE_COULDNT_READ_FILE; +@@ -390,7 +390,7 @@ static CURLcode file_do(struct connectda + + Curl_pgrsStartNow(data); + +- if(data->set.upload) ++ if(data->state.upload) + return file_upload(conn); + + file = conn->data->req.protop; +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -1371,7 +1371,7 @@ static CURLcode ftp_state_prepare_transf + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST")); + } +- else if(data->set.upload) { ++ else if(data->state.upload) { + PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file); + } + else { +@@ -3303,7 +3303,7 @@ static CURLcode ftp_done(struct connectd + /* the response code from the transfer showed an error already so no + use checking further */ + ; +- else if(data->set.upload) { ++ else if(data->state.upload) { + if((-1 != data->state.infilesize) && + (data->state.infilesize != data->req.writebytecount) && + !data->set.crlf && +@@ -3570,7 +3570,7 @@ static CURLcode ftp_do_more(struct conne + connected back to us */ + } + } +- else if(data->set.upload) { ++ else if(data->state.upload) { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); + if(result) + return result; +@@ -4209,7 +4209,7 @@ CURLcode ftp_parse_url_path(struct conne + ftpc->file = NULL; /* instead of point to a zero byte, + we make it a NULL pointer */ + +- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { ++ if(data->state.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name!"); + free(rawPath); +--- a/lib/http.c ++++ b/lib/http.c +@@ -2080,7 +2080,7 @@ CURLcode Curl_http(struct connectdata *c + } + + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && +- data->set.upload) { ++ data->state.upload) { + httpreq = HTTPREQ_PUT; + } + +@@ -2261,7 +2261,7 @@ CURLcode Curl_http(struct connectdata *c + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || +- ((data->set.upload || httpreq == HTTPREQ_POST) && ++ ((data->state.upload || httpreq == HTTPREQ_POST) && + data->state.infilesize == -1))) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -1469,11 +1469,11 @@ static CURLcode imap_done(struct connect + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && !imap->custom && +- (imap->uid || imap->mindex || data->set.upload || ++ (imap->uid || imap->mindex || data->state.upload || + data->set.mimepost.kind != MIMEKIND_NONE)) { + /* Handle responses after FETCH or APPEND transfer has finished */ + +- if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) ++ if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE) + state(conn, IMAP_FETCH_FINAL); + else { + /* End the APPEND command first by sending an empty line */ +@@ -1539,7 +1539,7 @@ static CURLcode imap_perform(struct conn + selected = TRUE; + + /* Start the first command in the DO phase */ +- if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) ++ if(conn->data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE) + /* APPEND can be executed directly */ + result = imap_perform_append(conn); + else if(imap->custom && (selected || !imap->mailbox)) +--- a/lib/rtsp.c ++++ b/lib/rtsp.c +@@ -499,7 +499,7 @@ static CURLcode rtsp_do(struct connectda + rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + +- if(data->set.upload) { ++ if(data->state.upload) { + putsize = data->state.infilesize; + data->set.httpreq = HTTPREQ_PUT; + +@@ -518,7 +518,7 @@ static CURLcode rtsp_do(struct connectda + result = + Curl_add_bufferf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", +- (data->set.upload ? putsize : postsize)); ++ (data->state.upload ? putsize : postsize)); + if(result) + return result; + } +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -258,8 +258,8 @@ CURLcode Curl_vsetopt(struct Curl_easy * + * We want to sent data to the remote host. If this is HTTP, that equals + * using the PUT request. + */ +- data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; +- if(data->set.upload) { ++ arg = va_arg(param, long); ++ if(arg) { + /* If this is HTTP, PUT is what's needed to "upload" */ + data->set.httpreq = HTTPREQ_PUT; + data->set.opt_no_body = FALSE; /* this is implied */ +@@ -486,7 +486,6 @@ CURLcode Curl_vsetopt(struct Curl_easy * + } + else + data->set.httpreq = HTTPREQ_GET; +- data->set.upload = FALSE; + break; + + case CURLOPT_COPYPOSTFIELDS: +@@ -797,7 +796,6 @@ CURLcode Curl_vsetopt(struct Curl_easy * + */ + if(va_arg(param, long)) { + data->set.httpreq = HTTPREQ_GET; +- data->set.upload = FALSE; /* switch off upload */ + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; +--- a/lib/smb.c ++++ b/lib/smb.c +@@ -516,7 +516,7 @@ static CURLcode smb_send_open(struct con + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } +@@ -792,7 +792,7 @@ static CURLcode smb_request_state(struct + smb_m = (const struct smb_nt_create_response*) msg; + req->fid = smb_swap16(smb_m->fid); + conn->data->req.offset = 0; +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + conn->data->req.size = conn->data->state.infilesize; + Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); + next_state = SMB_UPLOAD; +--- a/lib/smtp.c ++++ b/lib/smtp.c +@@ -1210,7 +1210,7 @@ static CURLcode smtp_done(struct connect + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && data->set.mail_rcpt && +- (data->set.upload || data->set.mimepost.kind)) { ++ (data->state.upload || data->set.mimepost.kind)) { + /* Calculate the EOB taking into account any terminating CRLF from the + previous line of the email or the CRLF of the DATA command when there + is "no mail data". RFC-5321, sect. 4.1.1.4. +@@ -1297,7 +1297,7 @@ static CURLcode smtp_perform(struct conn + smtp->eob = 2; + + /* Start the first command in the DO phase */ +- if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) ++ if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(conn); + else +--- a/lib/tftp.c ++++ b/lib/tftp.c +@@ -390,7 +390,7 @@ static CURLcode tftp_parse_option_ack(tf + + /* tsize should be ignored on upload: Who cares about the size of the + remote file? */ +- if(!data->set.upload) { ++ if(!data->state.upload) { + if(!tsize) { + failf(data, "invalid tsize -:%s:- value in OACK packet", value); + return CURLE_TFTP_ILLEGAL; +@@ -470,7 +470,7 @@ static CURLcode tftp_send_first(tftp_sta + return result; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + /* If we are uploading, send an WRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_WRQ); + state->conn->data->req.upload_fromhere = +@@ -505,7 +505,7 @@ static CURLcode tftp_send_first(tftp_sta + if(!data->set.tftp_no_options) { + char buf[64]; + /* add tsize option */ +- if(data->set.upload && (data->state.infilesize != -1)) ++ if(data->state.upload && (data->state.infilesize != -1)) + msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else +@@ -559,7 +559,7 @@ static CURLcode tftp_send_first(tftp_sta + break; + + case TFTP_EVENT_OACK: +- if(data->set.upload) { ++ if(data->state.upload) { + result = tftp_connect_for_tx(state, event); + } + else { +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1405,6 +1405,7 @@ void Curl_init_CONNECT(struct Curl_easy + { + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; ++ data->state.upload = (data->set.httpreq == HTTPREQ_PUT); + } + + /* +@@ -1816,7 +1817,7 @@ CURLcode Curl_retry_request(struct conne + + /* if we're talking upload, we can't do the checks below, unless the protocol + is HTTP as when uploading over HTTP we will still get a response */ +- if(data->set.upload && ++ if(data->state.upload && + !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) + return CURLE_OK; + +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1427,6 +1427,7 @@ struct UrlState { + BIT(stream_depends_e); /* set or don't set the Exclusive bit */ + BIT(previouslypending); /* this transfer WAS in the multi->pending queue */ + BIT(cookie_engine); ++ BIT(upload); /* upload request */ + }; + + +@@ -1762,7 +1763,6 @@ struct UserDefined { + BIT(http_auto_referer); /* set "correct" referer when following + location: */ + BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ +- BIT(upload); /* upload request */ + BIT(verbose); /* output verbosity */ + BIT(krb); /* Kerberos connection requested */ + BIT(reuse_forbid); /* forbidden to be reused, close after use */ +--- a/lib/vssh/libssh.c ++++ b/lib/vssh/libssh.c +@@ -1076,7 +1076,7 @@ static CURLcode myssh_statemach_act(stru + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(protop->path[strlen(protop->path)-1] == '/') +@@ -1686,7 +1686,7 @@ static CURLcode myssh_statemach_act(stru + /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */ + ssh_set_blocking(sshc->ssh_session, 1); + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -1787,7 +1787,7 @@ static CURLcode myssh_statemach_act(stru + break; + } + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); +--- a/lib/vssh/libssh2.c ++++ b/lib/vssh/libssh2.c +@@ -1664,7 +1664,7 @@ static CURLcode ssh_statemach_act(struct + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') +@@ -2366,7 +2366,7 @@ static CURLcode ssh_statemach_act(struct + break; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -2504,7 +2504,7 @@ static CURLcode ssh_statemach_act(struct + break; + + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); diff --git a/curl b/curl new file mode 160000 index 0000000000000000000000000000000000000000..01a24657ba991b6a7401271e3bc4c61423aadb57 --- /dev/null +++ b/curl @@ -0,0 +1 @@ +Subproject commit 01a24657ba991b6a7401271e3bc4c61423aadb57 diff --git a/debian/changelog b/debian/changelog index fd215eb3650c9fd142b74b76c5c31bc680cb7293..a8a242c300a7cd3c3113514994e2a30e1368bb78 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +curl (7.68.0-ok5.4) yangtze; urgency=medium + + * whu-zhangyao[CVE-2022-43552]A use after free vulnerability exists in curl <7.87.0. Curl can be asked to *tunnel* virtually all protocols it supports through an HTTP proxy. + + -- zhangyao <2022182210033@whu.edu.cn> Fri, 21 Jul 2023 09:52:25 +0800 + curl (7.68.0-ok5.3) yangtze; urgency=medium * CVE-2023-27538 diff --git a/git_tls13_gnutls.patch b/git_tls13_gnutls.patch new file mode 100644 index 0000000000000000000000000000000000000000..57c84dcb47f868d09ae863975749f17106414dca --- /dev/null +++ b/git_tls13_gnutls.patch @@ -0,0 +1,172 @@ +From b8c82c9a33be5b135dd390f7fc08708826a862e8 Mon Sep 17 00:00:00 2001 +From: Dirkjan Bussink +Date: Sun, 12 Apr 2020 11:29:09 +0000 +Subject: [PATCH] Ensure TLS 1.3 works with GnuTLS + +When SRP is requested in the priority string, GnuTLS will disable +support for TLS 1.3. Before this change, curl would always add +SRP to +the priority list, effectively always disabling TLS 1.3 support. + +With this change, +SRP is only added to the priority list when SRP +authentication is also requested. This also allows updating the error +handling here to not have to retry without SRP. This is because SRP is +only added when requested and in that case a retry is not needed. +--- + lib/vtls/gtls.c | 81 +++++++++++++++++++++++++++---------------------- + 1 file changed, 45 insertions(+), 36 deletions(-) + +Index: curl-7.68.0/lib/vtls/gtls.c +=================================================================== +--- curl-7.68.0.orig/lib/vtls/gtls.c ++++ curl-7.68.0/lib/vtls/gtls.c +@@ -447,32 +447,32 @@ set_ssl_version_min_max(const char **pri + switch(ssl_version | ssl_version_max) { + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:" GNUTLS_SRP; ++ "+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; ++ "+VERS-TLS1.0:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:" GNUTLS_SRP; ++ "+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: + #ifdef HAS_TLS13 + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.3:" GNUTLS_SRP; ++ "+VERS-TLS1.3"; + return CURLE_OK; + #else + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); +@@ -480,35 +480,35 @@ set_ssl_version_min_max(const char **pri + #endif + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" ++ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:+VERS-TLS1.2:" ++ "+VERS-TLS1.1:+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" ++ "+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" ++ "+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + } + +@@ -760,11 +760,11 @@ gtls_connect_step1(struct connectdata *c + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +- prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" ++ prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + break; + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: +@@ -783,24 +783,33 @@ gtls_connect_step1(struct connectdata *c + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } +- rc = gnutls_priority_set_direct(session, prioritylist, &err); +- if((rc == GNUTLS_E_INVALID_REQUEST) && err) { +- if(!strcmp(err, GNUTLS_SRP)) { +- /* This GnuTLS was probably compiled without support for SRP. +- * Note that fact and try again without it. */ +- int validprioritylen = curlx_uztosi(err - prioritylist); +- char *prioritycopy = strdup(prioritylist); +- if(!prioritycopy) +- return CURLE_OUT_OF_MEMORY; + ++#ifdef USE_TLS_SRP ++ /* Only add SRP to the cipher list if SRP is requested. Otherwise ++ * GnuTLS will disable TLS 1.3 support. */ ++ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ size_t len = strlen(prioritylist); ++ ++ char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); ++ if(!prioritysrp) ++ return CURLE_OUT_OF_MEMORY; ++ strcpy(prioritysrp, prioritylist); ++ strcpy(prioritysrp + len, ":" GNUTLS_SRP); ++ ++ rc = gnutls_priority_set_direct(session, prioritysrp, &err); ++ free(prioritysrp); ++ ++ if((rc == GNUTLS_E_INVALID_REQUEST) && err) { + infof(data, "This GnuTLS does not support SRP\n"); +- if(validprioritylen) +- /* Remove the :+SRP */ +- prioritycopy[validprioritylen - 1] = 0; +- rc = gnutls_priority_set_direct(session, prioritycopy, &err); +- free(prioritycopy); + } + } ++ else { ++#endif ++ rc = gnutls_priority_set_direct(session, prioritylist, &err); ++#ifdef USE_TLS_SRP ++ } ++#endif ++ + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "Error %d setting GnuTLS cipher list starting with %s", + rc, err); diff --git a/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch b/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch new file mode 100644 index 0000000000000000000000000000000000000000..694804d72c0b4913cbf9eaa985541029165ccb22 --- /dev/null +++ b/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch @@ -0,0 +1,59 @@ +From 1f5baccc5040294d28de6ad58d399db60fd2eee3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 28 Nov 2020 16:42:52 +0100 +Subject: [PATCH] openssl: use OPENSSL_init_ssl() with >= 1.1.0 + +Reported-by: Kovalkov Dmitrii and Per Nilsson +Fixes #6254 +Fixes #6256 +Closes #6260 + +(cherry picked from commit 1835cb916e0d40eb8bc1165d5627a0b64f911bac) +Signed-off-by: Dimitri John Ledkov +--- + + BugLink: https://bugs.launchpad.net/bugs/1940528 + + lib/vtls/openssl.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c +index 726ff6e7ca..5872a6805b 100644 +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -1025,6 +1025,21 @@ static int Curl_ossl_init(void) + char *keylog_file_name; + #endif + ++#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ ++ !defined(LIBRESSL_VERSION_NUMBER) ++ const uint64_t flags = ++#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN ++ /* not present in BoringSSL */ ++ OPENSSL_INIT_ENGINE_ALL_BUILTIN | ++#endif ++#ifdef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG ++ OPENSSL_INIT_NO_LOAD_CONFIG | ++#else ++ OPENSSL_INIT_LOAD_CONFIG | ++#endif ++ 0; ++ OPENSSL_init_ssl(flags, NULL); ++#else + OPENSSL_load_builtin_modules(); + + #ifdef USE_OPENSSL_ENGINE +@@ -1043,10 +1058,6 @@ static int Curl_ossl_init(void) + CONF_MFLAGS_IGNORE_MISSING_FILE); + #endif + +-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ +- !defined(LIBRESSL_VERSION_NUMBER) +- /* OpenSSL 1.1.0+ takes care of initialization itself */ +-#else + /* Lets get nice error messages */ + SSL_load_error_strings(); + +-- +2.32.0 + diff --git a/patch/04_workaround_as_needed_bug.patch b/patch/04_workaround_as_needed_bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..00fa7f7648e88c9947323a409b8547e7339557bc --- /dev/null +++ b/patch/04_workaround_as_needed_bug.patch @@ -0,0 +1,38 @@ +Description: Work around libtool --as-needed reordering bug +Origin: vendor +Bug-Debian: http://bugs.debian.org/347650 +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2016-08-03 + +--- a/ltmain.sh ++++ b/ltmain.sh +@@ -7312,6 +7312,11 @@ + arg=$func_stripname_result + ;; + ++ -Wl,--as-needed|-Wl,--no-as-needed) ++ deplibs="$arg $deplibs" ++ continue ++ ;; ++ + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result +@@ -7703,6 +7708,15 @@ + lib= + found=false + case $deplib in ++ -Wl,--as-needed|-Wl,--no-as-needed) ++ if test "$linkmode,$pass" = "prog,link"; then ++ compile_deplibs="$deplib $compile_deplibs" ++ finalize_deplibs="$deplib $finalize_deplibs" ++ else ++ deplibs="$deplib $deplibs" ++ fi ++ continue ++ ;; + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then diff --git a/patch/06_always-disable-valgrind.patch b/patch/06_always-disable-valgrind.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b8dbca3cbb23767a8b0aadd25c5f83301bc27c8 --- /dev/null +++ b/patch/06_always-disable-valgrind.patch @@ -0,0 +1,17 @@ +Description: Always disable valgrind tests +Origin: vendor +Bug-Debian: http://bugs.debian.org/690968 +Forwarded: not-needed +Last-Update: 2012-10-22 + +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -68,7 +68,7 @@ + if CROSSCOMPILING + TEST = @echo "NOTICE: we can't run the tests when cross-compiling!" + else # if not cross-compiling: +-TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl ++TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -n + TEST_Q = -a -s + TEST_AM = -a -am + TEST_F = -a -p -r diff --git a/patch/07_do-not-disable-debug-symbols.patch b/patch/07_do-not-disable-debug-symbols.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3b179c45ff74f1b7dea893e604d1f43c332c764 --- /dev/null +++ b/patch/07_do-not-disable-debug-symbols.patch @@ -0,0 +1,98 @@ +Description: Do not disable debug symbols without --enable-debug +Origin: vendor +Bug-Debian: http://bugs.debian.org/693110 +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2012-11-16 + +--- a/m4/curl-compilers.m4 ++++ b/m4/curl-compilers.m4 +@@ -115,7 +115,6 @@ + flags_dbg_all="$flags_dbg_all -gdwarf-2" + flags_dbg_all="$flags_dbg_all -gvms" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -Os -O3 -O4" + flags_opt_yes="-Os" + flags_opt_off="-O0" +@@ -139,7 +138,6 @@ + compiler_id="DEC_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g2" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4" + flags_opt_yes="-O1" + flags_opt_off="-O0" +@@ -175,7 +173,6 @@ + flags_dbg_all="$flags_dbg_all -gdwarf-2" + flags_dbg_all="$flags_dbg_all -gvms" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os -Og -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -220,7 +217,6 @@ + compiler_id="IBM_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -O4 -O5" + flags_opt_all="$flags_opt_all -qnooptimize" + flags_opt_all="$flags_opt_all -qoptimize=0" +@@ -254,7 +250,6 @@ + compiler_id="INTEL_UNIX_C" + flags_dbg_all="-g -g0" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Os" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -292,7 +287,6 @@ + compiler_id="LCC" + flags_dbg_all="-g" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" +@@ -318,7 +312,6 @@ + compiler_id="SGI_MIPS_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -345,7 +338,6 @@ + compiler_id="SGI_MIPSPRO_C" + flags_dbg_all="-g -g0 -g1 -g2 -g3" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -389,7 +381,6 @@ + compiler_id="TINY_C" + flags_dbg_all="-g -b" + flags_dbg_yes="-g" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" +@@ -413,7 +404,6 @@ + compiler_id="WATCOM_UNIX_C" + flags_dbg_all="-g1 -g1+ -g2 -g3" + flags_dbg_yes="-g2" +- flags_dbg_off="" + flags_opt_all="-O0 -O1 -O2 -O3" + flags_opt_yes="-O2" + flags_opt_off="-O0" +@@ -421,7 +411,6 @@ + compiler_id="WATCOM_WINDOWS_C" + flags_dbg_all="" + flags_dbg_yes="" +- flags_dbg_off="" + flags_opt_all="" + flags_opt_yes="" + flags_opt_off="" diff --git a/patch/08_enable-zsh.patch b/patch/08_enable-zsh.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a85e380afe316783857ebd576d1bf25b5718867 --- /dev/null +++ b/patch/08_enable-zsh.patch @@ -0,0 +1,20 @@ +Description: Enable zsh completion generation +Origin: vendor +Forwarded: not-needed +Author: Alessandro Ghedini +Reviewed-by: Alessandro Ghedini +Last-Update: 2016-08-03 + +--- a/Makefile.am ++++ b/Makefile.am +@@ -178,8 +178,8 @@ + + bin_SCRIPTS = curl-config + +-SUBDIRS = lib src +-DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs ++SUBDIRS = lib src scripts ++DIST_SUBDIRS = $(SUBDIRS) tests packages include docs + + pkgconfigdir = $(libdir)/pkgconfig + pkgconfig_DATA = libcurl.pc diff --git a/patch/11_omit-directories-from-config.patch b/patch/11_omit-directories-from-config.patch new file mode 100644 index 0000000000000000000000000000000000000000..59940faea80cefbe6c36271563044ab325b09797 --- /dev/null +++ b/patch/11_omit-directories-from-config.patch @@ -0,0 +1,53 @@ +Description: In order to (partially) multi-arch-ify curl-config, remove all + mention of @includedir@ and @libdir@ from the script. On Debian, the actual + header and library directories are architecture-dependent, but will always be + in the C compiler's default search path, so -I and -L options are not + necessary (and may be harmful in multi-arch environments.) +Origin: vendor +Bug-Debian: http://bugs.debian.org/731998 +Forwarded: not-needed +Author: Benjamin Moody +Reviewed-by: Alessandro Ghedini +Last-Update: 2017-01-10 + +--- a/curl-config.in ++++ b/curl-config.in +@@ -23,7 +23,6 @@ + + prefix=@prefix@ + exec_prefix=@exec_prefix@ +-includedir=@includedir@ + cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@ + + usage() +@@ -147,19 +146,11 @@ + else + CPPFLAG_CURL_STATICLIB="" + fi +- if test "X@includedir@" = "X/usr/include"; then +- echo "$CPPFLAG_CURL_STATICLIB" +- else +- echo "${CPPFLAG_CURL_STATICLIB}-I@includedir@" +- fi ++ echo "$CPPFLAG_CURL_STATICLIB" + ;; + + --libs) +- if test "X@libdir@" != "X/usr/lib" -a "X@libdir@" != "X/usr/lib64"; then +- CURLLIBDIR="-L@libdir@ " +- else +- CURLLIBDIR="" +- fi ++ CURLLIBDIR="" + if test "X@REQUIRE_LIB_DEPS@" = "Xyes"; then + echo ${CURLLIBDIR}-lcurl @LIBCURL_LIBS@ + else +@@ -172,7 +163,7 @@ + + --static-libs) + if test "X@ENABLE_STATIC@" != "Xno" ; then +- echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ ++ echo -Wl,-Bstatic -lcurl -Wl,-Bdynamic @LDFLAGS@ @LIBCURL_LIBS@ + else + echo "curl was built with static libraries disabled" >&2 + exit 1 diff --git a/patch/90_gnutls.patch b/patch/90_gnutls.patch new file mode 100644 index 0000000000000000000000000000000000000000..372a3786df47444c4e647705191c9b188c4798ce --- /dev/null +++ b/patch/90_gnutls.patch @@ -0,0 +1,142 @@ +Description: Build with GnuTLS. +Origin: vendor +Forwarded: not-needed +Author: Ramakrishnan Muthukrishnan +Reviewed-by: Alessandro Ghedini +Last-Update: 2018-05-23 + +--- a/docs/examples/Makefile.am ++++ b/docs/examples/Makefile.am +@@ -48,9 +48,9 @@ + + # Dependencies + if USE_EXPLICIT_LIB_DEPS +-LDADD = $(LIBDIR)/libcurl.la @LIBCURL_LIBS@ ++LDADD = $(LIBDIR)/libcurl-gnutls.la @LIBCURL_LIBS@ + else +-LDADD = $(LIBDIR)/libcurl.la ++LDADD = $(LIBDIR)/libcurl-gnutls.la + endif + + # This might hold -Werror +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -31,7 +31,7 @@ + config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ + firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl + +-lib_LTLIBRARIES = libcurl.la ++lib_LTLIBRARIES = libcurl-gnutls.la + + if BUILD_UNITTESTS + noinst_LTLIBRARIES = libcurlu.la +@@ -83,43 +83,43 @@ + AM_LDFLAGS = + AM_CFLAGS = + +-libcurl_la_CPPFLAGS_EXTRA = +-libcurl_la_LDFLAGS_EXTRA = +-libcurl_la_CFLAGS_EXTRA = ++libcurl_gnutls_la_CPPFLAGS_EXTRA = ++libcurl_gnutls_la_LDFLAGS_EXTRA = ++libcurl_gnutls_la_CFLAGS_EXTRA = + + if CURL_LT_SHLIB_USE_VERSION_INFO +-libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) ++libcurl_gnutls_la_LDFLAGS_EXTRA += $(VERSIONINFO) + endif + + if CURL_LT_SHLIB_USE_NO_UNDEFINED +-libcurl_la_LDFLAGS_EXTRA += -no-undefined ++libcurl_gnutls_la_LDFLAGS_EXTRA += -no-undefined + endif + + if CURL_LT_SHLIB_USE_MIMPURE_TEXT +-libcurl_la_LDFLAGS_EXTRA += -mimpure-text ++libcurl_gnutls_la_LDFLAGS_EXTRA += -mimpure-text + endif + + if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +-libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers ++libcurl_gnutls_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers + else + # if symbol-hiding is enabled, hide them! + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' ++libcurl_gnutls_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' + endif + endif + + if USE_CPPFLAG_CURL_STATICLIB +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB ++libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + endif + + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +-libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) ++libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS ++libcurl_gnutls_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) + endif + +-libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) +-libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) +-libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) ++libcurl_gnutls_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_gnutls_la_CPPFLAGS_EXTRA) ++libcurl_gnutls_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_gnutls_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) ++libcurl_gnutls_la_CFLAGS = $(AM_CFLAGS) $(libcurl_gnutls_la_CFLAGS_EXTRA) + + libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS + libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +@@ -128,7 +128,7 @@ + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_gnutls_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) + + CHECKSRC = $(CS_$(V)) +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -61,9 +61,9 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ + else +-curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ + endif + + curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ +--- a/tests/libtest/Makefile.am ++++ b/tests/libtest/Makefile.am +@@ -57,11 +57,11 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ + else +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + endif + + # Dependencies (may need to be overridden) +--- a/lib/libcurl.vers.in ++++ b/lib/libcurl.vers.in +@@ -6,7 +6,7 @@ + _save*; + }; + +-CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4 ++CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@3 + { + global: curl_*; + local: *; diff --git a/patch/99_nss.patch b/patch/99_nss.patch new file mode 100644 index 0000000000000000000000000000000000000000..b35f24666495c33887120ba69b45c86b1f8f6113 --- /dev/null +++ b/patch/99_nss.patch @@ -0,0 +1,131 @@ +Description: Build with NSS. +Origin: vendor +Forwarded: not-needed +Author: Ramakrishnan Muthukrishnan +Reviewed-by: Alessandro Ghedini +Last-Update: 2015-08-12 + +--- a/docs/examples/Makefile.am ++++ b/docs/examples/Makefile.am +@@ -48,9 +48,9 @@ + + # Dependencies + if USE_EXPLICIT_LIB_DEPS +-LDADD = $(LIBDIR)/libcurl-gnutls.la @LIBCURL_LIBS@ ++LDADD = $(LIBDIR)/libcurl-nss.la @LIBCURL_LIBS@ + else +-LDADD = $(LIBDIR)/libcurl-gnutls.la ++LDADD = $(LIBDIR)/libcurl-nss.la + endif + + # This might hold -Werror +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -31,7 +31,7 @@ + config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ + firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl + +-lib_LTLIBRARIES = libcurl-gnutls.la ++lib_LTLIBRARIES = libcurl-nss.la + + if BUILD_UNITTESTS + noinst_LTLIBRARIES = libcurlu.la +@@ -83,43 +83,43 @@ + AM_LDFLAGS = + AM_CFLAGS = + +-libcurl_gnutls_la_CPPFLAGS_EXTRA = +-libcurl_gnutls_la_LDFLAGS_EXTRA = +-libcurl_gnutls_la_CFLAGS_EXTRA = ++libcurl_nss_la_CPPFLAGS_EXTRA = ++libcurl_nss_la_LDFLAGS_EXTRA = ++libcurl_nss_la_CFLAGS_EXTRA = + + if CURL_LT_SHLIB_USE_VERSION_INFO +-libcurl_gnutls_la_LDFLAGS_EXTRA += $(VERSIONINFO) ++libcurl_nss_la_LDFLAGS_EXTRA += $(VERSIONINFO) + endif + + if CURL_LT_SHLIB_USE_NO_UNDEFINED +-libcurl_gnutls_la_LDFLAGS_EXTRA += -no-undefined ++libcurl_nss_la_LDFLAGS_EXTRA += -no-undefined + endif + + if CURL_LT_SHLIB_USE_MIMPURE_TEXT +-libcurl_gnutls_la_LDFLAGS_EXTRA += -mimpure-text ++libcurl_nss_la_LDFLAGS_EXTRA += -mimpure-text + endif + + if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +-libcurl_gnutls_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers ++libcurl_nss_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers + else + # if symbol-hiding is enabled, hide them! + if DOING_CURL_SYMBOL_HIDING +-libcurl_gnutls_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' ++libcurl_nss_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' + endif + endif + + if USE_CPPFLAG_CURL_STATICLIB +-libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB ++libcurl_nss_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + endif + + if DOING_CURL_SYMBOL_HIDING +-libcurl_gnutls_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +-libcurl_gnutls_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) ++libcurl_nss_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS ++libcurl_nss_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) + endif + +-libcurl_gnutls_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_gnutls_la_CPPFLAGS_EXTRA) +-libcurl_gnutls_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_gnutls_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) +-libcurl_gnutls_la_CFLAGS = $(AM_CFLAGS) $(libcurl_gnutls_la_CFLAGS_EXTRA) ++libcurl_nss_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_nss_la_CPPFLAGS_EXTRA) ++libcurl_nss_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_nss_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) ++libcurl_nss_la_CFLAGS = $(AM_CFLAGS) $(libcurl_nss_la_CFLAGS_EXTRA) + + libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS + libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +@@ -128,7 +128,7 @@ + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc + +-libcurl_gnutls_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_nss_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) + + CHECKSRC = $(CS_$(V)) +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -61,9 +61,9 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-nss.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ + else +-curl_LDADD = $(top_builddir)/lib/libcurl-gnutls.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ ++curl_LDADD = $(top_builddir)/lib/libcurl-nss.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ + endif + + curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ +--- a/tests/libtest/Makefile.am ++++ b/tests/libtest/Makefile.am +@@ -57,11 +57,11 @@ + LIBS = $(BLANK_AT_MAKETIME) + + if USE_EXPLICIT_LIB_DEPS +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @LIBCURL_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-nss.la @LIBCURL_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-nss.la @LIBCURL_LIBS@ + else +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-gnutls.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl-nss.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl-nss.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + endif + + # Dependencies (may need to be overridden) diff --git a/patch/CVE-2020-8169.patch b/patch/CVE-2020-8169.patch new file mode 100644 index 0000000000000000000000000000000000000000..c07409b20d320473fa5d55b01b0f23e1c483dc33 --- /dev/null +++ b/patch/CVE-2020-8169.patch @@ -0,0 +1,130 @@ +Backport of: + +From 600a8cded447cd7118ed50142c576567c0cf5158 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 14 May 2020 14:37:12 +0200 +Subject: [PATCH] url: make the updated credentials URL-encoded in the URL + +Found-by: Gregory Jefferis +Reported-by: Jeroen Ooms +Added test 1168 to verify. Bug spotted when doing a redirect. +Bug: https://github.com/jeroen/curl/issues/224 +Closes #5400 +--- + lib/url.c | 6 ++-- + tests/data/Makefile.inc | 1 + + tests/data/test1168 | 78 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 83 insertions(+), 2 deletions(-) + create mode 100644 tests/data/test1168 + +--- a/lib/url.c ++++ b/lib/url.c +@@ -2733,12 +2733,14 @@ static CURLcode override_login(struct Cu + + /* for updated strings, we update them in the URL */ + if(user_changed) { +- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0); ++ uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, ++ CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + } + if(passwd_changed) { +- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0); ++ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, ++ CURLU_URLENCODE); + if(uc) + return Curl_uc_to_curlcode(uc); + } +--- /dev/null ++++ b/tests/data/test1168 +@@ -0,0 +1,78 @@ ++ ++ ++ ++HTTP ++HTTP GET ++followlocation ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 301 This is a weirdo text message swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Location: /data/11680002.txt ++Connection: close ++ ++This server reply is for testing a simple Location: following ++ ++ ++ ++HTTP/1.1 200 Followed here fine swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 52 ++ ++If this is received, the location following worked ++ ++ ++ ++HTTP/1.1 301 This is a weirdo text message swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Location: /data/11680002.txt ++Connection: close ++ ++HTTP/1.1 200 Followed here fine swsclose ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 52 ++ ++If this is received, the location following worked ++ ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++HTTP redirect with credentials using # in user and password ++ ++ ++http://%HOSTIP:%HTTPPORT/want/1168 -L -u "catmai#d:#DZaRJYrixKE*gFY" ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET /want/1168 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ== ++Accept: */* ++ ++GET /data/11680002.txt HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ== ++Accept: */* ++ ++ ++ ++ +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -131,7 +131,7 @@ test1128 test1129 test1130 test1131 test + test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \ + test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \ + test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \ +-test1160 test1161 test1162 test1163 test1164 test1165 test1166 \ ++test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1168 \ + test1170 test1171 test1172 test1173 test1174 test1175 \ + \ + test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \ diff --git a/patch/CVE-2020-8177.patch b/patch/CVE-2020-8177.patch new file mode 100644 index 0000000000000000000000000000000000000000..da0895036bc29ccd64fd622fb47b3a13de01c268 --- /dev/null +++ b/patch/CVE-2020-8177.patch @@ -0,0 +1,60 @@ +Backport of: + +From 3b884d1cc588c6cfede9d2f124d43c93e93226e8 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sun, 31 May 2020 23:09:59 +0200 +Subject: [PATCH] tool_getparam: -i is not OK if -J is used + +Reported-by: sn on hackerone +Bug: https://curl.haxx.se/docs/CVE-2020-8177.html +--- + src/tool_cb_hdr.c | 22 ++++------------------ + src/tool_getparam.c | 5 +++++ + 2 files changed, 9 insertions(+), 18 deletions(-) + +--- a/src/tool_cb_hdr.c ++++ b/src/tool_cb_hdr.c +@@ -188,25 +188,11 @@ size_t tool_header_cb(char *ptr, size_t + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { +- int rc; +- /* already opened and possibly written to */ +- if(outs->fopened) +- fclose(outs->stream); +- outs->stream = NULL; +- +- /* rename the initial file name to the new file name */ +- rc = rename(outs->filename, filename); +- if(rc != 0) { +- warnf(outs->config->global, "Failed to rename %s -> %s: %s\n", +- outs->filename, filename, strerror(errno)); +- } +- if(outs->alloc_filename) +- Curl_safefree(outs->filename); +- if(rc != 0) { +- free(filename); +- return failure; +- } ++ /* indication of problem, get out! */ ++ free(filename); ++ return failure; + } ++ + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; +--- a/src/tool_getparam.c ++++ b/src/tool_getparam.c +@@ -1800,6 +1800,11 @@ ParameterError getparameter(const char * + } + break; + case 'i': ++ if(config->content_disposition) { ++ warnf(global, ++ "--include and --remote-header-name cannot be combined.\n"); ++ return PARAM_BAD_USE; ++ } + config->show_headers = toggle; /* show the headers as well in the + general output stream */ + break; diff --git a/patch/CVE-2020-8231.patch b/patch/CVE-2020-8231.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff94b178dc0db113f2d03c004942d82d5008b6e --- /dev/null +++ b/patch/CVE-2020-8231.patch @@ -0,0 +1,128 @@ +Backport of: + +From 8c899c70575126151628b1455429cdb7224894fc Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 3 Aug 2020 14:54:13 +0200 +Subject: [PATCH] Curl_easy: remember last connection by id, not by pointer + +CVE-2020-8231 + +Bug: https://curl.haxx.se/docs/CVE-2020-8231.html + +Reported-by: Marc Aldorasi +--- + lib/connect.c | 19 ++++++++++--------- + lib/easy.c | 3 +-- + lib/multi.c | 10 ++++++---- + lib/url.c | 2 +- + lib/urldata.h | 2 +- + 5 files changed, 19 insertions(+), 17 deletions(-) + +--- a/lib/connect.c ++++ b/lib/connect.c +@@ -1336,15 +1336,15 @@ CURLcode Curl_connecthost(struct connect + } + + struct connfind { +- struct connectdata *tofind; +- bool found; ++ long id_tofind; ++ struct connectdata *found; + }; + + static int conn_is_conn(struct connectdata *conn, void *param) + { + struct connfind *f = (struct connfind *)param; +- if(conn == f->tofind) { +- f->found = TRUE; ++ if(conn->connection_id == f->id_tofind) { ++ f->found = conn; + return 1; + } + return 0; +@@ -1366,21 +1366,22 @@ curl_socket_t Curl_getconnectinfo(struct + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ +- if(data->state.lastconnect && (data->multi_easy || data->multi)) { +- struct connectdata *c = data->state.lastconnect; ++ if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) { ++ struct connectdata *c; + struct connfind find; +- find.tofind = data->state.lastconnect; +- find.found = FALSE; ++ find.id_tofind = data->state.lastconnect_id; ++ find.found = NULL; + + Curl_conncache_foreach(data, data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); + + if(!find.found) { +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + return CURL_SOCKET_BAD; + } + ++ c = find.found; + if(connp) { + /* only store this if the caller cares for it */ + *connp = c; +--- a/lib/easy.c ++++ b/lib/easy.c +@@ -832,8 +832,7 @@ struct Curl_easy *curl_easy_duphandle(st + + /* the connection cache is setup on demand */ + outcurl->state.conn_cache = NULL; +- +- outcurl->state.lastconnect = NULL; ++ outcurl->state.lastconnect_id = -1; + + outcurl->progress.flags = data->progress.flags; + outcurl->progress.callback = data->progress.callback; +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -451,6 +451,7 @@ CURLMcode curl_multi_add_handle(struct C + data->state.conn_cache = &data->share->conn_cache; + else + data->state.conn_cache = &multi->conn_cache; ++ data->state.lastconnect_id = -1; + + #ifdef USE_LIBPSL + /* Do the same for PSL. */ +@@ -663,11 +664,11 @@ static CURLcode multi_done(struct Curl_e + CONN_UNLOCK(data); + if(Curl_conncache_return_conn(data, conn)) { + /* remember the most recently used connection */ +- data->state.lastconnect = conn; ++ data->state.lastconnect_id = conn->connection_id; + infof(data, "%s\n", buffer); + } + else +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + } + + Curl_free_request_state(data); +--- a/lib/url.c ++++ b/lib/url.c +@@ -618,7 +618,7 @@ CURLcode Curl_open(struct Curl_easy **cu + Curl_initinfo(data); + + /* most recent connection is not yet defined */ +- data->state.lastconnect = NULL; ++ data->state.lastconnect_id = -1; + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1301,7 +1301,7 @@ struct UrlState { + /* buffers to store authentication data in, as parsed from input options */ + struct curltime keeps_speed; /* for the progress meter really */ + +- struct connectdata *lastconnect; /* The last connection, NULL if undefined */ ++ long lastconnect_id; /* The last connection, -1 if undefined */ + + char *headerbuff; /* allocated buffer to store headers in */ + size_t headersize; /* size of the allocation */ diff --git a/patch/CVE-2020-8284.patch b/patch/CVE-2020-8284.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1627f6e60c6770d501fecc4592fc6afadeb913d --- /dev/null +++ b/patch/CVE-2020-8284.patch @@ -0,0 +1,179 @@ +Backport of: + +From 20ceeeeb6df4ad7444d0ac6f080557954e05ec1d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 24 Nov 2020 14:56:57 +0100 +Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default + +The command line tool also independently sets --ftp-skip-pasv-ip by +default. + +Ten test cases updated to adapt the modified --libcurl output. + +Bug: https://curl.se/docs/CVE-2020-8284.html +CVE-2020-8284 + +Reported-by: Varnavas Papaioannou +--- + docs/cmdline-opts/ftp-skip-pasv-ip.d | 2 ++ + docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 | 8 +++++--- + lib/url.c | 1 + + src/tool_cfgable.c | 1 + + tests/data/test1400 | 1 + + tests/data/test1401 | 1 + + tests/data/test1402 | 1 + + tests/data/test1403 | 1 + + tests/data/test1404 | 1 + + tests/data/test1405 | 1 + + tests/data/test1406 | 1 + + tests/data/test1407 | 1 + + tests/data/test1420 | 1 + + tests/data/test1465 | Bin 2909 -> 2964 bytes + 14 files changed, 18 insertions(+), 3 deletions(-) + +--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d ++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d +@@ -9,4 +9,6 @@ to curl's PASV command when curl connect + will re-use the same IP address it already uses for the control + connection. + ++Since curl 7.74.0 this option is enabled by default. ++ + This option has no effect if PORT, EPRT or EPSV is used instead of PASV. +--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 ++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 +@@ -5,7 +5,7 @@ + .\" * | (__| |_| | _ <| |___ + .\" * \___|\___/|_| \_\_____| + .\" * +-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. ++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + .\" * + .\" * This software is licensed as described in the file COPYING, which + .\" * you should have received as part of this distribution. The terms +@@ -36,11 +36,13 @@ address it already uses for the control + number from the 227-response. + + This option thus allows libcurl to work around broken server installations +-that due to NATs, firewalls or incompetence report the wrong IP address back. ++that due to NATs, firewalls or incompetence report the wrong IP address ++back. Setting the option also reduces the risk for various sorts of client ++abuse by malicious servers. + + This option has no effect if PORT, EPRT or EPSV is used instead of PASV. + .SH DEFAULT +-0 ++1 since 7.74.0, was 0 before then. + .SH PROTOCOLS + FTP + .SH EXAMPLE +--- a/lib/url.c ++++ b/lib/url.c +@@ -456,6 +456,7 @@ CURLcode Curl_init_userdefined(struct Cu + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; ++ set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ + #endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + +--- a/src/tool_cfgable.c ++++ b/src/tool_cfgable.c +@@ -44,6 +44,7 @@ void config_init(struct OperationConfig* + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; ++ config->ftp_skip_ip = TRUE; + } + + static void free_config_fields(struct OperationConfig *config) +--- a/tests/data/test1400 ++++ b/tests/data/test1400 +@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1401 ++++ b/tests/data/test1401 +@@ -90,6 +90,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE | + (long)CURLPROTO_FTP | +--- a/tests/data/test1402 ++++ b/tests/data/test1402 +@@ -81,6 +81,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1403 ++++ b/tests/data/test1403 +@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1404 ++++ b/tests/data/test1404 +@@ -147,6 +147,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped"); + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1405 ++++ b/tests/data/test1405 +@@ -89,6 +89,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2); + curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1406 ++++ b/tests/data/test1406 +@@ -79,6 +79,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406"); + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com"); + curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1); +--- a/tests/data/test1407 ++++ b/tests/data/test1407 +@@ -62,6 +62,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L); + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated +--- a/tests/data/test1420 ++++ b/tests/data/test1420 +@@ -67,6 +67,7 @@ int main(int argc, char *argv[]) + curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1"); + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret"); + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); + + /* Here is a list of options the curl code used that cannot get generated diff --git a/patch/CVE-2020-8285.patch b/patch/CVE-2020-8285.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a68a75e229cd0426cbba6b86ec2179a084a0849 --- /dev/null +++ b/patch/CVE-2020-8285.patch @@ -0,0 +1,249 @@ +Backport of: + +From c11171033d5eb8e6514bbabd49c710e0b9885e6f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 28 Nov 2020 00:27:21 +0100 +Subject: [PATCH] ftp: make wc_statemach loop instead of recurse + +--- + lib/ftp.c | 202 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 102 insertions(+), 100 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -3773,129 +3773,131 @@ static CURLcode init_wc_data(struct conn + return result; + } + +-/* This is called recursively */ + static CURLcode wc_statemach(struct connectdata *conn) + { + struct WildcardData * const wildcard = &(conn->data->wildcard); + CURLcode result = CURLE_OK; + +- switch(wildcard->state) { +- case CURLWC_INIT: +- result = init_wc_data(conn); +- if(wildcard->state == CURLWC_CLEAN) +- /* only listing! */ +- break; +- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; +- break; +- +- case CURLWC_MATCHING: { +- /* In this state is LIST response successfully parsed, so lets restore +- previous WRITEFUNCTION callback and WRITEDATA pointer */ +- struct ftp_wc *ftpwc = wildcard->protdata; +- conn->data->set.fwrite_func = ftpwc->backup.write_function; +- conn->data->set.out = ftpwc->backup.file_descriptor; +- ftpwc->backup.write_function = ZERO_NULL; +- ftpwc->backup.file_descriptor = NULL; +- wildcard->state = CURLWC_DOWNLOADING; +- +- if(Curl_ftp_parselist_geterror(ftpwc->parser)) { +- /* error found in LIST parsing */ +- wildcard->state = CURLWC_CLEAN; +- return wc_statemach(conn); +- } +- if(wildcard->filelist.size == 0) { +- /* no corresponding file */ +- wildcard->state = CURLWC_CLEAN; +- return CURLE_REMOTE_FILE_NOT_FOUND; ++ for(;;) { ++ switch(wildcard->state) { ++ case CURLWC_INIT: ++ result = init_wc_data(conn); ++ if(wildcard->state == CURLWC_CLEAN) ++ /* only listing! */ ++ return result; ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; ++ return result; ++ ++ case CURLWC_MATCHING: { ++ /* In this state is LIST response successfully parsed, so lets restore ++ previous WRITEFUNCTION callback and WRITEDATA pointer */ ++ struct ftp_wc *ftpwc = wildcard->protdata; ++ conn->data->set.fwrite_func = ftpwc->backup.write_function; ++ conn->data->set.out = ftpwc->backup.file_descriptor; ++ ftpwc->backup.write_function = ZERO_NULL; ++ ftpwc->backup.file_descriptor = NULL; ++ wildcard->state = CURLWC_DOWNLOADING; ++ ++ if(Curl_ftp_parselist_geterror(ftpwc->parser)) { ++ /* error found in LIST parsing */ ++ wildcard->state = CURLWC_CLEAN; ++ continue; ++ } ++ if(wildcard->filelist.size == 0) { ++ /* no corresponding file */ ++ wildcard->state = CURLWC_CLEAN; ++ return CURLE_REMOTE_FILE_NOT_FOUND; ++ } ++ continue; + } +- return wc_statemach(conn); +- } + +- case CURLWC_DOWNLOADING: { +- /* filelist has at least one file, lets get first one */ +- struct ftp_conn *ftpc = &conn->proto.ftpc; +- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; +- struct FTP *ftp = conn->data->req.protop; +- +- char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); +- if(!tmp_path) +- return CURLE_OUT_OF_MEMORY; +- +- /* switch default ftp->path and tmp_path */ +- free(ftp->pathalloc); +- ftp->pathalloc = ftp->path = tmp_path; +- +- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); +- if(conn->data->set.chunk_bgn) { +- long userresponse; +- Curl_set_in_callback(conn->data, true); +- userresponse = conn->data->set.chunk_bgn( +- finfo, wildcard->customptr, (int)wildcard->filelist.size); +- Curl_set_in_callback(conn->data, false); +- switch(userresponse) { +- case CURL_CHUNK_BGN_FUNC_SKIP: +- infof(conn->data, "Wildcard - \"%s\" skipped by user\n", +- finfo->filename); ++ case CURLWC_DOWNLOADING: { ++ /* filelist has at least one file, lets get first one */ ++ struct ftp_conn *ftpc = &conn->proto.ftpc; ++ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; ++ struct FTP *ftp = conn->data->req.protop; ++ ++ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); ++ if(!tmp_path) ++ return CURLE_OUT_OF_MEMORY; ++ ++ /* switch default ftp->path and tmp_path */ ++ free(ftp->pathalloc); ++ ftp->pathalloc = ftp->path = tmp_path; ++ ++ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); ++ if(conn->data->set.chunk_bgn) { ++ long userresponse; ++ Curl_set_in_callback(conn->data, true); ++ userresponse = conn->data->set.chunk_bgn( ++ finfo, wildcard->customptr, (int)wildcard->filelist.size); ++ Curl_set_in_callback(conn->data, false); ++ switch(userresponse) { ++ case CURL_CHUNK_BGN_FUNC_SKIP: ++ infof(conn->data, "Wildcard - \"%s\" skipped by user\n", ++ finfo->filename); ++ wildcard->state = CURLWC_SKIP; ++ continue; ++ case CURL_CHUNK_BGN_FUNC_FAIL: ++ return CURLE_CHUNK_FAILED; ++ } ++ } ++ ++ if(finfo->filetype != CURLFILETYPE_FILE) { + wildcard->state = CURLWC_SKIP; +- return wc_statemach(conn); +- case CURL_CHUNK_BGN_FUNC_FAIL: +- return CURLE_CHUNK_FAILED; ++ continue; ++ } ++ ++ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) ++ ftpc->known_filesize = finfo->size; ++ ++ result = ftp_parse_url_path(conn); ++ if(result) ++ return result; ++ ++ /* we don't need the Curl_fileinfo of first file anymore */ ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); ++ ++ if(wildcard->filelist.size == 0) { /* remains only one file to down. */ ++ wildcard->state = CURLWC_CLEAN; ++ /* after that will be ftp_do called once again and no transfer ++ will be done because of CURLWC_CLEAN state */ ++ return CURLE_OK; + } ++ return result; + } + +- if(finfo->filetype != CURLFILETYPE_FILE) { +- wildcard->state = CURLWC_SKIP; +- return wc_statemach(conn); ++ case CURLWC_SKIP: { ++ if(conn->data->set.chunk_end) { ++ Curl_set_in_callback(conn->data, true); ++ conn->data->set.chunk_end(conn->data->wildcard.customptr); ++ Curl_set_in_callback(conn->data, false); ++ } ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); ++ wildcard->state = (wildcard->filelist.size == 0) ? ++ CURLWC_CLEAN : CURLWC_DOWNLOADING; ++ continue; + } + +- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) +- ftpc->known_filesize = finfo->size; ++ case CURLWC_CLEAN: { ++ struct ftp_wc *ftpwc = wildcard->protdata; ++ result = CURLE_OK; ++ if(ftpwc) ++ result = Curl_ftp_parselist_geterror(ftpwc->parser); + +- result = ftp_parse_url_path(conn); +- if(result) ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; + return result; +- +- /* we don't need the Curl_fileinfo of first file anymore */ +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); +- +- if(wildcard->filelist.size == 0) { /* remains only one file to down. */ +- wildcard->state = CURLWC_CLEAN; +- /* after that will be ftp_do called once again and no transfer +- will be done because of CURLWC_CLEAN state */ +- return CURLE_OK; + } +- } break; + +- case CURLWC_SKIP: { +- if(conn->data->set.chunk_end) { +- Curl_set_in_callback(conn->data, true); +- conn->data->set.chunk_end(conn->data->wildcard.customptr); +- Curl_set_in_callback(conn->data, false); ++ case CURLWC_DONE: ++ case CURLWC_ERROR: ++ case CURLWC_CLEAR: ++ if(wildcard->dtor) ++ wildcard->dtor(wildcard->protdata); ++ return result; + } +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); +- wildcard->state = (wildcard->filelist.size == 0) ? +- CURLWC_CLEAN : CURLWC_DOWNLOADING; +- return wc_statemach(conn); +- } +- +- case CURLWC_CLEAN: { +- struct ftp_wc *ftpwc = wildcard->protdata; +- result = CURLE_OK; +- if(ftpwc) +- result = Curl_ftp_parselist_geterror(ftpwc->parser); +- +- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; +- } break; +- +- case CURLWC_DONE: +- case CURLWC_ERROR: +- case CURLWC_CLEAR: +- if(wildcard->dtor) +- wildcard->dtor(wildcard->protdata); +- break; + } +- +- return result; ++ /* UNREACHABLE */ + } + + /*********************************************************************** diff --git a/patch/CVE-2020-8286.patch b/patch/CVE-2020-8286.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e2ac5f9fa57b274c254bfd38d01f8292daf58f0 --- /dev/null +++ b/patch/CVE-2020-8286.patch @@ -0,0 +1,128 @@ +Backport of: + +From dd5ec983ccb8106484a787713346cdcabf52af62 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Wed, 2 Dec 2020 23:01:11 +0100 +Subject: [PATCH] openssl: make the OCSP verification verify the certificate id + +CVE-2020-8286 + +Reported by anonymous + +Bug: https://curl.se/docs/CVE-2020-8286.html +--- + lib/vtls/openssl.c | 83 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 29 deletions(-) + +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct conn + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; ++ X509 *cert; ++ OCSP_CERTID *id = NULL; ++ int cert_status, crl_reason; ++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; ++ int ret; + + long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status); + +@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct conn + goto end; + } + +- for(i = 0; i < OCSP_resp_count(br); i++) { +- int cert_status, crl_reason; +- OCSP_SINGLERESP *single = NULL; +- +- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; +- +- single = OCSP_resp_get0(br, i); +- if(!single) +- continue; +- +- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, +- &thisupd, &nextupd); +- +- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { +- failf(data, "OCSP response has expired"); +- result = CURLE_SSL_INVALIDCERTSTATUS; +- goto end; ++ /* Compute the certificate's ID */ ++ cert = SSL_get_peer_certificate(BACKEND->handle); ++ if(!cert) { ++ failf(data, "Error getting peer certficate"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ for(i = 0; i < sk_X509_num(ch); i++) { ++ X509 *issuer = sk_X509_value(ch, i); ++ if(X509_check_issued(issuer, cert) == X509_V_OK) { ++ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer); ++ break; + } ++ } ++ X509_free(cert); + +- infof(data, "SSL certificate status: %s (%d)\n", +- OCSP_cert_status_str(cert_status), cert_status); ++ if(!id) { ++ failf(data, "Error computing OCSP ID"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } + +- switch(cert_status) { +- case V_OCSP_CERTSTATUS_GOOD: +- break; +- +- case V_OCSP_CERTSTATUS_REVOKED: +- result = CURLE_SSL_INVALIDCERTSTATUS; +- +- failf(data, "SSL certificate revocation reason: %s (%d)", +- OCSP_crl_reason_str(crl_reason), crl_reason); +- goto end; +- +- case V_OCSP_CERTSTATUS_UNKNOWN: +- result = CURLE_SSL_INVALIDCERTSTATUS; +- goto end; +- } ++ /* Find the single OCSP response corresponding to the certificate ID */ ++ ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev, ++ &thisupd, &nextupd); ++ OCSP_CERTID_free(id); ++ if(ret != 1) { ++ failf(data, "Could not find certificate ID in OCSP response"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ /* Validate the corresponding single OCSP response */ ++ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { ++ failf(data, "OCSP response has expired"); ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; ++ } ++ ++ infof(data, "SSL certificate status: %s (%d)\n", ++ OCSP_cert_status_str(cert_status), cert_status); ++ ++ switch(cert_status) { ++ case V_OCSP_CERTSTATUS_GOOD: ++ break; ++ ++ case V_OCSP_CERTSTATUS_REVOKED: ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ failf(data, "SSL certificate revocation reason: %s (%d)", ++ OCSP_crl_reason_str(crl_reason), crl_reason); ++ goto end; ++ ++ case V_OCSP_CERTSTATUS_UNKNOWN: ++ default: ++ result = CURLE_SSL_INVALIDCERTSTATUS; ++ goto end; + } + + end: diff --git a/patch/CVE-2021-22876.patch b/patch/CVE-2021-22876.patch new file mode 100644 index 0000000000000000000000000000000000000000..a0410cf0cc40ee3002aa03b00b0375cd8cf4a2fc --- /dev/null +++ b/patch/CVE-2021-22876.patch @@ -0,0 +1,62 @@ +Backport of: + +From 3dec1183be112e587f89edc059c1c11cf8fdc0ae Mon Sep 17 00:00:00 2001 +From: Viktor Szakats +Date: Tue, 23 Feb 2021 14:54:46 +0100 +Subject: [PATCH] transfer: strip credentials from the auto-referer header + field + +Added test 2081 to verify. + +CVE-2021-22876 + +Bug: https://curl.se/docs/CVE-2021-22876.html +--- + lib/transfer.c | 25 ++++++++++++++-- + tests/data/Makefile.inc | 2 +- + tests/data/test2081 | 66 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 90 insertions(+), 3 deletions(-) + create mode 100644 tests/data/test2081 + +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1572,6 +1572,9 @@ CURLcode Curl_follow(struct Curl_easy *d + data->set.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { ++ CURLU *u; ++ char *referer; ++ + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ +@@ -1581,9 +1584,27 @@ CURLcode Curl_follow(struct Curl_easy *d + data->change.referer_alloc = FALSE; + } + +- data->change.referer = strdup(data->change.url); +- if(!data->change.referer) ++ /* Make a copy of the URL without crenditals and fragment */ ++ u = curl_url(); ++ if(!u) ++ return CURLE_OUT_OF_MEMORY; ++ ++ uc = curl_url_set(u, CURLUPART_URL, data->change.url, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_USER, NULL, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); ++ if(!uc) ++ uc = curl_url_get(u, CURLUPART_URL, &referer, 0); ++ ++ curl_url_cleanup(u); ++ ++ if(uc || referer == NULL) + return CURLE_OUT_OF_MEMORY; ++ ++ data->change.referer = referer; + data->change.referer_alloc = TRUE; /* yes, free this later */ + } + } diff --git a/patch/CVE-2021-22890.patch b/patch/CVE-2021-22890.patch new file mode 100644 index 0000000000000000000000000000000000000000..7322c6036c5ed097972687e2ed8a2db7459ad293 --- /dev/null +++ b/patch/CVE-2021-22890.patch @@ -0,0 +1,443 @@ +Backport of: + +From e9c835dbd51f482f5d572e6fb33a0e8ef60c846b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 19 Mar 2021 12:38:49 +0100 +Subject: [PATCH] vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid() + +To make sure we set and extract the correct session. + +Reported-by: Mingtao Yang +Bug: https://curl.se/docs/CVE-2021-22890.html + +CVE-2021-22890 +--- + lib/vtls/bearssl.c | 8 +++++-- + lib/vtls/gtls.c | 12 ++++++---- + lib/vtls/mbedtls.c | 12 ++++++---- + lib/vtls/mesalink.c | 14 ++++++++---- + lib/vtls/openssl.c | 54 +++++++++++++++++++++++++++++++++----------- + lib/vtls/schannel.c | 10 ++++---- + lib/vtls/sectransp.c | 10 ++++---- + lib/vtls/vtls.c | 12 +++++++--- + lib/vtls/vtls.h | 2 ++ + lib/vtls/wolfssl.c | 13 +++++++---- + 10 files changed, 103 insertions(+), 44 deletions(-) + +--- a/lib/vtls/bearssl.c ++++ b/lib/vtls/bearssl.c +@@ -372,7 +372,8 @@ static CURLcode bearssl_connect_step1(st + void *session; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &session, NULL, sockindex)) { + br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); + infof(data, "BearSSL: re-using session ID\n"); + } +@@ -560,10 +561,12 @@ static CURLcode bearssl_connect_step3(st + return CURLE_OUT_OF_MEMORY; + br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); ++ incache = !(Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &oldsession, NULL, sockindex)); + if(incache) + Curl_ssl_delsessionid(conn, oldsession); +- ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); ++ ret = Curl_ssl_addsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ session, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(ret) { + free(session); +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -942,7 +942,8 @@ gtls_connect_step1(struct connectdata *c + size_t ssl_idsize; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, &ssl_idsize, sockindex)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + +@@ -1490,7 +1491,8 @@ gtls_connect_step3(struct connectdata *c + gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, + sockindex)); + if(incache) { + /* there was one before in the cache, so instead of risking that the +@@ -1499,7 +1501,8 @@ gtls_connect_step3(struct connectdata *c + } + + /* store this session id */ +- result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, ++ result = Curl_ssl_addsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ connect_sessionid, connect_idsize, + sockindex); + Curl_ssl_sessionid_unlock(conn); + if(result) { +--- a/lib/vtls/mbedtls.c ++++ b/lib/vtls/mbedtls.c +@@ -453,7 +453,8 @@ mbed_connect_step1(struct connectdata *c + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &old_session, NULL, sockindex)) { + ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(conn); +@@ -709,6 +710,7 @@ mbed_connect_step3(struct connectdata *c + int ret; + mbedtls_ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; ++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) +@@ -727,10 +729,10 @@ mbed_connect_step3(struct connectdata *c + + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) ++ if(!Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, NULL, sockindex)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + +- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); ++ retcode = Curl_ssl_addsessionid(conn, isproxy, our_ssl_sessionid, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + mbedtls_ssl_session_free(our_ssl_sessionid); +--- a/lib/vtls/mesalink.c ++++ b/lib/vtls/mesalink.c +@@ -263,7 +263,8 @@ mesalink_connect_step1(struct connectdat + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); +@@ -347,12 +348,14 @@ mesalink_connect_step3(struct connectdat + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; ++ bool inproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + our_ssl_sessionid = SSL_get_session(BACKEND->handle); + + Curl_ssl_sessionid_lock(conn); + incache = +- !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)); ++ !(Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, ++ NULL, sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); +@@ -363,7 +366,7 @@ mesalink_connect_step3(struct connectdat + + if(!incache) { + result = Curl_ssl_addsessionid( +- conn, our_ssl_sessionid, 0 /* unknown size */, sockindex); ++ conn, isproxy, our_ssl_sessionid, 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -422,12 +422,23 @@ static int ossl_get_ssl_conn_index(void) + */ + static int ossl_get_ssl_sockindex_index(void) + { +- static int ssl_ex_data_sockindex_index = -1; +- if(ssl_ex_data_sockindex_index < 0) { +- ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, +- NULL); ++ static int sockindex_index = -1; ++ if(sockindex_index < 0) { ++ sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + } +- return ssl_ex_data_sockindex_index; ++ return sockindex_index; ++} ++ ++/* Return an extra data index for proxy boolean. ++ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). ++ */ ++static int ossl_get_proxy_index(void) ++{ ++ static int proxy_index = -1; ++ if(proxy_index < 0) { ++ proxy_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ++ } ++ return proxy_index; + } + + static int passwd_callback(char *buf, int num, int encrypting, +@@ -1079,7 +1090,8 @@ static int Curl_ossl_init(void) + #endif + + /* Initialize the extra data indexes */ +- if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0) ++ if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0 || ++ ossl_get_proxy_index() < 0) + return 0; + + return 1; +@@ -2367,8 +2379,10 @@ static int ossl_new_session_cb(SSL *ssl, + curl_socket_t *sockindex_ptr; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); ++ int proxy_idx = ossl_get_proxy_index(); ++ bool isproxy; + +- if(connectdata_idx < 0 || sockindex_idx < 0) ++ if(connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0) + return 0; + + conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx); +@@ -2381,13 +2395,18 @@ static int ossl_new_session_cb(SSL *ssl, + sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx); + sockindex = (int)(sockindex_ptr - conn->sock); + ++ isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE; ++ + if(SSL_SET_OPTION(primary.sessionid)) { + bool incache; + void *old_ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, +- sockindex)); ++ if(isproxy) ++ incache = FALSE; ++ else ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, ++ &old_ssl_sessionid, NULL, sockindex)); + if(incache) { + if(old_ssl_sessionid != ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); +@@ -2397,7 +2416,7 @@ static int ossl_new_session_cb(SSL *ssl, + } + + if(!incache) { +- if(!Curl_ssl_addsessionid(conn, ssl_sessionid, ++ if(!Curl_ssl_addsessionid(conn, isproxy, ssl_sessionid, + 0 /* unknown size */, sockindex)) { + /* the session has been put into the session cache */ + res = 1; +@@ -2894,16 +2913,25 @@ static CURLcode ossl_connect_step1(struc + void *ssl_sessionid = NULL; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); ++ int proxy_idx = ossl_get_proxy_index(); + +- if(connectdata_idx >= 0 && sockindex_idx >= 0) { ++ if(connectdata_idx >= 0 && sockindex_idx >= 0 && proxy_idx >= 0) { + /* Store the data needed for the "new session" callback. + * The sockindex is stored as a pointer to an array element. */ + SSL_set_ex_data(BACKEND->handle, connectdata_idx, conn); + SSL_set_ex_data(BACKEND->handle, sockindex_idx, conn->sock + sockindex); ++#ifndef CURL_DISABLE_PROXY ++ SSL_set_ex_data(BACKEND->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1: ++ NULL); ++#else ++ SSL_set_ex_data(BACKEND->handle, proxy_idx, NULL); ++#endif ++ + } + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); +--- a/lib/vtls/schannel.c ++++ b/lib/vtls/schannel.c +@@ -497,7 +497,8 @@ schannel_connect_step1(struct connectdat + /* check for an existing re-usable credential handle */ + if(SSL_SET_OPTION(primary.sessionid)) { + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ (void **)&old_cred, NULL, sockindex)) { + BACKEND->cred = old_cred; + DEBUGF(infof(data, "schannel: re-using existing credential handle\n")); + +@@ -1203,8 +1204,9 @@ schannel_connect_step3(struct connectdat + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; ++ bool isproxy = SSL_IS_PROXY(); + #ifdef DEBUGBUILD +- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ++ const char * const hostname = isproxy ? conn->http_proxy.host.name : + conn->host.name; + #endif + #ifdef HAS_ALPN +@@ -1278,7 +1280,7 @@ schannel_connect_step3(struct connectdat + struct curl_schannel_cred *old_cred = NULL; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, (void **)&old_cred, NULL, + sockindex)); + if(incache) { + if(old_cred != BACKEND->cred) { +@@ -1290,7 +1292,7 @@ schannel_connect_step3(struct connectdat + } + } + if(!incache) { +- result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred, ++ result = Curl_ssl_addsessionid(conn, isproxy, (void *)BACKEND->cred, + sizeof(struct curl_schannel_cred), + sockindex); + if(result) { +--- a/lib/vtls/sectransp.c ++++ b/lib/vtls/sectransp.c +@@ -1376,7 +1376,8 @@ static CURLcode sectransp_connect_step1( + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + char * const ssl_cert = SSL_SET_OPTION(cert); +- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ++ bool isproxy = SSL_IS_PROXY(); ++ const char * const hostname = isproxy ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; + #ifdef ENABLE_IPV6 +@@ -1584,7 +1585,7 @@ static CURLcode sectransp_connect_step1( + + #ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && +- (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { ++ (!isproxy || !conn->bits.tunnel_proxy)) { + CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID)); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +@@ -1916,7 +1917,7 @@ static CURLcode sectransp_connect_step1( + size_t ssl_sessionid_len; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, ++ if(!Curl_ssl_getsessionid(conn, isproxy, (void **)&ssl_sessionid, + &ssl_sessionid_len, sockindex)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); +@@ -1944,7 +1945,7 @@ static CURLcode sectransp_connect_step1( + return CURLE_SSL_CONNECT_ERROR; + } + +- result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, ++ result = Curl_ssl_addsessionid(conn, isproxy, ssl_sessionid, ssl_sessionid_len, + sockindex); + Curl_ssl_sessionid_unlock(conn); + if(result) { +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -305,6 +305,7 @@ void Curl_ssl_sessionid_unlock(struct co + * there's one suitable, it is provided. Returns TRUE when no entry matched. + */ + bool Curl_ssl_getsessionid(struct connectdata *conn, ++ const bool isProxy, + void **ssl_sessionid, + size_t *idsize, /* set 0 if unknown */ + int sockindex) +@@ -315,7 +316,6 @@ bool Curl_ssl_getsessionid(struct connec + long *general_age; + bool no_match = TRUE; + +- const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; +@@ -324,6 +324,11 @@ bool Curl_ssl_getsessionid(struct connec + int port = isProxy ? (int)conn->port : conn->remote_port; + *ssl_sessionid = NULL; + ++#ifdef CURL_DISABLE_PROXY ++ if(isProxy) ++ return TRUE; ++#endif ++ + DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); + + if(!SSL_SET_OPTION(primary.sessionid)) +@@ -411,6 +416,7 @@ void Curl_ssl_delsessionid(struct connec + * later on. + */ + CURLcode Curl_ssl_addsessionid(struct connectdata *conn, ++ bool isProxy, + void *ssl_sessionid, + size_t idsize, + int sockindex) +@@ -423,7 +429,6 @@ CURLcode Curl_ssl_addsessionid(struct co + char *clone_conn_to_host; + int conn_to_port; + long *general_age; +- const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; +--- a/lib/vtls/vtls.h ++++ b/lib/vtls/vtls.h +@@ -203,6 +203,7 @@ void Curl_ssl_sessionid_unlock(struct co + * under sessionid mutex). + */ + bool Curl_ssl_getsessionid(struct connectdata *conn, ++ const bool isproxy, + void **ssl_sessionid, + size_t *idsize, /* set 0 if unknown */ + int sockindex); +@@ -212,6 +213,7 @@ bool Curl_ssl_getsessionid(struct connec + * object with cache (e.g. incrementing refcount on success) + */ + CURLcode Curl_ssl_addsessionid(struct connectdata *conn, ++ const bool isProxy, + void *ssl_sessionid, + size_t idsize, + int sockindex); +--- a/lib/vtls/wolfssl.c ++++ b/lib/vtls/wolfssl.c +@@ -392,7 +392,8 @@ wolfssl_connect_step1(struct connectdata + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); +- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { ++ if(!Curl_ssl_getsessionid(conn, SSL_IS_PROXY() ? TRUE : FALSE, ++ &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + char error_buffer[WOLFSSL_MAX_ERROR_SZ]; +@@ -618,9 +619,10 @@ wolfssl_connect_step3(struct connectdata + void *old_ssl_sessionid = NULL; + + our_ssl_sessionid = SSL_get_session(BACKEND->handle); ++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + + Curl_ssl_sessionid_lock(conn); +- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, ++ incache = !(Curl_ssl_getsessionid(conn, isproxy, &old_ssl_sessionid, NULL, + sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { +@@ -631,7 +633,7 @@ wolfssl_connect_step3(struct connectdata + } + + if(!incache) { +- result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, ++ result = Curl_ssl_addsessionid(conn, isproxy, our_ssl_sessionid, + 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); diff --git a/patch/CVE-2021-22898.patch b/patch/CVE-2021-22898.patch new file mode 100644 index 0000000000000000000000000000000000000000..9da5524bb1c1726b11341334384bc68e418acfbd --- /dev/null +++ b/patch/CVE-2021-22898.patch @@ -0,0 +1,23 @@ +From 39ce47f219b09c380b81f89fe54ac586c8db6bde Mon Sep 17 00:00:00 2001 +From: Harry Sintonen +Date: Fri, 7 May 2021 13:09:57 +0200 +Subject: [PATCH] telnet: check sscanf() for correct number of matches + +CVE-2021-22898 + +Bug: https://curl.se/docs/CVE-2021-22898.html +--- + lib/telnet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -967,7 +967,7 @@ static void suboption(struct connectdata + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { +- if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { ++ if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); diff --git a/patch/CVE-2021-22924.patch b/patch/CVE-2021-22924.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f03402591a4a662715d85b1a6eae71494912f85 --- /dev/null +++ b/patch/CVE-2021-22924.patch @@ -0,0 +1,215 @@ +Backport of: + +From 5ea3145850ebff1dc2b13d17440300a01ca38161 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 19 Jun 2021 00:42:28 +0200 +Subject: [PATCH] vtls: fix connection reuse checks for issuer cert and case + sensitivity + +CVE-2021-22924 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2021-22924.html +--- + lib/url.c | 10 ++++++---- + lib/urldata.h | 4 ++-- + lib/vtls/gtls.c | 10 +++++----- + lib/vtls/nss.c | 4 ++-- + lib/vtls/openssl.c | 18 +++++++++--------- + lib/vtls/vtls.c | 26 +++++++++++++++++++++----- + 6 files changed, 45 insertions(+), 27 deletions(-) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -3523,6 +3523,9 @@ static CURLcode create_conn(struct Curl_ + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; ++ data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; ++ data->set.proxy_ssl.primary.issuercert = ++ data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; +@@ -3543,8 +3546,6 @@ static CURLcode create_conn(struct Curl_ + + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; +- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; +- data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -224,6 +224,7 @@ struct ssl_primary_config { + long version_max; /* max supported version the client wants to use*/ + char *CApath; /* certificate dir (doesn't work on windows) */ + char *CAfile; /* certificate to verify peer against */ ++ char *issuercert; /* optional issuer certificate filename */ + char *clientcert; + char *random_file; /* path to file containing "random" data */ + char *egdsocket; /* path to file containing the EGD daemon socket */ +@@ -240,7 +241,6 @@ struct ssl_config_data { + struct ssl_primary_config primary; + long certverifyresult; /* result from the certificate verification */ + char *CRLfile; /* CRL to check certificate revocation */ +- char *issuercert;/* optional issuer certificate filename */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + char *cert; /* client certificate file name */ +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -1064,7 +1064,7 @@ gtls_connect_step3(struct connectdata *c + if(!chainp) { + if(SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost) || +- SSL_SET_OPTION(issuercert)) { ++ SSL_CONN_CONFIG(issuercert)) { + #ifdef USE_TLS_SRP + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL +@@ -1246,21 +1246,21 @@ gtls_connect_step3(struct connectdata *c + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + gnutls_x509_crt_init(&x509_issuer); +- issuerp = load_file(SSL_SET_OPTION(issuercert)); ++ issuerp = load_file(SSL_CONN_CONFIG(issuercert)); + gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + gnutls_x509_crt_deinit(x509_issuer); + unload_file(issuerp); + if(rc <= 0) { + failf(data, "server certificate issuer check failed (IssuerCert: %s)", +- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); ++ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_ISSUER_ERROR; + } + infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", +- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); ++ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); + } + + size = sizeof(certbuf); +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -2151,9 +2151,9 @@ static CURLcode nss_do_connect(struct co + if(result) + goto error; + +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + SECStatus ret = SECFailure; +- char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); ++ char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert)); + if(nickname) { + /* we support only nicknames in case of issuercert for now */ + ret = check_issuer_cert(BACKEND->handle, nickname); +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -3592,7 +3592,7 @@ static CURLcode servercert(struct connec + deallocating the certificate. */ + + /* e.g. match issuer name with provided issuer certificate */ +- if(SSL_SET_OPTION(issuercert)) { ++ if(SSL_CONN_CONFIG(issuercert)) { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, +@@ -3605,10 +3605,10 @@ static CURLcode servercert(struct connec + return CURLE_OUT_OF_MEMORY; + } + +- if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { ++ if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; +@@ -3619,7 +3619,7 @@ static CURLcode servercert(struct connec + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(BACKEND->server_cert); +@@ -3630,7 +3630,7 @@ static CURLcode servercert(struct connec + if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(BACKEND->server_cert); +@@ -3639,7 +3639,7 @@ static CURLcode servercert(struct connec + } + + infof(data, " SSL certificate issuer check ok (%s)\n", +- SSL_SET_OPTION(issuercert)); ++ SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + } +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -82,6 +82,16 @@ + else \ + dest->var = NULL; + ++static bool safecmp(char *a, char *b) ++{ ++ if(a && b) ++ return !strcmp(a, b); ++ else if(!a && !b) ++ return TRUE; /* match */ ++ return FALSE; /* no match */ ++} ++ ++ + bool + Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) +@@ -91,11 +101,12 @@ Curl_ssl_config_matches(struct ssl_prima + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +- Curl_safe_strcasecompare(data->CApath, needle->CApath) && +- Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && +- Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && +- Curl_safe_strcasecompare(data->random_file, needle->random_file) && +- Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && ++ safecmp(data->CApath, needle->CApath) && ++ safecmp(data->CAfile, needle->CAfile) && ++ safecmp(data->issuercert, needle->issuercert) && ++ safecmp(data->clientcert, needle->clientcert) && ++ safecmp(data->random_file, needle->random_file) && ++ safecmp(data->egdsocket, needle->egdsocket) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && + Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) +@@ -117,6 +128,7 @@ Curl_clone_primary_ssl_config(struct ssl + + CLONE_STRING(CApath); + CLONE_STRING(CAfile); ++ CLONE_STRING(issuercert); + CLONE_STRING(clientcert); + CLONE_STRING(random_file); + CLONE_STRING(egdsocket); +@@ -131,6 +143,7 @@ void Curl_free_primary_ssl_config(struct + { + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->CAfile); ++ Curl_safefree(sslc->issuercert); + Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->random_file); + Curl_safefree(sslc->egdsocket); diff --git a/patch/CVE-2021-22925.patch b/patch/CVE-2021-22925.patch new file mode 100644 index 0000000000000000000000000000000000000000..71926e2cfcdf3ac604fbb0ab12409b7a27ab7bc7 --- /dev/null +++ b/patch/CVE-2021-22925.patch @@ -0,0 +1,39 @@ +From cfc17716133ad1f8b99094c9a0ad15f1cfb63525 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 12 Jun 2021 18:25:15 +0200 +Subject: [PATCH] telnet: fix option parser to not send uninitialized contents + +CVS-2021-22925 + +Reported-by: Red Hat Product Security +Bug: https://curl.se/docs/CVE-2021-22925.html +--- + lib/telnet.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -967,12 +967,17 @@ static void suboption(struct connectdata + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { +- if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { +- msnprintf((char *)&temp[len], sizeof(temp) - len, +- "%c%s%c%s", CURL_NEW_ENV_VAR, varname, +- CURL_NEW_ENV_VALUE, varval); +- len += tmplen; +- } ++ int rv; ++ char sep[2] = ""; ++ varval[0] = 0; ++ rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval); ++ if(rv == 1) ++ len += msnprintf((char *)&temp[len], sizeof(temp) - len, ++ "%c%s", CURL_NEW_ENV_VAR, varname); ++ else if(rv >= 2) ++ len += msnprintf((char *)&temp[len], sizeof(temp) - len, ++ "%c%s%c%s", CURL_NEW_ENV_VAR, varname, ++ CURL_NEW_ENV_VALUE, varval); + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, diff --git a/patch/CVE-2021-22946-pre1.patch b/patch/CVE-2021-22946-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..d86cfeba07e56c916b53efb0e9dcf67c4477ccee --- /dev/null +++ b/patch/CVE-2021-22946-pre1.patch @@ -0,0 +1,81 @@ +Backport of: + +From 1397a7de6e312e019a3b339f855ba0a5cafa9127 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 21 Sep 2020 09:15:51 +0200 +Subject: [PATCH] ftp: separate FTPS from FTP over "HTTPS proxy" + +When using HTTPS proxy, SSL is used but not in the view of the FTP +protocol handler itself so separate the connection's use of SSL from the +FTP control connection's sue. + +Reported-by: Mingtao Yang +Fixes #5523 +Closes #6006 +--- + lib/ftp.c | 16 ++++++---------- + lib/urldata.h | 1 + + tests/data/test1631 | 2 -- + tests/data/test1632 | 2 -- + 4 files changed, 7 insertions(+), 14 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2497,7 +2497,7 @@ static CURLcode ftp_state_loggedin(struc + { + CURLcode result = CURLE_OK; + +- if(conn->ssl[FIRSTSOCKET].use) { ++ if(conn->bits.ftp_use_control_ssl) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: +@@ -2643,11 +2643,8 @@ static CURLcode ftp_statemach_act(struct + } + #endif + +- if(data->set.use_ssl && +- (!conn->ssl[FIRSTSOCKET].use || +- (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && +- !conn->proxy_ssl[FIRSTSOCKET].use))) { +- /* We don't have a SSL/TLS connection yet, but FTPS is ++ if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { ++ /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; +@@ -2692,6 +2689,7 @@ static CURLcode ftp_statemach_act(struct + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ ++ conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(conn); + } + } +@@ -3082,7 +3080,7 @@ static CURLcode ftp_block_statemach(stru + * + */ + static CURLcode ftp_connect(struct connectdata *conn, +- bool *done) /* see description above */ ++ bool *done) /* see description above */ + { + CURLcode result; + struct ftp_conn *ftpc = &conn->proto.ftpc; +@@ -3103,6 +3101,7 @@ static CURLcode ftp_connect(struct conne + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(result) + return result; ++ conn->bits.ftp_use_control_ssl = TRUE; + } + + Curl_pp_init(pp); /* init the generic pingpong data */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -453,6 +453,7 @@ struct ConnectBits { + EPRT doesn't work we disable it for the forthcoming + requests */ + BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ ++ BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */ + #endif + BIT(netrc); /* name+password provided by netrc */ + BIT(userpwd_in_url); /* name+password found in url */ diff --git a/patch/CVE-2021-22946.patch b/patch/CVE-2021-22946.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ff93dc94ec902b054f2938dba0cd31bded081a9 --- /dev/null +++ b/patch/CVE-2021-22946.patch @@ -0,0 +1,310 @@ +Backport of: + +From 96d71feb27e533a8b337512841a537952916262c Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Wed, 8 Sep 2021 11:56:22 +0200 +Subject: [PATCH] ftp,imap,pop3: do not ignore --ssl-reqd + +In imap and pop3, check if TLS is required even when capabilities +request has failed. + +In ftp, ignore preauthentication (230 status of server greeting) if TLS +is required. + +Bug: https://curl.se/docs/CVE-2021-22946.html + +CVE-2021-22946 +--- + lib/ftp.c | 9 ++++--- + lib/imap.c | 24 ++++++++---------- + lib/pop3.c | 33 +++++++++++------------- + tests/data/Makefile.inc | 2 ++ + tests/data/test984 | 56 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test985 | 54 +++++++++++++++++++++++++++++++++++++++ + tests/data/test986 | 53 ++++++++++++++++++++++++++++++++++++++ + 7 files changed, 195 insertions(+), 36 deletions(-) + create mode 100644 tests/data/test984 + create mode 100644 tests/data/test985 + create mode 100644 tests/data/test986 + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2616,9 +2616,12 @@ static CURLcode ftp_statemach_act(struct + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: +- if(ftpcode == 230) +- /* 230 User logged in - already! */ +- return ftp_state_user_resp(conn, ftpcode, ftpc->state); ++ if(ftpcode == 230) { ++ /* 230 User logged in - already! Take as 220 if TLS required. */ ++ if(data->set.use_ssl <= CURLUSESSL_TRY || ++ conn->bits.ftp_use_control_ssl) ++ return ftp_state_user_resp(conn, ftpcode, ftpc->state); ++ } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -917,22 +917,18 @@ static CURLcode imap_state_capability_re + line += wordlen; + } + } +- else if(imapcode == IMAP_RESP_OK) { +- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { +- /* We don't have a SSL/TLS connection yet, but SSL is requested */ +- if(imapc->tls_supported) +- /* Switch to TLS connection now */ +- result = imap_perform_starttls(conn); +- else if(data->set.use_ssl == CURLUSESSL_TRY) +- /* Fallback and carry on with authentication */ +- result = imap_perform_authentication(conn); +- else { +- failf(data, "STARTTLS not supported."); +- result = CURLE_USE_SSL_FAILED; +- } ++ else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { ++ /* PREAUTH is not compatible with STARTTLS. */ ++ if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { ++ /* Switch to TLS connection now */ ++ result = imap_perform_starttls(conn); + } +- else ++ else if(data->set.use_ssl <= CURLUSESSL_TRY) + result = imap_perform_authentication(conn); ++ else { ++ failf(data, "STARTTLS not available."); ++ result = CURLE_USE_SSL_FAILED; ++ } + } + else + result = imap_perform_authentication(conn); +--- a/lib/pop3.c ++++ b/lib/pop3.c +@@ -721,28 +721,23 @@ static CURLcode pop3_state_capa_resp(str + } + } + } +- else if(pop3code == '+') { +- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { +- /* We don't have a SSL/TLS connection yet, but SSL is requested */ +- if(pop3c->tls_supported) +- /* Switch to TLS connection now */ +- result = pop3_perform_starttls(conn); +- else if(data->set.use_ssl == CURLUSESSL_TRY) +- /* Fallback and carry on with authentication */ +- result = pop3_perform_authentication(conn); +- else { +- failf(data, "STLS not supported."); +- result = CURLE_USE_SSL_FAILED; +- } +- } +- else +- result = pop3_perform_authentication(conn); +- } + else { + /* Clear text is supported when CAPA isn't recognised */ +- pop3c->authtypes |= POP3_TYPE_CLEARTEXT; ++ if(pop3code != '+') ++ pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + +- result = pop3_perform_authentication(conn); ++ if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use) ++ result = pop3_perform_authentication(conn); ++ else if(pop3code == '+' && pop3c->tls_supported) ++ /* Switch to TLS connection now */ ++ result = pop3_perform_starttls(conn); ++ else if(data->set.use_ssl <= CURLUSESSL_TRY) ++ /* Fallback and carry on with authentication */ ++ result = pop3_perform_authentication(conn); ++ else { ++ failf(data, "STLS not supported."); ++ result = CURLE_USE_SSL_FAILED; ++ } + } + + return result; +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -111,6 +111,8 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test984 test985 test986 \ ++\ + test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ + test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ + test1016 test1017 test1018 test1019 test1020 test1021 test1022 test1023 \ +--- /dev/null ++++ b/tests/data/test984 +@@ -0,0 +1,56 @@ ++ ++ ++ ++IMAP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY CAPABILITY A001 BAD Not implemented ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++imap ++ ++ ++IMAP require STARTTLS with failing capabilities ++ ++ ++imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl-reqd ++ ++ ++Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) ++From: Fred Foobar ++Subject: afternoon meeting ++To: joe@example.com ++Message-Id: ++MIME-Version: 1.0 ++Content-Type: TEXT/PLAIN; CHARSET=US-ASCII ++ ++Hello Joe, do you think we can meet at 3:30 tomorrow? ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++A001 CAPABILITY ++ ++ ++ +--- /dev/null ++++ b/tests/data/test985 +@@ -0,0 +1,54 @@ ++ ++ ++ ++POP3 ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY CAPA -ERR Not implemented ++ ++ ++From: me@somewhere ++To: fake@nowhere ++ ++body ++ ++-- ++ yours sincerely ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++pop3 ++ ++ ++POP3 require STARTTLS with failing capabilities ++ ++ ++pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl-reqd ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++CAPA ++ ++ ++ +--- /dev/null ++++ b/tests/data/test986 +@@ -0,0 +1,53 @@ ++ ++ ++ ++FTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY welcome 230 Welcome ++REPLY AUTH 500 unknown command ++ ++ ++ ++# Client-side ++ ++ ++SSL ++ ++ ++ftp ++ ++ ++FTP require STARTTLS while preauthenticated ++ ++ ++data ++ to ++ see ++that FTPS ++works ++ so does it? ++ ++ ++--ssl-reqd --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++# 64 is CURLE_USE_SSL_FAILED ++ ++64 ++ ++ ++AUTH SSL ++AUTH TLS ++ ++ ++ diff --git a/patch/CVE-2021-22947.patch b/patch/CVE-2021-22947.patch new file mode 100644 index 0000000000000000000000000000000000000000..b93339d783d8ea6fc0d6925c6ac3169c2403f9d4 --- /dev/null +++ b/patch/CVE-2021-22947.patch @@ -0,0 +1,328 @@ +Backport of: + +From 259b4f2e1fd01fbc55e569ee0a507afeae34f77c Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Tue, 7 Sep 2021 13:26:42 +0200 +Subject: [PATCH] ftp,imap,pop3,smtp: reject STARTTLS server response + pipelining + +If a server pipelines future responses within the STARTTLS response, the +former are preserved in the pingpong cache across TLS negotiation and +used as responses to the encrypted commands. + +This fix detects pipelined STARTTLS responses and rejects them with an +error. + +CVE-2021-22947 + +Bug: https://curl.se/docs/CVE-2021-22947.html +--- + lib/ftp.c | 3 +++ + lib/imap.c | 4 +++ + lib/pop3.c | 4 +++ + lib/smtp.c | 4 +++ + tests/data/Makefile.inc | 2 ++ + tests/data/test980 | 52 ++++++++++++++++++++++++++++++++++++ + tests/data/test981 | 59 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test982 | 57 +++++++++++++++++++++++++++++++++++++++ + tests/data/test983 | 52 ++++++++++++++++++++++++++++++++++++ + 9 files changed, 237 insertions(+) + create mode 100644 tests/data/test980 + create mode 100644 tests/data/test981 + create mode 100644 tests/data/test982 + create mode 100644 tests/data/test983 + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -2680,6 +2680,9 @@ static CURLcode ftp_statemach_act(struct + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + ++ if(pp->cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ ++ + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -946,6 +946,10 @@ static CURLcode imap_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.imapc.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(imapcode != IMAP_RESP_OK) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); +--- a/lib/pop3.c ++++ b/lib/pop3.c +@@ -753,6 +753,10 @@ static CURLcode pop3_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.pop3c.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); +--- a/lib/smtp.c ++++ b/lib/smtp.c +@@ -680,6 +680,10 @@ static CURLcode smtp_state_starttls_resp + + (void)instate; /* no use for this yet */ + ++ /* Pipelining in response is forbidden. */ ++ if(data->conn->proto.smtpc.pp.cache_size) ++ return CURLE_WEIRD_SERVER_REPLY; ++ + if(smtpcode != 220) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied, code %d", smtpcode); +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -111,6 +111,8 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test980 test981 test982 test983 \ ++\ + test984 test985 test986 \ + \ + test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ +--- /dev/null ++++ b/tests/data/test980 +@@ -0,0 +1,52 @@ ++ ++ ++ ++SMTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STARTTLS ++AUTH PLAIN ++REPLY STARTTLS 454 currently unavailable\r\n235 Authenticated\r\n250 2.1.0 Sender ok\r\n250 2.1.5 Recipient ok\r\n354 Enter mail\r\n250 2.0.0 Accepted ++REPLY AUTH 535 5.7.8 Authentication credentials invalid ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++smtp ++ ++ ++SMTP STARTTLS pipelined server response ++ ++ ++mail body ++ ++ ++smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret --ssl --sasl-ir -T - ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++EHLO %TESTNUMBER ++STARTTLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test981 +@@ -0,0 +1,59 @@ ++ ++ ++ ++IMAP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STARTTLS ++REPLY STARTTLS A002 BAD currently unavailable\r\nA003 OK Authenticated\r\nA004 OK Accepted ++REPLY LOGIN A003 BAD Authentication credentials invalid ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++imap ++ ++ ++IMAP STARTTLS pipelined server response ++ ++ ++imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl ++ ++ ++Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) ++From: Fred Foobar ++Subject: afternoon meeting ++To: joe@example.com ++Message-Id: ++MIME-Version: 1.0 ++Content-Type: TEXT/PLAIN; CHARSET=US-ASCII ++ ++Hello Joe, do you think we can meet at 3:30 tomorrow? ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++A001 CAPABILITY ++A002 STARTTLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test982 +@@ -0,0 +1,57 @@ ++ ++ ++ ++POP3 ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++CAPA STLS USER ++REPLY STLS -ERR currently unavailable\r\n+OK user accepted\r\n+OK authenticated ++REPLY PASS -ERR Authentication credentials invalid ++ ++ ++From: me@somewhere ++To: fake@nowhere ++ ++body ++ ++-- ++ yours sincerely ++ ++ ++ ++# ++# Client-side ++ ++ ++SSL ++ ++ ++pop3 ++ ++ ++POP3 STARTTLS pipelined server response ++ ++ ++pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++CAPA ++STLS ++ ++ ++ +--- /dev/null ++++ b/tests/data/test983 +@@ -0,0 +1,52 @@ ++ ++ ++ ++FTP ++STARTTLS ++ ++ ++ ++# ++# Server-side ++ ++ ++REPLY AUTH 500 unknown command\r\n500 unknown command\r\n331 give password\r\n230 Authenticated\r\n257 "/"\r\n200 OK\r\n200 OK\r\n200 OK\r\n226 Transfer complete ++REPLY PASS 530 Login incorrect ++ ++ ++ ++# Client-side ++ ++ ++SSL ++ ++ ++ftp ++ ++ ++FTP STARTTLS pipelined server response ++ ++ ++data ++ to ++ see ++that FTPS ++works ++ so does it? ++ ++ ++--ssl --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret -P %CLIENTIP ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++# 8 is CURLE_WEIRD_SERVER_REPLY ++ ++8 ++ ++ ++AUTH SSL ++ ++ ++ diff --git a/patch/CVE-2022-22576.patch b/patch/CVE-2022-22576.patch new file mode 100644 index 0000000000000000000000000000000000000000..33eb58beb03f9040e93751ccefbf91a782617758 --- /dev/null +++ b/patch/CVE-2022-22576.patch @@ -0,0 +1,73 @@ +From e193f712be95dc9e5e2b92eae6381d4572231152 Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Sun, 17 Apr 2022 23:29:46 +0200 +Subject: [PATCH] url: check sasl additional parameters for connection reuse. + +Also move static function safecmp() as non-static Curl_safecmp() since +its purpose is needed at several places. + +Bug: https://curl.se/docs/CVE-2022-22576.html + +CVE-2022-22576 +Index: curl-7.68.0/lib/strcase.c +=================================================================== +--- curl-7.68.0.orig/lib/strcase.c ++++ curl-7.68.0/lib/strcase.c +@@ -249,6 +249,16 @@ void Curl_strntolower(char *dest, const + } while(*src++ && --n); + } + ++/* Compare case-sensitive NUL-terminated strings, taking care of possible ++ * null pointers. Return true if arguments match. ++ */ ++bool Curl_safecmp(char *a, char *b) ++{ ++ if(a && b) ++ return !strcmp(a, b); ++ return !a && !b; ++} ++ + /* --- public functions --- */ + + int curl_strequal(const char *first, const char *second) +Index: curl-7.68.0/lib/strcase.h +=================================================================== +--- curl-7.68.0.orig/lib/strcase.h ++++ curl-7.68.0/lib/strcase.h +@@ -49,4 +49,6 @@ char Curl_raw_tolower(char in); + void Curl_strntoupper(char *dest, const char *src, size_t n); + void Curl_strntolower(char *dest, const char *src, size_t n); + ++bool Curl_safecmp(char *a, char *b); ++ + #endif /* HEADER_CURL_STRCASE_H */ +Index: curl-7.68.0/lib/url.c +=================================================================== +--- curl-7.68.0.orig/lib/url.c ++++ curl-7.68.0/lib/url.c +@@ -1219,7 +1219,9 @@ ConnectionExists(struct Curl_easy *data, + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ + if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd)) { ++ strcmp(needle->passwd, check->passwd) || ++ !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || ++ !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } +@@ -3353,6 +3355,14 @@ static CURLcode create_conn(struct Curl_ + result = CURLE_OUT_OF_MEMORY; + goto out; + } ++ } ++ ++ if(data->set.str[STRING_BEARER]) { ++ conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); ++ if(!conn->oauth_bearer) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + } + + #ifdef USE_UNIX_SOCKETS diff --git a/patch/CVE-2022-27774-1.patch b/patch/CVE-2022-27774-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..7128e9a8a0e251407bc50177637e28cf4e16f630 --- /dev/null +++ b/patch/CVE-2022-27774-1.patch @@ -0,0 +1,35 @@ +From b92ebe53f3fc7b4a4355724a22690fdef4f1bf2f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 1/3] connect: store "conn_remote_port" in the info struct + +To make it available after the connection ended. +Index: curl-7.68.0/lib/connect.c +=================================================================== +--- curl-7.68.0.orig/lib/connect.c ++++ curl-7.68.0/lib/connect.c +@@ -624,6 +624,7 @@ void Curl_persistconninfo(struct connect + conn->data->info.conn_scheme = conn->handler->scheme; + conn->data->info.conn_protocol = conn->handler->protocol; + conn->data->info.conn_primary_port = conn->primary_port; ++ conn->data->info.conn_remote_port = conn->remote_port; + conn->data->info.conn_local_port = conn->local_port; + } + +Index: curl-7.68.0/lib/urldata.h +=================================================================== +--- curl-7.68.0.orig/lib/urldata.h ++++ curl-7.68.0/lib/urldata.h +@@ -1115,7 +1115,11 @@ struct PureInfo { + reused, in the connection cache. */ + + char conn_primary_ip[MAX_IPADR_LEN]; +- long conn_primary_port; ++ int conn_primary_port; /* this is the destination port to the connection, ++ which might have been a proxy */ ++ int conn_remote_port; /* this is the "remote port", which is the port ++ number of the used URL, independent of proxy or ++ not */ + char conn_local_ip[MAX_IPADR_LEN]; + long conn_local_port; + const char *conn_scheme; diff --git a/patch/CVE-2022-27774-2.patch b/patch/CVE-2022-27774-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..a64064669154cdc46b2c0e743d983b0b4c8ffe09 --- /dev/null +++ b/patch/CVE-2022-27774-2.patch @@ -0,0 +1,69 @@ +From 2b4afd8dd2132a0edd16acbe7c8d4d5c4fd06e61 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 2/3] transfer: redirects to other protocols or ports clear + auth + +... unless explicitly permitted. + +Bug: https://curl.se/docs/CVE-2022-27774.html +Reported-by: Harry Sintonen +Index: curl-7.68.0/lib/transfer.c +=================================================================== +--- curl-7.68.0.orig/lib/transfer.c ++++ curl-7.68.0/lib/transfer.c +@@ -1629,10 +1629,53 @@ CURLcode Curl_follow(struct Curl_easy *d + return CURLE_OUT_OF_MEMORY; + } + else { +- + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); ++ ++ /* Clear auth if this redirects to a different port number or protocol, ++ unless permitted */ ++ if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { ++ char *portnum; ++ int port; ++ bool clear = FALSE; ++ ++ uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, ++ CURLU_DEFAULT_PORT); ++ if(uc) { ++ free(newurl); ++ return Curl_uc_to_curlcode(uc); ++ } ++ port = atoi(portnum); ++ free(portnum); ++ ++ if(port != data->info.conn_remote_port) { ++ infof(data, "Clear auth, redirects to port from %u to %u", ++ data->info.conn_remote_port, port); ++ clear = TRUE; ++ } ++ else { ++ char *scheme; ++ const struct Curl_handler *p; ++ uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); ++ if(uc) { ++ free(newurl); ++ return Curl_uc_to_curlcode(uc); ++ } ++ ++ p = Curl_builtin_scheme(scheme); ++ if(p && (p->protocol != data->info.conn_protocol)) { ++ infof(data, "Clear auth, redirects scheme from %s to %s", ++ data->info.conn_scheme, scheme); ++ clear = TRUE; ++ } ++ free(scheme); ++ } ++ if(clear) { ++ Curl_safefree(data->set.str[STRING_USERNAME]); ++ Curl_safefree(data->set.str[STRING_PASSWORD]); ++ } ++ } + } + + if(type == FOLLOW_FAKE) { diff --git a/patch/CVE-2022-27774-3.patch b/patch/CVE-2022-27774-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..d3cab2666f2531ea67b5e19e3df3acf387295a1c --- /dev/null +++ b/patch/CVE-2022-27774-3.patch @@ -0,0 +1,393 @@ +From 2bb9658d75c846d398d490a96a58b5712e43c135 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 3/3] tests: verify the fix for CVE-2022-27774 + + - Test 973 redirects from HTTP to FTP, clear auth + - Test 974 redirects from HTTP to HTTP different port, clear auth + - Test 975 redirects from HTTP to FTP, permitted to keep auth + - Test 976 redirects from HTTP to HTTP different port, permitted to keep + auth +--- + tests/data/Makefile.inc | 2 +- + tests/data/test973 | 88 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test974 | 87 ++++++++++++++++++++++++++++++++++++++++ + tests/data/test975 | 88 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test976 | 88 +++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 352 insertions(+), 1 deletion(-) + create mode 100644 tests/data/test973 + create mode 100644 tests/data/test974 + create mode 100644 tests/data/test975 + create mode 100644 tests/data/test976 + +Index: curl-7.81.0/tests/data/test973 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test973 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++FTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP w/o auth ++ ++ ++http://%HOSTIP:%HTTPPORT/973 -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET /973 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++USER anonymous ++PASS ftp@example.com ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9730002 ++RETR 9730002 ++QUIT ++ ++ ++ +Index: curl-7.81.0/tests/data/test974 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test974 +@@ -0,0 +1,87 @@ ++ ++ ++ ++HTTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.974:9999/a/path/9740002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.974:9999/a/path/9740002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port w/o auth ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.974 -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET http://firsthost.974/ HTTP/1.1 ++Host: firsthost.974 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.974:9999/a/path/9740002 HTTP/1.1 ++Host: firsthost.974:9999 ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +Index: curl-7.81.0/tests/data/test975 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test975 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++FTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP allowing auth to continue ++ ++ ++http://%HOSTIP:%HTTPPORT/975 --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET /975 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++USER joe ++PASS secret ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9750002 ++RETR 9750002 ++QUIT ++ ++ ++ +Index: curl-7.81.0/tests/data/test976 +=================================================================== +--- /dev/null ++++ curl-7.81.0/tests/data/test976 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.976:9999/a/path/9760002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.976:9999/a/path/9760002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port --location-trusted ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.976 --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++GET http://firsthost.976/ HTTP/1.1 ++Host: firsthost.976 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.976:9999/a/path/9760002 HTTP/1.1 ++Host: firsthost.976:9999 ++Authorization: Basic am9lOnNlY3JldA== ++User-Agent: curl/7.68.0 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ diff --git a/patch/CVE-2022-27774-3pre.patch b/patch/CVE-2022-27774-3pre.patch new file mode 100644 index 0000000000000000000000000000000000000000..aa69c1aa08b7e3b689d5b23b07ddad13a161f720 --- /dev/null +++ b/patch/CVE-2022-27774-3pre.patch @@ -0,0 +1,17 @@ +From 2bb9658d75c846d398d490a96a58b5712e43c135 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 19 Apr 2022 12:49:28 +0200 +Subject: [PATCH 3/3] tests: verify the fix for CVE-2022-27774 + +Index: curl-7.68.0/tests/data/Makefile.inc +=================================================================== +--- curl-7.68.0.orig/tests/data/Makefile.inc ++++ curl-7.68.0/tests/data/Makefile.inc +@@ -111,6 +111,7 @@ test936 test937 test938 test939 test940 + test945 test946 test947 test948 test949 test950 test951 test952 test953 \ + test954 \ + \ ++test973 test974 test975 test976 \ + test980 test981 test982 test983 \ + \ + test984 test985 test986 \ diff --git a/patch/CVE-2022-27775.patch b/patch/CVE-2022-27775.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff7cf0dafe15a6895cddcf02d4615316c92e4b2 --- /dev/null +++ b/patch/CVE-2022-27775.patch @@ -0,0 +1,33 @@ +From 46091487fbdb37ffbe9c495de86c62d14634b71a Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 21 Apr 2022 12:30:34 +0200 +Subject: [PATCH] conncache: include the zone id in the "bundle" hashkey + +Make connections to two separate IPv6 zone ids create separate +connections. + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27775.html +--- + lib/conncache.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +Index: curl-7.68.0/lib/conncache.c +=================================================================== +--- curl-7.68.0.orig/lib/conncache.c ++++ curl-7.68.0/lib/conncache.c +@@ -158,8 +158,12 @@ static void hashkey(struct connectdata * + /* report back which name we used */ + *hostp = hostname; + +- /* put the number first so that the hostname gets cut off if too long */ +- msnprintf(buf, len, "%ld%s", port, hostname); ++ /* put the numbers first so that the hostname gets cut off if too long */ ++#ifdef ENABLE_IPV6 ++ msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname); ++#else ++ msnprintf(buf, len, "%ld/%s", port, hostname); ++#endif + } + + void Curl_conncache_unlock(struct Curl_easy *data) diff --git a/patch/CVE-2022-27776.patch b/patch/CVE-2022-27776.patch new file mode 100644 index 0000000000000000000000000000000000000000..c8a4e2e5713e4fd12bd45c218037e33cfd7ef101 --- /dev/null +++ b/patch/CVE-2022-27776.patch @@ -0,0 +1,105 @@ +Backported of: + +From 125302094326ad5eb0ea87f2d2ece6ceab1b1e59 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 22 Apr 2022 08:19:18 +0200 +Subject: [PATCH] http: avoid auth/cookie on redirects same host diff port + +CVE-2022-27776 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27776.html +diff --git a/lib/http.c b/lib/http.c +index 837f53c..4d6626b 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -733,6 +733,21 @@ output_auth_headers(struct connectdata *conn, + return CURLE_OK; + } + ++/* ++ * allow_auth_to_host() tells if autentication, cookies or other "sensitive ++ * data" can (still) be sent to this host. ++ */ ++static bool allow_auth_to_host(struct Curl_easy *data) ++{ ++ struct connectdata *conn = data->conn; ++ return (!data->state.this_is_a_follow || ++ data->set.allow_auth_to_other_hosts || ++ (data->state.first_host && ++ strcasecompare(data->state.first_host, conn->host.name) && ++ (data->state.first_remote_port == conn->remote_port) && ++ (data->state.first_remote_protocol == conn->handler->protocol))); ++} ++ + /** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication +@@ -801,15 +816,12 @@ Curl_http_output_auth(struct connectdata *conn, + with it */ + authproxy->done = TRUE; + +- /* To prevent the user+password to get sent to other than the original +- host due to a location-follow, we do some weirdo checks here */ +- if(!data->state.this_is_a_follow || +- conn->bits.netrc || +- !data->state.first_host || +- data->set.allow_auth_to_other_hosts || +- strcasecompare(data->state.first_host, conn->host.name)) { ++ /* To prevent the user+password to get sent to other than the original host ++ due to a location-follow */ ++ if(allow_auth_to_host(data) ++ || conn->bits.netrc ++ ) + result = output_auth_headers(conn, authhost, request, path, FALSE); +- } + else + authhost->done = TRUE; + +@@ -1881,10 +1893,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Cookie:", compare)) && + /* be careful of sending this potentially sensitive header to + other hosts */ +- (data->state.this_is_a_follow && +- data->state.first_host && +- !data->set.allow_auth_to_other_hosts && +- !strcasecompare(data->state.first_host, conn->host.name))) ++ !allow_auth_to_host(data)) + ; + else { + result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); +@@ -2067,6 +2076,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) + return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; ++ data->state.first_remote_protocol = conn->handler->protocol; + } + + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && +diff --git a/lib/urldata.h b/lib/urldata.h +index 6993def..5ca0921 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1315,13 +1315,15 @@ struct UrlState { + char *ulbuf; /* allocated upload buffer or NULL */ + curl_off_t current_speed; /* the ProgressShow() function sets this, + bytes / second */ +- char *first_host; /* host name of the first (not followed) request. +- if set, this should be the host name that we will +- sent authorization to, no else. Used to make Location: +- following not keep sending user+password... This is +- strdup() data. +- */ +- int first_remote_port; /* remote port of the first (not followed) request */ ++ ++ /* host name, port number and protocol of the first (not followed) request. ++ if set, this should be the host name that we will sent authorization to, ++ no else. Used to make Location: following not keep sending user+password. ++ This is strdup()ed data. */ ++ char *first_host; ++ int first_remote_port; ++ unsigned int first_remote_protocol; ++ + struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ + long sessionage; /* number of the most recent session */ + unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ diff --git a/patch/CVE-2022-27781.patch b/patch/CVE-2022-27781.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc8a670743321e978138e35f2bb7225438c0319c --- /dev/null +++ b/patch/CVE-2022-27781.patch @@ -0,0 +1,42 @@ +Backport of: + +From 625924941cbd684c2a6b10d18aa6920a27c31db3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 3 May 2022 09:24:56 +0200 +Subject: [PATCH] nss: return error if seemingly stuck in a cert loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CVE-2022-27781 + +Reported-by: Florian Kohnhäuser +Bug: https://curl.se/docs/CVE-2022-27781.html +--- + lib/vtls/nss.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -950,6 +950,9 @@ static void display_cert_info(struct Cur + PR_Free(common_name); + } + ++/* A number of certs that will never occur in a real server handshake */ ++#define TOO_MANY_CERTS 300 ++ + static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) + { + CURLcode result = CURLE_OK; +@@ -986,6 +989,11 @@ static CURLcode display_conn_info(struct + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); + while(cert2) { + i++; ++ if(i >= TOO_MANY_CERTS) { ++ CERT_DestroyCertificate(cert2); ++ failf(conn->data, "certificate loop"); ++ return CURLE_SSL_CERTPROBLEM; ++ } + if(cert2->isRoot) { + CERT_DestroyCertificate(cert2); + break; diff --git a/patch/CVE-2022-27782.patch b/patch/CVE-2022-27782.patch new file mode 100644 index 0000000000000000000000000000000000000000..45928b999510ea2b26cc72bbfe38abce72ffdad0 --- /dev/null +++ b/patch/CVE-2022-27782.patch @@ -0,0 +1,445 @@ +Backport of: + +From 222b896a07ed1e183e7eacd6df10fc23264bd820 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 6 May 2022 10:48:58 +0200 +Subject: [PATCH 1/2] tls: check more TLS details for connection reuse + +CVE-2022-27782 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27782.html +--- + lib/setopt.c | 29 +++++++++++++++++------------ + lib/url.c | 23 ++++++++++++++++------- + lib/urldata.h | 13 +++++++------ + lib/vtls/gtls.c | 32 +++++++++++++++++--------------- + lib/vtls/openssl.c | 10 +++++----- + lib/vtls/vtls.c | 21 +++++++++++++++++++++ + 6 files changed, 83 insertions(+), 45 deletions(-) + +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -2130,6 +2130,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + + case CURLOPT_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.ssl.enable_beast = + (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); +@@ -2139,6 +2140,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + #ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.proxy_ssl.enable_beast = + (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); +@@ -2537,44 +2539,47 @@ CURLcode Curl_vsetopt(struct Curl_easy * + case CURLOPT_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to ++ SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + case CURLOPT_PROXY_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + #endif + #ifdef USE_ARES +--- a/lib/url.c ++++ b/lib/url.c +@@ -483,7 +483,7 @@ CURLcode Curl_init_userdefined(struct Cu + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; + #ifdef USE_TLS_SRP +- set->ssl.authtype = CURL_TLSAUTH_NONE; ++ set->ssl.primary.authtype = CURL_TLSAUTH_NONE; + #endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ +@@ -997,6 +997,12 @@ static void prune_dead_connections(struc + } + } + ++static bool ssh_config_matches(struct connectdata *one, ++ struct connectdata *two) ++{ ++ return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && ++ Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub)); ++} + /* + * Given one filled in connection struct (named needle), this function should + * detect if there already is one that has all the significant details +@@ -1227,6 +1233,11 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++ if(get_protocol_family(needle->handler->protocol) == PROTO_FAMILY_SSH) { ++ if(!ssh_config_matches(needle, check)) ++ continue; ++ } ++ + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + needle->bits.tunnel_proxy) { + /* The requested connection does not use a HTTP proxy or it uses SSL or +@@ -1608,10 +1619,16 @@ static struct connectdata *allocate_conn + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; ++ conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options; ++#ifdef USE_TLS_SRP ++#endif + conn->proxy_ssl_config.verifystatus = + data->set.proxy_ssl.primary.verifystatus; + conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; + conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; ++ conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; ++#ifdef USE_TLS_SRP ++#endif + conn->ip_version = data->set.ipver; + conn->bits.connect_only = data->set.connect_only; + conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ +@@ -3554,8 +3571,9 @@ static CURLcode create_conn(struct Curl_ + data->set.proxy_ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + +- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; +- data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; ++ data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; ++ data->set.proxy_ssl.primary.CRLfile = ++ data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; +@@ -3569,10 +3587,12 @@ static CURLcode create_conn(struct Curl_ + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + #ifdef USE_TLS_SRP +- data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; +- data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; +- data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; +- data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; ++ data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; ++ data->set.proxy_ssl.primary.username = ++ data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; ++ data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; ++ data->set.proxy_ssl.primary.password = ++ data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; + #endif + + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -231,6 +231,13 @@ struct ssl_primary_config { + char *cipher_list; /* list of ciphers to use */ + char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ + char *pinned_key; ++ char *CRLfile; /* CRL to check certificate revocation */ ++#ifdef USE_TLS_SRP ++ char *username; /* TLS username (for, e.g., SRP) */ ++ char *password; /* TLS password (for, e.g., SRP) */ ++ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ ++#endif ++ unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ + BIT(verifypeer); /* set TRUE if this is desired */ + BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ + BIT(verifystatus); /* set TRUE if certificate status must be checked */ +@@ -240,7 +247,6 @@ struct ssl_primary_config { + struct ssl_config_data { + struct ssl_primary_config primary; + long certverifyresult; /* result from the certificate verification */ +- char *CRLfile; /* CRL to check certificate revocation */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + char *cert; /* client certificate file name */ +@@ -248,11 +254,6 @@ struct ssl_config_data { + char *key; /* private key file name */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ +-#ifdef USE_TLS_SRP +- char *username; /* TLS username (for, e.g., SRP) */ +- char *password; /* TLS password (for, e.g., SRP) */ +- enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +-#endif + BIT(certinfo); /* gather lots of certificate info */ + BIT(falsestart); + BIT(enable_beast); /* allow this flaw for interoperability's sake*/ +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -581,8 +581,9 @@ gtls_connect_step1(struct connectdata *c + } + + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { +- infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { ++ infof(data, "Using TLS-SRP username: %s\n", ++ SSL_SET_OPTION(primary.username)); + + rc = gnutls_srp_allocate_client_credentials( + &BACKEND->srp_client_cred); +@@ -593,8 +594,8 @@ gtls_connect_step1(struct connectdata *c + } + + rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, +- SSL_SET_OPTION(username), +- SSL_SET_OPTION(password)); ++ SSL_SET_OPTION(primary.username), ++ SSL_SET_OPTION(primary.password)); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_set_client_cred() failed: %s", + gnutls_strerror(rc)); +@@ -648,19 +649,19 @@ gtls_connect_step1(struct connectdata *c + } + #endif + +- if(SSL_SET_OPTION(CRLfile)) { ++ if(SSL_SET_OPTION(primary.CRLfile)) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, +- SSL_SET_OPTION(CRLfile), ++ SSL_SET_OPTION(primary.CRLfile), + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)", +- SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); ++ SSL_SET_OPTION(primary.CRLfile), gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s\n", +- rc, SSL_SET_OPTION(CRLfile)); ++ rc, SSL_SET_OPTION(primary.CRLfile)); + } + + /* Initialize TLS session as a client */ +@@ -787,7 +788,7 @@ gtls_connect_step1(struct connectdata *c + #ifdef USE_TLS_SRP + /* Only add SRP to the cipher list if SRP is requested. Otherwise + * GnuTLS will disable TLS 1.3 support. */ +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { + size_t len = strlen(prioritylist); + + char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); +@@ -884,7 +885,7 @@ gtls_connect_step1(struct connectdata *c + + #ifdef USE_TLS_SRP + /* put the credentials to the current session */ +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) { + rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, + BACKEND->srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { +@@ -1066,8 +1067,8 @@ gtls_connect_step3(struct connectdata *c + SSL_CONN_CONFIG(verifyhost) || + SSL_CONN_CONFIG(issuercert)) { + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP +- && SSL_SET_OPTION(username) != NULL ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP ++ && SSL_SET_OPTION(primary.username) != NULL + && !SSL_CONN_CONFIG(verifypeer) + && gnutls_cipher_get(session)) { + /* no peer cert, but auth is ok if we have SRP user and cipher and no +@@ -1121,7 +1122,8 @@ gtls_connect_step3(struct connectdata *c + failf(data, "server certificate verification failed. CAfile: %s " + "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): + "none", +- SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); ++ SSL_SET_OPTION(primary.CRLfile) ? ++ SSL_SET_OPTION(primary.CRLfile) : "none"); + return CURLE_PEER_FAILED_VERIFICATION; + } + else +@@ -1708,8 +1710,8 @@ static int Curl_gtls_shutdown(struct con + gnutls_certificate_free_credentials(BACKEND->cred); + + #ifdef USE_TLS_SRP +- if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP +- && SSL_SET_OPTION(username) != NULL) ++ if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP ++ && SSL_SET_OPTION(primary.username) != NULL) + gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); + #endif + +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -2466,14 +2466,14 @@ static CURLcode ossl_connect_step1(struc + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const long int ssl_version = SSL_CONN_CONFIG(version); + #ifdef USE_TLS_SRP +- const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); ++ const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype); + #endif + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); +- const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); ++ const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile); + char error_buffer[256]; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); +@@ -2752,15 +2752,15 @@ static CURLcode ossl_connect_step1(struc + + #ifdef USE_TLS_SRP + if(ssl_authtype == CURL_TLSAUTH_SRP) { +- char * const ssl_username = SSL_SET_OPTION(username); +- ++ char * const ssl_username = SSL_SET_OPTION(primary.username); ++ char * const ssl_password = SSL_SET_OPTION(primary.password); + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +- if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { ++ if(!SSL_CTX_set_srp_password(BACKEND->ctx, ssl_password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -98,6 +98,7 @@ Curl_ssl_config_matches(struct ssl_prima + { + if((data->version == needle->version) && + (data->version_max == needle->version_max) && ++ (data->ssl_options == needle->ssl_options) && + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +@@ -107,8 +108,14 @@ Curl_ssl_config_matches(struct ssl_prima + safecmp(data->clientcert, needle->clientcert) && + safecmp(data->random_file, needle->random_file) && + safecmp(data->egdsocket, needle->egdsocket) && ++#ifdef USE_TLS_SRP ++ Curl_safecmp(data->username, needle->username) && ++ Curl_safecmp(data->password, needle->password) && ++ (data->authtype == needle->authtype) && ++#endif + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && ++ Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) && + Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) + return TRUE; + +@@ -125,6 +132,10 @@ Curl_clone_primary_ssl_config(struct ssl + dest->verifyhost = source->verifyhost; + dest->verifystatus = source->verifystatus; + dest->sessionid = source->sessionid; ++ dest->ssl_options = source->ssl_options; ++#ifdef USE_TLS_SRP ++ dest->authtype = source->authtype; ++#endif + + CLONE_STRING(CApath); + CLONE_STRING(CAfile); +@@ -135,6 +146,11 @@ Curl_clone_primary_ssl_config(struct ssl + CLONE_STRING(cipher_list); + CLONE_STRING(cipher_list13); + CLONE_STRING(pinned_key); ++ CLONE_STRING(CRLfile); ++#ifdef USE_TLS_SRP ++ CLONE_STRING(username); ++ CLONE_STRING(password); ++#endif + + return TRUE; + } +@@ -150,6 +166,11 @@ void Curl_free_primary_ssl_config(struct + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); + Curl_safefree(sslc->pinned_key); ++ Curl_safefree(sslc->CRLfile); ++#ifdef USE_TLS_SRP ++ Curl_safefree(sslc->username); ++ Curl_safefree(sslc->password); ++#endif + } + + #ifdef USE_SSL +--- a/lib/vssh/ssh.h ++++ b/lib/vssh/ssh.h +@@ -117,8 +117,8 @@ struct ssh_conn { + + /* common */ + const char *passphrase; /* pass-phrase to use */ +- char *rsa_pub; /* path name */ +- char *rsa; /* path name */ ++ char *rsa_pub; /* strdup'ed public key file */ ++ char *rsa; /* strdup'ed private key file */ + bool authed; /* the connection has been authenticated fine */ + sshstate state; /* always use ssh.c:state() to change state! */ + sshstate nextstate; /* the state to goto after stopping */ +--- a/lib/vtls/nss.c ++++ b/lib/vtls/nss.c +@@ -1955,13 +1955,13 @@ static CURLcode nss_setup_connect(struct + } + } + +- if(SSL_SET_OPTION(CRLfile)) { +- const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); ++ if(SSL_SET_OPTION(primary.CRLfile)) { ++ const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile)); + if(rv) { + result = rv; + goto error; + } +- infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); ++ infof(data, " CRLfile: %s\n", SSL_SET_OPTION(primary.CRLfile)); + } + + if(SSL_SET_OPTION(cert)) { diff --git a/patch/CVE-2022-32206.patch b/patch/CVE-2022-32206.patch new file mode 100644 index 0000000000000000000000000000000000000000..815247eea649375c031df3738af94b134e1c56a5 --- /dev/null +++ b/patch/CVE-2022-32206.patch @@ -0,0 +1,42 @@ +Backported of: + +From 7035676c3daa4f1c3766095561f12e7a0e82c736 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 16 May 2022 16:28:13 +0200 +Subject: [PATCH] content_encoding: return error on too many compression steps + +The max allowed steps is arbitrarily set to 5. +Index: curl-7.68.0/lib/content_encoding.c +=================================================================== +--- curl-7.68.0.orig/lib/content_encoding.c ++++ curl-7.68.0/lib/content_encoding.c +@@ -934,6 +934,9 @@ static const content_encoding *find_enco + return NULL; + } + ++/* allow no more than 5 "chained" compression steps */ ++#define MAX_ENCODE_STACK 5 ++ + /* Set-up the unencoding stack from the Content-Encoding header value. + * See RFC 7231 section 3.1.2.2. */ + CURLcode Curl_build_unencoding_stack(struct connectdata *conn, +@@ -941,6 +944,7 @@ CURLcode Curl_build_unencoding_stack(str + { + struct Curl_easy *data = conn->data; + struct SingleRequest *k = &data->req; ++ int counter = 0; + + do { + const char *name; +@@ -975,6 +979,11 @@ CURLcode Curl_build_unencoding_stack(str + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + ++ if(++counter >= MAX_ENCODE_STACK) { ++ failf(data, "Reject response due to %u content encodings", ++ counter); ++ return CURLE_BAD_CONTENT_ENCODING; ++ } + /* Stack the unencoding stage. */ + writer = new_unencoding_writer(conn, encoding, k->writer_stack); + if(!writer) diff --git a/patch/CVE-2022-32208.patch b/patch/CVE-2022-32208.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f861e7d94201123e5be52d24d5e1bb5e0517042 --- /dev/null +++ b/patch/CVE-2022-32208.patch @@ -0,0 +1,24 @@ +Backported from: + +From 4c3f77e871820d055a5f6c4cd7a6ac47a7f3877d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Jun 2022 09:27:24 +0200 +Subject: [PATCH] krb5: return error properly on decode errors + +diff --git a/lib/krb5.c b/lib/krb5.c +index f50287a..5b77e35 100644 +--- a/lib/krb5.c ++++ b/lib/krb5.c +@@ -86,11 +86,8 @@ krb5_decode(void *app_data, void *buf, int len, + enc.value = buf; + enc.length = len; + maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); +- if(maj != GSS_S_COMPLETE) { +- if(len >= 4) +- strcpy(buf, "599 "); ++ if(maj != GSS_S_COMPLETE) + return -1; +- } + + memcpy(buf, dec.value, dec.length); + len = curlx_uztosi(dec.length); diff --git a/patch/CVE-2022-32221.patch b/patch/CVE-2022-32221.patch new file mode 100644 index 0000000000000000000000000000000000000000..40b9ad500dd7275e290d0df9785281f4834ee317 --- /dev/null +++ b/patch/CVE-2022-32221.patch @@ -0,0 +1,24 @@ +Backport of: + +From a64e3e59938abd7d667e4470a18072a24d7e9de9 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 15 Sep 2022 09:22:45 +0200 +Subject: [PATCH] setopt: when POST is set, reset the 'upload' field + +Reported-by: RobBotic1 on github +Fixes #9507 +Closes #9511 +--- + lib/setopt.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -486,6 +486,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + } + else + data->set.httpreq = HTTPREQ_GET; ++ data->set.upload = FALSE; + break; + + case CURLOPT_COPYPOSTFIELDS: diff --git a/patch/CVE-2022-35252.patch b/patch/CVE-2022-35252.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d51a61acecbbb82e4d8cf9d3ad9a15a7fc6cd9b --- /dev/null +++ b/patch/CVE-2022-35252.patch @@ -0,0 +1,63 @@ +From 8dfc93e573ca740544a2d79ebb0ed786592c65c3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 29 Aug 2022 00:09:17 +0200 +Subject: [PATCH] cookie: reject cookies with "control bytes" + +Rejects 0x01 - 0x1f (except 0x09) plus 0x7f + +Reported-by: Axel Chong + +Bug: https://curl.se/docs/CVE-2022-35252.html + +CVE-2022-35252 + +Closes #9381 +--- + lib/cookie.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +--- a/lib/cookie.c ++++ b/lib/cookie.c +@@ -411,6 +411,30 @@ static bool bad_domain(const char *domai + return !strchr(domain, '.') && !strcasecompare(domain, "localhost"); + } + ++/* ++ RFC 6265 section 4.1.1 says a server should accept this range: ++ ++ cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E ++ ++ But Firefox and Chrome as of June 2022 accept space, comma and double-quotes ++ fine. The prime reason for filtering out control bytes is that some HTTP ++ servers return 400 for requests that contain such. ++*/ ++static int invalid_octets(const char *p) ++{ ++ /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */ ++ static const char badoctets[] = { ++ "\x01\x02\x03\x04\x05\x06\x07\x08\x0a" ++ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" ++ "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" ++ }; ++ size_t vlen, len; ++ /* scan for all the octets that are *not* in cookie-octet */ ++ len = strcspn(p, badoctets); ++ vlen = strlen(p); ++ return (len != vlen); ++} ++ + /**************************************************************************** + * + * Curl_cookie_add() +@@ -557,6 +581,11 @@ Curl_cookie_add(struct Curl_easy *data, + badcookie = TRUE; + break; + } ++ if(invalid_octets(whatptr) || invalid_octets(name)) { ++ infof(data, "invalid octets in name/value, cookie dropped"); ++ badcookie = TRUE; ++ break; ++ } + } + else if(!len) { + /* this was a "=" with no content, and we must allow diff --git a/patch/CVE-2022-43552.patch b/patch/CVE-2022-43552.patch new file mode 100644 index 0000000000000000000000000000000000000000..5085cc12764b664023a7f8b20c4f14b7e5b84f28 --- /dev/null +++ b/patch/CVE-2022-43552.patch @@ -0,0 +1,72 @@ +Backport of: + +From 4f20188ac644afe174be6005ef4f6ffba232b8b2 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 19 Dec 2022 08:38:37 +0100 +Subject: [PATCH] smb/telnet: do not free the protocol struct in *_done() + +It is managed by the generic layer. + +Reported-by: Trail of Bits + +Closes #10112 +--- + lib/smb.c | 14 ++------------ + lib/telnet.c | 3 --- + 2 files changed, 2 insertions(+), 15 deletions(-) + +--- a/lib/smb.c ++++ b/lib/smb.c +@@ -61,8 +61,6 @@ static CURLcode smb_connect(struct conne + static CURLcode smb_connection_state(struct connectdata *conn, bool *done); + static CURLcode smb_do(struct connectdata *conn, bool *done); + static CURLcode smb_request_state(struct connectdata *conn, bool *done); +-static CURLcode smb_done(struct connectdata *conn, CURLcode status, +- bool premature); + static CURLcode smb_disconnect(struct connectdata *conn, bool dead); + static int smb_getsock(struct connectdata *conn, curl_socket_t *socks); + static CURLcode smb_parse_url_path(struct connectdata *conn); +@@ -74,7 +72,7 @@ const struct Curl_handler Curl_handler_s + "SMB", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ +- smb_done, /* done */ ++ ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ +@@ -99,7 +97,7 @@ const struct Curl_handler Curl_handler_s + "SMBS", /* scheme */ + smb_setup_connection, /* setup_connection */ + smb_do, /* do_it */ +- smb_done, /* done */ ++ ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ +@@ -919,14 +917,6 @@ static CURLcode smb_request_state(struct + return CURLE_OK; + } + +-static CURLcode smb_done(struct connectdata *conn, CURLcode status, +- bool premature) +-{ +- (void) premature; +- Curl_safefree(conn->data->req.protop); +- return status; +-} +- + static CURLcode smb_disconnect(struct connectdata *conn, bool dead) + { + struct smb_conn *smbc = &conn->proto.smbc; +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -1295,8 +1295,6 @@ static CURLcode telnet_done(struct conne + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + +- Curl_safefree(conn->data->req.protop); +- + return CURLE_OK; + } + diff --git a/patch/CVE-2023-23916.patch b/patch/CVE-2023-23916.patch new file mode 100644 index 0000000000000000000000000000000000000000..fab115a93550f4a71bff9b14f2f17fb9f753daf9 --- /dev/null +++ b/patch/CVE-2023-23916.patch @@ -0,0 +1,221 @@ +Backport of: + +From 119fb187192a9ea13dc90d9d20c215fc82799ab9 Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Mon, 13 Feb 2023 08:33:09 +0100 +Subject: [PATCH] content_encoding: do not reset stage counter for each header + +Test 418 verifies + +Closes #10492 +--- + lib/content_encoding.c | 7 +- + lib/urldata.h | 1 + + tests/data/Makefile.inc | 2 +- + tests/data/test387 | 2 +- + tests/data/test418 | 152 ++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 158 insertions(+), 6 deletions(-) + create mode 100644 tests/data/test418 + +--- a/lib/content_encoding.c ++++ b/lib/content_encoding.c +@@ -944,7 +944,6 @@ CURLcode Curl_build_unencoding_stack(str + { + struct Curl_easy *data = conn->data; + struct SingleRequest *k = &data->req; +- int counter = 0; + + do { + const char *name; +@@ -979,9 +978,9 @@ CURLcode Curl_build_unencoding_stack(str + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + +- if(++counter >= MAX_ENCODE_STACK) { +- failf(data, "Reject response due to %u content encodings", +- counter); ++ if(k->writer_stack_depth++ >= MAX_ENCODE_STACK) { ++ failf(data, "Reject response due to more than %u content encodings", ++ MAX_ENCODE_STACK); + return CURLE_BAD_CONTENT_ENCODING; + } + /* Stack the unencoding stage. */ +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -643,6 +643,7 @@ struct SingleRequest { + #ifndef CURL_DISABLE_DOH + struct dohdata doh; /* DoH specific data for this request */ + #endif ++ unsigned char writer_stack_depth; /* Unencoding stack depth. */ + BIT(header); /* incoming data has HTTP header */ + BIT(content_range); /* set TRUE if Content-Range: was found */ + BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -63,7 +63,7 @@ test350 test351 test352 test353 test354 + test393 test394 test395 \ + \ + test400 test401 test402 test403 test404 test405 test406 test407 test408 \ +-test409 \ ++test409 test418 \ + \ + test490 test491 test492 \ + \ +--- /dev/null ++++ b/tests/data/test418 +@@ -0,0 +1,155 @@ ++ ++ ++ ++HTTP ++gzip ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 200 OK ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++Transfer-Encoding: gzip ++ ++-foo- ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++Response with multiple Transfer-Encoding headers ++ ++ ++http://%HOSTIP:%HTTPPORT/418 -sS ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent: curl/.* ++ ++ ++GET /418 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++User-Agent: curl/7.68.0 ++Accept: */* ++ ++ ++ ++# CURLE_BAD_CONTENT_ENCODING is 61 ++ ++61 ++ ++ ++curl: (61) Reject response due to more than 5 content encodings ++ ++ ++ diff --git a/patch/CVE-2023-27533.patch b/patch/CVE-2023-27533.patch new file mode 100644 index 0000000000000000000000000000000000000000..ddd5efa46e0e0821cdf760541e85a4749c61ba50 --- /dev/null +++ b/patch/CVE-2023-27533.patch @@ -0,0 +1,54 @@ +Backport of: + +From 538b1e79a6e7b0bb829ab4cecc828d32105d0684 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 6 Mar 2023 12:07:33 +0100 +Subject: [PATCH] telnet: only accept option arguments in ascii + +To avoid embedded telnet negotiation commands etc. + +Reported-by: Harry Sintonen +Closes #10728 +--- + lib/telnet.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/lib/telnet.c ++++ b/lib/telnet.c +@@ -815,6 +815,17 @@ static void printsub(struct Curl_easy *d + } + } + ++static bool str_is_nonascii(const char *str) ++{ ++ size_t len = strlen(str); ++ while(len--) { ++ if(*str & 0x80) ++ return TRUE; ++ str++; ++ } ++ return FALSE; ++} ++ + static CURLcode check_telnet_options(struct connectdata *conn) + { + struct curl_slist *head; +@@ -829,6 +840,8 @@ static CURLcode check_telnet_options(str + /* Add the user name as an environment variable if it + was given on the command line */ + if(conn->bits.user_passwd) { ++ if(str_is_nonascii(data->conn->user)) ++ return CURLE_BAD_FUNCTION_ARGUMENT; + msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { +@@ -844,6 +857,9 @@ static CURLcode check_telnet_options(str + if(sscanf(head->data, "%127[^= ]%*[ =]%255s", + option_keyword, option_arg) == 2) { + ++ if(str_is_nonascii(option_arg)) ++ continue; ++ + /* Terminal type */ + if(strcasecompare(option_keyword, "TTYPE")) { + strncpy(tn->subopt_ttype, option_arg, 31); diff --git a/patch/CVE-2023-27534-pre1.patch b/patch/CVE-2023-27534-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..efb03f6a71a38954c44a7a9236f3cdc079848443 --- /dev/null +++ b/patch/CVE-2023-27534-pre1.patch @@ -0,0 +1,33 @@ +From 6c51adeb71da076c5c40a45e339e06bb4394a86b Mon Sep 17 00:00:00 2001 +From: Eric Vigeant +Date: Wed, 2 Nov 2022 11:47:09 -0400 +Subject: [PATCH] cur_path: do not add '/' if homedir ends with one + +When using SFTP and a path relative to the user home, do not add a +trailing '/' to the user home dir if it already ends with one. + +Closes #9844 +--- + lib/curl_path.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/lib/curl_path.c ++++ b/lib/curl_path.c +@@ -70,10 +70,14 @@ CURLcode Curl_getworkingpath(struct conn + /* It is referenced to the home directory, so strip the + leading '/' */ + memcpy(real_path, homedir, homelen); +- real_path[homelen] = '/'; +- real_path[homelen + 1] = '\0'; ++ /* Only add a trailing '/' if homedir does not end with one */ ++ if(homelen == 0 || real_path[homelen - 1] != '/') { ++ real_path[homelen] = '/'; ++ homelen++; ++ real_path[homelen] = '\0'; ++ } + if(working_path_len > 3) { +- memcpy(real_path + homelen + 1, working_path + 3, ++ memcpy(real_path + homelen, working_path + 3, + 1 + working_path_len -3); + } + } diff --git a/patch/CVE-2023-27534.patch b/patch/CVE-2023-27534.patch new file mode 100644 index 0000000000000000000000000000000000000000..6eedebbfc011b6b3a0f46e8aa8900a156997e5cf --- /dev/null +++ b/patch/CVE-2023-27534.patch @@ -0,0 +1,24 @@ +Backport of: + +From 4e2b52b5f7a3bf50a0f1494155717b02cc1df6d6 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Mar 2023 16:22:11 +0100 +Subject: [PATCH] curl_path: create the new path with dynbuf + +Closes #10729 +--- + lib/curl_path.c | 75 +++++++++++++++++++++++-------------------------- + 1 file changed, 35 insertions(+), 40 deletions(-) + + +--- a/lib/curl_path.c ++++ b/lib/curl_path.c +@@ -60,7 +60,7 @@ CURLcode Curl_getworkingpath(struct conn + memcpy(real_path, working_path, 1 + working_path_len); + } + else if(conn->handler->protocol & CURLPROTO_SFTP) { +- if((working_path_len > 1) && (working_path[1] == '~')) { ++ if((working_path_len > 2) && !memcmp(working_path, "/~/", 3)) { + size_t homelen = strlen(homedir); + real_path = malloc(homelen + working_path_len + 1); + if(real_path == NULL) { diff --git a/patch/CVE-2023-27535-pre1.patch b/patch/CVE-2023-27535-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..4937686ca857539e3599c602028ce6e32556a46f --- /dev/null +++ b/patch/CVE-2023-27535-pre1.patch @@ -0,0 +1,156 @@ +Backport of: + +From ed5095ed94281989e103c72e032200b83be37878 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 6 Oct 2022 00:49:10 +0200 +Subject: [PATCH] strcase: add and use Curl_timestrcmp + +This is a strcmp() alternative function for comparing "secrets", +designed to take the same time no matter the content to not leak +match/non-match info to observers based on how fast it is. + +The time this function takes is only a function of the shortest input +string. + +Reported-by: Trail of Bits + +Closes #9658 +--- + lib/netrc.c | 6 +++--- + lib/strcase.c | 22 ++++++++++++++++++++++ + lib/strcase.h | 1 + + lib/url.c | 34 +++++++++++++--------------------- + lib/vauth/digest_sspi.c | 4 ++-- + lib/vtls/vtls.c | 4 ++-- + 6 files changed, 43 insertions(+), 28 deletions(-) + +--- a/lib/netrc.c ++++ b/lib/netrc.c +@@ -123,9 +123,9 @@ static int parsenetrc(const char *host, + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + if(specific_login) { +- state_our_login = strcasecompare(login, tok); ++ state_our_login = !Curl_timestrcmp(login, tok); + } +- else if(!login || strcmp(login, tok)) { ++ else if(!login || Curl_timestrcmp(login, tok)) { + if(login_alloc) { + free(login); + login_alloc = FALSE; +@@ -141,7 +141,7 @@ static int parsenetrc(const char *host, + } + else if(state_password) { + if((state_our_login || !specific_login) +- && (!password || strcmp(password, tok))) { ++ && (!password || Curl_timestrcmp(password, tok))) { + if(password_alloc) { + free(password); + password_alloc = FALSE; +--- a/lib/strcase.c ++++ b/lib/strcase.c +@@ -259,6 +259,28 @@ bool Curl_safecmp(char *a, char *b) + return !a && !b; + } + ++/* ++ * Curl_timestrcmp() returns 0 if the two strings are identical. The time this ++ * function spends is a function of the shortest string, not of the contents. ++ */ ++int Curl_timestrcmp(const char *a, const char *b) ++{ ++ int match = 0; ++ int i = 0; ++ ++ if(a && b) { ++ while(1) { ++ match |= a[i]^b[i]; ++ if(!a[i] || !b[i]) ++ break; ++ i++; ++ } ++ } ++ else ++ return a || b; ++ return match; ++} ++ + /* --- public functions --- */ + + int curl_strequal(const char *first, const char *second) +--- a/lib/strcase.h ++++ b/lib/strcase.h +@@ -50,5 +50,6 @@ void Curl_strntoupper(char *dest, const + void Curl_strntolower(char *dest, const char *src, size_t n); + + bool Curl_safecmp(char *a, char *b); ++int Curl_timestrcmp(const char *first, const char *second); + + #endif /* HEADER_CURL_STRCASE_H */ +--- a/lib/url.c ++++ b/lib/url.c +@@ -1224,10 +1224,10 @@ ConnectionExists(struct Curl_easy *data, + if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ +- if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd) || +- !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || +- !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd) || ++ Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) || ++ Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } +@@ -1293,8 +1293,8 @@ ConnectionExists(struct Curl_easy *data, + possible. (Especially we must not reuse the same connection if + partway through a handshake!) */ + if(wantNTLMhttp) { +- if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd)) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd)) { + + /* we prefer a credential match, but this is at least a connection + that can be reused and "upgraded" to NTLM */ +@@ -1315,8 +1315,10 @@ ConnectionExists(struct Curl_easy *data, + if(!check->http_proxy.user || !check->http_proxy.passwd) + continue; + +- if(strcmp(needle->http_proxy.user, check->http_proxy.user) || +- strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) ++ if(Curl_timestrcmp(needle->http_proxy.user, ++ check->http_proxy.user) || ++ Curl_timestrcmp(needle->http_proxy.passwd, ++ check->http_proxy.passwd)) + continue; + } + else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { +--- a/lib/vauth/digest_sspi.c ++++ b/lib/vauth/digest_sspi.c +@@ -450,8 +450,8 @@ CURLcode Curl_auth_create_digest_http_me + has changed then delete that context. */ + if((userp && !digest->user) || (!userp && digest->user) || + (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || +- (userp && digest->user && strcmp(userp, digest->user)) || +- (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { ++ (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || ++ (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -109,8 +109,8 @@ Curl_ssl_config_matches(struct ssl_prima + safecmp(data->random_file, needle->random_file) && + safecmp(data->egdsocket, needle->egdsocket) && + #ifdef USE_TLS_SRP +- Curl_safecmp(data->username, needle->username) && +- Curl_safecmp(data->password, needle->password) && ++ !Curl_timestrcmp(data->username, needle->username) && ++ !Curl_timestrcmp(data->password, needle->password) && + (data->authtype == needle->authtype) && + #endif + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && diff --git a/patch/CVE-2023-27535.patch b/patch/CVE-2023-27535.patch new file mode 100644 index 0000000000000000000000000000000000000000..b98337d4636b968e99906417283ce65ec3cc98a6 --- /dev/null +++ b/patch/CVE-2023-27535.patch @@ -0,0 +1,153 @@ +Backport of: + +From 8f4608468b890dce2dad9f91d5607ee7e9c1aba1 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 9 Mar 2023 17:47:06 +0100 +Subject: [PATCH] ftp: add more conditions for connection reuse + +Reported-by: Harry Sintonen +Closes #10730 +--- + lib/ftp.c | 28 ++++++++++++++++++++++++++-- + lib/ftp.h | 5 +++++ + lib/setopt.c | 2 +- + lib/url.c | 17 +++++++++++++++-- + lib/urldata.h | 4 ++-- + 5 files changed, 49 insertions(+), 7 deletions(-) + +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -4069,6 +4069,10 @@ static CURLcode ftp_disconnect(struct co + } + + freedirs(ftpc); ++ free(ftpc->account); ++ ftpc->account = NULL; ++ free(ftpc->alternative_to_user); ++ ftpc->alternative_to_user = NULL; + free(ftpc->prevpath); + ftpc->prevpath = NULL; + free(ftpc->server_os); +@@ -4336,11 +4340,31 @@ static CURLcode ftp_setup_connection(str + struct Curl_easy *data = conn->data; + char *type; + struct FTP *ftp; ++ struct ftp_conn *ftpc = &conn->proto.ftpc; + +- conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1); ++ ftp = calloc(sizeof(struct FTP), 1); + if(NULL == ftp) + return CURLE_OUT_OF_MEMORY; + ++ /* clone connection related data that is FTP specific */ ++ if(data->set.str[STRING_FTP_ACCOUNT]) { ++ ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]); ++ if(!ftpc->account) { ++ free(ftp); ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { ++ ftpc->alternative_to_user = ++ strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); ++ if(!ftpc->alternative_to_user) { ++ Curl_safefree(ftpc->account); ++ free(ftp); ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ conn->data->req.protop = ftp; ++ + ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=" that +@@ -4388,7 +4412,9 @@ static CURLcode ftp_setup_connection(str + if(isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + +- conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ ++ ftpc->known_filesize = -1; /* unknown size for now */ ++ ftpc->use_ssl = data->set.use_ssl; ++ ftpc->ccc = data->set.ftp_ccc; + + return CURLE_OK; + } +--- a/lib/ftp.h ++++ b/lib/ftp.h +@@ -118,6 +118,8 @@ struct FTP { + struct */ + struct ftp_conn { + struct pingpong pp; ++ char *account; ++ char *alternative_to_user; + char *entrypath; /* the PWD reply when we logged on */ + char **dirs; /* realloc()ed array for path components */ + int dirdepth; /* number of entries used in the 'dirs' array */ +@@ -143,6 +145,9 @@ struct ftp_conn { + ftpstate state; /* always use ftp.c:state() to change state! */ + ftpstate state_saved; /* transfer type saved to be reloaded after + data connection is established */ ++ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or ++ IMAP or POP3 or others! (type: curl_usessl)*/ ++ unsigned char ccc; /* ccc level for this connection */ + curl_off_t retr_size_saved; /* Size of retrieved file saved */ + char *server_os; /* The target server operating system. */ + curl_off_t known_filesize; /* file size is different from -1, if wildcard +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -2126,7 +2126,7 @@ CURLcode Curl_vsetopt(struct Curl_easy * + arg = va_arg(param, long); + if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; +- data->set.use_ssl = (curl_usessl)arg; ++ data->set.use_ssl = (unsigned char)arg; + break; + + case CURLOPT_SSL_OPTIONS: +--- a/lib/url.c ++++ b/lib/url.c +@@ -1238,10 +1238,24 @@ ConnectionExists(struct Curl_easy *data, + if(needle->gssapi_delegation != check->gssapi_delegation) + continue; + ++#ifdef USE_SSH + if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; + } ++#endif ++#ifndef CURL_DISABLE_FTP ++ else if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_FTP) { ++ /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */ ++ if(Curl_timestrcmp(needle->proto.ftpc.account, ++ check->proto.ftpc.account) || ++ Curl_timestrcmp(needle->proto.ftpc.alternative_to_user, ++ check->proto.ftpc.alternative_to_user) || ++ (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) || ++ (needle->proto.ftpc.ccc != check->proto.ftpc.ccc)) ++ continue; ++ } ++#endif + + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + needle->bits.tunnel_proxy) { +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1683,8 +1683,6 @@ struct UserDefined { + void *ssh_keyfunc_userp; /* custom pointer to callback */ + enum CURL_NETRC_OPTION + use_netrc; /* defined in include/curl.h */ +- curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or +- IMAP or POP3 or others! */ + long new_file_perms; /* Permissions to use when creating remote files */ + long new_directory_perms; /* Permissions to use when creating remote dirs */ + long ssh_auth_types; /* allowed SSH auth types */ +@@ -1802,6 +1800,8 @@ struct UserDefined { + BIT(doh); /* DNS-over-HTTPS enabled */ + BIT(doh_get); /* use GET for DoH requests, instead of POST */ + BIT(http09_allowed); /* allow HTTP/0.9 responses */ ++ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or ++ IMAP or POP3 or others! (type: curl_usessl)*/ + }; + + struct Names { diff --git a/patch/CVE-2023-27536.patch b/patch/CVE-2023-27536.patch new file mode 100644 index 0000000000000000000000000000000000000000..222c55b9fea5e0e636ce3c50a3823f4e745e2001 --- /dev/null +++ b/patch/CVE-2023-27536.patch @@ -0,0 +1,46 @@ +Backport of: + +From cb49e67303dbafbab1cebf4086e3ec15b7d56ee5 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 10 Mar 2023 09:22:43 +0100 +Subject: [PATCH] url: only reuse connections with same GSS delegation + +Reported-by: Harry Sintonen +Closes #10731 +--- + lib/url.c | 6 ++++++ + lib/urldata.h | 1 + + 2 files changed, 7 insertions(+) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -1233,6 +1233,11 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++ /* GSS delegation differences do not actually affect every connection ++ and auth method, but this check takes precaution before efficiency */ ++ if(needle->gssapi_delegation != check->gssapi_delegation) ++ continue; ++ + if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; +@@ -1661,6 +1666,7 @@ static struct connectdata *allocate_conn + conn->fclosesocket = data->set.fclosesocket; + conn->closesocket_client = data->set.closesocket_client; + conn->lastused = Curl_now(); /* used now */ ++ conn->gssapi_delegation = data->set.gssapi_delegation; + + return conn; + error: +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1085,6 +1085,7 @@ struct connectdata { + handle */ + BIT(writechannel_inuse); /* whether the write channel is in use by an easy + handle */ ++ long gssapi_delegation; /* inherited from set.gssapi_delegation */ + }; + + /* The end of connectdata. */ diff --git a/patch/CVE-2023-27538.patch b/patch/CVE-2023-27538.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e6c7fca52640f02b062985dda5a3f1b8e05b8ef --- /dev/null +++ b/patch/CVE-2023-27538.patch @@ -0,0 +1,24 @@ +Backport of: + +From af369db4d3833272b8ed443f7fcc2e757a0872eb Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 10 Mar 2023 08:22:51 +0100 +Subject: [PATCH] url: fix the SSH connection reuse check + +Reported-by: Harry Sintonen +Closes #10735 +--- + lib/url.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/url.c ++++ b/lib/url.c +@@ -1233,7 +1233,7 @@ ConnectionExists(struct Curl_easy *data, + } + } + +- if(get_protocol_family(needle->handler->protocol) == PROTO_FAMILY_SSH) { ++ if(get_protocol_family(needle->handler->protocol) & PROTO_FAMILY_SSH) { + if(!ssh_config_matches(needle, check)) + continue; + } diff --git a/patch/CVE-2023-28321.patch b/patch/CVE-2023-28321.patch new file mode 100644 index 0000000000000000000000000000000000000000..84408480bdbce3a5ef3c81da1c3e6aba406d6d78 --- /dev/null +++ b/patch/CVE-2023-28321.patch @@ -0,0 +1,269 @@ +This backport was obtained from SUSE. + +From 199f2d440d8659b42670c1b796220792b01a97bf Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 24 Apr 2023 21:07:02 +0200 +Subject: [PATCH] hostcheck: fix host name wildcard checking + +The leftmost "label" of the host name can now only match against single +'*'. Like the browsers have worked for a long time. + +- extended unit test 1397 for this +- move some SOURCE variables from unit/Makefile.am to unit/Makefile.inc + +Reported-by: Hiroki Kurosawa +Closes #11018 +--- + lib/hostcheck.c | 50 +++++++-------- + tests/data/test1397 | 10 ++- + tests/unit/Makefile.am | 94 ---------------------------- + tests/unit/Makefile.inc | 94 ++++++++++++++++++++++++++++ + tests/unit/unit1397.c | 134 ++++++++++++++++++++++++---------------- + 5 files changed, 202 insertions(+), 180 deletions(-) + +--- a/lib/hostcheck.c ++++ b/lib/hostcheck.c +@@ -58,15 +58,19 @@ + * apparent distinction between a name and an IP. We need to detect the use of + * an IP address and not wildcard match on such names. + * ++ * Only match on "*" being used for the leftmost label, not "a*", "a*b" nor ++ * "*b". ++ * ++ * @unittest: 1397 ++ * + * NOTE: hostmatch() gets called with copied buffers so that it can modify the + * contents at will. + */ + + static int hostmatch(char *hostname, char *pattern) + { +- const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; +- int wildcard_enabled; +- size_t prefixlen, suffixlen; ++ const char *pattern_label_end, *hostname_label_end; ++ size_t suffixlen; + struct in_addr ignored; + #ifdef ENABLE_IPV6 + struct sockaddr_in6 si6; +@@ -80,13 +84,12 @@ static int hostmatch(char *hostname, cha + if(pattern[len-1]=='.') + pattern[len-1] = 0; + +- pattern_wildcard = strchr(pattern, '*'); +- if(pattern_wildcard == NULL) ++ if(strncmp(pattern, "*.", 2)) + return strcasecompare(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + /* detect IP address as hostname and fail the match if so */ +- if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) ++ else if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) + return CURL_HOST_NOMATCH; + #ifdef ENABLE_IPV6 + if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) +@@ -95,14 +98,9 @@ static int hostmatch(char *hostname, cha + + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ +- wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); +- if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || +- pattern_wildcard > pattern_label_end || +- strncasecompare(pattern, "xn--", 4)) { +- wildcard_enabled = 0; +- } +- if(!wildcard_enabled) ++ if(pattern_label_end == NULL || ++ strchr(pattern_label_end + 1, '.') == NULL) + return strcasecompare(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + +@@ -117,11 +115,9 @@ static int hostmatch(char *hostname, cha + if(hostname_label_end - hostname < pattern_label_end - pattern) + return CURL_HOST_NOMATCH; + +- prefixlen = pattern_wildcard - pattern; +- suffixlen = pattern_label_end - (pattern_wildcard + 1); +- return strncasecompare(pattern, hostname, prefixlen) && +- strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, +- suffixlen) ? ++ suffixlen = pattern_label_end - (pattern + 1); ++ return strncasecompare(pattern + 1, hostname_label_end - suffixlen, ++ suffixlen) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + } + +--- a/tests/data/test1397 ++++ b/tests/data/test1397 +@@ -2,8 +2,7 @@ + + + unittest +-ssl +-wildcard ++Curl_cert_hostcheck + + + +@@ -16,12 +15,11 @@ none + + unittest + +- +-Check wildcard certificate matching function Curl_cert_hostcheck +- ++ ++Curl_cert_hostcheck unit tests ++ + + unit1397 + + +- + +--- a/tests/unit/unit1397.c ++++ b/tests/unit/unit1397.c +@@ -21,8 +21,6 @@ + ***************************************************************************/ + #include "curlcheck.h" + +-#include "hostcheck.h" /* from the lib dir */ +- + static CURLcode unit_setup(void) + { + return CURLE_OK; +@@ -30,50 +28,94 @@ static CURLcode unit_setup(void) + + static void unit_stop(void) + { +- /* done before shutting down and exiting */ + } + +-UNITTEST_START ++* only these backends define the tested functions */ ++#if defined(USE_OPENSSL) || defined(USE_GSKIT) || \ ++ defined(USE_SCHANNEL) ++#include "hostcheck.h" ++struct testcase { ++ const char *host; ++ const char *pattern; ++ bool match; ++}; ++ ++static struct testcase tests[] = { ++ {"", "", FALSE}, ++ {"a", "", FALSE}, ++ {"", "b", FALSE}, ++ {"a", "b", FALSE}, ++ {"aa", "bb", FALSE}, ++ {"\xff", "\xff", TRUE}, ++ {"aa.aa.aa", "aa.aa.bb", FALSE}, ++ {"aa.aa.aa", "aa.aa.aa", TRUE}, ++ {"aa.aa.aa", "*.aa.bb", FALSE}, ++ {"aa.aa.aa", "*.aa.aa", TRUE}, ++ {"192.168.0.1", "192.168.0.1", TRUE}, ++ {"192.168.0.1", "*.168.0.1", FALSE}, ++ {"192.168.0.1", "*.0.1", FALSE}, ++ {"h.ello", "*.ello", FALSE}, ++ {"h.ello.", "*.ello", FALSE}, ++ {"h.ello", "*.ello.", FALSE}, ++ {"h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo", " *.e.llo", FALSE}, ++ {" h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo", TRUE}, ++ {"*.e.llo.", "*.e.llo", TRUE}, ++ {"************.e.llo.", "*.e.llo", TRUE}, ++ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ++ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ++ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ++ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ++ "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" ++ ".e.llo.", "*.e.llo", TRUE}, ++ {"\xfe\xfe.e.llo.", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo.", TRUE}, ++ {"h.e.llo", "*.e.llo.", TRUE}, ++ {".h.e.llo", "*.e.llo.", FALSE}, ++ {"h.e.llo", "*.*.llo.", FALSE}, ++ {"h.e.llo", "h.*.llo", FALSE}, ++ {"h.e.llo", "h.e.*", FALSE}, ++ {"hello", "*.ello", FALSE}, ++ {"hello", "**llo", FALSE}, ++ {"bar.foo.example.com", "*.example.com", FALSE}, ++ {"foo.example.com", "*.example.com", TRUE}, ++ {"baz.example.net", "b*z.example.net", FALSE}, ++ {"foobaz.example.net", "*baz.example.net", FALSE}, ++ {"xn--l8j.example.local", "x*.example.local", FALSE}, ++ {"xn--l8j.example.net", "*.example.net", TRUE}, ++ {"xn--l8j.example.net", "*j.example.net", FALSE}, ++ {"xn--l8j.example.net", "xn--l8j.example.net", TRUE}, ++ {"xn--l8j.example.net", "xn--l8j.*.net", FALSE}, ++ {"xl8j.example.net", "*.example.net", TRUE}, ++ {"fe80::3285:a9ff:fe46:b619", "*::3285:a9ff:fe46:b619", FALSE}, ++ {"fe80::3285:a9ff:fe46:b619", "fe80::3285:a9ff:fe46:b619", TRUE}, ++ {NULL, NULL, FALSE} ++}; + +-/* only these backends define the tested functions */ +-#if defined(USE_OPENSSL) || defined(USE_GSKIT) ++UNITTEST_START ++{ ++ int i; ++ for(i = 0; tests[i].host; i++) { ++ if(tests[i].match != Curl_cert_hostcheck(tests[i].pattern, ++ tests[i].host)) { ++ fprintf(stderr, ++ "HOST: %s\n" ++ "PTRN: %s\n" ++ "did %sMATCH\n", ++ tests[i].host, ++ tests[i].pattern, ++ tests[i].match ? "NOT ": ""); ++ unitfail++; ++ } ++ } ++} + +- /* here you start doing things and checking that the results are good */ ++UNITTEST_STOP ++#else + +-fail_unless(Curl_cert_hostcheck("www.example.com", "www.example.com"), +- "good 1"); +-fail_unless(Curl_cert_hostcheck("*.example.com", "www.example.com"), +- "good 2"); +-fail_unless(Curl_cert_hostcheck("xxx*.example.com", "xxxwww.example.com"), +- "good 3"); +-fail_unless(Curl_cert_hostcheck("f*.example.com", "foo.example.com"), +- "good 4"); +-fail_unless(Curl_cert_hostcheck("192.168.0.0", "192.168.0.0"), +- "good 5"); +- +-fail_if(Curl_cert_hostcheck("xxx.example.com", "www.example.com"), "bad 1"); +-fail_if(Curl_cert_hostcheck("*", "www.example.com"), "bad 2"); +-fail_if(Curl_cert_hostcheck("*.*.com", "www.example.com"), "bad 3"); +-fail_if(Curl_cert_hostcheck("*.example.com", "baa.foo.example.com"), "bad 4"); +-fail_if(Curl_cert_hostcheck("f*.example.com", "baa.example.com"), "bad 5"); +-fail_if(Curl_cert_hostcheck("*.com", "example.com"), "bad 6"); +-fail_if(Curl_cert_hostcheck("*fail.com", "example.com"), "bad 7"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example."), "bad 8"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example"), "bad 9"); +-fail_if(Curl_cert_hostcheck("", "www"), "bad 10"); +-fail_if(Curl_cert_hostcheck("*", "www"), "bad 11"); +-fail_if(Curl_cert_hostcheck("*.168.0.0", "192.168.0.0"), "bad 12"); +-fail_if(Curl_cert_hostcheck("www.example.com", "192.168.0.0"), "bad 13"); +- +-#ifdef ENABLE_IPV6 +-fail_if(Curl_cert_hostcheck("*::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "bad 14"); +-fail_unless(Curl_cert_hostcheck("fe80::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "good 6"); +-#endif ++UNITTEST_START + ++UNITTEST_STOP + #endif + +- /* you end the test code like this: */ +- +-UNITTEST_STOP diff --git a/patch/CVE-2023-28322.patch b/patch/CVE-2023-28322.patch new file mode 100644 index 0000000000000000000000000000000000000000..568415e2821ab6a8d4275d103142e320c474f8c8 --- /dev/null +++ b/patch/CVE-2023-28322.patch @@ -0,0 +1,375 @@ +Backport of: + +From 7815647d6582c0a4900be2e1de6c5e61272c496b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 25 Apr 2023 08:28:01 +0200 +Subject: [PATCH] lib: unify the upload/method handling + +By making sure we set state.upload based on the set.method value and not +independently as set.upload, we reduce confusion and mixup risks, both +internally and externally. + +Closes #11017 +--- + lib/curl_rtmp.c | 4 ++-- + lib/file.c | 4 ++-- + lib/ftp.c | 8 ++++---- + lib/http.c | 4 ++-- + lib/imap.c | 6 +++--- + lib/rtsp.c | 4 ++-- + lib/setopt.c | 6 ++---- + lib/smb.c | 6 +++--- + lib/smtp.c | 4 ++-- + lib/tftp.c | 8 ++++---- + lib/transfer.c | 4 ++-- + lib/urldata.h | 2 +- + lib/vssh/libssh.c | 6 +++--- + lib/vssh/libssh2.c | 6 +++--- + lib/vssh/wolfssh.c | 2 +- + 15 files changed, 36 insertions(+), 38 deletions(-) + +--- a/lib/curl_rtmp.c ++++ b/lib/curl_rtmp.c +@@ -213,7 +213,7 @@ static CURLcode rtmp_connect(struct conn + /* We have to know if it's a write before we send the + * connect request packet + */ +- if(conn->data->set.upload) ++ if(conn->data->state.upload) + r->Link.protocol |= RTMP_FEATURE_WRITE; + + /* For plain streams, use the buffer toggle trick to keep data flowing */ +@@ -245,7 +245,7 @@ static CURLcode rtmp_do(struct connectda + if(!RTMP_ConnectStream(r, 0)) + return CURLE_FAILED_INIT; + +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + } +--- a/lib/file.c ++++ b/lib/file.c +@@ -198,7 +198,7 @@ static CURLcode file_connect(struct conn + file->freepath = real_path; /* free this when done */ + + file->fd = fd; +- if(!data->set.upload && (fd == -1)) { ++ if(!data->state.upload && (fd == -1)) { + failf(data, "Couldn't open file %s", data->state.up.path); + file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); + return CURLE_FILE_COULDNT_READ_FILE; +@@ -390,7 +390,7 @@ static CURLcode file_do(struct connectda + + Curl_pgrsStartNow(data); + +- if(data->set.upload) ++ if(data->state.upload) + return file_upload(conn); + + file = conn->data->req.protop; +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -1371,7 +1371,7 @@ static CURLcode ftp_state_prepare_transf + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST")); + } +- else if(data->set.upload) { ++ else if(data->state.upload) { + PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file); + } + else { +@@ -3303,7 +3303,7 @@ static CURLcode ftp_done(struct connectd + /* the response code from the transfer showed an error already so no + use checking further */ + ; +- else if(data->set.upload) { ++ else if(data->state.upload) { + if((-1 != data->state.infilesize) && + (data->state.infilesize != data->req.writebytecount) && + !data->set.crlf && +@@ -3570,7 +3570,7 @@ static CURLcode ftp_do_more(struct conne + connected back to us */ + } + } +- else if(data->set.upload) { ++ else if(data->state.upload) { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); + if(result) + return result; +@@ -4209,7 +4209,7 @@ CURLcode ftp_parse_url_path(struct conne + ftpc->file = NULL; /* instead of point to a zero byte, + we make it a NULL pointer */ + +- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { ++ if(data->state.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name!"); + free(rawPath); +--- a/lib/http.c ++++ b/lib/http.c +@@ -2080,7 +2080,7 @@ CURLcode Curl_http(struct connectdata *c + } + + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && +- data->set.upload) { ++ data->state.upload) { + httpreq = HTTPREQ_PUT; + } + +@@ -2261,7 +2261,7 @@ CURLcode Curl_http(struct connectdata *c + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || +- ((data->set.upload || httpreq == HTTPREQ_POST) && ++ ((data->state.upload || httpreq == HTTPREQ_POST) && + data->state.infilesize == -1))) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -1469,11 +1469,11 @@ static CURLcode imap_done(struct connect + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && !imap->custom && +- (imap->uid || imap->mindex || data->set.upload || ++ (imap->uid || imap->mindex || data->state.upload || + data->set.mimepost.kind != MIMEKIND_NONE)) { + /* Handle responses after FETCH or APPEND transfer has finished */ + +- if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) ++ if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE) + state(conn, IMAP_FETCH_FINAL); + else { + /* End the APPEND command first by sending an empty line */ +@@ -1539,7 +1539,7 @@ static CURLcode imap_perform(struct conn + selected = TRUE; + + /* Start the first command in the DO phase */ +- if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) ++ if(conn->data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE) + /* APPEND can be executed directly */ + result = imap_perform_append(conn); + else if(imap->custom && (selected || !imap->mailbox)) +--- a/lib/rtsp.c ++++ b/lib/rtsp.c +@@ -499,7 +499,7 @@ static CURLcode rtsp_do(struct connectda + rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + +- if(data->set.upload) { ++ if(data->state.upload) { + putsize = data->state.infilesize; + data->set.httpreq = HTTPREQ_PUT; + +@@ -518,7 +518,7 @@ static CURLcode rtsp_do(struct connectda + result = + Curl_add_bufferf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", +- (data->set.upload ? putsize : postsize)); ++ (data->state.upload ? putsize : postsize)); + if(result) + return result; + } +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -258,8 +258,8 @@ CURLcode Curl_vsetopt(struct Curl_easy * + * We want to sent data to the remote host. If this is HTTP, that equals + * using the PUT request. + */ +- data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; +- if(data->set.upload) { ++ arg = va_arg(param, long); ++ if(arg) { + /* If this is HTTP, PUT is what's needed to "upload" */ + data->set.httpreq = HTTPREQ_PUT; + data->set.opt_no_body = FALSE; /* this is implied */ +@@ -486,7 +486,6 @@ CURLcode Curl_vsetopt(struct Curl_easy * + } + else + data->set.httpreq = HTTPREQ_GET; +- data->set.upload = FALSE; + break; + + case CURLOPT_COPYPOSTFIELDS: +@@ -797,7 +796,6 @@ CURLcode Curl_vsetopt(struct Curl_easy * + */ + if(va_arg(param, long)) { + data->set.httpreq = HTTPREQ_GET; +- data->set.upload = FALSE; /* switch off upload */ + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; +--- a/lib/smb.c ++++ b/lib/smb.c +@@ -516,7 +516,7 @@ static CURLcode smb_send_open(struct con + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } +@@ -792,7 +792,7 @@ static CURLcode smb_request_state(struct + smb_m = (const struct smb_nt_create_response*) msg; + req->fid = smb_swap16(smb_m->fid); + conn->data->req.offset = 0; +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + conn->data->req.size = conn->data->state.infilesize; + Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); + next_state = SMB_UPLOAD; +--- a/lib/smtp.c ++++ b/lib/smtp.c +@@ -1210,7 +1210,7 @@ static CURLcode smtp_done(struct connect + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && data->set.mail_rcpt && +- (data->set.upload || data->set.mimepost.kind)) { ++ (data->state.upload || data->set.mimepost.kind)) { + /* Calculate the EOB taking into account any terminating CRLF from the + previous line of the email or the CRLF of the DATA command when there + is "no mail data". RFC-5321, sect. 4.1.1.4. +@@ -1297,7 +1297,7 @@ static CURLcode smtp_perform(struct conn + smtp->eob = 2; + + /* Start the first command in the DO phase */ +- if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) ++ if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(conn); + else +--- a/lib/tftp.c ++++ b/lib/tftp.c +@@ -390,7 +390,7 @@ static CURLcode tftp_parse_option_ack(tf + + /* tsize should be ignored on upload: Who cares about the size of the + remote file? */ +- if(!data->set.upload) { ++ if(!data->state.upload) { + if(!tsize) { + failf(data, "invalid tsize -:%s:- value in OACK packet", value); + return CURLE_TFTP_ILLEGAL; +@@ -470,7 +470,7 @@ static CURLcode tftp_send_first(tftp_sta + return result; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + /* If we are uploading, send an WRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_WRQ); + state->conn->data->req.upload_fromhere = +@@ -505,7 +505,7 @@ static CURLcode tftp_send_first(tftp_sta + if(!data->set.tftp_no_options) { + char buf[64]; + /* add tsize option */ +- if(data->set.upload && (data->state.infilesize != -1)) ++ if(data->state.upload && (data->state.infilesize != -1)) + msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else +@@ -559,7 +559,7 @@ static CURLcode tftp_send_first(tftp_sta + break; + + case TFTP_EVENT_OACK: +- if(data->set.upload) { ++ if(data->state.upload) { + result = tftp_connect_for_tx(state, event); + } + else { +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1405,6 +1405,7 @@ void Curl_init_CONNECT(struct Curl_easy + { + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; ++ data->state.upload = (data->set.httpreq == HTTPREQ_PUT); + } + + /* +@@ -1816,7 +1817,7 @@ CURLcode Curl_retry_request(struct conne + + /* if we're talking upload, we can't do the checks below, unless the protocol + is HTTP as when uploading over HTTP we will still get a response */ +- if(data->set.upload && ++ if(data->state.upload && + !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) + return CURLE_OK; + +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1427,6 +1427,7 @@ struct UrlState { + BIT(stream_depends_e); /* set or don't set the Exclusive bit */ + BIT(previouslypending); /* this transfer WAS in the multi->pending queue */ + BIT(cookie_engine); ++ BIT(upload); /* upload request */ + }; + + +@@ -1762,7 +1763,6 @@ struct UserDefined { + BIT(http_auto_referer); /* set "correct" referer when following + location: */ + BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ +- BIT(upload); /* upload request */ + BIT(verbose); /* output verbosity */ + BIT(krb); /* Kerberos connection requested */ + BIT(reuse_forbid); /* forbidden to be reused, close after use */ +--- a/lib/vssh/libssh.c ++++ b/lib/vssh/libssh.c +@@ -1076,7 +1076,7 @@ static CURLcode myssh_statemach_act(stru + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(protop->path[strlen(protop->path)-1] == '/') +@@ -1686,7 +1686,7 @@ static CURLcode myssh_statemach_act(stru + /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */ + ssh_set_blocking(sshc->ssh_session, 1); + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -1787,7 +1787,7 @@ static CURLcode myssh_statemach_act(stru + break; + } + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); +--- a/lib/vssh/libssh2.c ++++ b/lib/vssh/libssh2.c +@@ -1664,7 +1664,7 @@ static CURLcode ssh_statemach_act(struct + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') +@@ -2366,7 +2366,7 @@ static CURLcode ssh_statemach_act(struct + break; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -2504,7 +2504,7 @@ static CURLcode ssh_statemach_act(struct + break; + + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); diff --git a/patch/git_tls13_gnutls.patch b/patch/git_tls13_gnutls.patch new file mode 100644 index 0000000000000000000000000000000000000000..57c84dcb47f868d09ae863975749f17106414dca --- /dev/null +++ b/patch/git_tls13_gnutls.patch @@ -0,0 +1,172 @@ +From b8c82c9a33be5b135dd390f7fc08708826a862e8 Mon Sep 17 00:00:00 2001 +From: Dirkjan Bussink +Date: Sun, 12 Apr 2020 11:29:09 +0000 +Subject: [PATCH] Ensure TLS 1.3 works with GnuTLS + +When SRP is requested in the priority string, GnuTLS will disable +support for TLS 1.3. Before this change, curl would always add +SRP to +the priority list, effectively always disabling TLS 1.3 support. + +With this change, +SRP is only added to the priority list when SRP +authentication is also requested. This also allows updating the error +handling here to not have to retry without SRP. This is because SRP is +only added when requested and in that case a retry is not needed. +--- + lib/vtls/gtls.c | 81 +++++++++++++++++++++++++++---------------------- + 1 file changed, 45 insertions(+), 36 deletions(-) + +Index: curl-7.68.0/lib/vtls/gtls.c +=================================================================== +--- curl-7.68.0.orig/lib/vtls/gtls.c ++++ curl-7.68.0/lib/vtls/gtls.c +@@ -447,32 +447,32 @@ set_ssl_version_min_max(const char **pri + switch(ssl_version | ssl_version_max) { + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:" GNUTLS_SRP; ++ "+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; ++ "+VERS-TLS1.0:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:" GNUTLS_SRP; ++ "+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" GNUTLS_SRP; ++ "+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: + #ifdef HAS_TLS13 + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.3:" GNUTLS_SRP; ++ "+VERS-TLS1.3"; + return CURLE_OK; + #else + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); +@@ -480,35 +480,35 @@ set_ssl_version_min_max(const char **pri + #endif + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" ++ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.1:+VERS-TLS1.2:" ++ "+VERS-TLS1.1:+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" ++ "+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" +- "+VERS-TLS1.2:" ++ "+VERS-TLS1.2" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + return CURLE_OK; + } + +@@ -760,11 +760,11 @@ gtls_connect_step1(struct connectdata *c + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +- prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" ++ prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0" + #ifdef HAS_TLS13 +- "+VERS-TLS1.3:" ++ ":+VERS-TLS1.3" + #endif +- GNUTLS_SRP; ++ ; + break; + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: +@@ -783,24 +783,33 @@ gtls_connect_step1(struct connectdata *c + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } +- rc = gnutls_priority_set_direct(session, prioritylist, &err); +- if((rc == GNUTLS_E_INVALID_REQUEST) && err) { +- if(!strcmp(err, GNUTLS_SRP)) { +- /* This GnuTLS was probably compiled without support for SRP. +- * Note that fact and try again without it. */ +- int validprioritylen = curlx_uztosi(err - prioritylist); +- char *prioritycopy = strdup(prioritylist); +- if(!prioritycopy) +- return CURLE_OUT_OF_MEMORY; + ++#ifdef USE_TLS_SRP ++ /* Only add SRP to the cipher list if SRP is requested. Otherwise ++ * GnuTLS will disable TLS 1.3 support. */ ++ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { ++ size_t len = strlen(prioritylist); ++ ++ char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); ++ if(!prioritysrp) ++ return CURLE_OUT_OF_MEMORY; ++ strcpy(prioritysrp, prioritylist); ++ strcpy(prioritysrp + len, ":" GNUTLS_SRP); ++ ++ rc = gnutls_priority_set_direct(session, prioritysrp, &err); ++ free(prioritysrp); ++ ++ if((rc == GNUTLS_E_INVALID_REQUEST) && err) { + infof(data, "This GnuTLS does not support SRP\n"); +- if(validprioritylen) +- /* Remove the :+SRP */ +- prioritycopy[validprioritylen - 1] = 0; +- rc = gnutls_priority_set_direct(session, prioritycopy, &err); +- free(prioritycopy); + } + } ++ else { ++#endif ++ rc = gnutls_priority_set_direct(session, prioritylist, &err); ++#ifdef USE_TLS_SRP ++ } ++#endif ++ + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "Error %d setting GnuTLS cipher list starting with %s", + rc, err); diff --git a/patch/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch b/patch/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch new file mode 100644 index 0000000000000000000000000000000000000000..694804d72c0b4913cbf9eaa985541029165ccb22 --- /dev/null +++ b/patch/lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch @@ -0,0 +1,59 @@ +From 1f5baccc5040294d28de6ad58d399db60fd2eee3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 28 Nov 2020 16:42:52 +0100 +Subject: [PATCH] openssl: use OPENSSL_init_ssl() with >= 1.1.0 + +Reported-by: Kovalkov Dmitrii and Per Nilsson +Fixes #6254 +Fixes #6256 +Closes #6260 + +(cherry picked from commit 1835cb916e0d40eb8bc1165d5627a0b64f911bac) +Signed-off-by: Dimitri John Ledkov +--- + + BugLink: https://bugs.launchpad.net/bugs/1940528 + + lib/vtls/openssl.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c +index 726ff6e7ca..5872a6805b 100644 +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -1025,6 +1025,21 @@ static int Curl_ossl_init(void) + char *keylog_file_name; + #endif + ++#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ ++ !defined(LIBRESSL_VERSION_NUMBER) ++ const uint64_t flags = ++#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN ++ /* not present in BoringSSL */ ++ OPENSSL_INIT_ENGINE_ALL_BUILTIN | ++#endif ++#ifdef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG ++ OPENSSL_INIT_NO_LOAD_CONFIG | ++#else ++ OPENSSL_INIT_LOAD_CONFIG | ++#endif ++ 0; ++ OPENSSL_init_ssl(flags, NULL); ++#else + OPENSSL_load_builtin_modules(); + + #ifdef USE_OPENSSL_ENGINE +@@ -1043,10 +1058,6 @@ static int Curl_ossl_init(void) + CONF_MFLAGS_IGNORE_MISSING_FILE); + #endif + +-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ +- !defined(LIBRESSL_VERSION_NUMBER) +- /* OpenSSL 1.1.0+ takes care of initialization itself */ +-#else + /* Lets get nice error messages */ + SSL_load_error_strings(); + +-- +2.32.0 + diff --git a/patch/series b/patch/series new file mode 100644 index 0000000000000000000000000000000000000000..c1aee8e35cc1ee4020358dc6f42a0f489f69ab6c --- /dev/null +++ b/patch/series @@ -0,0 +1,49 @@ +git_tls13_gnutls.patch +04_workaround_as_needed_bug.patch +06_always-disable-valgrind.patch +07_do-not-disable-debug-symbols.patch +08_enable-zsh.patch +11_omit-directories-from-config.patch +CVE-2020-8169.patch +CVE-2020-8177.patch +CVE-2020-8231.patch +CVE-2020-8284.patch +CVE-2020-8285.patch +CVE-2020-8286.patch +CVE-2021-22876.patch +CVE-2021-22890.patch +CVE-2021-22898.patch +CVE-2021-22924.patch +CVE-2021-22925.patch +CVE-2021-22946-pre1.patch +CVE-2021-22946.patch +CVE-2021-22947.patch +lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch +CVE-2022-22576.patch +CVE-2022-27774-1.patch +CVE-2022-27774-2.patch +CVE-2022-27774-3pre.patch +CVE-2022-27774-3.patch +CVE-2022-27775.patch +CVE-2022-27776.patch +CVE-2022-27781.patch +CVE-2022-27782.patch +CVE-2022-32206.patch +CVE-2022-32208.patch +CVE-2022-35252.patch +CVE-2022-32221.patch +CVE-2022-43552.patch +CVE-2023-23916.patch +CVE-2023-27533.patch +CVE-2023-27534-pre1.patch +CVE-2023-27534.patch +CVE-2023-27538.patch +CVE-2023-27535-pre1.patch +CVE-2023-27536.patch +CVE-2023-27535.patch +CVE-2023-28321.patch +CVE-2023-28322.patch + +# do not add patches below +90_gnutls.patch +99_nss.patch diff --git a/series b/series new file mode 100644 index 0000000000000000000000000000000000000000..c1aee8e35cc1ee4020358dc6f42a0f489f69ab6c --- /dev/null +++ b/series @@ -0,0 +1,49 @@ +git_tls13_gnutls.patch +04_workaround_as_needed_bug.patch +06_always-disable-valgrind.patch +07_do-not-disable-debug-symbols.patch +08_enable-zsh.patch +11_omit-directories-from-config.patch +CVE-2020-8169.patch +CVE-2020-8177.patch +CVE-2020-8231.patch +CVE-2020-8284.patch +CVE-2020-8285.patch +CVE-2020-8286.patch +CVE-2021-22876.patch +CVE-2021-22890.patch +CVE-2021-22898.patch +CVE-2021-22924.patch +CVE-2021-22925.patch +CVE-2021-22946-pre1.patch +CVE-2021-22946.patch +CVE-2021-22947.patch +lp1940528-openssl-use-OPENSSL_init_ssl-with-1.1.0.patch +CVE-2022-22576.patch +CVE-2022-27774-1.patch +CVE-2022-27774-2.patch +CVE-2022-27774-3pre.patch +CVE-2022-27774-3.patch +CVE-2022-27775.patch +CVE-2022-27776.patch +CVE-2022-27781.patch +CVE-2022-27782.patch +CVE-2022-32206.patch +CVE-2022-32208.patch +CVE-2022-35252.patch +CVE-2022-32221.patch +CVE-2022-43552.patch +CVE-2023-23916.patch +CVE-2023-27533.patch +CVE-2023-27534-pre1.patch +CVE-2023-27534.patch +CVE-2023-27538.patch +CVE-2023-27535-pre1.patch +CVE-2023-27536.patch +CVE-2023-27535.patch +CVE-2023-28321.patch +CVE-2023-28322.patch + +# do not add patches below +90_gnutls.patch +99_nss.patch