diff options
Diffstat (limited to 'libs/libcurl/src')
87 files changed, 1237 insertions, 5505 deletions
diff --git a/libs/libcurl/src/Makefile.Watcom b/libs/libcurl/src/Makefile.Watcom index 5f335cedbd..942cd0c7b4 100644 --- a/libs/libcurl/src/Makefile.Watcom +++ b/libs/libcurl/src/Makefile.Watcom @@ -157,7 +157,7 @@ CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H -I"$(LIBSSH2_ROOT)/include" -I"$(LIBSSH !endif !ifdef %use_ssl -CFLAGS += -wcd=138 -dUSE_OPENSSL -dUSE_SSLEAY -I"$(OPENSSL_ROOT)/inc32" +CFLAGS += -wcd=138 -dUSE_OPENSSL -I"$(OPENSSL_ROOT)/inc32" !endif !ifdef %use_ares diff --git a/libs/libcurl/src/Makefile.b32 b/libs/libcurl/src/Makefile.b32 deleted file mode 100644 index 5b5b5fa9fc..0000000000 --- a/libs/libcurl/src/Makefile.b32 +++ /dev/null @@ -1,185 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2000, Jaepil Kim, <pit@paradise.net.nz>. -# Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -############################################################ -# -# Makefile.b32 - Borland's C++ Compiler 5.X -# -# 'BCCDIR' has to be set up to point to the base directory -# of the compiler, i.e. SET BCCDIR = c:\Borland\BCC55 -# -############################################################ - -!if "$(__MAKE__)" == "" -!error __MAKE__ not defined. Use Borlands's MAKE to process this makefile. -!endif - -# Borland's $(MAKEDIR) expands to the path where make.exe is located, -# use this feature to define BCCDIR when user has not defined BCCDIR. -!ifndef BCCDIR -BCCDIR = $(MAKEDIR)\.. -!endif - -# Edit the path below to point to the base of your Zlib sources. -!ifndef ZLIB_PATH -ZLIB_PATH = ..\..\zlib-1.2.8 -!endif - -# Edit the path below to point to the base of your OpenSSL package. -!ifndef OPENSSL_PATH -OPENSSL_PATH = ..\..\openssl-1.0.2a -!endif - -# Set libcurl static lib, dll and import lib -LIBCURL_LIB = libcurl.lib -LIBCURL_DLL = libcurl.dll -LIBCURL_IMPLIB = libcurl_imp.lib - -# Setup environment -PP_CMD = cpp32 -q -P- -CC_CMD = bcc32 -q -c -LD = bcc32 -RM = del 2>NUL -MKDIR = md -RMDIR = rd /q -LIB = tlib -IMPLIB = implib - -CC_FLAGS = -5 -O2 -tWM -w -w-aus -w-ccc -w-dup -w-prc -w-pro -w-rch -w-sig -w-spa -w-inl -w-pia -w-pin -Dinline=__inline -LIBFLAGS = /C /P32 -LDFLAGS = -q -lq -laa -tWD - -SRCDIR = .;.\vauth;.\vtls -OBJDIR = .\BCC_objs -INCDIRS = -I.;.\lib;..\include -LINKLIB = $(BCCDIR)\lib\cw32mt.lib $(BCCDIR)\lib\ws2_32.lib -DEFINES = -DNDEBUG -DWIN32 -DBUILDING_LIBCURL - -# By default SSPI support is enabled for BCC -!ifndef DISABLE_SSPI -DEFINES = $(DEFINES) -DUSE_WINDOWS_SSPI -!endif - -# By default LDAP support is disabled for BCC -!ifndef WITH_LDAP -DEFINES = $(DEFINES) -DCURL_DISABLE_LDAP -!endif - -# ZLIB support is enabled setting WITH_ZLIB=1 -!ifdef WITH_ZLIB -DEFINES = $(DEFINES) -DHAVE_LIBZ -DHAVE_ZLIB_H -INCDIRS = $(INCDIRS);$(ZLIB_PATH) -LINKLIB = $(LINKLIB) $(ZLIB_PATH)\zlib.lib -!endif - -# SSL support is enabled setting WITH_SSL=1 -!ifdef WITH_SSL -DEFINES = $(DEFINES) -DUSE_OPENSSL -INCDIRS = $(INCDIRS);$(OPENSSL_PATH)\inc32;$(OPENSSL_PATH)\inc32\openssl -LINKLIB = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\libeay32.lib -!endif - -.autodepend - -.path.c = $(SRCDIR) -.path.obj = $(OBJDIR) -.path.int = $(OBJDIR) - -# Makefile.inc provides the CSOURCES and HHEADERS defines -!include Makefile.inc - -# Borland's command line librarian program TLIB version 4.5 is not capable -# of building a library when any of its objects contains an hyphen in its -# name, due to a command line parsing bug. In order to workaround this, we -# build source files with hyphens in their name as objects with underscores -# using explicit compilation build rules instead of implicit ones. - -NOHYPHEN1 = $(CSOURCES:-=_) -NOHYPHEN2 = $(NOHYPHEN1:vauth/=) -NOHYPHEN3 = $(NOHYPHEN2:vtls/=) - -OBJECTS = $(NOHYPHEN3:.c=.obj) -PREPROCESSED = $(NOHYPHEN3:.c=.int) - -# Borland's command line compiler (BCC32) version 5.5.1 integrated -# preprocessor has a bug which results in silently generating wrong -# definitions for libcurl macros such as CURL_OFF_T_C, on the other -# hand Borland's command line preprocessor (CPP32) version 5.5.1 does -# not have the bug and achieves proper results. In order to avoid the -# silent bug we first preprocess source files and later compile the -# preprocessed result. - -.c.obj: - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(<) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -all: $(OBJDIR) $(LIBCURL_LIB) $(LIBCURL_DLL) - -asyn_ares.obj: asyn-ares.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -asyn_thread.obj: asyn-thread.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -non_ascii.obj: non-ascii.c - @-$(RM) $(@R).int - $(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) - $(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int - -clean: - cd $(OBJDIR) - @-$(RM) $(OBJECTS) - @-$(RM) $(PREPROCESSED) - cd .. - @-$(RMDIR) $(OBJDIR) - @-$(RM) $(LIBCURL_LIB) - @-$(RM) $(LIBCURL_IMPLIB) - @-$(RM) libcurl.tds - -$(OBJDIR): - @-$(RMDIR) $(OBJDIR) - @-$(MKDIR) $(OBJDIR) - -$(LIBCURL_LIB): $(OBJECTS) - @-$(RM) $(LIBCURL_LIB) - $(LIB) $(LIBFLAGS) $@ @&&! -+$(**: = &^ -+) -! - -$(LIBCURL_DLL) $(LIBCURL_IMPLIB): $(OBJECTS) $(LINKLIB) - @-$(RM) $(LIBCURL_DLL) - @-$(RM) $(LIBCURL_IMPLIB) - $(LD) $(LDFLAGS) -e$(LIBCURL_DLL) @&&! -$(**: = ^ -) -! - $(IMPLIB) $(LIBCURL_IMPLIB) $(LIBCURL_DLL) - - -# End of Makefile.b32 diff --git a/libs/libcurl/src/Makefile.in b/libs/libcurl/src/Makefile.in index c93fec818f..43c5d442b4 100644 --- a/libs/libcurl/src/Makefile.in +++ b/libs/libcurl/src/Makefile.in @@ -243,8 +243,8 @@ am__objects_3 = vtls/libcurl_la-openssl.lo vtls/libcurl_la-gtls.lo \ vtls/libcurl_la-vtls.lo vtls/libcurl_la-nss.lo \ vtls/libcurl_la-polarssl.lo \ vtls/libcurl_la-polarssl_threadlock.lo \ - vtls/libcurl_la-axtls.lo vtls/libcurl_la-cyassl.lo \ - vtls/libcurl_la-schannel.lo vtls/libcurl_la-schannel_verify.lo \ + vtls/libcurl_la-cyassl.lo vtls/libcurl_la-schannel.lo \ + vtls/libcurl_la-schannel_verify.lo \ vtls/libcurl_la-darwinssl.lo vtls/libcurl_la-gskit.lo \ vtls/libcurl_la-mbedtls.lo vtls/libcurl_la-mesalink.lo am__objects_4 = $(am__objects_1) $(am__objects_2) $(am__objects_3) @@ -325,8 +325,7 @@ am__objects_9 = vtls/libcurlu_la-openssl.lo vtls/libcurlu_la-gtls.lo \ vtls/libcurlu_la-vtls.lo vtls/libcurlu_la-nss.lo \ vtls/libcurlu_la-polarssl.lo \ vtls/libcurlu_la-polarssl_threadlock.lo \ - vtls/libcurlu_la-axtls.lo vtls/libcurlu_la-cyassl.lo \ - vtls/libcurlu_la-schannel.lo \ + vtls/libcurlu_la-cyassl.lo vtls/libcurlu_la-schannel.lo \ vtls/libcurlu_la-schannel_verify.lo \ vtls/libcurlu_la-darwinssl.lo vtls/libcurlu_la-gskit.lo \ vtls/libcurlu_la-mbedtls.lo vtls/libcurlu_la-mesalink.lo @@ -594,7 +593,6 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-amigaos.Plo \ vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo \ vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo \ vauth/$(DEPDIR)/libcurlu_la-vauth.Plo \ - vtls/$(DEPDIR)/libcurl_la-axtls.Plo \ vtls/$(DEPDIR)/libcurl_la-cyassl.Plo \ vtls/$(DEPDIR)/libcurl_la-darwinssl.Plo \ vtls/$(DEPDIR)/libcurl_la-gskit.Plo \ @@ -608,7 +606,6 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-amigaos.Plo \ vtls/$(DEPDIR)/libcurl_la-schannel.Plo \ vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo \ vtls/$(DEPDIR)/libcurl_la-vtls.Plo \ - vtls/$(DEPDIR)/libcurlu_la-axtls.Plo \ vtls/$(DEPDIR)/libcurlu_la-cyassl.Plo \ vtls/$(DEPDIR)/libcurlu_la-darwinssl.Plo \ vtls/$(DEPDIR)/libcurlu_la-gskit.Plo \ @@ -806,7 +803,6 @@ STRIP = @STRIP@ SUPPORT_FEATURES = @SUPPORT_FEATURES@ SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@ USE_ARES = @USE_ARES@ -USE_AXTLS = @USE_AXTLS@ USE_CYASSL = @USE_CYASSL@ USE_DARWINSSL = @USE_DARWINSSL@ USE_GNUTLS = @USE_GNUTLS@ @@ -964,12 +960,12 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ + vtls/polarssl.c vtls/polarssl_threadlock.c \ vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \ vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ + vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \ vtls/mbedtls.h vtls/mesalink.h @@ -1170,8 +1166,6 @@ vtls/libcurl_la-polarssl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurl_la-polarssl_threadlock.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurl_la-axtls.lo: vtls/$(am__dirstamp) \ - vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurl_la-cyassl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurl_la-schannel.lo: vtls/$(am__dirstamp) \ @@ -1225,8 +1219,6 @@ vtls/libcurlu_la-polarssl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-polarssl_threadlock.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) -vtls/libcurlu_la-axtls.lo: vtls/$(am__dirstamp) \ - vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-cyassl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-schannel.lo: vtls/$(am__dirstamp) \ @@ -1501,7 +1493,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-vauth.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-axtls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-cyassl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-darwinssl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gskit.Plo@am__quote@ # am--include-marker @@ -1515,7 +1506,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-vtls.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-axtls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-cyassl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-darwinssl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gskit.Plo@am__quote@ # am--include-marker @@ -2463,13 +2453,6 @@ vtls/libcurl_la-polarssl_threadlock.lo: vtls/polarssl_threadlock.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c -vtls/libcurl_la-axtls.lo: vtls/axtls.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-axtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-axtls.Tpo -c -o vtls/libcurl_la-axtls.lo `test -f 'vtls/axtls.c' || echo '$(srcdir)/'`vtls/axtls.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-axtls.Tpo vtls/$(DEPDIR)/libcurl_la-axtls.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/axtls.c' object='vtls/libcurl_la-axtls.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-axtls.lo `test -f 'vtls/axtls.c' || echo '$(srcdir)/'`vtls/axtls.c - vtls/libcurl_la-cyassl.lo: vtls/cyassl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-cyassl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-cyassl.Tpo -c -o vtls/libcurl_la-cyassl.lo `test -f 'vtls/cyassl.c' || echo '$(srcdir)/'`vtls/cyassl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-cyassl.Tpo vtls/$(DEPDIR)/libcurl_la-cyassl.Plo @@ -3422,13 +3405,6 @@ vtls/libcurlu_la-polarssl_threadlock.lo: vtls/polarssl_threadlock.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-polarssl_threadlock.lo `test -f 'vtls/polarssl_threadlock.c' || echo '$(srcdir)/'`vtls/polarssl_threadlock.c -vtls/libcurlu_la-axtls.lo: vtls/axtls.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-axtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-axtls.Tpo -c -o vtls/libcurlu_la-axtls.lo `test -f 'vtls/axtls.c' || echo '$(srcdir)/'`vtls/axtls.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-axtls.Tpo vtls/$(DEPDIR)/libcurlu_la-axtls.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/axtls.c' object='vtls/libcurlu_la-axtls.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-axtls.lo `test -f 'vtls/axtls.c' || echo '$(srcdir)/'`vtls/axtls.c - vtls/libcurlu_la-cyassl.lo: vtls/cyassl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-cyassl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-cyassl.Tpo -c -o vtls/libcurlu_la-cyassl.lo `test -f 'vtls/cyassl.c' || echo '$(srcdir)/'`vtls/cyassl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-cyassl.Tpo vtls/$(DEPDIR)/libcurlu_la-cyassl.Plo @@ -3865,7 +3841,6 @@ distclean: distclean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-axtls.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-cyassl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-darwinssl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gskit.Plo @@ -3879,7 +3854,6 @@ distclean: distclean-am -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-axtls.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-cyassl.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-darwinssl.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-gskit.Plo @@ -4184,7 +4158,6 @@ maintainer-clean: maintainer-clean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo - -rm -f vtls/$(DEPDIR)/libcurl_la-axtls.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-cyassl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-darwinssl.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-gskit.Plo @@ -4198,7 +4171,6 @@ maintainer-clean: maintainer-clean-am -rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo -rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo - -rm -f vtls/$(DEPDIR)/libcurlu_la-axtls.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-cyassl.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-darwinssl.Plo -rm -f vtls/$(DEPDIR)/libcurlu_la-gskit.Plo diff --git a/libs/libcurl/src/Makefile.inc b/libs/libcurl/src/Makefile.inc index 4aa0422591..54acd6cea1 100644 --- a/libs/libcurl/src/Makefile.inc +++ b/libs/libcurl/src/Makefile.inc @@ -28,12 +28,12 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ + vtls/polarssl.c vtls/polarssl_threadlock.c \ vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \ vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ + vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \ vtls/mbedtls.h vtls/mesalink.h diff --git a/libs/libcurl/src/Makefile.netware b/libs/libcurl/src/Makefile.netware index fa6beec00f..29885a19ea 100644 --- a/libs/libcurl/src/Makefile.netware +++ b/libs/libcurl/src/Makefile.netware @@ -6,7 +6,7 @@ # \___|\___/|_| \_\_____| # # Copyright (C) 2004 - 2015, Guenter Knauf -# Copyright (C) 2001 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 2001 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -49,11 +49,6 @@ ifndef LIBSSH2_PATH LIBSSH2_PATH = ../../libssh2-1.5.0 endif -# Edit the path below to point to the base of your axTLS package. -ifndef AXTLS_PATH -AXTLS_PATH = ../../axTLS-1.2.7 -endif - # Edit the path below to point to the base of your libidn package. ifndef LIBIDN_PATH LIBIDN_PATH = ../../libidn-1.18 @@ -230,10 +225,6 @@ WITH_SSH2 = 1 WITH_SSL = 1 WITH_ZLIB = 1 endif -ifeq ($(findstring -axtls,$(CFG)),-axtls) -WITH_AXTLS = 1 -WITH_SSL = -else ifeq ($(findstring -ssl,$(CFG)),-ssl) WITH_SSL = 1 ifeq ($(findstring -srp,$(CFG)),-srp) @@ -242,7 +233,6 @@ WITH_SRP = 1 endif endif endif -endif ifeq ($(findstring -zlib,$(CFG)),-zlib) WITH_ZLIB = 1 endif @@ -280,16 +270,6 @@ ifdef WITH_SSL IMPORTS += GetProcessSwitchCount RunningProcess INSTDEP += ca-bundle.crt else -ifdef WITH_AXTLS - INCLUDES += -I$(AXTLS_PATH)/inc - ifdef LINK_STATIC - LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT) - else - MODULES += libaxtls.nlm - IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp - endif - INSTDEP += ca-bundle.crt -endif endif ifdef WITH_ZLIB INCLUDES += -I$(ZLIB_PATH) @@ -652,7 +632,6 @@ ifdef WITH_ZLIB @echo $(DL)#define HAVE_LIBZ 1$(DL) >> $@ endif ifdef WITH_SSL - @echo $(DL)#define USE_SSLEAY 1$(DL) >> $@ @echo $(DL)#define USE_OPENSSL 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_X509_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_SSL_H 1$(DL) >> $@ @@ -665,16 +644,12 @@ ifdef WITH_SSL @echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ ifdef WITH_SRP - @echo $(DL)#define HAVE_SSLEAY_SRP 1$(DL) >> $@ @echo $(DL)#define USE_TLS_SRP 1$(DL) >> $@ endif ifdef WITH_SPNEGO @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ endif else -ifdef WITH_AXTLS - @echo $(DL)#define USE_AXTLS 1$(DL) >> $@ -endif endif ifdef WITH_SSH2 @echo $(DL)#define USE_LIBSSH2 1$(DL) >> $@ diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c index 5cfb2602df..6a49566c86 100644 --- a/libs/libcurl/src/asyn-ares.c +++ b/libs/libcurl/src/asyn-ares.c @@ -119,6 +119,17 @@ void Curl_resolver_global_cleanup(void) #endif } + +static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd, + int readable, int writable) +{ + struct Curl_easy *easy = data; + if(!readable && !writable) { + DEBUGASSERT(easy); + Curl_multi_closed(easy, socket_fd); + } +} + /* * Curl_resolver_init() * @@ -126,9 +137,14 @@ void Curl_resolver_global_cleanup(void) * URL-state specific environment ('resolver' member of the UrlState * structure). Fills the passed pointer by the initialized ares_channel. */ -CURLcode Curl_resolver_init(void **resolver) +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) { - int status = ares_init((ares_channel*)resolver); + int status; + struct ares_options options; + int optmask = ARES_OPT_SOCK_STATE_CB; + options.sock_state_cb = Curl_ares_sock_state_cb; + options.sock_state_cb_data = easy; + status = ares_init_options((ares_channel*)resolver, &options, optmask); if(status != ARES_SUCCESS) { if(status == ARES_ENOMEM) return CURLE_OUT_OF_MEMORY; @@ -159,12 +175,15 @@ void Curl_resolver_cleanup(void *resolver) * environment ('resolver' member of the UrlState structure). Duplicates the * 'from' ares channel and passes the resulting channel to the 'to' pointer. */ -int Curl_resolver_duphandle(void **to, void *from) +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) { - /* Clone the ares channel for the new handle */ - if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from)) - return CURLE_FAILED_INIT; - return CURLE_OK; + (void)from; + /* + * it would be better to call ares_dup instead, but right now + * it is not possible to set 'sock_state_cb_data' outside of + * ares_init_options + */ + return Curl_resolver_init(easy, to); } static void destroy_async_data(struct Curl_async *async); diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c index 2a59294e5c..74208d7ec5 100644 --- a/libs/libcurl/src/asyn-thread.c +++ b/libs/libcurl/src/asyn-thread.c @@ -108,8 +108,9 @@ void Curl_resolver_global_cleanup(void) * URL-state specific environment ('resolver' member of the UrlState * structure). */ -CURLcode Curl_resolver_init(void **resolver) +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) { + (void)easy; *resolver = calloc(1, sizeof(struct resdata)); if(!*resolver) return CURLE_OUT_OF_MEMORY; @@ -132,10 +133,10 @@ void Curl_resolver_cleanup(void *resolver) * Called from curl_easy_duphandle() to duplicate resolver URL state-specific * environment ('resolver' member of the UrlState structure). */ -int Curl_resolver_duphandle(void **to, void *from) +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) { (void)from; - return Curl_resolver_init(to); + return Curl_resolver_init(easy, to); } static void destroy_async_data(struct Curl_async *); @@ -276,7 +277,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg) char service[12]; int rc; - snprintf(service, sizeof(service), "%d", tsd->port); + msnprintf(service, sizeof(service), "%d", tsd->port); rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); @@ -678,7 +679,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, hints.ai_family = pf; hints.ai_socktype = conn->socktype; - snprintf(sbuf, sizeof(sbuf), "%d", port); + msnprintf(sbuf, sizeof(sbuf), "%d", port); reslv->start = Curl_now(); /* fire up a new resolver thread! */ diff --git a/libs/libcurl/src/asyn.h b/libs/libcurl/src/asyn.h index 3adc3664a2..43625bc3be 100644 --- a/libs/libcurl/src/asyn.h +++ b/libs/libcurl/src/asyn.h @@ -60,7 +60,7 @@ void Curl_resolver_global_cleanup(void); * Returning anything else than CURLE_OK fails curl_easy_init() with the * correspondent code. */ -CURLcode Curl_resolver_init(void **resolver); +CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver); /* * Curl_resolver_cleanup() @@ -79,7 +79,8 @@ void Curl_resolver_cleanup(void *resolver); * pointer. Returning anything else than CURLE_OK causes failed * curl_easy_duphandle() call. */ -int Curl_resolver_duphandle(void **to, void *from); +CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, + void *from); /* * Curl_resolver_cancel(). @@ -150,8 +151,8 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_getsock(x,y,z) 0 -#define Curl_resolver_duphandle(x,y) CURLE_OK -#define Curl_resolver_init(x) CURLE_OK +#define Curl_resolver_duphandle(x,y,z) CURLE_OK +#define Curl_resolver_init(x,y) CURLE_OK #define Curl_resolver_global_init() CURLE_OK #define Curl_resolver_global_cleanup() Curl_nop_stmt #define Curl_resolver_cleanup(x) Curl_nop_stmt diff --git a/libs/libcurl/src/base64.c b/libs/libcurl/src/base64.c index 6370e4cdfb..431b643573 100644 --- a/libs/libcurl/src/base64.c +++ b/libs/libcurl/src/base64.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -233,24 +233,24 @@ static CURLcode base64_encode(const char *table64, switch(inputparts) { case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); + msnprintf(output, 5, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); break; case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); + msnprintf(output, 5, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); break; default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); + msnprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]]); break; } output += 4; diff --git a/libs/libcurl/src/checksrc.pl b/libs/libcurl/src/checksrc.pl index 15e9aff8ee..965f0bab1d 100644 --- a/libs/libcurl/src/checksrc.pl +++ b/libs/libcurl/src/checksrc.pl @@ -35,6 +35,7 @@ my $suppressed; # whitelisted problems my $file; my $dir="."; my $wlist=""; +my @alist; my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin'; my $verbose; my %whitelist; @@ -44,6 +45,10 @@ my %ignore_set; my %ignore_used; my @ignore_line; +my %warnings_extended = ( + 'COPYRIGHTYEAR' => 'copyright year incorrect', + ); + my %warnings = ( 'LONGLINE' => "Line longer than $max_column", 'TABS' => 'TAB characters not allowed', @@ -74,6 +79,7 @@ my %warnings = ( 'SEMINOSPACE' => 'semicolon without following space', 'MULTISPACE' => 'multiple spaces used when not suitable', 'SIZEOFNOPAREN' => 'use of sizeof without parentheses', + 'SNPRINTF' => 'use of snprintf', ); sub readwhitelist { @@ -86,6 +92,35 @@ sub readwhitelist { close(W); } +# Reads the .checksrc in $dir for any extended warnings to enable locally. +# Currently there is no support for disabling warnings from the standard set, +# and since that's already handled via !checksrc! commands there is probably +# little use to add it. +sub readlocalfile { + my $i = 0; + + open(my $rcfile, "<", "$dir/.checksrc") or return; + + while(<$rcfile>) { + $i++; + + # Lines starting with '#' are considered comments + if (/^\s*(#.*)/) { + next; + } + elsif (/^\s*enable ([A-Z]+)$/) { + if(!defined($warnings_extended{$1})) { + print STDERR "invalid warning specified in .checksrc: \"$1\"\n"; + next; + } + $warnings{$1} = $warnings_extended{$1}; + } + else { + die "Invalid format in $dir/.checksrc on line $i\n"; + } + } +} + sub checkwarn { my ($name, $num, $col, $file, $line, $msg, $error) = @_; @@ -153,6 +188,11 @@ while(1) { $file = shift @ARGV; next; } + elsif($file =~ /-A(.+)/) { + push @alist, $1; + $file = shift @ARGV; + next; + } elsif($file =~ /-i([1-9])/) { $indent = $1 + 0; $file = shift @ARGV; @@ -174,6 +214,7 @@ while(1) { if(!$file) { print "checksrc.pl [option] <file1> [file2] ...\n"; print " Options:\n"; + print " -A[rule] Accept this violation, can be used multiple times\n"; print " -D[DIR] Directory to prepend file names\n"; print " -h Show help output\n"; print " -W[file] Whitelist the given file - ignore all its flaws\n"; @@ -187,6 +228,7 @@ if(!$file) { } readwhitelist(); +readlocalfile(); do { if("$wlist" !~ / $file /) { @@ -198,6 +240,17 @@ do { } while($file); +sub accept_violations { + for my $r (@alist) { + if(!$warnings{$r}) { + print "'$r' is not a warning to accept!\n"; + exit; + } + $ignore{$r}=999999; + $ignore_used{$r}=0; + } +} + sub checksrc_clear { undef %ignore; undef %ignore_set; @@ -295,8 +348,9 @@ sub scanfile { open(R, "<$file") || die "failed to open $file"; my $incomment=0; - my $copyright=0; + my @copyright=(); checksrc_clear(); # for file based ignores + accept_violations(); while(<R>) { $windows_os ? $_ =~ s/\r?\n$// : chomp; @@ -310,9 +364,16 @@ sub scanfile { checksrc($cmd, $line, $file, $l) } - # check for a copyright statement - if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) { - $copyright=1; + # check for a copyright statement and save the years + if($l =~ /\* +copyright .* \d\d\d\d/i) { + while($l =~ /([\d]{4})/g) { + push @copyright, { + year => $1, + line => $line, + col => index($l, $1), + code => $l + }; + } } # detect long lines @@ -511,6 +572,13 @@ sub scanfile { "use of $2 is banned"); } + # scan for use of snprintf for curl-internals reasons + if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) { + checkwarn("SNPRINTF", + $line, length($1), $file, $ol, + "use of $2 is banned"); + } + # scan for use of non-binary fopen without the macro if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { my $mode = $2; @@ -623,9 +691,49 @@ sub scanfile { $prevl = $ol; } - if(!$copyright) { + if(!scalar(@copyright)) { checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1); } + + # COPYRIGHTYEAR is a extended warning so we must first see if it has been + # enabled in .checksrc + if(defined($warnings{"COPYRIGHTYEAR"})) { + # The check for updated copyrightyear is overly complicated in order to + # not punish current hacking for past sins. The copyright years are + # right now a bit behind, so enforcing copyright year checking on all + # files would cause hundreds of errors. Instead we only look at files + # which are tracked in the Git repo and edited in the workdir, or + # committed locally on the branch without being in upstream master. + # + # The simple and naive test is to simply check for the current year, + # but updating the year even without an edit is against project policy + # (and it would fail every file on January 1st). + # + # A rather more interesting, and correct, check would be to not test + # only locally committed files but inspect all files wrt the year of + # their last commit. Removing the `git rev-list origin/master..HEAD` + # condition below will enfore copyright year checks against the year + # the file was last committed (and thus edited to some degree). + my $commityear = undef; + @copyright = sort {$$b{year} cmp $$a{year}} @copyright; + + if(`git status -s -- $file` =~ /^ [MARCU]/) { + $commityear = (localtime(time))[5] + 1900; + } + elsif (`git rev-list --count origin/master..HEAD -- $file` !~ /^0/) { + my $grl = `git rev-list --max-count=1 --timestamp HEAD -- $file`; + $commityear = (localtime((split(/ /, $grl))[0]))[5] + 1900; + } + + if(defined($commityear) && scalar(@copyright) && + $copyright[0]{year} != $commityear) { + checkwarn("COPYRIGHTYEAR", $copyright[0]{line}, $copyright[0]{col}, + $file, $copyright[0]{code}, + "Copyright year out of date, should be $commityear, " . + "is $copyright[0]{year}", 1); + } + } + if($incomment) { checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1); } diff --git a/libs/libcurl/src/conncache.c b/libs/libcurl/src/conncache.c index 6fbf3b1d27..08e9042a6f 100644 --- a/libs/libcurl/src/conncache.c +++ b/libs/libcurl/src/conncache.c @@ -175,7 +175,7 @@ static void hashkey(struct connectdata *conn, char *buf, DEBUGASSERT(len > 32); /* put the number first so that the hostname gets cut off if too long */ - snprintf(buf, len, "%ld%s", conn->port, hostname); + msnprintf(buf, len, "%ld%s", conn->port, hostname); } void Curl_conncache_unlock(struct connectdata *conn) diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c index 41f2202681..ec3cd3a795 100644 --- a/libs/libcurl/src/connect.c +++ b/libs/libcurl/src/connect.c @@ -522,7 +522,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) err = 0; } #endif -#ifdef __minix +#if defined(EBADIOCTL) && defined(__minix) /* Minix 3.1.x doesn't support getsockopt on UDP sockets */ if(EBADIOCTL == err) { SET_SOCKERRNO(0); @@ -655,7 +655,7 @@ bool Curl_getaddressinfo(struct sockaddr *sa, char *addr, #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) case AF_UNIX: su = (struct sockaddr_un*)sa; - snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); + msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); *port = 0; return TRUE; #endif @@ -1314,7 +1314,7 @@ int Curl_closesocket(struct connectdata *conn, conn->sock_accepted[SECONDARYSOCKET] = FALSE; else { int rc; - Curl_multi_closed(conn, sock); + Curl_multi_closed(conn->data, sock); Curl_set_in_callback(conn->data, true); rc = conn->fclosesocket(conn->closesocket_client, sock); Curl_set_in_callback(conn->data, false); @@ -1324,7 +1324,7 @@ int Curl_closesocket(struct connectdata *conn, if(conn) /* tell the multi-socket code about this */ - Curl_multi_closed(conn, sock); + Curl_multi_closed(conn->data, sock); sclose(sock); diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c index 5b7ab66337..3dc85ee5ca 100644 --- a/libs/libcurl/src/cookie.c +++ b/libs/libcurl/src/cookie.c @@ -675,7 +675,10 @@ Curl_cookie_add(struct Curl_easy *data, /* overflow, used max value */ co->expires = CURL_OFF_T_MAX; else if(!offt) { - if(CURL_OFF_T_MAX - now < co->expires) + if(!co->expires) + /* already expired */ + co->expires = 1; + else if(CURL_OFF_T_MAX - now < co->expires) /* would overflow */ co->expires = CURL_OFF_T_MAX; else @@ -1456,22 +1459,9 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) unsigned int j; struct Cookie **array; - if((NULL == c) || (0 == c->numcookies)) - /* If there are no known cookies, we don't write or even create any - destination file */ - return 0; - /* at first, remove expired cookies */ remove_expired(c); - /* make sure we still have cookies after expiration */ - if(0 == c->numcookies) - return 0; - - array = malloc(sizeof(struct Cookie *) * c->numcookies); - if(!array) - return 1; - if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; @@ -1480,7 +1470,6 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) else { out = fopen(dumphere, FOPEN_WRITETEXT); if(!out) { - free(array); return 1; /* failure */ } } @@ -1490,32 +1479,40 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) "# This file was generated by libcurl! Edit at your own risk.\n\n", out); - j = 0; - for(i = 0; i < COOKIE_HASH_SIZE; i++) { - for(co = c->cookies[i]; co; co = co->next) { - if(!co->domain) - continue; - array[j++] = co; - } - } - - qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct); - - for(i = 0; i < j; i++) { - format_ptr = get_netscape_format(array[i]); - if(format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - free(array); + if(c->numcookies) { + array = malloc(sizeof(struct Cookie *) * c->numcookies); + if(!array) { if(!use_stdout) fclose(out); return 1; } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); - } - free(array); + j = 0; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(co = c->cookies[i]; co; co = co->next) { + if(!co->domain) + continue; + array[j++] = co; + } + } + qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct); + + for(i = 0; i < j; i++) { + format_ptr = get_netscape_format(array[i]); + if(format_ptr == NULL) { + fprintf(out, "#\n# Fatal libcurl error\n"); + free(array); + if(!use_stdout) + fclose(out); + return 1; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); + } + + free(array); + } if(!use_stdout) fclose(out); diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in index 477d61eb4a..781006f20f 100644 --- a/libs/libcurl/src/curl_config.h.in +++ b/libs/libcurl/src/curl_config.h.in @@ -175,9 +175,6 @@ /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H -/* Define to 1 if you have the `ENGINE_cleanup' function. */ -#undef HAVE_ENGINE_CLEANUP - /* Define to 1 if you have the <errno.h> header file. */ #undef HAVE_ERRNO_H @@ -928,9 +925,6 @@ /* Define to enable c-ares support */ #undef USE_ARES -/* if axTLS is enabled */ -#undef USE_AXTLS - /* if CyaSSL/WolfSSL is enabled */ #undef USE_CYASSL diff --git a/libs/libcurl/src/curl_gssapi.c b/libs/libcurl/src/curl_gssapi.c index f007986c0d..d854ab0c7f 100644 --- a/libs/libcurl/src/curl_gssapi.c +++ b/libs/libcurl/src/curl_gssapi.c @@ -97,9 +97,9 @@ static size_t display_gss_error(OM_uint32 status, int type, &msg_ctx, &status_string); if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { - len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len, - "%.*s. ", (int)status_string.length, - (char *)status_string.value); + len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, + "%.*s. ", (int)status_string.length, + (char *)status_string.value); } gss_release_buffer(&min_stat, &status_string); } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); diff --git a/libs/libcurl/src/curl_multibyte.c b/libs/libcurl/src/curl_multibyte.c index e78bb5002e..e48334faff 100644 --- a/libs/libcurl/src/curl_multibyte.c +++ b/libs/libcurl/src/curl_multibyte.c @@ -64,13 +64,13 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) char *str_utf8 = NULL; if(str_w) { - int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL, - 0, NULL, NULL); - if(str_utf8_len > 0) { - str_utf8 = malloc(str_utf8_len * sizeof(wchar_t)); + int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, + NULL, 0, NULL, NULL); + if(bytes > 0) { + str_utf8 = malloc(bytes); if(str_utf8) { - if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len, - NULL, FALSE) == 0) { + if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes, + NULL, NULL) == 0) { free(str_utf8); return NULL; } diff --git a/libs/libcurl/src/curl_ntlm_core.c b/libs/libcurl/src/curl_ntlm_core.c index 922e85a926..9eb6c43c8c 100644 --- a/libs/libcurl/src/curl_ntlm_core.c +++ b/libs/libcurl/src/curl_ntlm_core.c @@ -54,23 +54,13 @@ #ifdef USE_OPENSSL -# ifdef USE_OPENSSL -# include <openssl/des.h> -# ifndef OPENSSL_NO_MD4 -# include <openssl/md4.h> -# endif -# include <openssl/md5.h> -# include <openssl/ssl.h> -# include <openssl/rand.h> -# else -# include <des.h> -# ifndef OPENSSL_NO_MD4 -# include <md4.h> -# endif -# include <md5.h> -# include <ssl.h> -# include <rand.h> +# include <openssl/des.h> +# ifndef OPENSSL_NO_MD4 +# include <openssl/md4.h> # endif +# include <openssl/md5.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> # if (OPENSSL_VERSION_NUMBER < 0x00907001L) # define DES_key_schedule des_key_schedule # define DES_cblock des_cblock @@ -753,12 +743,12 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, return CURLE_OUT_OF_MEMORY; /* Create the BLOB structure */ - snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, - "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ - "%c%c%c%c", /* Reserved = 0 */ - NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], - NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], - 0, 0, 0, 0); + msnprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, + "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ + "%c%c%c%c", /* Reserved = 0 */ + NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], + NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], + 0, 0, 0, 0); Curl_write64_le(tw, ptr + 24); memcpy(ptr + 32, challenge_client, 8); diff --git a/libs/libcurl/src/curl_printf.h b/libs/libcurl/src/curl_printf.h index 49857cdb0d..0d37b8e572 100644 --- a/libs/libcurl/src/curl_printf.h +++ b/libs/libcurl/src/curl_printf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,7 +31,7 @@ # undef printf # undef fprintf -# undef snprintf +# undef msnprintf # undef vprintf # undef vfprintf # undef vsnprintf @@ -39,18 +39,10 @@ # undef vaprintf # define printf curl_mprintf # define fprintf curl_mfprintf -# define snprintf curl_msnprintf +# define msnprintf curl_msnprintf # define vprintf curl_mvprintf # define vfprintf curl_mvfprintf -# define vsnprintf curl_mvsnprintf +# define mvsnprintf curl_mvsnprintf # define aprintf curl_maprintf # define vaprintf curl_mvaprintf - -/* We define away the sprintf functions unconditonally since we don't want - internal code to be using them, intentionally or by mistake!*/ -# undef sprintf -# undef vsprintf -# define sprintf sprintf_was_used -# define vsprintf vsprintf_was_used - #endif /* HEADER_CURL_PRINTF_H */ diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h index b84501556f..f83e1ea4f7 100644 --- a/libs/libcurl/src/curl_setup.h +++ b/libs/libcurl/src/curl_setup.h @@ -646,7 +646,7 @@ int netware_init(void); #define LIBIDN_REQUIRED_VERSION "0.4.1" #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ - defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \ + defined(USE_POLARSSL) || defined(USE_MBEDTLS) || \ defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ defined(USE_DARWINSSL) || defined(USE_GSKIT) || defined(USE_MESALINK) #define USE_SSL /* SSL support has been enabled */ diff --git a/libs/libcurl/src/curlx.h b/libs/libcurl/src/curlx.h index 4c77d4f2e8..3e9b516f82 100644 --- a/libs/libcurl/src/curlx.h +++ b/libs/libcurl/src/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -81,22 +81,21 @@ # undef printf # undef fprintf # undef sprintf -# undef snprintf +# undef msnprintf # undef vprintf # undef vfprintf # undef vsprintf -# undef vsnprintf +# undef mvsnprintf # undef aprintf # undef vaprintf # define printf curlx_mprintf # define fprintf curlx_mfprintf # define sprintf curlx_msprintf -# define snprintf curlx_msnprintf +# define msnprintf curlx_msnprintf # define vprintf curlx_mvprintf # define vfprintf curlx_mvfprintf -# define vsprintf curlx_mvsprintf -# define vsnprintf curlx_mvsnprintf +# define mvsnprintf curlx_mvsnprintf # define aprintf curlx_maprintf # define vaprintf curlx_mvaprintf #endif /* ENABLE_CURLX_PRINTF */ diff --git a/libs/libcurl/src/doh.c b/libs/libcurl/src/doh.c index ef6013db9d..1e76c96f91 100644 --- a/libs/libcurl/src/doh.c +++ b/libs/libcurl/src/doh.c @@ -26,13 +26,13 @@ #include "curl_addrinfo.h" #include "doh.h" -#ifdef USE_NGHTTP2 #include "sendf.h" #include "multiif.h" #include "url.h" #include "share.h" #include "curl_base64.h" #include "connect.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -143,8 +143,8 @@ doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp) /* suspiciously much for us */ return 0; - mem->memory = realloc(mem->memory, mem->size + realsize); - if(mem->memory == NULL) + mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize); + if(!mem->memory) /* out of memory! */ return 0; @@ -234,7 +234,9 @@ static CURLcode dohprobe(struct Curl_easy *data, ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen); } ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers); +#ifdef USE_NGHTTP2 ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); +#endif #ifndef CURLDEBUG /* enforce HTTPS if not debug */ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); @@ -524,7 +526,7 @@ UNITTEST DOHcode doh_decode(unsigned char *doh, if(dohlen < 12) return DOH_TOO_SMALL_BUFFER; /* too small */ - if(doh[0] || doh[1]) + if(!doh || doh[0] || doh[1]) return DOH_DNS_BAD_ID; /* bad ID */ rcode = doh[3] & 0x0f; if(rcode) @@ -660,13 +662,13 @@ static void showdoh(struct Curl_easy *data, char buffer[128]; char *ptr; size_t len; - snprintf(buffer, 128, "DOH AAAA: "); + msnprintf(buffer, 128, "DOH AAAA: "); ptr = &buffer[10]; len = 118; for(j = 0; j < 16; j += 2) { size_t l; - snprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j], - d->addr[i].ip.v6[j + 1]); + msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j], + d->addr[i].ip.v6[j + 1]); l = strlen(ptr); len -= l; ptr += l; @@ -853,7 +855,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, &de); free(data->req.doh.probe[1].serverdoh.memory); if(rc2) { - infof(data, "DOG: %s type %s for %s\n", doh_strerror(rc2), + infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc2), type2name(data->req.doh.probe[1].dnstype), data->req.doh.host); } @@ -893,28 +895,3 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, return CURLE_OK; } - -#else /* !USE_NGHTTP2 */ -/* - */ -Curl_addrinfo *Curl_doh(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - (void)conn; - (void)hostname; - (void)port; - (void)waitp; - return NULL; -} - -CURLcode Curl_doh_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dnsp) -{ - (void)conn; - (void)dnsp; - return CURLE_NOT_BUILT_IN; -} - -#endif /* USE_NGHTTP2 */ diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c index 4de4e6522f..e592d7a71e 100644 --- a/libs/libcurl/src/easy.c +++ b/libs/libcurl/src/easy.c @@ -664,12 +664,12 @@ static CURLcode easy_transfer(struct Curl_multi *multi) while(!done && !mcode) { int still_running = 0; - int rc; + bool gotsocket = FALSE; - mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); + mcode = Curl_multi_wait(multi, NULL, 0, 1000, NULL, &gotsocket); if(!mcode) { - if(!rc) { + if(!gotsocket) { long sleep_ms; /* If it returns without any filedescriptor instantly, we need to @@ -688,6 +688,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi) /* only read 'still_running' if curl_multi_perform() return OK */ if(!mcode && !still_running) { + int rc; CURLMsg *msg = curl_multi_info_read(multi, &rc); if(msg) { result = msg->data.result; @@ -966,7 +967,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) } /* Clone the resolver handle, if present, for the new handle */ - if(Curl_resolver_duphandle(&outcurl->state.resolver, + if(Curl_resolver_duphandle(outcurl, + &outcurl->state.resolver, data->state.resolver)) goto fail; diff --git a/libs/libcurl/src/escape.c b/libs/libcurl/src/escape.c index afd3899f9f..7121db31c2 100644 --- a/libs/libcurl/src/escape.c +++ b/libs/libcurl/src/escape.c @@ -122,7 +122,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, return NULL; } - snprintf(&ns[strindex], 4, "%%%02X", in); + msnprintf(&ns[strindex], 4, "%%%02X", in); strindex += 3; } diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c index 722b55e9d2..8bba3b9165 100644 --- a/libs/libcurl/src/file.c +++ b/libs/libcurl/src/file.c @@ -417,8 +417,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done) struct tm buffer; const struct tm *tm = &buffer; char header[80]; - snprintf(header, sizeof(header), - "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); + msnprintf(header, sizeof(header), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", + expected_size); result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0); if(result) return result; @@ -434,16 +435,16 @@ static CURLcode file_do(struct connectdata *conn, bool *done) return result; /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(header, sizeof(header), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec, - data->set.opt_no_body ? "": "\r\n"); + msnprintf(header, sizeof(header), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + data->set.opt_no_body ? "": "\r\n"); result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0); if(result) return result; diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c index 793d991ccb..581df09d77 100644 --- a/libs/libcurl/src/ftp.c +++ b/libs/libcurl/src/ftp.c @@ -1272,7 +1272,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, source++; } *dest = 0; - snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); + msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); if(result) { @@ -2061,9 +2061,9 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, char timebuf[24]; time_t secs = time(NULL); - snprintf(timebuf, sizeof(timebuf), - "%04d%02d%02d %02d:%02d:%02d GMT", - year, month, day, hour, minute, second); + msnprintf(timebuf, sizeof(timebuf), + "%04d%02d%02d %02d:%02d:%02d GMT", + year, month, day, hour, minute, second); /* now, convert this into a time() value: */ data->info.filetime = curl_getdate(timebuf, &secs); } @@ -2086,15 +2086,15 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, return result; /* format: "Tue, 15 Nov 1994 12:45:26" */ - snprintf(headerbuf, sizeof(headerbuf), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + msnprintf(headerbuf, sizeof(headerbuf), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0); if(result) return result; @@ -2276,8 +2276,8 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, #ifdef CURL_FTP_HTTPSTYLE_HEAD if(-1 != filesize) { char clbuf[128]; - snprintf(clbuf, sizeof(clbuf), - "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); + msnprintf(clbuf, sizeof(clbuf), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0); if(result) return result; diff --git a/libs/libcurl/src/ftplistparser.c b/libs/libcurl/src/ftplistparser.c index 249fe09c84..1b1de5c3cd 100644 --- a/libs/libcurl/src/ftplistparser.c +++ b/libs/libcurl/src/ftplistparser.c @@ -405,7 +405,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->state.UNIX.main = PL_UNIX_FILETYPE; /* start FSM again not considering size of directory */ finfo->b_used = 0; - i--; + continue; } break; case PL_UNIX_TOTALSIZE_READING: diff --git a/libs/libcurl/src/hostcheck.c b/libs/libcurl/src/hostcheck.c index c9d8112d86..6fcd0a9011 100644 --- a/libs/libcurl/src/hostcheck.c +++ b/libs/libcurl/src/hostcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,7 +23,6 @@ #include "curl_setup.h" #if defined(USE_OPENSSL) \ - || defined(USE_AXTLS) \ || defined(USE_GSKIT) \ || defined(USE_SCHANNEL) /* these backends use functions from this file */ @@ -150,4 +149,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) return res; } -#endif /* OPENSSL, AXTLS, GSKIT or schannel+wince */ +#endif /* OPENSSL, GSKIT or schannel+wince */ diff --git a/libs/libcurl/src/hostip4.c b/libs/libcurl/src/hostip4.c index 9d6f115ae6..e6ba710d83 100644 --- a/libs/libcurl/src/hostip4.c +++ b/libs/libcurl/src/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -145,7 +145,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; if(port) { - snprintf(sbuf, sizeof(sbuf), "%d", port); + msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } diff --git a/libs/libcurl/src/hostip6.c b/libs/libcurl/src/hostip6.c index 3bf47b467d..e06d0343a5 100644 --- a/libs/libcurl/src/hostip6.c +++ b/libs/libcurl/src/hostip6.c @@ -178,7 +178,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #endif if(port) { - snprintf(sbuf, sizeof(sbuf), "%d", port); + msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c index 46ac15a6e2..345100f6c8 100644 --- a/libs/libcurl/src/http.c +++ b/libs/libcurl/src/http.c @@ -526,6 +526,12 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) pickhost = pickoneauth(&data->state.authhost, authmask); if(!pickhost) data->state.authproblem = TRUE; + if(data->state.authhost.picked == CURLAUTH_NTLM && + conn->httpversion > 11) { + infof(data, "Forcing HTTP/1.1 for NTLM"); + connclose(conn, "Force HTTP/1.1 connection"); + conn->data->set.httpversion = CURL_HTTP_VERSION_1_1; + } } if(conn->bits.proxy_user_passwd && ((data->req.httpcode == 407) || @@ -610,7 +616,6 @@ output_auth_headers(struct connectdata *conn, result = Curl_output_negotiate(conn, proxy); if(result) return result; - authstatus->done = TRUE; negdata->state = GSS_AUTHSENT; } else @@ -697,7 +702,7 @@ output_auth_headers(struct connectdata *conn, * * @param conn all information about the current connection * @param request pointer to the request keyword - * @param path pointer to the requested path + * @param path pointer to the requested path; should include query part * @param proxytunnel boolean if this is the request setting up a "proxy * tunnel" * @@ -1479,14 +1484,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn) strcpy(tcp_version, "TCP4"); } - snprintf(proxy_header, - sizeof(proxy_header), - "PROXY %s %s %s %li %li\r\n", - tcp_version, - conn->data->info.conn_local_ip, - conn->data->info.conn_primary_ip, - conn->data->info.conn_local_port, - conn->data->info.conn_primary_port); + msnprintf(proxy_header, + sizeof(proxy_header), + "PROXY %s %s %s %li %li\r\n", + tcp_version, + conn->data->info.conn_local_ip, + conn->data->info.conn_primary_ip, + conn->data->info.conn_local_port, + conn->data->info.conn_primary_port); req_buffer = Curl_add_buffer_init(); if(!req_buffer) @@ -1850,16 +1855,16 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data, */ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(datestr, sizeof(datestr), - "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - condp, - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + msnprintf(datestr, sizeof(datestr), + "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + condp, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); @@ -1995,9 +2000,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* setup the authentication headers */ - result = Curl_http_output_auth(conn, request, path, FALSE); - if(result) - return result; + { + char *pq = NULL; + if(query && *query) { + pq = aprintf("%s?%s", path, query); + if(!pq) + return CURLE_OUT_OF_MEMORY; + } + result = Curl_http_output_auth(conn, request, (pq ? pq : path), FALSE); + free(pq); + if(result) + return result; + } if((data->state.authhost.multipass || data->state.authproxy.multipass) && (httpreq != HTTPREQ_GET) && @@ -2293,8 +2307,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!*data->state.up.path && path[strlen(path) - 1] != '/') { *p++ = '/'; } - snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", - data->set.prefer_ascii ? 'a' : 'i'); + msnprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", + data->set.prefer_ascii ? 'a' : 'i'); } } if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) @@ -3652,13 +3666,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } switch(k->httpcode) { - case 204: - /* (quote from RFC2616, section 10.2.5): The server has - * fulfilled the request but does not need to return an - * entity-body ... The 204 response MUST NOT include a - * message-body, and thus is always terminated by the first - * empty line after the header fields. */ - /* FALLTHROUGH */ case 304: /* (quote from RFC2616, section 10.3.5): The 304 response * MUST NOT contain a message-body, and thus is always @@ -3666,6 +3673,13 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * fields. */ if(data->set.timecondition) data->info.timecond = TRUE; + /* FALLTHROUGH */ + case 204: + /* (quote from RFC2616, section 10.2.5): The server has + * fulfilled the request but does not need to return an + * entity-body ... The 204 response MUST NOT include a + * message-body, and thus is always terminated by the first + * empty line after the header fields. */ k->size = 0; k->maxdownload = 0; k->ignorecl = TRUE; /* ignore Content-Length headers */ diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c index 0c5f6db0b4..a61d8c2403 100644 --- a/libs/libcurl/src/http2.c +++ b/libs/libcurl/src/http2.c @@ -350,7 +350,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = { int Curl_http2_ver(char *p, size_t len) { nghttp2_info *h2 = nghttp2_version(0); - return snprintf(p, len, " nghttp2/%s", h2->version_str); + return msnprintf(p, len, " nghttp2/%s", h2->version_str); } /* HTTP/2 error code to name based on the Error Code Registry. @@ -2367,6 +2367,14 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data) Curl_http2_remove_child(data->set.stream_depends_on, data); } +/* Only call this function for a transfer that already got a HTTP/2 + CURLE_HTTP2_STREAM error! */ +bool Curl_h2_http_1_1_error(struct connectdata *conn) +{ + struct http_conn *httpc = &conn->proto.httpc; + return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED); +} + #else /* !USE_NGHTTP2 */ /* Satisfy external references even if http2 is not compiled in. */ diff --git a/libs/libcurl/src/http2.h b/libs/libcurl/src/http2.h index 4492ec2113..67db3dffb0 100644 --- a/libs/libcurl/src/http2.h +++ b/libs/libcurl/src/http2.h @@ -59,6 +59,9 @@ CURLcode Curl_http2_add_child(struct Curl_easy *parent, void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child); void Curl_http2_cleanup_dependencies(struct Curl_easy *data); + +/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */ +bool Curl_h2_http_1_1_error(struct connectdata *conn); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL @@ -74,6 +77,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data); #define Curl_http2_add_child(x, y, z) #define Curl_http2_remove_child(x, y) #define Curl_http2_cleanup_dependencies(x) +#define Curl_h2_http_1_1_error(x) 0 #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/libs/libcurl/src/http_negotiate.c b/libs/libcurl/src/http_negotiate.c index ddcd65b3b9..444265d11f 100644 --- a/libs/libcurl/src/http_negotiate.c +++ b/libs/libcurl/src/http_negotiate.c @@ -49,6 +49,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, /* Point to the correct struct with this */ struct negotiatedata *neg_ctx; + struct auth *authp; if(proxy) { userp = conn->http_proxy.user; @@ -57,6 +58,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; host = conn->http_proxy.host.name; neg_ctx = &data->state.proxyneg; + authp = &conn->data->state.authproxy; } else { userp = conn->user; @@ -65,6 +67,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, data->set.str[STRING_SERVICE_NAME] : "HTTP"; host = conn->host.name; neg_ctx = &data->state.negotiate; + authp = &conn->data->state.authhost; } /* Not set means empty */ @@ -95,6 +98,11 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, if(result) Curl_auth_spnego_cleanup(neg_ctx); + else + /* If the status is different than 0 and we encountered no errors + it means we have to continue. 0 is the OK value for both GSSAPI + (GSS_S_COMPLETE) and SSPI (SEC_E_OK) */ + authp->done = !neg_ctx->status; return result; } diff --git a/libs/libcurl/src/if2ip.c b/libs/libcurl/src/if2ip.c index ce38ea117b..566061a564 100644 --- a/libs/libcurl/src/if2ip.c +++ b/libs/libcurl/src/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -169,7 +169,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } #endif if(scopeid) - snprintf(scope, sizeof(scope), "%%%u", scopeid); + msnprintf(scope, sizeof(scope), "%%%u", scopeid); } else #endif @@ -177,7 +177,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; res = IF2IP_FOUND; ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); - snprintf(buf, buf_size, "%s%s", ip, scope); + msnprintf(buf, buf_size, "%s%s", ip, scope); break; } } diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c index 3ef89097f9..a8320e3f18 100644 --- a/libs/libcurl/src/imap.c +++ b/libs/libcurl/src/imap.c @@ -1749,8 +1749,8 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) imapc->cmdid = (imapc->cmdid + 1) % 1000; /* Calculate the tag based on the connection ID and command ID */ - snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", - 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); + msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", + 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); /* Prefix the format with the tag */ taggedfmt = aprintf("%s %s", imapc->resptag, fmt); diff --git a/libs/libcurl/src/inet_ntop.c b/libs/libcurl/src/inet_ntop.c index ac5d2d4d6f..855981c666 100644 --- a/libs/libcurl/src/inet_ntop.c +++ b/libs/libcurl/src/inet_ntop.c @@ -55,11 +55,11 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) DEBUGASSERT(size >= 16); tmp[0] = '\0'; - (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", - ((int)((unsigned char)src[0])) & 0xff, - ((int)((unsigned char)src[1])) & 0xff, - ((int)((unsigned char)src[2])) & 0xff, - ((int)((unsigned char)src[3])) & 0xff); + (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", + ((int)((unsigned char)src[0])) & 0xff, + ((int)((unsigned char)src[1])) & 0xff, + ((int)((unsigned char)src[2])) & 0xff, + ((int)((unsigned char)src[3])) & 0xff); len = strlen(tmp); if(len == 0 || len >= size) { @@ -148,7 +148,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) tp += strlen(tp); break; } - tp += snprintf(tp, 5, "%lx", words[i]); + tp += msnprintf(tp, 5, "%lx", words[i]); } /* Was it a trailing run of 0x00's? diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c index ceaa71d089..a149f8cbc3 100644 --- a/libs/libcurl/src/ldap.c +++ b/libs/libcurl/src/ldap.c @@ -839,6 +839,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *path; + char *query; char *p; char *q; size_t i; @@ -846,7 +847,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) if(!conn->data || !conn->data->state.up.path || conn->data->state.up.path[0] != '/' || - !strcasecompare("LDAP", conn->data->state.up.scheme)) + !strncasecompare("LDAP", conn->data->state.up.scheme, 4)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; @@ -858,11 +859,14 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) if(!path) return LDAP_NO_MEMORY; - /* Parse the DN (Distinguished Name) */ - q = strchr(p, '?'); - if(q) - *q++ = '\0'; + /* Duplicate the query */ + q = query = strdup(conn->data->state.up.query); + if(!query) { + free(path); + return LDAP_NO_MEMORY; + } + /* Parse the DN (Distinguished Name) */ if(*p) { char *dn = p; char *unescaped; @@ -1039,6 +1043,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) quit: free(path); + free(query); return rc; } diff --git a/libs/libcurl/src/libcurl.plist b/libs/libcurl/src/libcurl.plist index 54d0480bec..ca8d642076 100644 --- a/libs/libcurl/src/libcurl.plist +++ b/libs/libcurl/src/libcurl.plist @@ -15,7 +15,7 @@ <string>se.haxx.curl.libcurl</string> <key>CFBundleVersion</key> - <string>7.62.0</string> + <string>7.63.0</string> <key>CFBundleName</key> <string>libcurl</string> @@ -27,9 +27,9 @@ <string>????</string> <key>CFBundleShortVersionString</key> - <string>libcurl 7.62.0</string> + <string>libcurl 7.63.0</string> <key>CFBundleGetInfoString</key> - <string>libcurl.plist 7.62.0</string> + <string>libcurl.plist 7.63.0</string> </dict> </plist> diff --git a/libs/libcurl/src/libcurl.rc b/libs/libcurl/src/libcurl.rc index 3316fba191..4839d0a651 100644 --- a/libs/libcurl/src/libcurl.rc +++ b/libs/libcurl/src/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,22 +22,22 @@ #include <winver.h> #include "../include/curl/curlver.h" -LANGUAGE 0x09,0x01 +LANGUAGE 0, 0 #define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0 VS_VERSION_INFO VERSIONINFO FILEVERSION RC_VERSION PRODUCTVERSION RC_VERSION - FILEFLAGSMASK 0x3fL + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #if defined(DEBUGBUILD) || defined(_DEBUG) - FILEFLAGS 1 + FILEFLAGS VS_FF_DEBUG #else - FILEFLAGS 0 + FILEFLAGS 0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL - FILESUBTYPE 0x0L + FILESUBTYPE 0L BEGIN BLOCK "StringFileInfo" diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c index d350602163..4691904be4 100644 --- a/libs/libcurl/src/md4.c +++ b/libs/libcurl/src/md4.c @@ -1,4 +1,5 @@ /* + * !checksrc! disable COPYRIGHT * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. * MD4 Message-Digest Algorithm (RFC 1320). * diff --git a/libs/libcurl/src/md5.c b/libs/libcurl/src/md5.c index 45f45bbd9e..a17a58fa61 100644 --- a/libs/libcurl/src/md5.c +++ b/libs/libcurl/src/md5.c @@ -163,13 +163,6 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) CryptReleaseContext(ctx->hCryptProv, 0); } -#elif defined(USE_AXTLS) -#include <axTLS/config.h> -#include <axTLS/os_int.h> -#include <axTLS/crypto.h> -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" #else /* When no other crypto library is available we use this code segment */ /* diff --git a/libs/libcurl/src/memdebug.c b/libs/libcurl/src/memdebug.c index 2b81c26a6f..05590a8f83 100644 --- a/libs/libcurl/src/memdebug.c +++ b/libs/libcurl/src/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -504,7 +504,7 @@ void curl_memlog(const char *format, ...) return; va_start(ap, format); - nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap); + nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap); va_end(ap); if(nchars > LOGLINE_BUFSIZE - 1) diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c index d2d91d7438..e190936782 100644 --- a/libs/libcurl/src/mprintf.c +++ b/libs/libcurl/src/mprintf.c @@ -835,7 +835,7 @@ static int dprintf_formatf( while(width-- > 0) OUTCHAR(' '); - while((len-- > 0) && *str) + for(; len && *str; len--) OUTCHAR(*str++); if(p->flags&FLAGS_LEFT) while(width-- > 0) diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c index 0db2a97308..56b3faf2fa 100644 --- a/libs/libcurl/src/multi.c +++ b/libs/libcurl/src/multi.c @@ -46,6 +46,7 @@ #include "vtls/vtls.h" #include "connect.h" #include "http_proxy.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -634,13 +635,13 @@ static CURLcode multi_done(struct connectdata **connp, else { char buffer[256]; /* create string before returning the connection */ - snprintf(buffer, sizeof(buffer), - "Connection #%ld to host %s left intact", - conn->connection_id, - conn->bits.socksproxy ? conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname); + msnprintf(buffer, sizeof(buffer), + "Connection #%ld to host %s left intact", + conn->connection_id, + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname); /* the connection is no longer in use by this transfer */ if(Curl_conncache_return_conn(conn)) { @@ -985,11 +986,12 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, #define NUM_POLLS_ON_STACK 10 -CURLMcode curl_multi_wait(struct Curl_multi *multi, +CURLMcode Curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, - int *ret) + int *ret, + bool *gotsocket) /* if any socket was checked */ { struct Curl_easy *data; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; @@ -1003,6 +1005,9 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, int retcode = 0; struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; + if(gotsocket) + *gotsocket = FALSE; + if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -1135,9 +1140,21 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, free(ufds); if(ret) *ret = retcode; + if(gotsocket && (extra_fds || curlfds)) + /* if any socket was checked */ + *gotsocket = TRUE; + return CURLM_OK; } +CURLMcode curl_multi_wait(struct Curl_multi *multi, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret) +{ + return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, NULL); +} /* * Curl_multi_connchanged() is called to tell that there is a connection in * this multi handle that has changed state (pipelining become possible, the @@ -1337,8 +1354,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLMcode rc; CURLcode result = CURLE_OK; struct SingleRequest *k; - time_t timeout_ms; - time_t recv_timeout_ms; + timediff_t timeout_ms; + timediff_t recv_timeout_ms; timediff_t send_timeout_ms; int control; @@ -1939,6 +1956,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, done = TRUE; } } + else if((CURLE_HTTP2_STREAM == result) && + Curl_h2_http_1_1_error(data->easy_conn)) { + CURLcode ret = Curl_retry_request(data->easy_conn, &newurl); + + infof(data, "Forcing HTTP/1.1 for NTLM"); + data->set.httpversion = CURL_HTTP_VERSION_1_1; + + if(!ret) + retry = (newurl)?TRUE:FALSE; + else + result = ret; + + if(retry) { + /* if we are to retry, set the result to OK and consider the + request as done */ + result = CURLE_OK; + done = TRUE; + } + } if(result) { /* @@ -2466,11 +2502,11 @@ void Curl_updatesocket(struct Curl_easy *data) * socket again and it gets the same file descriptor number. */ -void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) +void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s) { - if(conn->data) { + if(data) { /* if there's still an easy handle associated with this connection */ - struct Curl_multi *multi = conn->data->multi; + struct Curl_multi *multi = data->multi; if(multi) { /* this is set if this connection is part of a handle that is added to a multi handle, and only then this is necessary */ @@ -2478,7 +2514,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) if(entry) { if(multi->socket_cb) - multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, + multi->socket_cb(data, s, CURL_POLL_REMOVE, multi->socket_userp, entry->socketp); diff --git a/libs/libcurl/src/multiif.h b/libs/libcurl/src/multiif.h index c8fb5ca0d1..e44646bf9d 100644 --- a/libs/libcurl/src/multiif.h +++ b/libs/libcurl/src/multiif.h @@ -89,7 +89,7 @@ void Curl_multi_connchanged(struct Curl_multi *multi); * socket again and it gets the same file descriptor number. */ -void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); +void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s); /* * Add a handle and move it into PERFORM state at once. For pushed streams. @@ -97,4 +97,12 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, struct Curl_easy *data, struct connectdata *conn); + +CURLMcode Curl_multi_wait(struct Curl_multi *multi, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret, + bool *gotsocket); /* if any socket was checked */ + #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/libs/libcurl/src/netrc.c b/libs/libcurl/src/netrc.c index 1724b35b0b..aba355b760 100644 --- a/libs/libcurl/src/netrc.c +++ b/libs/libcurl/src/netrc.c @@ -53,6 +53,8 @@ enum host_lookup_state { int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, + bool *login_changed, + bool *password_changed, char *netrcfile) { FILE *file; @@ -164,7 +166,7 @@ int Curl_parsenetrc(const char *host, if(specific_login) { state_our_login = strcasecompare(login, tok); } - else { + else if(!login || strcmp(login, tok)) { if(login_alloc) { free(login); login_alloc = FALSE; @@ -179,7 +181,8 @@ int Curl_parsenetrc(const char *host, state_login = 0; } else if(state_password) { - if(state_our_login || !specific_login) { + if((state_our_login || !specific_login) + && (!password || strcmp(password, tok))) { if(password_alloc) { free(password); password_alloc = FALSE; @@ -211,15 +214,19 @@ int Curl_parsenetrc(const char *host, out: if(!retcode) { + *login_changed = FALSE; + *password_changed = FALSE; if(login_alloc) { if(*loginp) free(*loginp); *loginp = login; + *login_changed = TRUE; } if(password_alloc) { if(*passwordp) free(*passwordp); *passwordp = password; + *password_changed = TRUE; } } else { diff --git a/libs/libcurl/src/netrc.h b/libs/libcurl/src/netrc.h index d980166e6b..fe3dc357ec 100644 --- a/libs/libcurl/src/netrc.h +++ b/libs/libcurl/src/netrc.h @@ -26,6 +26,8 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, + bool *login_changed, + bool *password_changed, char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c index c6cb794343..bc007883e3 100644 --- a/libs/libcurl/src/openldap.c +++ b/libs/libcurl/src/openldap.c @@ -220,8 +220,8 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) ptr = hosturl + 4; if(conn->handler->flags & PROTOPT_SSL) *ptr++ = 's'; - snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", - conn->host.name, conn->remote_port); + msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", + conn->host.name, conn->remote_port); #ifdef CURL_OPENLDAP_DEBUG static int do_trace = 0; diff --git a/libs/libcurl/src/openssl.c b/libs/libcurl/src/openssl.c deleted file mode 100644 index 7e1b681b2b..0000000000 --- a/libs/libcurl/src/openssl.c +++ /dev/null @@ -1,3661 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - */ - -/* - * The original SSLeay-using code for curl was written by Linas Vepstas and - * Sampo Kellomaki 1998. - */ - -#include "curl_setup.h" - -#ifdef USE_OPENSSL - -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif - -#include "urldata.h" -#include "sendf.h" -#include "formdata.h" /* for the boundary function */ -#include "url.h" /* for the ssl config check function */ -#include "inet_pton.h" -#include "openssl.h" -#include "connect.h" -#include "slist.h" -#include "select.h" -#include "vtls/vtls.h" -#include "strcase.h" -#include "hostcheck.h" -#include "curl_printf.h" -#include <openssl/ssl.h> -#ifdef HAVE_OPENSSL_ENGINE_H -#include <openssl/engine.h> -#endif -#include <openssl/rand.h> -#include <openssl/x509v3.h> -#ifndef OPENSSL_NO_DSA -#include <openssl/dsa.h> -#endif -#include <openssl/dh.h> -#include <openssl/err.h> -#include <openssl/md5.h> -#include <openssl/conf.h> -#include <openssl/bn.h> -#include <openssl/rsa.h> -#include <openssl/bio.h> -#include <openssl/buffer.h> - -#ifndef OPENSSL_IS_BORINGSSL -/* BoringSSL does not support PKCS12 */ -#define HAVE_PKCS12_SUPPORT 1 -#include <openssl/pkcs12.h> -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) -#include <openssl/ocsp.h> -#endif - -#include "warnless.h" -#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */ - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef OPENSSL_VERSION_NUMBER -#error "OPENSSL_VERSION_NUMBER not defined" -#endif - -#if defined(HAVE_OPENSSL_ENGINE_H) -#include <openssl/ui.h> -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00909000L -#define SSL_METHOD_QUAL const -#else -#define SSL_METHOD_QUAL -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) -#define HAVE_ERR_REMOVE_THREAD_STATE 1 -#endif - -#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ - OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */ -#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */ -#define OPENSSL_NO_SSL2 -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ - !defined(LIBRESSL_VERSION_NUMBER) -#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER -#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ -#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ -#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ -#define CONST_EXTS const -#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 -#else -/* For OpenSSL before 1.1.0 */ -#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) -#define X509_get0_notBefore(x) X509_get_notBefore(x) -#define X509_get0_notAfter(x) X509_get_notAfter(x) -#define CONST_EXTS /* nope */ -#ifdef LIBRESSL_VERSION_NUMBER -static unsigned long OpenSSL_version_num(void) -{ - return LIBRESSL_VERSION_NUMBER; -} -#else -#define OpenSSL_version_num() SSLeay() -#endif -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ - !defined(LIBRESSL_VERSION_NUMBER) -#define HAVE_X509_GET0_SIGNATURE 1 -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ - OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ - !defined(OPENSSL_NO_COMP) -#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 -#endif - -#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) -/* not present in older OpenSSL */ -#define OPENSSL_load_builtin_modules(x) -#endif - -/* - * Whether SSL_CTX_set_keylog_callback is available. - * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 - * BoringSSL: supported since d28f59c27bac (committed 2015-11-19) - * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it - * lies and pretends to be OpenSSL 2.0.0). - */ -#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ - !defined(LIBRESSL_VERSION_NUMBER)) || \ - defined(OPENSSL_IS_BORINGSSL) -#define HAVE_KEYLOG_CALLBACK -#endif - -#if defined(LIBRESSL_VERSION_NUMBER) -#define OSSL_PACKAGE "LibreSSL" -#elif defined(OPENSSL_IS_BORINGSSL) -#define OSSL_PACKAGE "BoringSSL" -#else -#define OSSL_PACKAGE "OpenSSL" -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) -/* up2date versions of OpenSSL maintain the default reasonably secure without - * breaking compatibility, so it is better not to override the default by curl - */ -#define DEFAULT_CIPHER_SELECTION NULL -#else -/* ... but it is not the case with old versions of OpenSSL */ -#define DEFAULT_CIPHER_SELECTION \ - "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" -#endif - -#ifdef ENABLE_SSLKEYLOGFILE -typedef struct ssl_tap_state { - int master_key_length; - unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; - unsigned char client_random[SSL3_RANDOM_SIZE]; -} ssl_tap_state_t; -#endif /* ENABLE_SSLKEYLOGFILE */ - -struct ssl_backend_data { - /* these ones requires specific SSL-types */ - SSL_CTX* ctx; - SSL* handle; - X509* server_cert; -#ifdef ENABLE_SSLKEYLOGFILE - /* tap_state holds the last seen master key if we're logging them */ - ssl_tap_state_t tap_state; -#endif -}; - -#define BACKEND connssl->backend - -/* - * Number of bytes to read from the random number seed file. This must be - * a finite value (because some entropy "files" like /dev/urandom have - * an infinite length), but must be large enough to provide enough - * entropy to properly seed OpenSSL's PRNG. - */ -#define RAND_LOAD_LENGTH 1024 - -#ifdef ENABLE_SSLKEYLOGFILE -/* The fp for the open SSLKEYLOGFILE, or NULL if not open */ -static FILE *keylog_file_fp; - -#ifdef HAVE_KEYLOG_CALLBACK -static void ossl_keylog_callback(const SSL *ssl, const char *line) -{ - (void)ssl; - - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - if(keylog_file_fp && line && *line) { - char stackbuf[256]; - char *buf; - size_t linelen = strlen(line); - - if(linelen <= sizeof(stackbuf) - 2) - buf = stackbuf; - else { - buf = malloc(linelen + 2); - if(!buf) - return; - } - strncpy(buf, line, linelen); - buf[linelen] = '\n'; - buf[linelen + 1] = '\0'; - - fputs(buf, keylog_file_fp); - if(buf != stackbuf) - free(buf); - } -} -#else -#define KEYLOG_PREFIX "CLIENT_RANDOM " -#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1) -/* - * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL - * being used doesn't have native support for doing that. - */ -static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) -{ - const char *hex = "0123456789ABCDEF"; - int pos, i; - char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 + - 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1]; - const SSL_SESSION *session = SSL_get_session(ssl); - unsigned char client_random[SSL3_RANDOM_SIZE]; - unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; - int master_key_length = 0; - - if(!session || !keylog_file_fp) - return; - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that - * we have a valid SSL context if we have a non-NULL session. */ - SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); - master_key_length = - SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); -#else - if(ssl->s3 && session->master_key_length > 0) { - master_key_length = session->master_key_length; - memcpy(master_key, session->master_key, session->master_key_length); - memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE); - } -#endif - - if(master_key_length <= 0) - return; - - /* Skip writing keys if there is no key or it did not change. */ - if(state->master_key_length == master_key_length && - !memcmp(state->master_key, master_key, master_key_length) && - !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) { - return; - } - - state->master_key_length = master_key_length; - memcpy(state->master_key, master_key, master_key_length); - memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE); - - memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN); - pos = KEYLOG_PREFIX_LEN; - - /* Client Random for SSLv3/TLS */ - for(i = 0; i < SSL3_RANDOM_SIZE; i++) { - line[pos++] = hex[client_random[i] >> 4]; - line[pos++] = hex[client_random[i] & 0xF]; - } - line[pos++] = ' '; - - /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */ - for(i = 0; i < master_key_length; i++) { - line[pos++] = hex[master_key[i] >> 4]; - line[pos++] = hex[master_key[i] & 0xF]; - } - line[pos++] = '\n'; - line[pos] = '\0'; - - /* Using fputs here instead of fprintf since libcurl's fprintf replacement - may not be thread-safe. */ - fputs(line, keylog_file_fp); -} -#endif /* !HAVE_KEYLOG_CALLBACK */ -#endif /* ENABLE_SSLKEYLOGFILE */ - -static const char *SSL_ERROR_to_str(int err) -{ - switch(err) { - case SSL_ERROR_NONE: - return "SSL_ERROR_NONE"; - case SSL_ERROR_SSL: - return "SSL_ERROR_SSL"; - case SSL_ERROR_WANT_READ: - return "SSL_ERROR_WANT_READ"; - case SSL_ERROR_WANT_WRITE: - return "SSL_ERROR_WANT_WRITE"; - case SSL_ERROR_WANT_X509_LOOKUP: - return "SSL_ERROR_WANT_X509_LOOKUP"; - case SSL_ERROR_SYSCALL: - return "SSL_ERROR_SYSCALL"; - case SSL_ERROR_ZERO_RETURN: - return "SSL_ERROR_ZERO_RETURN"; - case SSL_ERROR_WANT_CONNECT: - return "SSL_ERROR_WANT_CONNECT"; - case SSL_ERROR_WANT_ACCEPT: - return "SSL_ERROR_WANT_ACCEPT"; -#if defined(SSL_ERROR_WANT_ASYNC) - case SSL_ERROR_WANT_ASYNC: - return "SSL_ERROR_WANT_ASYNC"; -#endif -#if defined(SSL_ERROR_WANT_ASYNC_JOB) - case SSL_ERROR_WANT_ASYNC_JOB: - return "SSL_ERROR_WANT_ASYNC_JOB"; -#endif -#if defined(SSL_ERROR_WANT_EARLY) - case SSL_ERROR_WANT_EARLY: - return "SSL_ERROR_WANT_EARLY"; -#endif - default: - return "SSL_ERROR unknown"; - } -} - -/* Return error string for last OpenSSL error - */ -static char *ossl_strerror(unsigned long error, char *buf, size_t size) -{ - ERR_error_string_n(error, buf, size); - return buf; -} - -static int passwd_callback(char *buf, int num, int encrypting, - void *global_passwd) -{ - DEBUGASSERT(0 == encrypting); - - if(!encrypting) { - int klen = curlx_uztosi(strlen((char *)global_passwd)); - if(num > klen) { - memcpy(buf, global_passwd, klen + 1); - return klen; - } - } - return 0; -} - -/* - * rand_enough() returns TRUE if we have seeded the random engine properly. - */ -static bool rand_enough(void) -{ - return (0 != RAND_status()) ? TRUE : FALSE; -} - -static CURLcode Curl_ossl_seed(struct Curl_easy *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - char fname[256]; - - if(ssl_seeded) - return CURLE_OK; - - if(rand_enough()) { - /* OpenSSL 1.1.0+ will return here */ - ssl_seeded = TRUE; - return CURLE_OK; - } - -#ifndef RANDOM_FILE - /* if RANDOM_FILE isn't defined, we only perform this if an option tells - us to! */ - if(data->set.str[STRING_SSL_RANDOM_FILE]) -#define RANDOM_FILE "" /* doesn't matter won't be used */ -#endif - { - /* let the option override the define */ - RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? - data->set.str[STRING_SSL_RANDOM_FILE]: - RANDOM_FILE), - RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; - } - -#if defined(HAVE_RAND_EGD) - /* only available in OpenSSL 0.9.5 and later */ - /* EGD_SOCKET is set at configure time or not at all */ -#ifndef EGD_SOCKET - /* If we don't have the define set, we only do this if the egd-option - is set */ - if(data->set.str[STRING_SSL_EGDSOCKET]) -#define EGD_SOCKET "" /* doesn't matter won't be used */ -#endif - { - /* If there's an option and a define, the option overrides the - define */ - int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? - data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); - if(-1 != ret) { - if(rand_enough()) - return CURLE_OK; - } - } -#endif - - /* fallback to a custom seeding of the PRNG using a hash based on a current - time */ - do { - unsigned char randb[64]; - size_t len = sizeof(randb); - size_t i, i_max; - for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { - struct curltime tv = Curl_now(); - Curl_wait_ms(1); - tv.tv_sec *= i + 1; - tv.tv_usec *= (unsigned int)i + 2; - tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) * - (i + 3)) << 8; - tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec + - Curl_now().tv_usec) * - (i + 4)) << 16; - memcpy(&randb[i * sizeof(struct curltime)], &tv, - sizeof(struct curltime)); - } - RAND_add(randb, (int)len, (double)len/2); - } while(!rand_enough()); - - /* generates a default path for the random seed file */ - fname[0] = 0; /* blank it first */ - RAND_file_name(fname, sizeof(fname)); - if(fname[0]) { - /* we got a file name to try */ - RAND_load_file(fname, RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; - } - - infof(data, "libcurl is now using a weak random seed!\n"); - return (rand_enough() ? CURLE_OK : - CURLE_SSL_CONNECT_ERROR /* confusing error code */); -} - -#ifndef SSL_FILETYPE_ENGINE -#define SSL_FILETYPE_ENGINE 42 -#endif -#ifndef SSL_FILETYPE_PKCS12 -#define SSL_FILETYPE_PKCS12 43 -#endif -static int do_file_type(const char *type) -{ - if(!type || !type[0]) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "PEM")) - return SSL_FILETYPE_PEM; - if(strcasecompare(type, "DER")) - return SSL_FILETYPE_ASN1; - if(strcasecompare(type, "ENG")) - return SSL_FILETYPE_ENGINE; - if(strcasecompare(type, "P12")) - return SSL_FILETYPE_PKCS12; - return -1; -} - -#if defined(HAVE_OPENSSL_ENGINE_H) -/* - * Supply default password to the engine user interface conversation. - * The password is passed by OpenSSL engine from ENGINE_load_private_key() - * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. - */ -static int ssl_ui_reader(UI *ui, UI_STRING *uis) -{ - const char *password; - switch(UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - password = (const char *)UI_get0_user_data(ui); - if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { - UI_set_result(ui, uis, password); - return 1; - } - default: - break; - } - return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); -} - -/* - * Suppress interactive request for a default password if available. - */ -static int ssl_ui_writer(UI *ui, UI_STRING *uis) -{ - switch(UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - if(UI_get0_user_data(ui) && - (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { - return 1; - } - default: - break; - } - return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); -} -#endif - -static -int cert_stuff(struct connectdata *conn, - SSL_CTX* ctx, - char *cert_file, - const char *cert_type, - char *key_file, - const char *key_type, - char *key_passwd) -{ - struct Curl_easy *data = conn->data; - char error_buffer[256]; - bool check_privkey = TRUE; - - int file_type = do_file_type(cert_type); - - if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { - SSL *ssl; - X509 *x509; - int cert_done = 0; - - if(key_passwd) { - /* set the password in the callback userdata */ - SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); - /* Set passwd callback: */ - SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); - } - - - switch(file_type) { - case SSL_FILETYPE_PEM: - /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if(SSL_CTX_use_certificate_chain_file(ctx, - cert_file) != 1) { - failf(data, - "could not load PEM client certificate, " OSSL_PACKAGE - " error %s, " - "(no key found, wrong pass phrase, or wrong file format?)", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - break; - - case SSL_FILETYPE_ASN1: - /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but - we use the case above for PEM so this can only be performed with - ASN1 files. */ - if(SSL_CTX_use_certificate_file(ctx, - cert_file, - file_type) != 1) { - failf(data, - "could not load ASN1 client certificate, " OSSL_PACKAGE - " error %s, " - "(no key found, wrong pass phrase, or wrong file format?)", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) - { - if(data->state.engine) { - const char *cmd_name = "LOAD_CERT_CTRL"; - struct { - const char *cert_id; - X509 *cert; - } params; - - params.cert_id = cert_file; - params.cert = NULL; - - /* Does the engine supports LOAD_CERT_CTRL ? */ - if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, (void *)cmd_name, NULL)) { - failf(data, "ssl engine does not support loading certificates"); - return 0; - } - - /* Load the certificate from the engine */ - if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, - 0, ¶ms, NULL, 1)) { - failf(data, "ssl engine cannot load client cert with id" - " '%s' [%s]", cert_file, - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - - if(!params.cert) { - failf(data, "ssl engine didn't initialized the certificate " - "properly."); - return 0; - } - - if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { - failf(data, "unable to set client certificate"); - X509_free(params.cert); - return 0; - } - X509_free(params.cert); /* we don't need the handle any more... */ - } - else { - failf(data, "crypto engine not set, can't load certificate"); - return 0; - } - } - break; -#else - failf(data, "file type ENG for certificate not implemented"); - return 0; -#endif - - case SSL_FILETYPE_PKCS12: - { -#ifdef HAVE_PKCS12_SUPPORT - FILE *f; - PKCS12 *p12; - EVP_PKEY *pri; - STACK_OF(X509) *ca = NULL; - - f = fopen(cert_file, "rb"); - if(!f) { - failf(data, "could not open PKCS12 file '%s'", cert_file); - return 0; - } - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); - - if(!p12) { - failf(data, "error reading PKCS12 file '%s'", cert_file); - return 0; - } - - PKCS12_PBE_add(); - - if(!PKCS12_parse(p12, key_passwd, &pri, &x509, - &ca)) { - failf(data, - "could not parse PKCS12 file, check password, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - PKCS12_free(p12); - return 0; - } - - PKCS12_free(p12); - - if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, - "could not load PKCS12 client certificate, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - goto fail; - } - - if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { - failf(data, "unable to use private key from PKCS12 file '%s'", - cert_file); - goto fail; - } - - if(!SSL_CTX_check_private_key (ctx)) { - failf(data, "private key from PKCS12 file '%s' " - "does not match certificate in same file", cert_file); - goto fail; - } - /* Set Certificate Verification chain */ - if(ca) { - while(sk_X509_num(ca)) { - /* - * Note that sk_X509_pop() is used below to make sure the cert is - * removed from the stack properly before getting passed to - * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously - * we used sk_X509_value() instead, but then we'd clean it in the - * subsequent sk_X509_pop_free() call. - */ - X509 *x = sk_X509_pop(ca); - if(!SSL_CTX_add_client_CA(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to client CA list"); - goto fail; - } - if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to certificate chain"); - goto fail; - } - } - } - - cert_done = 1; - fail: - EVP_PKEY_free(pri); - X509_free(x509); - sk_X509_pop_free(ca, X509_free); - - if(!cert_done) - return 0; /* failure! */ - break; -#else - failf(data, "file type P12 for certificate not supported"); - return 0; -#endif - } - default: - failf(data, "not supported file type '%s' for certificate", cert_type); - return 0; - } - - file_type = do_file_type(key_type); - - switch(file_type) { - case SSL_FILETYPE_PEM: - if(cert_done) - break; - if(!key_file) - /* cert & key can only be in PEM case in the same file */ - key_file = cert_file; - /* FALLTHROUGH */ - case SSL_FILETYPE_ASN1: - if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { - failf(data, "unable to set private key file: '%s' type %s", - key_file, key_type?key_type:"PEM"); - return 0; - } - break; - case SSL_FILETYPE_ENGINE: -#ifdef HAVE_OPENSSL_ENGINE_H - { /* XXXX still needs some work */ - EVP_PKEY *priv_key = NULL; - if(data->state.engine) { - UI_METHOD *ui_method = - UI_create_method((char *)"curl user interface"); - if(!ui_method) { - failf(data, "unable do create " OSSL_PACKAGE - " user-interface method"); - return 0; - } - UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); - UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); - UI_method_set_reader(ui_method, ssl_ui_reader); - UI_method_set_writer(ui_method, ssl_ui_writer); - /* the typecast below was added to please mingw32 */ - priv_key = (EVP_PKEY *) - ENGINE_load_private_key(data->state.engine, key_file, - ui_method, - key_passwd); - UI_destroy_method(ui_method); - if(!priv_key) { - failf(data, "failed to load private key from crypto engine"); - return 0; - } - if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { - failf(data, "unable to set private key"); - EVP_PKEY_free(priv_key); - return 0; - } - EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ - } - else { - failf(data, "crypto engine not set, can't load private key"); - return 0; - } - } - break; -#else - failf(data, "file type ENG for private key not supported"); - return 0; -#endif - case SSL_FILETYPE_PKCS12: - if(!cert_done) { - failf(data, "file type P12 for private key not supported"); - return 0; - } - break; - default: - failf(data, "not supported file type for private key"); - return 0; - } - - ssl = SSL_new(ctx); - if(!ssl) { - failf(data, "unable to create an SSL structure"); - return 0; - } - - x509 = SSL_get_certificate(ssl); - - /* This version was provided by Evan Jordan and is supposed to not - leak memory as the previous version: */ - if(x509) { - EVP_PKEY *pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); - EVP_PKEY_free(pktmp); - } - -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) - { - /* If RSA is used, don't check the private key if its flags indicate - * it doesn't support it. */ - EVP_PKEY *priv_key = SSL_get_privatekey(ssl); - int pktype; -#ifdef HAVE_OPAQUE_EVP_PKEY - pktype = EVP_PKEY_id(priv_key); -#else - pktype = priv_key->type; -#endif - if(pktype == EVP_PKEY_RSA) { - RSA *rsa = EVP_PKEY_get1_RSA(priv_key); - if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK) - check_privkey = FALSE; - RSA_free(rsa); /* Decrement reference count */ - } - } -#endif - - SSL_free(ssl); - - /* If we are using DSA, we can copy the parameters from - * the private key */ - - if(check_privkey == TRUE) { - /* Now we know that a key and cert have been set against - * the SSL context */ - if(!SSL_CTX_check_private_key(ctx)) { - failf(data, "Private key does not match the certificate public key"); - return 0; - } - } - } - return 1; -} - -/* returns non-zero on failure */ -static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) -{ -#if 0 - return X509_NAME_oneline(a, buf, size); -#else - BIO *bio_out = BIO_new(BIO_s_mem()); - BUF_MEM *biomem; - int rc; - - if(!bio_out) - return 1; /* alloc failed! */ - - rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); - BIO_get_mem_ptr(bio_out, &biomem); - - if((size_t)biomem->length < size) - size = biomem->length; - else - size--; /* don't overwrite the buffer end */ - - memcpy(buf, biomem->data, size); - buf[size] = 0; - - BIO_free(bio_out); - - return !rc; -#endif -} - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -static int Curl_ossl_init(void) -{ -#ifdef ENABLE_SSLKEYLOGFILE - const char *keylog_file_name; -#endif - - OPENSSL_load_builtin_modules(); - -#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES - ENGINE_load_builtin_engines(); -#endif - - /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately - that function makes an exit() call on wrongly formatted config files - which makes it hard to use in some situations. OPENSSL_config() itself - calls CONF_modules_load_file() and we use that instead and we ignore - its return code! */ - - /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and - 0.9.8e */ -#ifndef CONF_MFLAGS_DEFAULT_SECTION -#define CONF_MFLAGS_DEFAULT_SECTION 0x0 -#endif - - CONF_modules_load_file(NULL, NULL, - CONF_MFLAGS_DEFAULT_SECTION| - CONF_MFLAGS_IGNORE_MISSING_FILE); - -#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(); - - /* Init the global ciphers and digests */ - if(!SSLeay_add_ssl_algorithms()) - return 0; - - OpenSSL_add_all_algorithms(); -#endif - -#ifdef ENABLE_SSLKEYLOGFILE - keylog_file_name = curl_getenv("SSLKEYLOGFILE"); - if(keylog_file_name && !keylog_file_fp) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); - if(keylog_file_fp) { - if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } - } - } -#endif - - return 1; -} - -/* Global cleanup */ -static void Curl_ossl_cleanup(void) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) - /* OpenSSL 1.1 deprecates all these cleanup functions and - turns them into no-ops in OpenSSL 1.0 compatibility mode */ -#else - /* Free ciphers and digests lists */ - EVP_cleanup(); - -#ifdef HAVE_ENGINE_CLEANUP - /* Free engine list */ - ENGINE_cleanup(); -#endif - - /* Free OpenSSL error strings */ - ERR_free_strings(); - - /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE - ERR_remove_thread_state(NULL); -#else - ERR_remove_state(0); -#endif - - /* Free all memory allocated by all configuration modules */ - CONF_modules_free(); - -#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS - SSL_COMP_free_compression_methods(); -#endif -#endif - -#ifdef ENABLE_SSLKEYLOGFILE - if(keylog_file_fp) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; - } -#endif -} - -/* - * This function is used to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_ossl_check_cxn(struct connectdata *conn) -{ - /* SSL_peek takes data out of the raw recv buffer without peeking so we use - recv MSG_PEEK instead. Bug #795 */ -#ifdef MSG_PEEK - char buf; - ssize_t nread; - nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); - if(nread == 0) - return 0; /* connection has been closed */ - if(nread == 1) - return 1; /* connection still in place */ - else if(nread == -1) { - int err = SOCKERRNO; - if(err == EINPROGRESS || -#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) - err == EAGAIN || -#endif - err == EWOULDBLOCK) - return 1; /* connection still in place */ - if(err == ECONNRESET || -#ifdef ECONNABORTED - err == ECONNABORTED || -#endif -#ifdef ENETDOWN - err == ENETDOWN || -#endif -#ifdef ENETRESET - err == ENETRESET || -#endif -#ifdef ESHUTDOWN - err == ESHUTDOWN || -#endif -#ifdef ETIMEDOUT - err == ETIMEDOUT || -#endif - err == ENOTCONN) - return 0; /* connection has been closed */ - } -#endif - return -1; /* connection status unknown */ -} - -/* Selects an OpenSSL crypto engine - */ -static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, - const char *engine) -{ -#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *e; - -#if OPENSSL_VERSION_NUMBER >= 0x00909000L - e = ENGINE_by_id(engine); -#else - /* avoid memory leak */ - for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - const char *e_id = ENGINE_get_id(e); - if(!strcmp(engine, e_id)) - break; - } -#endif - - if(!e) { - failf(data, "SSL Engine '%s' not found", engine); - return CURLE_SSL_ENGINE_NOTFOUND; - } - - if(data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } - if(!ENGINE_init(e)) { - char buf[256]; - - ENGINE_free(e); - failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); - return CURLE_SSL_ENGINE_INITFAILED; - } - data->state.engine = e; - return CURLE_OK; -#else - (void)engine; - failf(data, "SSL Engine not supported"); - return CURLE_SSL_ENGINE_NOTFOUND; -#endif -} - -/* Sets engine as default for all SSL operations - */ -static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if(data->state.engine) { - if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { - infof(data, "set default crypto engine '%s'\n", - ENGINE_get_id(data->state.engine)); - } - else { - failf(data, "set default crypto engine '%s' failed", - ENGINE_get_id(data->state.engine)); - return CURLE_SSL_ENGINE_SETFAILED; - } - } -#else - (void) data; -#endif - return CURLE_OK; -} - -/* Return list of OpenSSL crypto engine names. - */ -static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) -{ - struct curl_slist *list = NULL; -#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg; - ENGINE *e; - - for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - beg = curl_slist_append(list, ENGINE_get_id(e)); - if(!beg) { - curl_slist_free_all(list); - return NULL; - } - list = beg; - } -#endif - (void) data; - return list; -} - - -static void ossl_close(struct ssl_connect_data *connssl) -{ - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_set_connect_state(BACKEND->handle); - - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; - } -} - -/* - * This function is called when an SSL connection is closed. - */ -static void Curl_ossl_close(struct connectdata *conn, int sockindex) -{ - ossl_close(&conn->ssl[sockindex]); - ossl_close(&conn->proxy_ssl[sockindex]); -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) -{ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - char buf[256]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 256 bytes long. */ - unsigned long sslerror; - ssize_t nread; - int buffsize; - int err; - int done = 0; - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(BACKEND->handle); - - if(BACKEND->handle) { - buffsize = (int)sizeof(buf); - while(!done) { - int what = SOCKET_READABLE(conn->sock[sockindex], - SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - ERR_clear_error(); - - /* Something to read, let's do it and hope that it is the close - notify alert from the server */ - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); - err = SSL_get_error(BACKEND->handle, (int)nread); - - switch(err) { - case SSL_ERROR_NONE: /* this is not an error */ - case SSL_ERROR_ZERO_RETURN: /* no more data */ - /* This is the expected response. There was no data but only - the close notify alert */ - done = 1; - break; - case SSL_ERROR_WANT_READ: - /* there's data pending, re-invoke SSL_read() */ - infof(data, "SSL_ERROR_WANT_READ\n"); - break; - case SSL_ERROR_WANT_WRITE: - /* SSL wants a write. Really odd. Let's bail out. */ - infof(data, "SSL_ERROR_WANT_WRITE\n"); - done = 1; - break; - default: - /* openssl/ssl.h says "look at error stack/return value/errno" */ - sslerror = ERR_get_error(); - failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d", - (sslerror ? - ossl_strerror(sslerror, buf, sizeof(buf)) : - SSL_ERROR_to_str(err)), - SOCKERRNO); - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - done = 1; - } - } /* while()-loop for the select() */ - - if(data->set.verbose) { -#ifdef HAVE_SSL_GET_SHUTDOWN - switch(SSL_get_shutdown(BACKEND->handle)) { - case SSL_SENT_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); - break; - case SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); - break; - case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" - "SSL_RECEIVED__SHUTDOWN\n"); - break; - } -#endif - } - - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; - } - return retval; -} - -static void Curl_ossl_session_free(void *ptr) -{ - /* free the ID */ - SSL_SESSION_free(ptr); -} - -/* - * This function is called when the 'data' struct is going away. Close - * down everything and free all resources! - */ -static void Curl_ossl_close_all(struct Curl_easy *data) -{ -#ifdef HAVE_OPENSSL_ENGINE_H - if(data->state.engine) { - ENGINE_finish(data->state.engine); - ENGINE_free(data->state.engine); - data->state.engine = NULL; - } -#else - (void)data; -#endif -#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ - defined(HAVE_ERR_REMOVE_THREAD_STATE) - /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread - so we need to clean it here in case the thread will be killed. All OpenSSL - code should extract the error in association with the error so clearing - this queue here should be harmless at worst. */ - ERR_remove_thread_state(NULL); -#endif -} - -/* ====================================================== */ - - -/* Quote from RFC2818 section 3.1 "Server Identity" - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - Certification Authorities are encouraged to use the dNSName instead. - - Matching is performed using the matching rules specified by - [RFC2459]. If more than one identity of a given type is present in - the certificate (e.g., more than one dNSName name, a match in any one - of the set is considered acceptable.) Names may contain the wildcard - character * which is considered to match any single domain name - component or component fragment. E.g., *.a.com matches foo.a.com but - not bar.foo.a.com. f*.com matches foo.com but not bar.com. - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. - -*/ -static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) -{ - bool matched = FALSE; - int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ - size_t addrlen = 0; - struct Curl_easy *data = conn->data; - STACK_OF(GENERAL_NAME) *altnames; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - CURLcode result = CURLE_OK; - bool dNSName = FALSE; /* if a dNSName field exists in the cert */ - bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - -#ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, hostname, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in6_addr); - } - else -#endif - if(Curl_inet_pton(AF_INET, hostname, &addr)) { - target = GEN_IPADD; - addrlen = sizeof(struct in_addr); - } - - /* get a "list" of alternative names */ - altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); - - if(altnames) { - int numalts; - int i; - bool dnsmatched = FALSE; - bool ipmatched = FALSE; - - /* get amount of alternatives, RFC2459 claims there MUST be at least - one, but we don't depend on it... */ - numalts = sk_GENERAL_NAME_num(altnames); - - /* loop through all alternatives - until a dnsmatch */ - for(i = 0; (i < numalts) && !dnsmatched; i++) { - /* get a handle to alternative name number i */ - const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); - - if(check->type == GEN_DNS) - dNSName = TRUE; - else if(check->type == GEN_IPADD) - iPAddress = TRUE; - - /* only check alternatives of the same type the target is */ - if(check->type == target) { - /* get data and length */ - const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); - size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); - - switch(target) { - case GEN_DNS: /* name/pattern comparison */ - /* The OpenSSL man page explicitly says: "In general it cannot be - assumed that the data returned by ASN1_STRING_data() is null - terminated or does not contain embedded nulls." But also that - "The actual format of the data will depend on the actual string - type itself: for example for and IA5String the data will be ASCII" - - Gisle researched the OpenSSL sources: - "I checked the 0.9.6 and 0.9.8 sources before my patch and - it always 0-terminates an IA5String." - */ - if((altlen == strlen(altptr)) && - /* if this isn't true, there was an embedded zero in the name - string and we cannot match it. */ - Curl_cert_hostcheck(altptr, hostname)) { - dnsmatched = TRUE; - infof(data, - " subjectAltName: host \"%s\" matched cert's \"%s\"\n", - dispname, altptr); - } - break; - - case GEN_IPADD: /* IP address comparison */ - /* compare alternative IP address if the data chunk is the same size - our server IP address is */ - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { - ipmatched = TRUE; - infof(data, - " subjectAltName: host \"%s\" matched cert's IP address!\n", - dispname); - } - break; - } - } - } - GENERAL_NAMES_free(altnames); - - if(dnsmatched || ipmatched) - matched = TRUE; - } - - if(matched) - /* an alternative name matched */ - ; - else if(dNSName || iPAddress) { - infof(data, " subjectAltName does not match %s\n", dispname); - failf(data, "SSL: no alternative certificate subject name matches " - "target host name '%s'", dispname); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else { - /* we have to look to the last occurrence of a commonName in the - distinguished one to get the most significant one. */ - int j, i = -1; - - /* The following is done because of a bug in 0.9.6b */ - - unsigned char *nulstr = (unsigned char *)""; - unsigned char *peer_CN = nulstr; - - X509_NAME *name = X509_get_subject_name(server_cert); - if(name) - while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) - i = j; - - /* we have the name entry and we will now convert this to a string - that we can use for comparison. Doing this we support BMPstring, - UTF8 etc. */ - - if(i >= 0) { - ASN1_STRING *tmp = - X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); - - /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input - is already UTF-8 encoded. We check for this case and copy the raw - string manually to avoid the problem. This code can be made - conditional in the future when OpenSSL has been fixed. Work-around - brought by Alexis S. L. Carvalho. */ - if(tmp) { - if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { - j = ASN1_STRING_length(tmp); - if(j >= 0) { - peer_CN = OPENSSL_malloc(j + 1); - if(peer_CN) { - memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); - peer_CN[j] = '\0'; - } - } - } - else /* not a UTF8 name */ - j = ASN1_STRING_to_UTF8(&peer_CN, tmp); - - if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) { - /* there was a terminating zero before the end of string, this - cannot match and we return failure! */ - failf(data, "SSL: illegal cert name field"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - } - } - - if(peer_CN == nulstr) - peer_CN = NULL; - else { - /* convert peer_CN from UTF8 */ - CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN, - strlen((char *)peer_CN)); - /* Curl_convert_from_utf8 calls failf if unsuccessful */ - if(rc) { - OPENSSL_free(peer_CN); - return rc; - } - } - - if(result) - /* error already detected, pass through */ - ; - else if(!peer_CN) { - failf(data, - "SSL: unable to obtain common name from peer certificate"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, dispname); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else { - infof(data, " common name: %s (matched)\n", peer_CN); - } - if(peer_CN) - OPENSSL_free(peer_CN); - } - - return result; -} - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) -static CURLcode verifystatus(struct connectdata *conn, - struct ssl_connect_data *connssl) -{ - int i, ocsp_status; - const unsigned char *p; - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - - OCSP_RESPONSE *rsp = NULL; - OCSP_BASICRESP *br = NULL; - X509_STORE *st = NULL; - STACK_OF(X509) *ch = NULL; - - long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p); - - if(!p) { - failf(data, "No OCSP response received"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - rsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if(!rsp) { - failf(data, "Invalid OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - ocsp_status = OCSP_response_status(rsp); - if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - failf(data, "Invalid OCSP response status: %s (%d)", - OCSP_response_status_str(ocsp_status), ocsp_status); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - br = OCSP_response_get1_basic(rsp); - if(!br) { - failf(data, "Invalid OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - - ch = SSL_get_peer_cert_chain(BACKEND->handle); - st = SSL_CTX_get_cert_store(BACKEND->ctx); - -#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) - /* The authorized responder cert in the OCSP response MUST be signed by the - peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, - no problem, but if it's an intermediate cert OpenSSL has a bug where it - expects this issuer to be present in the chain embedded in the OCSP - response. So we add it if necessary. */ - - /* First make sure the peer cert chain includes both a peer and an issuer, - and the OCSP response contains a responder cert. */ - if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { - X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); - - /* Find issuer of responder cert and add it to the OCSP response chain */ - for(i = 0; i < sk_X509_num(ch); i++) { - X509 *issuer = sk_X509_value(ch, i); - if(X509_check_issued(issuer, responder) == X509_V_OK) { - if(!OCSP_basic_add1_cert(br, issuer)) { - failf(data, "Could not add issuer cert to OCSP response"); - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - } - } - } -#endif - - if(OCSP_basic_verify(br, ch, st, 0) <= 0) { - failf(data, "OCSP response verification failed"); - result = CURLE_SSL_INVALIDCERTSTATUS; - 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; - } - - 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: - result = CURLE_SSL_INVALIDCERTSTATUS; - goto end; - } - } - -end: - if(br) OCSP_BASICRESP_free(br); - OCSP_RESPONSE_free(rsp); - - return result; -} -#endif - -#endif /* USE_OPENSSL */ - -/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions - and thus this cannot be done there. */ -#ifdef SSL_CTRL_SET_MSG_CALLBACK - -static const char *ssl_msg_type(int ssl_ver, int msg) -{ -#ifdef SSL2_VERSION_MAJOR - if(ssl_ver == SSL2_VERSION_MAJOR) { - switch(msg) { - case SSL2_MT_ERROR: - return "Error"; - case SSL2_MT_CLIENT_HELLO: - return "Client hello"; - case SSL2_MT_CLIENT_MASTER_KEY: - return "Client key"; - case SSL2_MT_CLIENT_FINISHED: - return "Client finished"; - case SSL2_MT_SERVER_HELLO: - return "Server hello"; - case SSL2_MT_SERVER_VERIFY: - return "Server verify"; - case SSL2_MT_SERVER_FINISHED: - return "Server finished"; - case SSL2_MT_REQUEST_CERTIFICATE: - return "Request CERT"; - case SSL2_MT_CLIENT_CERTIFICATE: - return "Client CERT"; - } - } - else -#endif - if(ssl_ver == SSL3_VERSION_MAJOR) { - switch(msg) { - case SSL3_MT_HELLO_REQUEST: - return "Hello request"; - case SSL3_MT_CLIENT_HELLO: - return "Client hello"; - case SSL3_MT_SERVER_HELLO: - return "Server hello"; -#ifdef SSL3_MT_NEWSESSION_TICKET - case SSL3_MT_NEWSESSION_TICKET: - return "Newsession Ticket"; -#endif - case SSL3_MT_CERTIFICATE: - return "Certificate"; - case SSL3_MT_SERVER_KEY_EXCHANGE: - return "Server key exchange"; - case SSL3_MT_CLIENT_KEY_EXCHANGE: - return "Client key exchange"; - case SSL3_MT_CERTIFICATE_REQUEST: - return "Request CERT"; - case SSL3_MT_SERVER_DONE: - return "Server finished"; - case SSL3_MT_CERTIFICATE_VERIFY: - return "CERT verify"; - case SSL3_MT_FINISHED: - return "Finished"; -#ifdef SSL3_MT_CERTIFICATE_STATUS - case SSL3_MT_CERTIFICATE_STATUS: - return "Certificate Status"; -#endif - } - } - return "Unknown"; -} - -static const char *tls_rt_type(int type) -{ - switch(type) { -#ifdef SSL3_RT_HEADER - case SSL3_RT_HEADER: - return "TLS header"; -#endif - case SSL3_RT_CHANGE_CIPHER_SPEC: - return "TLS change cipher"; - case SSL3_RT_ALERT: - return "TLS alert"; - case SSL3_RT_HANDSHAKE: - return "TLS handshake"; - case SSL3_RT_APPLICATION_DATA: - return "TLS app data"; - default: - return "TLS Unknown"; - } -} - - -/* - * Our callback from the SSL/TLS layers. - */ -static void ssl_tls_trace(int direction, int ssl_ver, int content_type, - const void *buf, size_t len, SSL *ssl, - void *userp) -{ - struct Curl_easy *data; - const char *msg_name, *tls_rt_name; - char ssl_buf[1024]; - char unknown[32]; - int msg_type, txt_len; - const char *verstr = NULL; - struct connectdata *conn = userp; - - if(!conn || !conn->data || !conn->data->set.fdebug || - (direction != 0 && direction != 1)) - return; - - data = conn->data; - - switch(ssl_ver) { -#ifdef SSL2_VERSION /* removed in recent versions */ - case SSL2_VERSION: - verstr = "SSLv2"; - break; -#endif -#ifdef SSL3_VERSION - case SSL3_VERSION: - verstr = "SSLv3"; - break; -#endif - case TLS1_VERSION: - verstr = "TLSv1.0"; - break; -#ifdef TLS1_1_VERSION - case TLS1_1_VERSION: - verstr = "TLSv1.1"; - break; -#endif -#ifdef TLS1_2_VERSION - case TLS1_2_VERSION: - verstr = "TLSv1.2"; - break; -#endif -#ifdef TLS1_3_VERSION - case TLS1_3_VERSION: - verstr = "TLSv1.3"; - break; -#endif - case 0: - break; - default: - snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); - verstr = unknown; - break; - } - - if(ssl_ver) { - /* the info given when the version is zero is not that useful for us */ - - ssl_ver >>= 8; /* check the upper 8 bits only below */ - - /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL - * always pass-up content-type as 0. But the interesting message-type - * is at 'buf[0]'. - */ - if(ssl_ver == SSL3_VERSION_MAJOR && content_type) - tls_rt_name = tls_rt_type(content_type); - else - tls_rt_name = ""; - - msg_type = *(char *)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); - - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", - verstr, direction?"OUT":"IN", - tls_rt_name, msg_name, msg_type); - Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); - } - - Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : - CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); - (void) ssl; -} -#endif - -#ifdef USE_OPENSSL -/* ====================================================== */ - -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -# define use_sni(x) sni = (x) -#else -# define use_sni(x) Curl_nop_stmt -#endif - -/* Check for OpenSSL 1.0.2 which has ALPN support. */ -#undef HAS_ALPN -#if OPENSSL_VERSION_NUMBER >= 0x10002000L \ - && !defined(OPENSSL_NO_TLSEXT) -# define HAS_ALPN 1 -#endif - -/* Check for OpenSSL 1.0.1 which has NPN support. */ -#undef HAS_NPN -#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ - && !defined(OPENSSL_NO_TLSEXT) \ - && !defined(OPENSSL_NO_NEXTPROTONEG) -# define HAS_NPN 1 -#endif - -#ifdef HAS_NPN - -/* - * in is a list of length prefixed strings. this function has to select - * the protocol we want to use from the list and write its string into out. - */ - -static int -select_next_protocol(unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const char *key, unsigned int keylen) -{ - unsigned int i; - for(i = 0; i + keylen <= inlen; i += in[i] + 1) { - if(memcmp(&in[i + 1], key, keylen) == 0) { - *out = (unsigned char *) &in[i + 1]; - *outlen = in[i]; - return 0; - } - } - return -1; -} - -static int -select_next_proto_cb(SSL *ssl, - unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - void *arg) -{ - struct connectdata *conn = (struct connectdata*) arg; - - (void)ssl; - -#ifdef USE_NGHTTP2 - if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && - !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN)) { - infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", - NGHTTP2_PROTO_VERSION_ID); - conn->negnpn = CURL_HTTP_VERSION_2; - return SSL_TLSEXT_ERR_OK; - } -#endif - - if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH)) { - infof(conn->data, "NPN, negotiated HTTP1.1\n"); - conn->negnpn = CURL_HTTP_VERSION_1_1; - return SSL_TLSEXT_ERR_OK; - } - - infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); - *out = (unsigned char *)ALPN_HTTP_1_1; - *outlen = ALPN_HTTP_1_1_LENGTH; - conn->negnpn = CURL_HTTP_VERSION_1_1; - - return SSL_TLSEXT_ERR_OK; -} -#endif /* HAS_NPN */ - -static const char * -get_ssl_version_txt(SSL *ssl) -{ - if(!ssl) - return ""; - - switch(SSL_version(ssl)) { -#ifdef TLS1_3_VERSION - case TLS1_3_VERSION: - return "TLSv1.3"; -#endif -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - case TLS1_2_VERSION: - return "TLSv1.2"; - case TLS1_1_VERSION: - return "TLSv1.1"; -#endif - case TLS1_VERSION: - return "TLSv1.0"; - case SSL3_VERSION: - return "SSLv3"; - case SSL2_VERSION: - return "SSLv2"; - } - return "unknown"; -} - -static CURLcode -set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, - int sockindex) -{ -#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION) - /* convoluted #if condition just to avoid compiler warnings on unused - variable */ - struct Curl_easy *data = conn->data; -#endif - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - - if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { - ssl_version_max = ssl_version << 16; - } - - switch(ssl_version) { - case CURL_SSLVERSION_TLSv1_3: -#ifdef TLS1_3_VERSION - { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); - *ctx_options |= SSL_OP_NO_TLSv1_2; - } -#else - (void)sockindex; - failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_2: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_1; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_1: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); - return CURLE_NOT_BUILT_IN; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_TLSv1_0: - *ctx_options |= SSL_OP_NO_SSLv2; - *ctx_options |= SSL_OP_NO_SSLv3; - break; - } - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_TLSv1_0: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_1; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_MAX_TLSv1_1: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - *ctx_options |= SSL_OP_NO_TLSv1_2; -#endif - /* FALLTHROUGH */ - case CURL_SSLVERSION_MAX_TLSv1_2: - case CURL_SSLVERSION_MAX_DEFAULT: -#ifdef TLS1_3_VERSION - *ctx_options |= SSL_OP_NO_TLSv1_3; -#endif - break; - case CURL_SSLVERSION_MAX_TLSv1_3: -#ifdef TLS1_3_VERSION - break; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); - return CURLE_NOT_BUILT_IN; -#endif - } - return CURLE_OK; -} - -static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - char *ciphers; - struct Curl_easy *data = conn->data; - SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; - X509_LOOKUP *lookup = NULL; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long ctx_options = 0; -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - bool sni; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif -#endif - long * const certverifyresult = SSL_IS_PROXY() ? - &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); -#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); - char error_buffer[256]; - - DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); - - /* Make funny stuff to get random input */ - result = Curl_ossl_seed(data); - if(result) - return result; - - *certverifyresult = !X509_V_OK; - - /* check to see if we've been told to use an explicit SSL/TLS version */ - - switch(ssl_version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - /* it will be handled later with the context options */ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) - req_method = TLS_client_method(); -#else - req_method = SSLv23_client_method(); -#endif - use_sni(TRUE); - break; - case CURL_SSLVERSION_SSLv2: -#ifdef OPENSSL_NO_SSL2 - failf(data, OSSL_PACKAGE " was built without SSLv2 support"); - return CURLE_NOT_BUILT_IN; -#else -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) - return CURLE_SSL_CONNECT_ERROR; -#endif - req_method = SSLv2_client_method(); - use_sni(FALSE); - break; -#endif - case CURL_SSLVERSION_SSLv3: -#ifdef OPENSSL_NO_SSL3_METHOD - failf(data, OSSL_PACKAGE " was built without SSLv3 support"); - return CURLE_NOT_BUILT_IN; -#else -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) - return CURLE_SSL_CONNECT_ERROR; -#endif - req_method = SSLv3_client_method(); - use_sni(FALSE); - break; -#endif - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); - - if(!BACKEND->ctx) { - failf(data, "SSL: couldn't create a context: %s", - ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); - return CURLE_OUT_OF_MEMORY; - } - -#ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS); -#endif - -#ifdef SSL_CTRL_SET_MSG_CALLBACK - if(data->set.fdebug && data->set.verbose) { - /* the SSL trace callback is only used for verbose logging */ - SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace); - SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn); - } -#endif - - /* OpenSSL contains code to work-around lots of bugs and flaws in various - SSL-implementations. SSL_CTX_set_options() is used to enabled those - work-arounds. The man page for this option states that SSL_OP_ALL enables - all the work-arounds and that "It is usually safe to use SSL_OP_ALL to - enable the bug workaround options if compatibility with somewhat broken - implementations is desired." - - The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to - disable "rfc4507bis session ticket support". rfc4507bis was later turned - into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 - - The enabled extension concerns the session management. I wonder how often - libcurl stops a connection and then resumes a TLS session. also, sending - the session data is some overhead. .I suggest that you just use your - proposed patch (which explicitly disables TICKET). - - If someone writes an application with libcurl and openssl who wants to - enable the feature, one can do this in the SSL callback. - - SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper - interoperability with web server Netscape Enterprise Server 2.0.1 which - was released back in 1996. - - Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has - become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate - CVE-2010-4180 when using previous OpenSSL versions we no longer enable - this option regardless of OpenSSL version and SSL_OP_ALL definition. - - OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability - (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to - SSL_OP_ALL that _disables_ that work-around despite the fact that - SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to - keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit - must not be set. - */ - - ctx_options = SSL_OP_ALL; - -#ifdef SSL_OP_NO_TICKET - ctx_options |= SSL_OP_NO_TICKET; -#endif - -#ifdef SSL_OP_NO_COMPRESSION - ctx_options |= SSL_OP_NO_COMPRESSION; -#endif - -#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG - /* mitigate CVE-2010-4180 */ - ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; -#endif - -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - /* unless the user explicitly ask to allow the protocol vulnerability we - use the work-around */ - if(!SSL_SET_OPTION(enable_beast)) - ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; -#endif - - switch(ssl_version) { - case CURL_SSLVERSION_SSLv3: -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) { - infof(data, "Set version TLSv1.x for SRP authorisation\n"); - } -#endif - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_TLSv1; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif -#endif - break; - - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; - break; - - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - result = set_ssl_version_min_max(&ctx_options, conn, sockindex); - if(result != CURLE_OK) - return result; - break; - - case CURL_SSLVERSION_SSLv2: -#ifndef OPENSSL_NO_SSL2 - ctx_options |= SSL_OP_NO_SSLv3; - ctx_options |= SSL_OP_NO_TLSv1; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif -#endif - break; -#else - failf(data, OSSL_PACKAGE " was built without SSLv2 support"); - return CURLE_NOT_BUILT_IN; -#endif - - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - SSL_CTX_set_options(BACKEND->ctx, ctx_options); - -#ifdef HAS_NPN - if(conn->bits.tls_enable_npn) - SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn); -#endif - -#ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { - int cur = 0; - unsigned char protocols[128]; - -#ifdef USE_NGHTTP2 - if(data->set.httpversion >= CURL_HTTP_VERSION_2 && - (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; - - memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN); - cur += NGHTTP2_PROTO_VERSION_ID_LEN; - infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); - } -#endif - - protocols[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - - /* expects length prefixed preference ordered list of protocols in wire - * format - */ - SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); - } -#endif - - if(ssl_cert || ssl_cert_type) { - if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type, - SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), - SSL_SET_OPTION(key_passwd))) { - /* failf() is already done in cert_stuff() */ - return CURLE_SSL_CERTPROBLEM; - } - } - - ciphers = SSL_CONN_CONFIG(cipher_list); - if(!ciphers) - ciphers = (char *)DEFAULT_CIPHER_SELECTION; - if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { - failf(data, "failed setting cipher list: %s", ciphers); - return CURLE_SSL_CIPHER; - } - infof(data, "Cipher selection: %s\n", ciphers); - } - -#ifdef USE_TLS_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) { - char * const ssl_username = SSL_SET_OPTION(username); - - 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))) { - failf(data, "failed setting SRP password"); - return CURLE_BAD_FUNCTION_ARGUMENT; - } - if(!SSL_CONN_CONFIG(cipher_list)) { - infof(data, "Setting cipher list SRP\n"); - - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) { - failf(data, "failed setting SRP cipher list"); - return CURLE_SSL_CIPHER; - } - } - } -#endif - - if(ssl_cafile || ssl_capath) { - /* tell SSL where to find CA certificates that are used to verify - the servers certificate. */ - if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) { - if(verifypeer) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:\n" - " CAfile: %s\n CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - /* Just continue with a warning if no strict certificate verification - is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); - } - infof(data, - " CAfile: %s\n" - " CApath: %s\n", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - } -#ifdef CURL_CA_FALLBACK - else if(verifypeer) { - /* verfying the peer without any CA certificates won't - work so use openssl's built in default as fallback */ - SSL_CTX_set_default_verify_paths(BACKEND->ctx); - } -#endif - - if(ssl_crlfile) { - /* tell SSL where to find CRL file that is used to check certificate - * revocation */ - lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_LOOKUP_file()); - if(!lookup || - (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { - failf(data, "error loading CRL file: %s", ssl_crlfile); - return CURLE_SSL_CRL_BADFILE; - } - /* Everything is fine. */ - infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - - infof(data, " CRLfile: %s\n", ssl_crlfile); - } - - /* Try building a chain using issuers in the trusted store first to avoid - problems with server-sent legacy intermediates. - Newer versions of OpenSSL do alternate chain checking by default which - gives us the same fix without as much of a performance hit (slight), so we - prefer that if available. - https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest - */ -#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) - if(verifypeer) { - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), - X509_V_FLAG_TRUSTED_FIRST); - } -#endif - - /* SSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(BACKEND->ctx, - verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); - - /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ -#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK) - if(keylog_file) { - SSL_CTX_set_keylog_callback(connssl->ctx, ossl_keylog_callback); - } -#endif - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, - data->set.ssl.fsslctxp); - if(result) { - failf(data, "error signaled by ssl ctx callback"); - return result; - } - } - - /* Lets make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { - failf(data, "SSL: couldn't create a context (handle)!"); - return CURLE_OUT_OF_MEMORY; - } - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - if(SSL_CONN_CONFIG(verifystatus)) - SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); -#endif - - SSL_set_connect_state(BACKEND->handle); - - BACKEND->server_cert = 0x0; -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && -#ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && -#endif - sni && - !SSL_set_tlsext_host_name(BACKEND->handle, hostname)) - infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); -#endif - - /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { - void *ssl_sessionid = NULL; - - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { - /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "SSL: SSL_set_session failed: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - Curl_ssl_sessionid_unlock(conn); - } - - if(conn->proxy_ssl[sockindex].use) { - BIO *const bio = BIO_new(BIO_f_ssl()); - SSL *handle = conn->proxy_ssl[sockindex].backend->handle; - DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(handle != NULL); - DEBUGASSERT(bio != NULL); - BIO_set_ssl(bio, handle, FALSE); - SSL_set_bio(BACKEND->handle, bio, bio); - } - else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { - /* pass the raw socket into the SSL layers */ - failf(data, "SSL: SSL_set_fd failed: %s", - ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - int err; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); - - ERR_clear_error(); - - err = SSL_connect(BACKEND->handle); - /* If keylogging is enabled but the keylog callback is not supported then log - secrets here, immediately after SSL_connect by using tap_ssl_key. */ -#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK) - tap_ssl_key(BACKEND->handle, &BACKEND->tap_state); -#endif - - /* 1 is fine - 0 is "not successful but was shut down controlled" - <0 is "handshake was not successful, because a fatal error occurred" */ - if(1 != err) { - int detail = SSL_get_error(BACKEND->handle, err); - - if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - else { - /* untreated error */ - unsigned long errdetail; - char error_buffer[256]=""; - CURLcode result; - long lerr; - int lib; - int reason; - - /* the connection failed, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_2; - - /* Get the earliest error code from the thread's error queue and removes - the entry. */ - errdetail = ERR_get_error(); - - /* Extract which lib and reason */ - lib = ERR_GET_LIB(errdetail); - reason = ERR_GET_REASON(errdetail); - - if((lib == ERR_LIB_SSL) && - (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { - result = CURLE_SSL_CACERT; - - lerr = SSL_get_verify_result(BACKEND->handle); - if(lerr != X509_V_OK) { - *certverifyresult = lerr; - snprintf(error_buffer, sizeof(error_buffer), - "SSL certificate problem: %s", - X509_verify_cert_error_string(lerr)); - } - else - /* strcpy() is fine here as long as the string fits within - error_buffer */ - strcpy(error_buffer, "SSL certificate verification failed"); - } - else { - result = CURLE_SSL_CONNECT_ERROR; - ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); - } - - /* detail is already set to the SSL error above */ - - /* If we e.g. use SSLv2 request-method and the server doesn't like us - * (RST connection etc.), OpenSSL gives no explanation whatsoever and - * the SO_ERROR is also lost. - */ - if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { - const char * const hostname = SSL_IS_PROXY() ? - conn->http_proxy.host.name : conn->host.name; - const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ", - SSL_ERROR_to_str(detail), hostname, port); - return result; - } - - /* Could be a CERT problem */ - failf(data, "%s", error_buffer); - - return result; - } - } - else { - /* we have been connected fine, we're not waiting for anything else. */ - connssl->connecting_state = ssl_connect_3; - - /* Informational message */ - infof(data, "SSL connection using %s / %s\n", - get_ssl_version_txt(BACKEND->handle), - SSL_get_cipher(BACKEND->handle)); - -#ifdef HAS_ALPN - /* Sets data and len to negotiated protocol, len is 0 if no protocol was - * negotiated - */ - if(conn->bits.tls_enable_alpn) { - const unsigned char *neg_protocol; - unsigned int len; - SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len); - if(len != 0) { - infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); - -#ifdef USE_NGHTTP2 - if(len == NGHTTP2_PROTO_VERSION_ID_LEN && - !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(len == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, "ALPN, server did not agree to a protocol\n"); - } -#endif - - return CURLE_OK; - } -} - -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) -{ - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; -} - -#define push_certinfo(_label, _num) \ -do { \ - long info_len = BIO_get_mem_data(mem, &ptr); \ - Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ - if(1 != BIO_reset(mem)) \ - break; \ -} WHILE_FALSE - -static void pubkey_show(struct Curl_easy *data, - BIO *mem, - int num, - const char *type, - const char *name, -#ifdef HAVE_OPAQUE_RSA_DSA_DH - const -#endif - BIGNUM *bn) -{ - char *ptr; - char namebuf[32]; - - snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - - if(bn) - BN_print(mem, bn); - push_certinfo(namebuf, num); -} - -#ifdef HAVE_OPAQUE_RSA_DSA_DH -#define print_pubkey_BN(_type, _name, _num) \ - pubkey_show(data, mem, _num, #_type, #_name, _name) - -#else -#define print_pubkey_BN(_type, _name, _num) \ -do { \ - if(_type->_name) { \ - pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ - } \ -} WHILE_FALSE -#endif - -static int X509V3_ext(struct Curl_easy *data, - int certnum, - CONST_EXTS STACK_OF(X509_EXTENSION) *exts) -{ - int i; - size_t j; - - if((int)sk_X509_EXTENSION_num(exts) <= 0) - /* no extensions, bail out */ - return 1; - - for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { - ASN1_OBJECT *obj; - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - BUF_MEM *biomem; - char buf[512]; - char *ptr = buf; - char namebuf[128]; - BIO *bio_out = BIO_new(BIO_s_mem()); - - if(!bio_out) - return 1; - - obj = X509_EXTENSION_get_object(ext); - - asn1_object_dump(obj, namebuf, sizeof(namebuf)); - - if(!X509V3_EXT_print(bio_out, ext, 0, 0)) - ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); - - BIO_get_mem_ptr(bio_out, &biomem); - - for(j = 0; j < (size_t)biomem->length; j++) { - const char *sep = ""; - if(biomem->data[j] == '\n') { - sep = ", "; - j++; /* skip the newline */ - }; - while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) - j++; - if(j<(size_t)biomem->length) - ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, - biomem->data[j]); - } - - Curl_ssl_push_certinfo(data, certnum, namebuf, buf); - - BIO_free(bio_out); - - } - return 0; /* all is fine */ -} - -static CURLcode get_cert_chain(struct connectdata *conn, - struct ssl_connect_data *connssl) - -{ - CURLcode result; - STACK_OF(X509) *sk; - int i; - struct Curl_easy *data = conn->data; - int numcerts; - BIO *mem; - - sk = SSL_get_peer_cert_chain(BACKEND->handle); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } - - numcerts = sk_X509_num(sk); - - result = Curl_ssl_init_certinfo(data, numcerts); - if(result) { - return result; - } - - mem = BIO_new(BIO_s_mem()); - - for(i = 0; i < numcerts; i++) { - ASN1_INTEGER *num; - X509 *x = sk_X509_value(sk, i); - EVP_PKEY *pubkey = NULL; - int j; - char *ptr; - const ASN1_BIT_STRING *psig = NULL; - - X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Subject", i); - - X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Issuer", i); - - BIO_printf(mem, "%lx", X509_get_version(x)); - push_certinfo("Version", i); - - num = X509_get_serialNumber(x); - if(num->type == V_ASN1_NEG_INTEGER) - BIO_puts(mem, "-"); - for(j = 0; j < num->length; j++) - BIO_printf(mem, "%02x", num->data[j]); - push_certinfo("Serial Number", i); - -#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) - { - const X509_ALGOR *palg = NULL; - ASN1_STRING *a = ASN1_STRING_new(); - if(a) { - X509_get0_signature(&psig, &palg, x); - X509_signature_print(mem, palg, a); - ASN1_STRING_free(a); - - if(palg) { - i2a_ASN1_OBJECT(mem, palg->algorithm); - push_certinfo("Public Key Algorithm", i); - } - } - X509V3_ext(data, i, X509_get0_extensions(x)); - } -#else - { - /* before OpenSSL 1.0.2 */ - X509_CINF *cinf = x->cert_info; - - i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); - push_certinfo("Signature Algorithm", i); - - i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); - push_certinfo("Public Key Algorithm", i); - - X509V3_ext(data, i, cinf->extensions); - - psig = x->signature; - } -#endif - - ASN1_TIME_print(mem, X509_get0_notBefore(x)); - push_certinfo("Start date", i); - - ASN1_TIME_print(mem, X509_get0_notAfter(x)); - push_certinfo("Expire date", i); - - pubkey = X509_get_pubkey(x); - if(!pubkey) - infof(data, " Unable to load public key\n"); - else { - int pktype; -#ifdef HAVE_OPAQUE_EVP_PKEY - pktype = EVP_PKEY_id(pubkey); -#else - pktype = pubkey->type; -#endif - switch(pktype) { - case EVP_PKEY_RSA: - { - RSA *rsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - rsa = EVP_PKEY_get0_RSA(pubkey); -#else - rsa = pubkey->pkey.rsa; -#endif - -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *n; - const BIGNUM *e; - - RSA_get0_key(rsa, &n, &e, NULL); - BN_print(mem, n); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); - } -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); -#endif - - break; - } - case EVP_PKEY_DSA: - { -#ifndef OPENSSL_NO_DSA - DSA *dsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - dsa = EVP_PKEY_get0_DSA(pubkey); -#else - dsa = pubkey->pkey.dsa; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - - DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, NULL); - - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); - } -#else - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); -#endif -#endif /* !OPENSSL_NO_DSA */ - break; - } - case EVP_PKEY_DH: - { - DH *dh; -#ifdef HAVE_OPAQUE_EVP_PKEY - dh = EVP_PKEY_get0_DH(pubkey); -#else - dh = pubkey->pkey.dh; -#endif -#ifdef HAVE_OPAQUE_RSA_DSA_DH - { - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *g; - const BIGNUM *pub_key; - DH_get0_pqg(dh, &p, &q, &g); - DH_get0_key(dh, &pub_key, NULL); - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, q, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); - } -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, pub_key, i); -#endif - break; - } -#if 0 - case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */ - /* left TODO */ - break; -#endif - } - EVP_PKEY_free(pubkey); - } - - if(psig) { - for(j = 0; j < psig->length; j++) - BIO_printf(mem, "%02x:", psig->data[j]); - push_certinfo("Signature", i); - } - - PEM_write_bio_X509(mem, x); - push_certinfo("Cert", i); - } - - BIO_free(mem); - - return CURLE_OK; -} - -/* - * Heavily modified from: - * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL - */ -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, - const char *pinnedpubkey) -{ - /* Scratch */ - int len1 = 0, len2 = 0; - unsigned char *buff1 = NULL, *temp = NULL; - - /* Result is returned to caller */ - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - /* if a path wasn't specified, don't pin */ - if(!pinnedpubkey) - return CURLE_OK; - - if(!cert) - return result; - - do { - /* Begin Gyrations to get the subjectPublicKeyInfo */ - /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ - - /* https://groups.google.com/group/mailing.openssl.users/browse_thread - /thread/d61858dae102c6c7 */ - len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); - if(len1 < 1) - break; /* failed */ - - /* https://www.openssl.org/docs/crypto/buffer.html */ - buff1 = temp = malloc(len1); - if(!buff1) - break; /* failed */ - - /* https://www.openssl.org/docs/crypto/d2i_X509.html */ - len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); - - /* - * These checks are verifying we got back the same values as when we - * sized the buffer. It's pretty weak since they should always be the - * same. But it gives us something to test. - */ - if((len1 != len2) || !temp || ((temp - buff1) != len1)) - break; /* failed */ - - /* End Gyrations */ - - /* The one good exit point */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); - } while(0); - - /* https://www.openssl.org/docs/crypto/buffer.html */ - if(buff1) - free(buff1); - - return result; -} - -/* - * Get the server cert, verify it and show it etc, only call failf() if the - * 'strict' argument is TRUE as otherwise all this is for informational - * purposes only! - * - * We check certificates to authenticate the server; otherwise we risk - * man-in-the-middle attack. - */ -static CURLcode servercert(struct connectdata *conn, - struct ssl_connect_data *connssl, - bool strict) -{ - CURLcode result = CURLE_OK; - int rc; - long lerr, len; - struct Curl_easy *data = conn->data; - X509 *issuer; - FILE *fp; - char buffer[2048]; - const char *ptr; - long * const certverifyresult = SSL_IS_PROXY() ? - &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; - BIO *mem = BIO_new(BIO_s_mem()); - - if(data->set.ssl.certinfo) - /* we've been asked to gather certificate info! */ - (void)get_cert_chain(conn, connssl); - - BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); - if(!BACKEND->server_cert) { - BIO_free(mem); - if(!strict) - return CURLE_OK; - - failf(data, "SSL: couldn't get peer certificate!"); - return CURLE_PEER_FAILED_VERIFICATION; - } - - infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); - - rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), - buffer, sizeof(buffer)); - infof(data, " subject: %s\n", rc?"[NONE]":buffer); - - ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert)); - len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " start date: %.*s\n", len, ptr); - (void)BIO_reset(mem); - - ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert)); - len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " expire date: %.*s\n", len, ptr); - (void)BIO_reset(mem); - - BIO_free(mem); - - if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(conn, BACKEND->server_cert); - if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return result; - } - } - - rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), - buffer, sizeof(buffer)); - if(rc) { - if(strict) - failf(data, "SSL: couldn't get X509-issuer name!"); - result = CURLE_SSL_CONNECT_ERROR; - } - else { - infof(data, " issuer: %s\n", buffer); - - /* We could do all sorts of certificate verification stuff here before - deallocating the certificate. */ - - /* e.g. match issuer name with provided issuer certificate */ - if(SSL_SET_OPTION(issuercert)) { - fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT); - if(!fp) { - if(strict) - failf(data, "SSL: Unable to open issuer cert (%s)", - SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - - issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL); - if(!issuer) { - if(strict) - failf(data, "SSL: Unable to read issuer cert (%s)", - SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); - X509_free(issuer); - fclose(fp); - return CURLE_SSL_ISSUER_ERROR; - } - - fclose(fp); - - 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)); - X509_free(BACKEND->server_cert); - X509_free(issuer); - BACKEND->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - - infof(data, " SSL certificate issuer check ok (%s)\n", - SSL_SET_OPTION(issuercert)); - X509_free(issuer); - } - - lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); - - if(*certverifyresult != X509_V_OK) { - if(SSL_CONN_CONFIG(verifypeer)) { - /* We probably never reach this, because SSL_connect() will fail - and we return earlier if verifypeer is set? */ - if(strict) - failf(data, "SSL certificate verify result: %s (%ld)", - X509_verify_cert_error_string(lerr), lerr); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, " SSL certificate verify result: %s (%ld)," - " continuing anyway.\n", - X509_verify_cert_error_string(lerr), lerr); - } - else - infof(data, " SSL certificate verify ok.\n"); - } - -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - if(SSL_CONN_CONFIG(verifystatus)) { - result = verifystatus(conn, connssl); - if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - return result; - } - } -#endif - - if(!strict) - /* when not strict, we don't bother about the verify cert problems */ - result = CURLE_OK; - - ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; - if(!result && ptr) { - result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr); - if(result) - failf(data, "SSL: public key does not match pinned public key!"); - } - - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; - connssl->connecting_state = ssl_connect_done; - - return result; -} - -static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(SSL_SET_OPTION(primary.sessionid)) { - bool incache; - SSL_SESSION *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = SSL_get1_session(BACKEND->handle); - - /* SSL_get1_session() will increment the reference count and the session - will stay in memory until explicitly freed with SSL_SESSION_free(3), - regardless of its state. */ - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, - sockindex)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } - - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */, sockindex); - if(result) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "failed to store ssl session"); - return result; - } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); - } - Curl_ssl_sessionid_unlock(conn); - } - - /* - * We check certificates to authenticate the server; otherwise we risk - * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to - * verify the peer ignore faults and failures from the server cert - * operations. - */ - - result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) || - SSL_CONN_CONFIG(verifyhost))); - - if(!result) - connssl->connecting_state = ssl_connect_done; - - return result; -} - -static Curl_recv ossl_recv; -static Curl_send ossl_send; - -static CURLcode ossl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - CURLcode result; - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; - time_t timeout_ms; - int what; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - result = ossl_connect_step1(conn, sockindex); - if(result) - return result; - } - - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ - result = ossl_connect_step2(conn, sockindex); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return result; - - } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3 == connssl->connecting_state) { - result = ossl_connect_step3(conn, sockindex); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = ossl_recv; - conn->send[sockindex] = ossl_send; - *done = TRUE; - } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) -{ - return ossl_connect_common(conn, sockindex, TRUE, done); -} - -static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode result; - bool done = FALSE; - - result = ossl_connect_common(conn, sockindex, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static bool Curl_ossl_data_pending(const struct connectdata *conn, - int connindex) -{ - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; - if(BACKEND->handle) - /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle) || - (proxyssl->backend->handle && - 0 != SSL_pending(proxyssl->backend->handle))) ? - TRUE : FALSE; - return FALSE; -} - -static size_t Curl_ossl_version(char *buffer, size_t size); - -static ssize_t ossl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - /* SSL_write() is said to return 'int' while write() and send() returns - 'size_t' */ - int err; - char error_buffer[256]; - unsigned long sslerror; - int memlen; - int rc; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - ERR_clear_error(); - - memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(BACKEND->handle, mem, memlen); - - if(rc <= 0) { - err = SSL_get_error(BACKEND->handle, rc); - - switch(err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* The operation did not complete; the same TLS/SSL I/O function - should be called again later. This is basically an EWOULDBLOCK - equivalent. */ - *curlcode = CURLE_AGAIN; - return -1; - case SSL_ERROR_SYSCALL: - failf(conn->data, "SSL_write() returned SYSCALL, errno = %d", - SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - return -1; - case SSL_ERROR_SSL: - /* A failure in the SSL library occurred, usually a protocol error. - The OpenSSL error queue contains more information on the error. */ - sslerror = ERR_get_error(); - if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && - ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && - conn->ssl[sockindex].state == ssl_connection_complete && - conn->proxy_ssl[sockindex].state == ssl_connection_complete) { - char ver[120]; - Curl_ossl_version(ver, 120); - failf(conn->data, "Error: %s does not support double SSL tunneling.", - ver); - } - else - failf(conn->data, "SSL_write() error: %s", - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - /* a true error */ - failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d", - SSL_ERROR_to_str(err), SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - *curlcode = CURLE_OK; - return (ssize_t)rc; /* number of bytes */ -} - -static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - char error_buffer[256]; - unsigned long sslerror; - ssize_t nread; - int buffsize; - struct ssl_connect_data *connssl = &conn->ssl[num]; - - ERR_clear_error(); - - buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); - if(nread <= 0) { - /* failed SSL_read */ - int err = SSL_get_error(BACKEND->handle, (int)nread); - - switch(err) { - case SSL_ERROR_NONE: /* this is not an error */ - case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_read() */ - *curlcode = CURLE_AGAIN; - return -1; - default: - /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return - value/errno" */ - /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ - sslerror = ERR_get_error(); - if((nread < 0) || sslerror) { - /* If the return code was negative or there actually is an error in the - queue */ - failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d", - (sslerror ? - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) : - SSL_ERROR_to_str(err)), - SOCKERRNO); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - } - } - return nread; -} - -static size_t Curl_ossl_version(char *buffer, size_t size) -{ -#ifdef OPENSSL_IS_BORINGSSL - return snprintf(buffer, size, OSSL_PACKAGE); -#else /* OPENSSL_IS_BORINGSSL */ - char sub[3]; - unsigned long ssleay_value; - sub[2]='\0'; - sub[1]='\0'; - ssleay_value = OpenSSL_version_num(); - if(ssleay_value < 0x906000) { - ssleay_value = SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { - int minor_ver = (ssleay_value >> 4) & 0xff; - if(minor_ver > 26) { - /* handle extended version introduced for 0.9.8za */ - sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); - sub[0] = 'z'; - } - else { - sub[0] = (char) (minor_ver + 'a' - 1); - } - } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", - OSSL_PACKAGE, - (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); -#endif /* OPENSSL_IS_BORINGSSL */ -} - -/* can be called with data == NULL */ -static CURLcode Curl_ossl_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ - int rc; - if(data) { - if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */ - return CURLE_FAILED_INIT; /* couldn't seed for some reason */ - } - else { - if(!rand_enough()) - return CURLE_FAILED_INIT; - } - /* RAND_bytes() returns 1 on success, 0 otherwise. */ - rc = RAND_bytes(entropy, curlx_uztosi(length)); - return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); -} - -static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum /* output */, - size_t unused) -{ - MD5_CTX MD5pw; - (void)unused; - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, tmplen); - MD5_Final(md5sum, &MD5pw); - return CURLE_OK; -} - -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum /* output */, - size_t unused) -{ - SHA256_CTX SHA256pw; - (void)unused; - SHA256_Init(&SHA256pw); - SHA256_Update(&SHA256pw, tmp, tmplen); - SHA256_Final(sha256sum, &SHA256pw); -} -#endif - -static bool Curl_ossl_cert_status_request(void) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - return TRUE; -#else - return FALSE; -#endif -} - -static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info) -{ - /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ - return info == CURLINFO_TLS_SESSION ? - (void *)BACKEND->ctx : (void *)BACKEND->handle; -} - -const struct Curl_ssl Curl_ssl_openssl = { - { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ - - 1, /* have_ca_path */ - 1, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 1, /* have_ssl_ctx */ - 1, /* support_https_proxy */ - - sizeof(struct ssl_backend_data), - - Curl_ossl_init, /* init */ - Curl_ossl_cleanup, /* cleanup */ - Curl_ossl_version, /* version */ - Curl_ossl_check_cxn, /* check_cxn */ - Curl_ossl_shutdown, /* shutdown */ - Curl_ossl_data_pending, /* data_pending */ - Curl_ossl_random, /* random */ - Curl_ossl_cert_status_request, /* cert_status_request */ - Curl_ossl_connect, /* connect */ - Curl_ossl_connect_nonblocking, /* connect_nonblocking */ - Curl_ossl_get_internals, /* get_internals */ - Curl_ossl_close, /* close_one */ - Curl_ossl_close_all, /* close_all */ - Curl_ossl_session_free, /* session_free */ - Curl_ossl_set_engine, /* set_engine */ - Curl_ossl_set_engine_default, /* set_engine_default */ - Curl_ossl_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_ossl_md5sum, /* md5sum */ -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) - Curl_ossl_sha256sum /* sha256sum */ -#else - NULL /* sha256sum */ -#endif -}; - -#endif /* USE_OPENSSL */ diff --git a/libs/libcurl/src/openssl.h b/libs/libcurl/src/openssl.h deleted file mode 100644 index 114dc4baeb..0000000000 --- a/libs/libcurl/src/openssl.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_CURL_SSLUSE_H -#define HEADER_CURL_SSLUSE_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_OPENSSL -/* - * This header should only be needed to get included by vtls.c and openssl.c - */ - -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_openssl; - -#endif /* USE_OPENSSL */ -#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c index 5e0fd2299b..05853f001d 100644 --- a/libs/libcurl/src/pop3.c +++ b/libs/libcurl/src/pop3.c @@ -443,7 +443,7 @@ static CURLcode pop3_perform_apop(struct connectdata *conn) /* Convert the calculated 16 octet digest into a 32 byte hex string */ for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&secret[2 * i], 3, "%02x", digest[i]); + msnprintf(&secret[2 * i], 3, "%02x", digest[i]); result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); @@ -629,6 +629,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, if(line[i] == '<') { /* Calculate the length of the timestamp */ size_t timestamplen = len - 1 - i; + char *at; if(!timestamplen) break; @@ -642,8 +643,15 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, memcpy(pop3c->apoptimestamp, line + i, timestamplen); pop3c->apoptimestamp[timestamplen] = '\0'; - /* Store the APOP capability */ - pop3c->authtypes |= POP3_TYPE_APOP; + /* If the timestamp does not contain '@' it is not (as required by + RFC-1939) conformant to the RFC-822 message id syntax, and we + therefore do not use APOP authentication. */ + at = strchr(pop3c->apoptimestamp, '@'); + if(!at) + Curl_safefree(pop3c->apoptimestamp); + else + /* Store the APOP capability */ + pop3c->authtypes |= POP3_TYPE_APOP; break; } } diff --git a/libs/libcurl/src/progress.c b/libs/libcurl/src/progress.c index a94668dc2a..d37e1d5a63 100644 --- a/libs/libcurl/src/progress.c +++ b/libs/libcurl/src/progress.c @@ -44,8 +44,8 @@ static void time2str(char *r, curl_off_t seconds) if(h <= CURL_OFF_T_C(99)) { curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); - snprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T - ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); + msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output @@ -53,10 +53,10 @@ static void time2str(char *r, curl_off_t seconds) curl_off_t d = seconds / CURL_OFF_T_C(86400); h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); if(d <= CURL_OFF_T_C(999)) - snprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T - "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); + msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else - snprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); + msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } @@ -72,40 +72,40 @@ static char *max5data(curl_off_t bytes, char *max5) #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) if(bytes < CURL_OFF_T_C(100000)) - snprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) /* 'XX.XM' is good as long as we're less than 100 megs */ - snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, - (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, + (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); #if (CURL_SIZEOF_CURL_OFF_T > 4) else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) /* 'XXXXM' is good until we're at 10000MB or above */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) /* 10000 MB - 100 GB, we show it as XX.XG */ - snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, - (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, + (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) /* up to 10000GB, display without decimal: XXXXG */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) /* up to 10000TB, display without decimal: XXXXT */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); else /* up to 10000PB, display without decimal: XXXXP */ - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can hold, but our data type is signed so 8192PB will be the maximum. */ @@ -113,7 +113,7 @@ static char *max5data(curl_off_t bytes, char *max5) #else else - snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); #endif diff --git a/libs/libcurl/src/security.c b/libs/libcurl/src/security.c index 6165d0af01..7f13071f6f 100644 --- a/libs/libcurl/src/security.c +++ b/libs/libcurl/src/security.c @@ -10,7 +10,7 @@ * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * - * Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2001 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * All rights reserved. * @@ -120,7 +120,7 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) char print_buffer[50]; va_start(args, message); - vsnprintf(print_buffer, sizeof(print_buffer), message, args); + mvsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); if(Curl_ftpsend(conn, print_buffer)) { diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c index d3c10b3690..e8598e6173 100644 --- a/libs/libcurl/src/sendf.c +++ b/libs/libcurl/src/sendf.c @@ -237,7 +237,18 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...) size_t len; char print_buffer[2048 + 1]; va_start(ap, fmt); - vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); + len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); + /* + * Indicate truncation of the input by replacing the last 3 characters + * with "...", and transfer the newline over in case the format had one. + */ + if(len >= sizeof(print_buffer)) { + len = strlen(fmt); + if(fmt[--len] == '\n') + msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n"); + else + msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "..."); + } va_end(ap); len = strlen(print_buffer); Curl_debug(data, CURLINFO_TEXT, print_buffer, len); @@ -255,7 +266,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) size_t len; char error[CURL_ERROR_SIZE + 2]; va_start(ap, fmt); - vsnprintf(error, CURL_ERROR_SIZE, fmt, ap); + mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); len = strlen(error); if(data->set.errorbuffer && !data->state.errorbuf) { diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c index 22956a20fb..1627aba6df 100644 --- a/libs/libcurl/src/setopt.c +++ b/libs/libcurl/src/setopt.c @@ -1204,6 +1204,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; data->set.low_speed_time = arg; break; + case CURLOPT_CURLU: + /* + * pass CURLU to set URL + */ + data->set.uh = va_arg(param, CURLU *); + break; case CURLOPT_URL: /* * The URL to fetch. diff --git a/libs/libcurl/src/socks_gssapi.c b/libs/libcurl/src/socks_gssapi.c index 96948ac4ba..65294bbebd 100644 --- a/libs/libcurl/src/socks_gssapi.c +++ b/libs/libcurl/src/socks_gssapi.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com> - * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -151,8 +151,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; service.length = serviceptr_length + strlen(conn->socks_proxy.host.name) + 1; - snprintf(service.value, service.length + 1, "%s@%s", - serviceptr, conn->socks_proxy.host.name); + msnprintf(service.value, service.length + 1, "%s@%s", + serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, GSS_C_NT_HOSTBASED_SERVICE, &server); diff --git a/libs/libcurl/src/socks_sspi.c b/libs/libcurl/src/socks_sspi.c index 34699d3742..bedb01ebbc 100644 --- a/libs/libcurl/src/socks_sspi.c +++ b/libs/libcurl/src/socks_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com> * * This software is licensed as described in the file COPYING, which @@ -107,9 +107,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, strlen(conn->socks_proxy.host.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; - snprintf(service_name, service_length + - strlen(conn->socks_proxy.host.name) + 2, "%s/%s", - service, conn->socks_proxy.host.name); + msnprintf(service_name, service_length + + strlen(conn->socks_proxy.host.name) + 2, "%s/%s", + service, conn->socks_proxy.host.name); } input_desc.cBuffers = 1; diff --git a/libs/libcurl/src/ssh-libssh.c b/libs/libcurl/src/ssh-libssh.c index 7d590891ca..e38c01ac74 100644 --- a/libs/libcurl/src/ssh-libssh.c +++ b/libs/libcurl/src/ssh-libssh.c @@ -1342,8 +1342,8 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) break; } - snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path, - sshc->readdir_filename); + msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path, + sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_LINK); break; @@ -1406,12 +1406,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) } sshc->readdir_line = new_readdir_line; - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, - " -> %s", - sshc->readdir_filename); + sshc->readdir_currLen += msnprintf(sshc->readdir_line + + sshc->readdir_currLen, + sshc->readdir_totalLen - + sshc->readdir_currLen, + " -> %s", + sshc->readdir_filename); sftp_attributes_free(sshc->readdir_link_attrs); sshc->readdir_link_attrs = NULL; @@ -1421,10 +1421,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_READDIR_BOTTOM); /* FALLTHROUGH */ case SSH_SFTP_READDIR_BOTTOM: - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, "\n"); + sshc->readdir_currLen += msnprintf(sshc->readdir_line + + sshc->readdir_currLen, + sshc->readdir_totalLen - + sshc->readdir_currLen, "\n"); result = Curl_client_write(conn, CLIENTWRITE_BODY, sshc->readdir_line, sshc->readdir_currLen); diff --git a/libs/libcurl/src/ssh.c b/libs/libcurl/src/ssh.c index da896196f3..f3b0a58be6 100644 --- a/libs/libcurl/src/ssh.c +++ b/libs/libcurl/src/ssh.c @@ -599,7 +599,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) if(fingerprint) { /* The fingerprint points to static storage (!), don't free() it. */ for(i = 0; i < 16; i++) - snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); } @@ -1999,8 +1999,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } - snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path, - sshc->readdir_filename); + msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path, + sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_LINK); break; } @@ -2055,21 +2055,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } sshc->readdir_line = new_readdir_line; - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, - " -> %s", - sshc->readdir_filename); + sshc->readdir_currLen += msnprintf(sshc->readdir_line + + sshc->readdir_currLen, + sshc->readdir_totalLen - + sshc->readdir_currLen, + " -> %s", + sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_BOTTOM); break; case SSH_SFTP_READDIR_BOTTOM: - sshc->readdir_currLen += snprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, "\n"); + sshc->readdir_currLen += msnprintf(sshc->readdir_line + + sshc->readdir_currLen, + sshc->readdir_totalLen - + sshc->readdir_currLen, "\n"); result = Curl_client_write(conn, CLIENTWRITE_BODY, sshc->readdir_line, sshc->readdir_currLen); diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c index 47ef44a66d..bf30c89077 100644 --- a/libs/libcurl/src/strerror.c +++ b/libs/libcurl/src/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2004 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -681,7 +681,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) if(!get_winsock_error(err, buf, max) && !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, buf, (DWORD)max, NULL)) - snprintf(buf, max, "Unknown error %d (%#x)", err, err); + msnprintf(buf, max, "Unknown error %d (%#x)", err, err); } #endif @@ -695,7 +695,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) */ if(0 != strerror_r(err, buf, max)) { if('\0' == buf[0]) - snprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, max, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) /* @@ -709,7 +709,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) if(msg) strncpy(buf, msg, max); else - snprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, max, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R) /* @@ -721,7 +721,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) if(OK == strerror_r(err, buffer)) strncpy(buf, buffer, max); else - snprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, max, "Unknown error %d", err); } #else { @@ -729,7 +729,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) if(msg) strncpy(buf, msg, max); else - snprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, max, "Unknown error %d", err); } #endif @@ -1032,14 +1032,14 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) if(err == SEC_E_OK) strncpy(outbuf, txt, outmax); else if(err == SEC_E_ILLEGAL_MESSAGE) - snprintf(outbuf, outmax, - "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " - "when a fatal SSL/TLS alert is received (e.g. handshake failed). " - "More detail may be available in the Windows System event log.", - err); + msnprintf(outbuf, outmax, + "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " + "when a fatal SSL/TLS alert is received (e.g. handshake failed)." + " More detail may be available in the Windows System event log.", + err); else { str = txtbuf; - snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); + msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); txtbuf[sizeof(txtbuf)-1] = '\0'; #ifdef _WIN32_WCE @@ -1075,7 +1075,7 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) msg = msgbuf; } if(msg) - snprintf(outbuf, outmax, "%s - %s", str, msg); + msnprintf(outbuf, outmax, "%s - %s", str, msg); else strncpy(outbuf, str, outmax); } diff --git a/libs/libcurl/src/telnet.c b/libs/libcurl/src/telnet.c index 05fe744dbd..e4c0bac3dc 100644 --- a/libs/libcurl/src/telnet.c +++ b/libs/libcurl/src/telnet.c @@ -829,7 +829,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* Add the user name as an environment variable if it was given on the command line */ if(conn->bits.user_passwd) { - snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); + msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { curl_slist_free_all(tn->telnet_vars); @@ -935,9 +935,9 @@ static void suboption(struct connectdata *conn) switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: len = strlen(tn->subopt_ttype) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; @@ -947,9 +947,9 @@ static void suboption(struct connectdata *conn) break; case CURL_TELOPT_XDISPLOC: len = strlen(tn->subopt_xdisploc) + 4 + 2; - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; @@ -958,9 +958,9 @@ static void suboption(struct connectdata *conn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); len = 4; for(v = tn->telnet_vars; v; v = v->next) { @@ -968,15 +968,15 @@ static void suboption(struct connectdata *conn) /* Add the variable only if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { - snprintf((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, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); len += tmplen; } } } - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%c", CURL_IAC, CURL_SE); + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); len += 2; bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c index 5b74e8e08c..269b3cde4b 100644 --- a/libs/libcurl/src/tftp.c +++ b/libs/libcurl/src/tftp.c @@ -496,9 +496,9 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) return CURLE_TFTP_ILLEGAL; /* too long file name field */ } - snprintf((char *)state->spacket.data + 2, - state->blksize, - "%s%c%s%c", filename, '\0', mode, '\0'); + msnprintf((char *)state->spacket.data + 2, + state->blksize, + "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); /* optional addition of TFTP options */ @@ -506,8 +506,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) char buf[64]; /* add tsize option */ if(data->set.upload && (data->state.infilesize != -1)) - snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, - data->state.infilesize); + msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); else strcpy(buf, "0"); /* the destination is large enough */ @@ -517,7 +517,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) sbytes += tftp_option_add(state, sbytes, (char *)state->spacket.data + sbytes, buf); /* add blksize option */ - snprintf(buf, sizeof(buf), "%d", state->requested_blksize); + msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); sbytes += tftp_option_add(state, sbytes, (char *)state->spacket.data + sbytes, TFTP_OPTION_BLKSIZE); @@ -525,7 +525,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) (char *)state->spacket.data + sbytes, buf); /* add timeout option */ - snprintf(buf, sizeof(buf), "%d", state->retry_time); + msnprintf(buf, sizeof(buf), "%d", state->retry_time); sbytes += tftp_option_add(state, sbytes, (char *)state->spacket.data + sbytes, TFTP_OPTION_INTERVAL); diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c index b73f94d9e7..6390821bba 100644 --- a/libs/libcurl/src/transfer.c +++ b/libs/libcurl/src/transfer.c @@ -218,8 +218,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, endofline_native = "\r\n"; endofline_network = "\x0d\x0a"; } - hexlen = snprintf(hexbuffer, sizeof(hexbuffer), - "%x%s", nread, endofline_native); + hexlen = msnprintf(hexbuffer, sizeof(hexbuffer), + "%x%s", nread, endofline_native); /* move buffer pointer */ data->req.upload_fromhere -= hexlen; @@ -844,6 +844,11 @@ static CURLcode readwrite_data(struct Curl_easy *data, k->keepon &= ~KEEP_RECV; } + if(k->keepon & KEEP_RECV_PAUSE) { + /* this is a paused transfer */ + break; + } + } while(data_pending(conn) && maxloops--); if(maxloops <= 0) { @@ -1348,17 +1353,30 @@ void Curl_init_CONNECT(struct Curl_easy *data) CURLcode Curl_pretransfer(struct Curl_easy *data) { CURLcode result; - if(!data->change.url) { + + if(!data->change.url && !data->set.uh) { /* we can't do anything without URL */ failf(data, "No URL set!"); return CURLE_URL_MALFORMAT; } + /* since the URL may have been redirected in a previous use of this handle */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ Curl_safefree(data->change.url); data->change.url_alloc = FALSE; } + + if(!data->change.url && data->set.uh) { + CURLUcode uc; + uc = curl_url_get(data->set.uh, + CURLUPART_URL, &data->set.str[STRING_SET_URL], 0); + if(uc) { + failf(data, "No URL set!"); + return CURLE_URL_MALFORMAT; + } + } + data->change.url = data->set.str[STRING_SET_URL]; /* Init the SSL session ID cache here. We do it here since we want to do it @@ -1514,13 +1532,24 @@ CURLcode Curl_follow(struct Curl_easy *data, disallowport = TRUE; DEBUGASSERT(data->state.uh); - uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, 0); - if(uc) - return Curl_uc_to_curlcode(uc); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : 0); + if(uc) { + if(type != FOLLOW_FAKE) + return Curl_uc_to_curlcode(uc); + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + 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); + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + } if(type == FOLLOW_FAKE) { /* we're only figuring out the new url if we would've followed locations diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c index 0d5a13f996..7839dfa7ce 100644 --- a/libs/libcurl/src/url.c +++ b/libs/libcurl/src/url.c @@ -127,7 +127,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "memdebug.h" static void conn_free(struct connectdata *conn); -static void free_fixed_hostname(struct hostname *host); +static void free_idnconverted_hostname(struct hostname *host); static unsigned int get_protocol_family(unsigned int protocol); /* Some parts of the code (e.g. chunked encoding) assume this buffer has at @@ -570,7 +570,7 @@ CURLcode Curl_open(struct Curl_easy **curl) data->magic = CURLEASY_MAGIC_NUMBER; - result = Curl_resolver_init(&data->state.resolver); + result = Curl_resolver_init(data, &data->state.resolver); if(result) { DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); free(data); @@ -708,6 +708,7 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ + Curl_safefree(conn->hostname_resolve); Curl_safefree(conn->secondaryhostname); Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ @@ -788,10 +789,10 @@ CURLcode Curl_disconnect(struct Curl_easy *data, infof(data, "Closing connection %ld\n", conn->connection_id); Curl_conncache_remove_conn(conn, TRUE); - free_fixed_hostname(&conn->host); - free_fixed_hostname(&conn->conn_to_host); - free_fixed_hostname(&conn->http_proxy.host); - free_fixed_hostname(&conn->socks_proxy.host); + free_idnconverted_hostname(&conn->host); + free_idnconverted_hostname(&conn->conn_to_host); + free_idnconverted_hostname(&conn->http_proxy.host); + free_idnconverted_hostname(&conn->socks_proxy.host); DEBUGASSERT(conn->data == data); /* this assumes that the pointer is still there after the connection was @@ -1679,11 +1680,23 @@ static bool is_ASCII_name(const char *hostname) } /* - * Perform any necessary IDN conversion of hostname + * Strip single trailing dot in the hostname, + * primarily for SNI and http host header. */ -static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host) +static void strip_trailing_dot(struct hostname *host) { size_t len; + len = strlen(host->name); + if(len && (host->name[len-1] == '.')) + host->name[len-1] = 0; +} + +/* + * Perform any necessary IDN conversion of hostname + */ +static CURLcode idnconvert_hostname(struct connectdata *conn, + struct hostname *host) +{ struct Curl_easy *data = conn->data; #ifndef USE_LIBIDN2 @@ -1696,12 +1709,6 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host) /* set the name we use to display the host name */ host->dispname = host->name; - len = strlen(host->name); - if(len && (host->name[len-1] == '.')) - /* strip off a single trailing dot if present, primarily for SNI but - there's no use for it */ - host->name[len-1] = 0; - /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { #ifdef USE_LIBIDN2 @@ -1756,9 +1763,9 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host) } /* - * Frees data allocated by fix_hostname() + * Frees data allocated by idnconvert_hostname() */ -static void free_fixed_hostname(struct hostname *host) +static void free_idnconverted_hostname(struct hostname *host) { #if defined(USE_LIBIDN2) if(host->encalloc) { @@ -2026,7 +2033,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, Curl_up_free(data); /* cleanup previous leftovers first */ /* parse the URL */ - uh = data->state.uh = curl_url(); + if(data->set.uh) { + uh = data->set.uh; + } + else { + uh = data->state.uh = curl_url(); + } + if(!uh) return CURLE_OUT_OF_MEMORY; @@ -2043,14 +2056,18 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, data->change.url_alloc = TRUE; } - uc = curl_url_set(uh, CURLUPART_URL, data->change.url, + if(!data->set.uh) { + uc = curl_url_set(uh, CURLUPART_URL, data->change.url, CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME | (data->set.disallow_username_in_url ? CURLU_DISALLOW_USER : 0) | (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); - if(uc) - return Curl_uc_to_curlcode(uc); + if(uc) { + DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url)); + return Curl_uc_to_curlcode(uc); + } + } uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0); if(uc) @@ -2191,6 +2208,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_OK; } + /* * If we're doing a resumed transfer, we need to setup our stuff * properly. @@ -2979,7 +2997,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data, char portbuf[16]; CURLUcode uc; conn->remote_port = (unsigned short)data->set.use_port; - snprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port); + msnprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port); uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); if(uc) return CURLE_OUT_OF_MEMORY; @@ -2999,6 +3017,20 @@ static CURLcode override_login(struct Curl_easy *data, bool user_changed = FALSE; bool passwd_changed = FALSE; CURLUcode uc; + + if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) { + /* ignore user+password in the URL */ + if(*userp) { + Curl_safefree(*userp); + user_changed = TRUE; + } + if(*passwdp) { + Curl_safefree(*passwdp); + passwd_changed = TRUE; + } + conn->bits.user_passwd = FALSE; /* disable user+password */ + } + if(data->set.str[STRING_USERNAME]) { free(*userp); *userp = strdup(data->set.str[STRING_USERNAME]); @@ -3025,16 +3057,15 @@ static CURLcode override_login(struct Curl_easy *data, } conn->bits.netrc = FALSE; - if(data->set.use_netrc != CURL_NETRC_IGNORED) { - char *nuser = NULL; - char *npasswd = NULL; + if(data->set.use_netrc != CURL_NETRC_IGNORED && + (!*userp || !**userp || !*passwdp || !**passwdp)) { + bool netrc_user_changed = FALSE; + bool netrc_passwd_changed = FALSE; int ret; - if(data->set.use_netrc == CURL_NETRC_OPTIONAL) - nuser = *userp; /* to separate otherwise identical machines */ - ret = Curl_parsenetrc(conn->host.name, - &nuser, &npasswd, + userp, passwdp, + &netrc_user_changed, &netrc_passwd_changed, data->set.str[STRING_NETRC_FILE]); if(ret > 0) { infof(data, "Couldn't find host %s in the " @@ -3051,31 +3082,11 @@ static CURLcode override_login(struct Curl_easy *data, conn->bits.netrc = TRUE; conn->bits.user_passwd = TRUE; /* enable user+password */ - if(data->set.use_netrc == CURL_NETRC_OPTIONAL) { - /* prefer credentials outside netrc */ - if(nuser && !*userp) { - free(*userp); - *userp = nuser; - user_changed = TRUE; - } - if(npasswd && !*passwdp) { - free(*passwdp); - *passwdp = npasswd; - passwd_changed = TRUE; - } + if(netrc_user_changed) { + user_changed = TRUE; } - else { - /* prefer netrc credentials */ - if(nuser) { - free(*userp); - *userp = nuser; - user_changed = TRUE; - } - if(npasswd) { - free(*passwdp); - *passwdp = npasswd; - passwd_changed = TRUE; - } + if(netrc_passwd_changed) { + passwd_changed = TRUE; } } } @@ -3369,7 +3380,7 @@ static CURLcode resolve_server(struct Curl_easy *data, *************************************************************/ if(conn->bits.reuse) /* We're reusing the connection - no need to resolve anything, and - fix_hostname() was called already in create_conn() for the re-use + idnconvert_hostname() was called already in create_conn() for the re-use case. */ *async = FALSE; @@ -3424,7 +3435,10 @@ static CURLcode resolve_server(struct Curl_easy *data, conn->port = conn->remote_port; /* Resolve target host right on */ - rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, + conn->hostname_resolve = strdup(connhost->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; @@ -3445,7 +3459,10 @@ static CURLcode resolve_server(struct Curl_easy *data, &conn->socks_proxy.host : &conn->http_proxy.host; /* resolve proxy */ - rc = Curl_resolv_timeout(conn, host->name, (int)conn->port, + conn->hostname_resolve = strdup(host->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) @@ -3475,8 +3492,8 @@ static CURLcode resolve_server(struct Curl_easy *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { - free_fixed_hostname(&old_conn->http_proxy.host); - free_fixed_hostname(&old_conn->socks_proxy.host); + free_idnconverted_hostname(&old_conn->http_proxy.host); + free_idnconverted_hostname(&old_conn->socks_proxy.host); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); @@ -3520,14 +3537,18 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ - free_fixed_hostname(&conn->host); - free_fixed_hostname(&conn->conn_to_host); + free_idnconverted_hostname(&conn->host); + free_idnconverted_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); Curl_safefree(conn->conn_to_host.rawalloc); conn->host = old_conn->host; conn->conn_to_host = old_conn->conn_to_host; conn->conn_to_port = old_conn->conn_to_port; conn->remote_port = old_conn->remote_port; + Curl_safefree(conn->hostname_resolve); + + conn->hostname_resolve = old_conn->hostname_resolve; + old_conn->hostname_resolve = NULL; /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -3677,30 +3698,30 @@ static CURLcode create_conn(struct Curl_easy *data, goto out; /************************************************************* - * IDN-fix the hostnames + * IDN-convert the hostnames *************************************************************/ - result = fix_hostname(conn, &conn->host); + result = idnconvert_hostname(conn, &conn->host); if(result) goto out; if(conn->bits.conn_to_host) { - result = fix_hostname(conn, &conn->conn_to_host); + result = idnconvert_hostname(conn, &conn->conn_to_host); if(result) goto out; } if(conn->bits.httpproxy) { - result = fix_hostname(conn, &conn->http_proxy.host); + result = idnconvert_hostname(conn, &conn->http_proxy.host); if(result) goto out; } if(conn->bits.socksproxy) { - result = fix_hostname(conn, &conn->socks_proxy.host); + result = idnconvert_hostname(conn, &conn->socks_proxy.host); if(result) goto out; } /************************************************************* * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-fixed. + * Do this after the hostnames have been IDN-converted. *************************************************************/ if(conn->bits.conn_to_host && strcasecompare(conn->conn_to_host.name, conn->host.name)) { @@ -4028,6 +4049,15 @@ static CURLcode create_conn(struct Curl_easy *data, *************************************************************/ result = resolve_server(data, conn, async); + /* Strip trailing dots. resolve_server copied the name. */ + strip_trailing_dot(&conn->host); + if(conn->bits.httpproxy) + strip_trailing_dot(&conn->http_proxy.host); + if(conn->bits.socksproxy) + strip_trailing_dot(&conn->socks_proxy.host); + if(conn->bits.conn_to_host) + strip_trailing_dot(&conn->conn_to_host); + out: return result; } diff --git a/libs/libcurl/src/urlapi-int.h b/libs/libcurl/src/urlapi-int.h index a57d2e22bd..75a3605423 100644 --- a/libs/libcurl/src/urlapi-int.h +++ b/libs/libcurl/src/urlapi-int.h @@ -30,4 +30,9 @@ bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); char *Curl_concat_url(const char *base, const char *relurl); size_t Curl_strlen_url(const char *url, bool relative); void Curl_strcpy_url(char *output, const char *url, bool relative); + +#ifdef DEBUGBUILD +CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname); +#endif + #endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c index c53e523434..5cbda6a98c 100644 --- a/libs/libcurl/src/urlapi.c +++ b/libs/libcurl/src/urlapi.c @@ -67,6 +67,12 @@ struct Curl_URL { #define DEFAULT_SCHEME "https" +#ifdef DEBUGBUILD +#define UNITTEST +#else +#define UNITTEST static +#endif + static void free_urlhandle(struct Curl_URL *u) { free(u->scheme); @@ -203,7 +209,7 @@ void Curl_strcpy_url(char *output, const char *url, bool relative) /* FALLTHROUGH */ default: if(urlchar_needs_escaping(*iptr)) { - snprintf(optr, 4, "%%%02x", *iptr); + msnprintf(optr, 4, "%%%02x", *iptr); optr += 3; } else @@ -238,7 +244,7 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) #endif for(i = 0; i < buflen && url[i]; ++i) { char s = url[i]; - if(s == ':') { + if((s == ':') && (url[i + 1] == '/')) { if(buf) buf[i] = 0; return TRUE; @@ -488,19 +494,37 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, return result; } -static CURLUcode parse_port(struct Curl_URL *u, char *hostname) +UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname) { - char *portptr; + char *portptr = NULL; char endbracket; int len; - if((1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.%%]%c%n", - &endbracket, &len)) && - (']' == endbracket)) { - /* this is a RFC2732-style specified IP-address */ - portptr = &hostname[len]; - if (*portptr != ':') + /* + * Find the end of an IPv6 address, either on the ']' ending bracket or + * a percent-encoded zone index. + */ + if(1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.]%c%n", + &endbracket, &len)) { + if(']' == endbracket) + portptr = &hostname[len]; + else if('%' == endbracket) { + int zonelen = len; + if(1 == sscanf(hostname + zonelen, "25%*[^]]]%c%n", &endbracket, &len)) + portptr = &hostname[--zonelen + len]; + else + return CURLUE_MALFORMED_INPUT; + } + else return CURLUE_MALFORMED_INPUT; + + /* this is a RFC2732-style specified IP-address */ + if(portptr && *portptr) { + if(*portptr != ':') + return CURLUE_MALFORMED_INPUT; + } + else + portptr = NULL; } else portptr = strchr(hostname, ':'); @@ -527,7 +551,7 @@ static CURLUcode parse_port(struct Curl_URL *u, char *hostname) *portptr++ = '\0'; /* cut off the name there */ *rest = 0; /* generate a new to get rid of leading zeroes etc */ - snprintf(portbuf, sizeof(portbuf), "%ld", port); + msnprintf(portbuf, sizeof(portbuf), "%ld", port); u->portnum = port; u->port = strdup(portbuf); if(!u->port) @@ -827,7 +851,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(result) return result; - result = parse_port(u, hostname); + result = Curl_parse_port(u, hostname); if(result) return result; @@ -960,7 +984,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, const struct Curl_handler *h = Curl_builtin_scheme(u->scheme); if(h) { - snprintf(portbuf, sizeof(portbuf), "%ld", h->defport); + msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport); ptr = portbuf; } } @@ -1019,7 +1043,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, /* there's no stored port number, but asked to deliver a default one for the scheme */ if(h) { - snprintf(portbuf, sizeof(portbuf), "%ld", h->defport); + msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport); port = portbuf; } } @@ -1099,6 +1123,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, bool plusencode = FALSE; bool urlskipslash = FALSE; bool appendquery = FALSE; + bool equalsencode = FALSE; if(!u) return CURLUE_BAD_HANDLE; @@ -1179,6 +1204,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, case CURLUPART_QUERY: plusencode = urlencode; appendquery = (flags & CURLU_APPENDQUERY)?1:0; + equalsencode = appendquery; storep = &u->query; break; case CURLUPART_FRAGMENT: @@ -1272,13 +1298,16 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, for(i = part, o = enc; *i; i++) { if(Curl_isunreserved(*i) || ((*i == '/') && urlskipslash) || - ((*i == '=') && appendquery) || + ((*i == '=') && equalsencode) || ((*i == '+') && plusencode)) { + if((*i == '=') && equalsencode) + /* only skip the first equals sign */ + equalsencode = FALSE; *o = *i; o++; } else { - snprintf(o, 4, "%%%02x", *i); + msnprintf(o, 4, "%%%02x", *i); o += 3; } } diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h index 11a6a22c61..448437d2ad 100644 --- a/libs/libcurl/src/urldata.h +++ b/libs/libcurl/src/urldata.h @@ -828,6 +828,7 @@ struct connectdata { int socktype; /* SOCK_STREAM or SOCK_DGRAM */ struct hostname host; + char *hostname_resolve; /* host name to resolve to address, allocated */ char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ @@ -1728,6 +1729,7 @@ struct UserDefined { bool doh_get; /* use GET for DoH requests, instead of POST */ multidone_func fmultidone; struct Curl_easy *dohfor; /* this is a DoH request for that transfer */ + CURLU *uh; /* URL handle for the current parsed URL */ }; struct Names { diff --git a/libs/libcurl/src/vauth/digest.c b/libs/libcurl/src/vauth/digest.c index ab5156eb75..0f2e6509ef 100644 --- a/libs/libcurl/src/vauth/digest.c +++ b/libs/libcurl/src/vauth/digest.c @@ -143,7 +143,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ { int i; for(i = 0; i < 16; i++) - snprintf((char *) &dest[i * 2], 3, "%02x", source[i]); + msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Convert sha256 chunk to RFC7616 -suitable ascii string*/ @@ -152,7 +152,7 @@ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ { int i; for(i = 0; i < 32; i++) - snprintf((char *) &dest[i * 2], 3, "%02x", source[i]); + msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Perform quoted-string escaping as described in RFC2616 and its errata */ @@ -432,7 +432,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* Convert calculated 16 octet hex into 32 bytes string */ for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); /* Generate our SPN */ spn = Curl_auth_build_spn(service, realm, NULL); @@ -455,7 +455,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); /* Now calculate the response hash */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); @@ -485,7 +485,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); /* Generate the response */ response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," diff --git a/libs/libcurl/src/vauth/ntlm.c b/libs/libcurl/src/vauth/ntlm.c index 11f42f5042..458b272539 100644 --- a/libs/libcurl/src/vauth/ntlm.c +++ b/libs/libcurl/src/vauth/ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -409,38 +409,38 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, #else #define NTLM2FLAG 0 #endif - snprintf((char *)ntlmbuf, NTLM_BUFSIZE, - NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host name offset */ - "%c%c" /* 2 zeroes */ - "%s" /* host name */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0, 0, 0, /* part of type-1 long */ - - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLM2FLAG | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0, 0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0, 0, - host, /* this is empty */ - domain /* this is empty */); + msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host name offset */ + "%c%c" /* 2 zeroes */ + "%s" /* host name */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0, 0, 0, /* part of type-1 long */ + + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0, 0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0, 0, + host, /* this is empty */ + domain /* this is empty */); /* Initial packet length */ size = 32 + hostlen + domlen; @@ -678,88 +678,88 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, hostoff = useroff + userlen; /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* 32-bit type = 3 */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c", /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - - 0, /* zero termination */ - 0, 0, 0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, + size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* 32-bit type = 3 */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c", /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + + 0, /* zero termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, #ifdef USE_NTRESPONSES - SHORTPAIR(ntresplen), /* NT-response length, twice */ - SHORTPAIR(ntresplen), - SHORTPAIR(ntrespoff), - 0x0, 0x0, + SHORTPAIR(ntresplen), /* NT-response length, twice */ + SHORTPAIR(ntresplen), + SHORTPAIR(ntrespoff), + 0x0, 0x0, #else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, #endif - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); DEBUGASSERT(size == 64); DEBUGASSERT(size == (size_t)lmrespoff); diff --git a/libs/libcurl/src/version.c b/libs/libcurl/src/version.c index 05c2cd8b06..e553100c21 100644 --- a/libs/libcurl/src/version.c +++ b/libs/libcurl/src/version.c @@ -95,7 +95,7 @@ static size_t brotli_version(char *buf, size_t bufsz) unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; unsigned int patch = brotli_version & 0x00000FFF; - return snprintf(buf, bufsz, "%u.%u.%u", major, minor, patch); + return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch); } #endif @@ -126,12 +126,12 @@ char *curl_version(void) } #ifdef HAVE_LIBZ - len = snprintf(ptr, left, " zlib/%s", zlibVersion()); + len = msnprintf(ptr, left, " zlib/%s", zlibVersion()); left -= len; ptr += len; #endif #ifdef HAVE_BROTLI - len = snprintf(ptr, left, "%s", " brotli/"); + len = msnprintf(ptr, left, "%s", " brotli/"); left -= len; ptr += len; len = brotli_version(ptr, left); @@ -140,45 +140,45 @@ char *curl_version(void) #endif #ifdef USE_ARES /* this function is only present in c-ares, not in the original ares */ - len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL)); + len = msnprintf(ptr, left, " c-ares/%s", ares_version(NULL)); left -= len; ptr += len; #endif #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { - len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); + len = msnprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); left -= len; ptr += len; } #endif #ifdef USE_LIBPSL - len = snprintf(ptr, left, " libpsl/%s", psl_get_version()); + len = msnprintf(ptr, left, " libpsl/%s", psl_get_version()); left -= len; ptr += len; #endif #ifdef USE_WIN32_IDN - len = snprintf(ptr, left, " WinIDN"); + len = msnprintf(ptr, left, " WinIDN"); left -= len; ptr += len; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION - len = snprintf(ptr, left, " iconv/%d.%d", - _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); + len = msnprintf(ptr, left, " iconv/%d.%d", + _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); #else /* version unknown */ - len = snprintf(ptr, left, " iconv"); + len = msnprintf(ptr, left, " iconv"); #endif /* _LIBICONV_VERSION */ left -= len; ptr += len; #endif #ifdef USE_LIBSSH2 - len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION); + len = msnprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION); left -= len; ptr += len; #endif #ifdef USE_LIBSSH - len = snprintf(ptr, left, " libssh/%s", CURL_LIBSSH_VERSION); + len = msnprintf(ptr, left, " libssh/%s", CURL_LIBSSH_VERSION); left -= len; ptr += len; #endif @@ -197,14 +197,14 @@ char *curl_version(void) else suff[0] = '\0'; - snprintf(ptr, left, " librtmp/%d.%d%s", - RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, - suff); + msnprintf(ptr, left, " librtmp/%d.%d%s", + RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, + suff); /* If another lib version is added below this one, this code would also have to do: - len = what snprintf() returned + len = what msnprintf() returned left -= len; ptr += len; @@ -436,10 +436,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp) #endif #if defined(USE_LIBSSH2) - snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION); + msnprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION); version_info.libssh_version = ssh_buffer; #elif defined(USE_LIBSSH) - snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh/%s", CURL_LIBSSH_VERSION); + msnprintf(ssh_buffer, sizeof(ssh_buffer), "libssh/%s", CURL_LIBSSH_VERSION); version_info.libssh_version = ssh_buffer; #endif diff --git a/libs/libcurl/src/vtls/axtls.c b/libs/libcurl/src/vtls/axtls.c deleted file mode 100644 index b262392a00..0000000000 --- a/libs/libcurl/src/vtls/axtls.c +++ /dev/null @@ -1,741 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>. - * Copyright (C) 2010 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all axTLS-specific code for the TLS/SSL layer. No code - * but vtls.c should ever call or use these functions. - */ - -#include "curl_setup.h" - -#ifdef USE_AXTLS - -#error axTLS support has been disabled in curl due to doubts about quality, -#error user dedication and a lack of use/testing. We urge users to consider -#error using a more established TLS backend instead. - -#include <axTLS/config.h> -#include <axTLS/ssl.h> -#include "axtls.h" - -#include "sendf.h" -#include "inet_pton.h" -#include "vtls.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "curl_printf.h" -#include "hostcheck.h" -#include <unistd.h> - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -struct ssl_backend_data { - SSL_CTX* ssl_ctx; - SSL* ssl; -}; - -#define BACKEND connssl->backend - -static CURLcode map_error_to_curl(int axtls_err) -{ - switch(axtls_err) { - case SSL_ERROR_NOT_SUPPORTED: - case SSL_ERROR_INVALID_VERSION: - case -70: /* protocol version alert from server */ - return CURLE_UNSUPPORTED_PROTOCOL; - break; - case SSL_ERROR_NO_CIPHER: - return CURLE_SSL_CIPHER; - break; - case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */ - case SSL_ERROR_NO_CERT_DEFINED: - case -42: /* bad certificate alert from server */ - case -43: /* unsupported cert alert from server */ - case -44: /* cert revoked alert from server */ - case -45: /* cert expired alert from server */ - case -46: /* cert unknown alert from server */ - return CURLE_SSL_CERTPROBLEM; - break; - case SSL_X509_ERROR(X509_NOT_OK): - case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): - case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): - case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): - case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): - case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): - case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): - case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): - case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): - return CURLE_PEER_FAILED_VERIFICATION; - break; - case -48: /* unknown ca alert from server */ - return CURLE_SSL_CACERT; - break; - case -49: /* access denied alert from server */ - return CURLE_REMOTE_ACCESS_DENIED; - break; - case SSL_ERROR_CONN_LOST: - case SSL_ERROR_SOCK_SETUP_FAILURE: - case SSL_ERROR_INVALID_HANDSHAKE: - case SSL_ERROR_INVALID_PROT_MSG: - case SSL_ERROR_INVALID_HMAC: - case SSL_ERROR_INVALID_SESSION: - case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */ - case SSL_ERROR_FINISHED_INVALID: - case SSL_ERROR_NO_CLIENT_RENOG: - default: - return CURLE_SSL_CONNECT_ERROR; - break; - } -} - -static Curl_recv axtls_recv; -static Curl_send axtls_send; - -static void free_ssl_structs(struct ssl_connect_data *connssl) -{ - if(BACKEND->ssl) { - ssl_free(BACKEND->ssl); - BACKEND->ssl = NULL; - } - if(BACKEND->ssl_ctx) { - ssl_ctx_free(BACKEND->ssl_ctx); - BACKEND->ssl_ctx = NULL; - } -} - -/* - * For both blocking and non-blocking connects, this function sets up the - * ssl context and state. This function is called after the TCP connect - * has completed. - */ -static CURLcode connect_prep(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - SSL_CTX *ssl_ctx; - SSL *ssl = NULL; - int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; - int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; - int i, ssl_fcn_return; - - /* Assuming users will not compile in custom key/cert to axTLS. - * Also, even for blocking connects, use axTLS non-blocking feature. - */ - uint32_t client_option = SSL_NO_DEFAULT_KEY | - SSL_SERVER_VERIFY_LATER | - SSL_CONNECT_IN_PARTS; - - if(connssl->state == ssl_connection_complete) - /* to make us tolerant against being called more than once for the - same connection */ - return CURLE_OK; - - if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { - failf(data, "axtls does not support CURL_SSLVERSION_MAX"); - return CURLE_SSL_CONNECT_ERROR; - } - - - /* axTLS only supports TLSv1 */ - /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - break; - default: - failf(data, "axTLS only supports TLS 1.0 and 1.1, " - "and it cannot be specified which one to use"); - return CURLE_SSL_CONNECT_ERROR; - } - -#ifdef AXTLSDEBUG - client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS; -#endif /* AXTLSDEBUG */ - - /* Allocate an SSL_CTX struct */ - ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS); - if(ssl_ctx == NULL) { - failf(data, "unable to create client SSL context"); - return CURLE_SSL_CONNECT_ERROR; - } - - BACKEND->ssl_ctx = ssl_ctx; - BACKEND->ssl = NULL; - - /* Load the trusted CA cert bundle file */ - if(SSL_CONN_CONFIG(CAfile)) { - if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, - SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) { - infof(data, "error reading ca cert file %s \n", - SSL_CONN_CONFIG(CAfile)); - if(SSL_CONN_CONFIG(verifypeer)) { - return CURLE_SSL_CACERT_BADFILE; - } - } - else - infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile)); - } - - /* gtls.c tasks we're skipping for now: - * 1) certificate revocation list checking - * 2) dns name assignment to host - * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore - * 4) set certificate priority. axTLS ignores type and sends certs in - * order added. can probably ignore this. - */ - - /* Load client certificate */ - if(SSL_SET_OPTION(cert)) { - i = 0; - /* Instead of trying to analyze cert type here, let axTLS try them all. */ - while(cert_types[i] != 0) { - ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], - SSL_SET_OPTION(cert), NULL); - if(ssl_fcn_return == SSL_OK) { - infof(data, "successfully read cert file %s \n", - SSL_SET_OPTION(cert)); - break; - } - i++; - } - /* Tried all cert types, none worked. */ - if(cert_types[i] == 0) { - failf(data, "%s is not x509 or pkcs12 format", - SSL_SET_OPTION(cert)); - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load client key. - If a pkcs12 file successfully loaded a cert, then there's nothing to do - because the key has already been loaded. */ - if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) { - i = 0; - /* Instead of trying to analyze key type here, let axTLS try them all. */ - while(key_types[i] != 0) { - ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], - SSL_SET_OPTION(key), NULL); - if(ssl_fcn_return == SSL_OK) { - infof(data, "successfully read key file %s \n", - SSL_SET_OPTION(key)); - break; - } - i++; - } - /* Tried all key types, none worked. */ - if(key_types[i] == 0) { - failf(data, "Failure: %s is not a supported key file", - SSL_SET_OPTION(key)); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* gtls.c does more here that is being left out for now - * 1) set session credentials. can probably ignore since axtls puts this - * info in the ssl_ctx struct - * 2) setting up callbacks. these seem gnutls specific - */ - - if(SSL_SET_OPTION(primary.sessionid)) { - const uint8_t *ssl_sessionid; - size_t ssl_idsize; - - /* In axTLS, handshaking happens inside ssl_client_new. */ - Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize, - sockindex)) { - /* we got a session id, use it! */ - infof(data, "SSL re-using session ID\n"); - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], - ssl_sessionid, (uint8_t)ssl_idsize, NULL); - } - Curl_ssl_sessionid_unlock(conn); - } - - if(!ssl) - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL); - - BACKEND->ssl = ssl; - return CURLE_OK; -} - -static void Curl_axtls_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - infof(conn->data, " Curl_axtls_close\n"); - - /* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl); - axTLS compat layer does nothing for SSL_shutdown */ - - /* The following line is from openssl.c. There seems to be no axTLS - equivalent. ssl_free and ssl_ctx_free close things. - SSL_set_connect_state(connssl->handle); */ - - free_ssl_structs(connssl); -} - -/* - * For both blocking and non-blocking connects, this function finalizes the - * SSL connection. - */ -static CURLcode connect_finish(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL *ssl = BACKEND->ssl; - const char *peer_CN; - uint32_t dns_altname_index; - const char *dns_altname; - int8_t found_subject_alt_names = 0; - int8_t found_subject_alt_name_matching_conn = 0; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; - const char * const dispname = SSL_IS_PROXY() ? - conn->http_proxy.host.dispname : conn->host.dispname; - - /* Here, gtls.c gets the peer certificates and fails out depending on - * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? - */ - - /* Verify server's certificate */ - if(SSL_CONN_CONFIG(verifypeer)) { - if(ssl_verify_cert(ssl) != SSL_OK) { - Curl_axtls_close(conn, sockindex); - failf(data, "server cert verify failed"); - return CURLE_PEER_FAILED_VERIFICATION; - } - } - else - infof(data, "\t server certificate verification SKIPPED\n"); - - /* Here, gtls.c does issuer verification. axTLS has no straightforward - * equivalent, so omitting for now.*/ - - /* Here, gtls.c does the following - * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but - * it seems useful. This is now implemented, by Oscar Koeroo - * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert - * 3) displays a bunch of cert information. axTLS doesn't support most of - * this, but a couple fields are available. - */ - - /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a - risk of an inifite loop */ - for(dns_altname_index = 0; ; dns_altname_index++) { - dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index); - if(dns_altname == NULL) { - break; - } - found_subject_alt_names = 1; - - infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n", - dns_altname, hostname); - if(Curl_cert_hostcheck(dns_altname, hostname)) { - found_subject_alt_name_matching_conn = 1; - break; - } - } - - /* RFC2818 checks */ - if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { - if(SSL_CONN_CONFIG(verifyhost)) { - /* Break connection ! */ - Curl_axtls_close(conn, sockindex); - failf(data, "\tsubjectAltName(s) do not match %s\n", dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\tsubjectAltName(s) do not match %s\n", dispname); - } - else if(found_subject_alt_names == 0) { - /* Per RFC2818, when no Subject Alt Names were available, examine the peer - CN as a legacy fallback */ - peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); - if(peer_CN == NULL) { - if(SSL_CONN_CONFIG(verifyhost)) { - Curl_axtls_close(conn, sockindex); - failf(data, "unable to obtain common name from peer certificate"); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "unable to obtain common name from peer certificate"); - } - else { - if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { - if(SSL_CONN_CONFIG(verifyhost)) { - /* Break connection ! */ - Curl_axtls_close(conn, sockindex); - failf(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, dispname); - } - } - } - - /* General housekeeping */ - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = axtls_recv; - conn->send[sockindex] = axtls_send; - - /* Put our freshly minted SSL session in cache */ - if(SSL_SET_OPTION(primary.sessionid)) { - const uint8_t *ssl_sessionid = ssl_get_session_id(ssl); - size_t ssl_idsize = ssl_get_session_id_size(ssl); - Curl_ssl_sessionid_lock(conn); - if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize, - sockindex) != CURLE_OK) - infof(data, "failed to add session to cache\n"); - Curl_ssl_sessionid_unlock(conn); - } - - return CURLE_OK; -} - -/* - * Use axTLS's non-blocking connection feature to open an SSL connection. - * This is called after a TCP connection is already established. - */ -static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn, - int sockindex, bool *done) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CURLcode conn_step; - int ssl_fcn_return; - int i; - - *done = FALSE; - /* connectdata is calloc'd and connecting_state is only changed in this - function, so this is safe, as the state is effectively initialized. */ - if(connssl->connecting_state == ssl_connect_1) { - conn_step = connect_prep(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - connssl->connecting_state = ssl_connect_2; - } - - if(connssl->connecting_state == ssl_connect_2) { - /* Check to make sure handshake was ok. */ - if(ssl_handshake_status(BACKEND->ssl) != SSL_OK) { - /* Loop to perform more work in between sleeps. This is work around the - fact that axtls does not expose any knowledge about when work needs - to be performed. This can save ~25% of time on SSL handshakes. */ - for(i = 0; i<5; i++) { - ssl_fcn_return = ssl_read(BACKEND->ssl, NULL); - if(ssl_fcn_return < 0) { - Curl_axtls_close(conn, sockindex); - ssl_display_error(ssl_fcn_return); /* goes to stdout. */ - return map_error_to_curl(ssl_fcn_return); - } - return CURLE_OK; - } - } - infof(conn->data, "handshake completed successfully\n"); - connssl->connecting_state = ssl_connect_3; - } - - if(connssl->connecting_state == ssl_connect_3) { - conn_step = connect_finish(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - /* Reset connect state */ - connssl->connecting_state = ssl_connect_1; - - *done = TRUE; - return CURLE_OK; - } - - /* Unrecognized state. Things are very bad. */ - connssl->state = ssl_connection_none; - connssl->connecting_state = ssl_connect_1; - /* Return value perhaps not strictly correct, but distinguishes the issue.*/ - return CURLE_BAD_FUNCTION_ARGUMENT; -} - - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic for a blocking connect. - */ -static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex) -{ - struct Curl_easy *data = conn->data; - CURLcode conn_step = connect_prep(conn, sockindex); - int ssl_fcn_return; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL *ssl = BACKEND->ssl; - long timeout_ms; - - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - /* Check to make sure handshake was ok. */ - while(ssl_handshake_status(ssl) != SSL_OK) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - ssl_fcn_return = ssl_read(ssl, NULL); - if(ssl_fcn_return < 0) { - Curl_axtls_close(conn, sockindex); - ssl_display_error(ssl_fcn_return); /* goes to stdout. */ - return map_error_to_curl(ssl_fcn_return); - } - /* TODO: avoid polling */ - Curl_wait_ms(10); - } - infof(conn->data, "handshake completed successfully\n"); - - conn_step = connect_finish(conn, sockindex); - if(conn_step != CURLE_OK) { - Curl_axtls_close(conn, sockindex); - return conn_step; - } - - return CURLE_OK; -} - -/* return number of sent (non-SSL) bytes */ -static ssize_t axtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *err) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ - int rc = ssl_write(BACKEND->ssl, mem, (int)len); - - infof(conn->data, " axtls_send\n"); - - if(rc < 0) { - *err = map_error_to_curl(rc); - rc = -1; /* generic error code for send failure */ - } - - *err = CURLE_OK; - return rc; -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) -{ - /* Outline taken from openssl.c since functions are in axTLS compat layer. - axTLS's error set is much smaller, so a lot of error-handling was removed. - */ - int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct Curl_easy *data = conn->data; - uint8_t *buf; - ssize_t nread; - - infof(conn->data, " Curl_axtls_shutdown\n"); - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - (void)SSL_shutdown(BACKEND->ssl); - */ - - if(BACKEND->ssl) { - int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - /* Something to read, let's do it and hope that it is the close - notify alert from the server. buf is managed internally by - axTLS and will be released upon calling ssl_free via - free_ssl_structs. */ - nread = (ssize_t)ssl_read(BACKEND->ssl, &buf); - - if(nread < SSL_OK) { - failf(data, "close notify alert not received during shutdown"); - retval = -1; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - } - - free_ssl_structs(connssl); - } - return retval; -} - -static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *err) -{ - struct ssl_connect_data *connssl = &conn->ssl[num]; - ssize_t ret = 0; - uint8_t *read_buf; - - infof(conn->data, " axtls_recv\n"); - - *err = CURLE_OK; - if(connssl) { - ret = ssl_read(BACKEND->ssl, &read_buf); - if(ret > SSL_OK) { - /* ssl_read returns SSL_OK if there is more data to read, so if it is - larger, then all data has been read already. */ - memcpy(buf, read_buf, - (size_t)ret > buffersize ? buffersize : (size_t)ret); - } - else if(ret == SSL_OK) { - /* more data to be read, signal caller to call again */ - *err = CURLE_AGAIN; - ret = -1; - } - else if(ret == -3) { - /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS - team approves proposed fix. */ - Curl_axtls_close(conn, num); - } - else { - failf(conn->data, "axTLS recv error (%d)", ret); - *err = map_error_to_curl((int) ret); - ret = -1; - } - } - - return ret; -} - -/* - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int Curl_axtls_check_cxn(struct connectdata *conn) -{ - /* openssl.c line: - rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1); - axTLS compat layer always returns the last argument, so connection is - always alive? */ - - infof(conn->data, " Curl_axtls_check_cxn\n"); - return 1; /* connection still in place */ -} - -static void Curl_axtls_session_free(void *ptr) -{ - (void)ptr; - /* free the ID */ - /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL - compatibility layer does nothing, so we do nothing too. */ -} - -static size_t Curl_axtls_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "axTLS/%s", ssl_version()); -} - -static CURLcode Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, size_t length) -{ - static bool ssl_seeded = FALSE; - (void)data; - if(!ssl_seeded) { - ssl_seeded = TRUE; - /* Initialize the seed if not already done. This call is not exactly thread - * safe (and neither is the ssl_seeded check), but the worst effect of a - * race condition is that some global resources will leak. */ - RNG_initialize(); - } - get_random((int)length, entropy); - return CURLE_OK; -} - -static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - (void)info; - return BACKEND->ssl; -} - -const struct Curl_ssl Curl_ssl_axtls = { - { CURLSSLBACKEND_AXTLS, "axtls" }, /* info */ - 0, /* no fancy stuff */ - sizeof(struct ssl_backend_data), - - /* - * axTLS has no global init. Everything is done through SSL and SSL_CTX - * structs stored in connectdata structure. - */ - Curl_none_init, /* init */ - /* axTLS has no global cleanup. */ - Curl_none_cleanup, /* cleanup */ - Curl_axtls_version, /* version */ - Curl_axtls_check_cxn, /* check_cxn */ - Curl_axtls_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ - Curl_axtls_random, /* random */ - Curl_none_cert_status_request, /* cert_status_request */ - Curl_axtls_connect, /* connect */ - Curl_axtls_connect_nonblocking, /* connect_nonblocking */ - Curl_axtls_get_internals, /* get_internals */ - Curl_axtls_close, /* close_one */ - Curl_none_close_all, /* close_all */ - Curl_axtls_session_free, /* session_free */ - Curl_none_set_engine, /* set_engine */ - Curl_none_set_engine_default, /* set_engine_default */ - Curl_none_engines_list, /* engines_list */ - Curl_none_false_start, /* false_start */ - Curl_none_md5sum, /* md5sum */ - NULL /* sha256sum */ -}; - -#endif /* USE_AXTLS */ diff --git a/libs/libcurl/src/vtls/axtls.h b/libs/libcurl/src/vtls/axtls.h deleted file mode 100644 index cb8187272d..0000000000 --- a/libs/libcurl/src/vtls/axtls.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef HEADER_CURL_AXTLS_H -#define HEADER_CURL_AXTLS_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com> - * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#ifdef USE_AXTLS -#include "curl/curl.h" -#include "urldata.h" - -extern const struct Curl_ssl Curl_ssl_axtls; - -#endif /* USE_AXTLS */ -#endif /* HEADER_CURL_AXTLS_H */ diff --git a/libs/libcurl/src/vtls/cyassl.c b/libs/libcurl/src/vtls/cyassl.c index e10398ac3f..0d45afbf0c 100644 --- a/libs/libcurl/src/vtls/cyassl.c +++ b/libs/libcurl/src/vtls/cyassl.c @@ -777,13 +777,13 @@ static void Curl_cyassl_session_free(void *ptr) static size_t Curl_cyassl_version(char *buffer, size_t size) { #if LIBCYASSL_VERSION_HEX >= 0x03006000 - return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); + return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); #elif defined(WOLFSSL_VERSION) - return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); + return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); #elif defined(CYASSL_VERSION) - return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); + return msnprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); #else - return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); + return msnprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); #endif } diff --git a/libs/libcurl/src/vtls/darwinssl.c b/libs/libcurl/src/vtls/darwinssl.c index e8116b8a11..25b101282c 100644 --- a/libs/libcurl/src/vtls/darwinssl.c +++ b/libs/libcurl/src/vtls/darwinssl.c @@ -950,7 +950,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data, if(!c) { failf(data, "SSL: invalid CA certificate subject"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; } /* If the subject is already available as UTF-8 encoded (ie 'direct') then @@ -970,7 +970,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data, if(!CFStringGetCString(c, cbuf, cbuf_size, kCFStringEncodingUTF8)) { failf(data, "SSL: invalid CA certificate subject"); - result = CURLE_SSL_CACERT; + result = CURLE_PEER_FAILED_VERIFICATION; } else /* pass back the buffer */ @@ -1649,7 +1649,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } CFRelease(cert); - if(result == CURLE_SSL_CACERT) + if(result == CURLE_PEER_FAILED_VERIFICATION) return CURLE_SSL_CERTPROBLEM; if(result) return result; @@ -2429,37 +2429,37 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* These are all certificate problems with the server: */ case errSSLXCertChainInvalid: failf(data, "SSL certificate problem: Invalid certificate chain"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLUnknownRootCert: failf(data, "SSL certificate problem: Untrusted root certificate"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLNoRootCert: failf(data, "SSL certificate problem: No root certificate"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLCertNotYetValid: failf(data, "SSL certificate problem: The certificate chain had a " "certificate that is not yet valid"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLCertExpired: case errSSLPeerCertExpired: failf(data, "SSL certificate problem: Certificate chain had an " "expired certificate"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLBadCert: case errSSLPeerBadCert: failf(data, "SSL certificate problem: Couldn't understand the server " "certificate format"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerUnsupportedCert: failf(data, "SSL certificate problem: An unsupported certificate " "format was encountered"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerCertRevoked: failf(data, "SSL certificate problem: The certificate was revoked"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerCertUnknown: failf(data, "SSL certificate problem: The certificate is unknown"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; /* These are all certificate problems with the client: */ case errSecAuthFailed: @@ -3015,7 +3015,7 @@ static void Curl_darwinssl_session_free(void *ptr) static size_t Curl_darwinssl_version(char *buffer, size_t size) { - return snprintf(buffer, size, "SecureTransport"); + return msnprintf(buffer, size, "SecureTransport"); } /* diff --git a/libs/libcurl/src/vtls/gskit.c b/libs/libcurl/src/vtls/gskit.c index 8d1b3d6afc..c4afc89041 100644 --- a/libs/libcurl/src/vtls/gskit.c +++ b/libs/libcurl/src/vtls/gskit.c @@ -1314,7 +1314,7 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) static size_t Curl_gskit_version(char *buffer, size_t size) { - return snprintf(buffer, size, "GSKit"); + return msnprintf(buffer, size, "GSKit"); } diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c index 37662a748f..9035ec483e 100644 --- a/libs/libcurl/src/vtls/gtls.c +++ b/libs/libcurl/src/vtls/gtls.c @@ -227,17 +227,17 @@ static void showtime(struct Curl_easy *data, if(result) return; - snprintf(str, - sizeof(str), - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", - text, - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + msnprintf(str, + sizeof(str), + "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", + text, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); infof(data, "%s\n", str); } #endif @@ -1110,7 +1110,7 @@ gtls_connect_step3(struct connectdata *conn, "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate verification FAILED\n"); @@ -1748,7 +1748,7 @@ static void Curl_gtls_session_free(void *ptr) static size_t Curl_gtls_version(char *buffer, size_t size) { - return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); + return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } #ifndef USE_GNUTLS_NETTLE diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c index c5ed8872ef..6a20e276e3 100644 --- a/libs/libcurl/src/vtls/mbedtls.c +++ b/libs/libcurl/src/vtls/mbedtls.c @@ -580,7 +580,7 @@ mbed_connect_step2(struct connectdata *conn, if(ret & MBEDTLS_X509_BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; } if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) @@ -812,8 +812,8 @@ static void Curl_mbedtls_session_free(void *ptr) static size_t Curl_mbedtls_version(char *buffer, size_t size) { unsigned int version = mbedtls_version_get_number(); - return snprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24, - (version>>16)&0xff, (version>>8)&0xff); + return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24, + (version>>16)&0xff, (version>>8)&0xff); } static CURLcode Curl_mbedtls_random(struct Curl_easy *data, diff --git a/libs/libcurl/src/vtls/mesalink.c b/libs/libcurl/src/vtls/mesalink.c index 6a2b67e633..db14115593 100644 --- a/libs/libcurl/src/vtls/mesalink.c +++ b/libs/libcurl/src/vtls/mesalink.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2017-2018, Yiming Jing, <jingyiming@baidu.com> - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com> + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -424,7 +424,7 @@ mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, static size_t Curl_mesalink_version(char *buffer, size_t size) { - return snprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING); + return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING); } static int diff --git a/libs/libcurl/src/vtls/nss.c b/libs/libcurl/src/vtls/nss.c index a3d3e58bbe..08ee1aaaf2 100644 --- a/libs/libcurl/src/vtls/nss.c +++ b/libs/libcurl/src/vtls/nss.c @@ -246,6 +246,32 @@ static void nss_print_error_message(struct Curl_easy *data, PRUint32 err) failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); } +static char *nss_sslver_to_name(PRUint16 nssver) +{ + switch(nssver) { + case SSL_LIBRARY_VERSION_2: + return strdup("SSLv2"); + case SSL_LIBRARY_VERSION_3_0: + return strdup("SSLv3"); + case SSL_LIBRARY_VERSION_TLS_1_0: + return strdup("TLSv1.0"); +#ifdef SSL_LIBRARY_VERSION_TLS_1_1 + case SSL_LIBRARY_VERSION_TLS_1_1: + return strdup("TLSv1.1"); +#endif +#ifdef SSL_LIBRARY_VERSION_TLS_1_2 + case SSL_LIBRARY_VERSION_TLS_1_2: + return strdup("TLSv1.2"); +#endif +#ifdef SSL_LIBRARY_VERSION_TLS_1_3 + case SSL_LIBRARY_VERSION_TLS_1_3: + return strdup("TLSv1.3"); +#endif + default: + return curl_maprintf("0x%04x", nssver); + } +} + static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, char *cipher_list) { @@ -1638,17 +1664,6 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version) { switch(version) { - case CURL_SSLVERSION_TLSv1: - /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */ -#ifdef SSL_LIBRARY_VERSION_TLS_1_2 - *nssver = SSL_LIBRARY_VERSION_TLS_1_2; -#elif defined SSL_LIBRARY_VERSION_TLS_1_1 - *nssver = SSL_LIBRARY_VERSION_TLS_1_1; -#else - *nssver = SSL_LIBRARY_VERSION_TLS_1_0; -#endif - return CURLE_OK; - case CURL_SSLVERSION_SSLv2: *nssver = SSL_LIBRARY_VERSION_2; return CURLE_OK; @@ -1709,10 +1724,8 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver, } switch(min) { - case CURL_SSLVERSION_DEFAULT: - break; case CURL_SSLVERSION_TLSv1: - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + case CURL_SSLVERSION_DEFAULT: break; default: result = nss_sslver_from_curl(&sslver->min, min); @@ -1789,10 +1802,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result; bool second_layer = FALSE; + SSLVersionRange sslver_supported; SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, /* min */ - SSL_LIBRARY_VERSION_TLS_1_0 /* max */ +#ifdef SSL_LIBRARY_VERSION_TLS_1_3 + SSL_LIBRARY_VERSION_TLS_1_3 /* max */ +#elif defined SSL_LIBRARY_VERSION_TLS_1_2 + SSL_LIBRARY_VERSION_TLS_1_2 +#elif defined SSL_LIBRARY_VERSION_TLS_1_1 + SSL_LIBRARY_VERSION_TLS_1_1 +#else + SSL_LIBRARY_VERSION_TLS_1_0 +#endif }; BACKEND->data = data; @@ -1841,6 +1863,20 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* enable/disable the requested SSL version(s) */ if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) goto error; + if(SSL_VersionRangeGetSupported(ssl_variant_stream, + &sslver_supported) != SECSuccess) + goto error; + if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) { + char *sslver_req_str, *sslver_supp_str; + sslver_req_str = nss_sslver_to_name(sslver.max); + sslver_supp_str = nss_sslver_to_name(sslver_supported.max); + if(sslver_req_str && sslver_supp_str) + infof(data, "Falling back from %s to max supported SSL version (%s)\n", + sslver_req_str, sslver_supp_str); + free(sslver_req_str); + free(sslver_supp_str); + sslver.max = sslver_supported.max; + } if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) goto error; @@ -2090,7 +2126,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) result = CURLE_PEER_FAILED_VERIFICATION; else if(*certverifyresult != 0) - result = CURLE_SSL_CACERT; + result = CURLE_PEER_FAILED_VERIFICATION; goto error; } @@ -2164,7 +2200,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, if(!blocking) /* CURLE_AGAIN in non-blocking mode is not an error */ return CURLE_OK; - /* fall through */ + /* FALLTHROUGH */ default: return result; } @@ -2279,7 +2315,7 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */ static size_t Curl_nss_version(char *buffer, size_t size) { - return snprintf(buffer, size, "NSS/%s", NSS_VERSION); + return msnprintf(buffer, size, "NSS/%s", NSS_VERSION); } /* data might be NULL */ diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index 4c5e8c19c0..8bddb9a8c6 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -69,7 +69,7 @@ #include <openssl/ocsp.h> #endif -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && /* 0.9.8 or later */ \ +#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \ !defined(OPENSSL_NO_ENGINE) #define USE_OPENSSL_ENGINE #include <openssl/engine.h> @@ -82,6 +82,13 @@ #include "curl_memory.h" #include "memdebug.h" +/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS + renegotiations when built with BoringSSL. Renegotiating is non-compliant + with HTTP/2 and "an extremely dangerous protocol feature". Beware. + +#define ALLOW_RENEG 1 + */ + #ifndef OPENSSL_VERSION_NUMBER #error "OPENSSL_VERSION_NUMBER not defined" #endif @@ -384,6 +391,31 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) return buf; } +/* Return an extra data index for the connection data. + * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). + */ +static int ossl_get_ssl_conn_index(void) +{ + static int ssl_ex_data_conn_index = -1; + if(ssl_ex_data_conn_index < 0) { + ssl_ex_data_conn_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + } + return ssl_ex_data_conn_index; +} + +/* Return an extra data index for the sockindex. + * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). + */ +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); + } + return ssl_ex_data_sockindex_index; +} + static int passwd_callback(char *buf, int num, int encrypting, void *global_passwd) { @@ -1035,6 +1067,10 @@ 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) + return 0; + return 1; } @@ -1049,7 +1085,7 @@ static void Curl_ossl_cleanup(void) /* Free ciphers and digests lists */ EVP_cleanup(); -#ifdef HAVE_ENGINE_CLEANUP +#ifdef USE_OPENSSL_ENGINE /* Free engine list */ ENGINE_cleanup(); #endif @@ -1867,15 +1903,8 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Unknown"; } -static const char *tls_rt_type(int type, const void *buf, size_t buflen) +static const char *tls_rt_type(int type) { - (void)buf; - (void)buflen; -#ifdef SSL3_RT_INNER_CONTENT_TYPE - if(type == SSL3_RT_INNER_CONTENT_TYPE && buf && buflen >= 1) - type = *(unsigned char *)buf; -#endif - switch(type) { #ifdef SSL3_RT_HEADER case SSL3_RT_HEADER: @@ -1945,12 +1974,20 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, case 0: break; default: - snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); + msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); verstr = unknown; break; } - if(ssl_ver) { + /* Log progress for interesting records only (like Handshake or Alert), skip + * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0). + * For TLS 1.3, skip notification of the decrypted inner Content Type. + */ + if(ssl_ver +#ifdef SSL3_RT_INNER_CONTENT_TYPE + && content_type != SSL3_RT_INNER_CONTENT_TYPE +#endif + ) { const char *msg_name, *tls_rt_name; char ssl_buf[1024]; int msg_type, txt_len; @@ -1964,17 +2001,10 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, * is at 'buf[0]'. */ if(ssl_ver == SSL3_VERSION_MAJOR && content_type) - tls_rt_name = tls_rt_type(content_type, buf, len); + tls_rt_name = tls_rt_type(content_type); else tls_rt_name = ""; -#ifdef SSL3_RT_INNER_CONTENT_TYPE - if(content_type == SSL3_RT_INNER_CONTENT_TYPE) { - msg_type = 0; - msg_name = "[no content]"; - } - else -#endif if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) { msg_type = *(char *)buf; msg_name = "Change cipher spec"; @@ -1988,9 +2018,9 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, msg_name = ssl_msg_type(ssl_ver, msg_type); } - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", - verstr, direction?"OUT":"IN", - tls_rt_name, msg_name, msg_type); + txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", + verstr, direction?"OUT":"IN", + tls_rt_name, msg_name, msg_type); if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) { Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len); } @@ -2137,6 +2167,7 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, } #else (void)sockindex; + (void)ctx_options; failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); return CURLE_NOT_BUILT_IN; #endif @@ -2189,6 +2220,62 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, return CURLE_OK; } +/* The "new session" callback must return zero if the session can be removed + * or non-zero if the session has been put into the session cache. + */ +static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) +{ + int res = 0; + struct connectdata *conn; + struct Curl_easy *data; + int sockindex; + curl_socket_t *sockindex_ptr; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); + + if(connectdata_idx < 0 || sockindex_idx < 0) + return 0; + + conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx); + if(!conn) + return 0; + + data = conn->data; + + /* The sockindex has been stored as a pointer to an array element */ + sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx); + sockindex = (int)(sockindex_ptr - conn->sock); + + 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(incache) { + if(old_ssl_sessionid != ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } + } + + if(!incache) { + if(!Curl_ssl_addsessionid(conn, ssl_sessionid, + 0 /* unknown size */, sockindex)) { + /* the session has been put into the session cache */ + res = 1; + } + else + failf(data, "failed to store ssl session"); + } + Curl_ssl_sessionid_unlock(conn); + } + + return res; +} + static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; @@ -2585,6 +2672,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to avoid that OpenSSL creates + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(BACKEND->ctx, + SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(BACKEND->ctx, ossl_new_session_cb); + /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, @@ -2610,6 +2705,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); #endif +#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(BACKEND->handle, ssl_renegotiate_freely); +#endif + SSL_set_connect_state(BACKEND->handle); BACKEND->server_cert = 0x0; @@ -2627,6 +2726,15 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); + + if(connectdata_idx >= 0 && sockindex_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); + } Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { @@ -2721,14 +2829,14 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) if((lib == ERR_LIB_SSL) && (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { - result = CURLE_SSL_CACERT; + result = CURLE_PEER_FAILED_VERIFICATION; lerr = SSL_get_verify_result(BACKEND->handle); if(lerr != X509_V_OK) { *certverifyresult = lerr; - snprintf(error_buffer, sizeof(error_buffer), - "SSL certificate problem: %s", - X509_verify_cert_error_string(lerr)); + msnprintf(error_buffer, sizeof(error_buffer), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); } else /* strcpy() is fine here as long as the string fits within @@ -2839,7 +2947,7 @@ static void pubkey_show(struct Curl_easy *data, char *ptr; char namebuf[32]; - snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); if(bn) BN_print(mem, bn); @@ -2900,8 +3008,8 @@ static int X509V3_ext(struct Curl_easy *data, while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) j++; if(j<(size_t)biomem->length) - ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, - biomem->data[j]); + ptr += msnprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, + biomem->data[j]); } Curl_ssl_push_certinfo(data, certnum, namebuf, buf); @@ -3214,20 +3322,8 @@ static CURLcode servercert(struct connectdata *conn, /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); - fp = BIO_new(BIO_s_file()); - if(fp == NULL) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - BIO_free(mem); - return CURLE_OUT_OF_MEMORY; - } - BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); if(!BACKEND->server_cert) { - BIO_free(fp); BIO_free(mem); if(!strict) return CURLE_OK; @@ -3262,7 +3358,6 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifyhost)) { result = verifyhost(conn, BACKEND->server_cert); if(result) { - BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; @@ -3284,6 +3379,18 @@ static CURLcode servercert(struct connectdata *conn, /* e.g. match issuer name with provided issuer certificate */ if(SSL_SET_OPTION(issuercert)) { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } + if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", @@ -3319,6 +3426,7 @@ static CURLcode servercert(struct connectdata *conn, infof(data, " SSL certificate issuer check ok (%s)\n", SSL_SET_OPTION(issuercert)); + BIO_free(fp); X509_free(issuer); } @@ -3347,7 +3455,6 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { - BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; @@ -3367,7 +3474,6 @@ static CURLcode servercert(struct connectdata *conn, failf(data, "SSL: public key does not match pinned public key!"); } - BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; connssl->connecting_state = ssl_connect_done; @@ -3378,52 +3484,10 @@ static CURLcode servercert(struct connectdata *conn, static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(SSL_SET_OPTION(primary.sessionid)) { - bool incache; - SSL_SESSION *our_ssl_sessionid; - void *old_ssl_sessionid = NULL; - - our_ssl_sessionid = SSL_get1_session(BACKEND->handle); - - /* SSL_get1_session() will increment the reference count and the session - will stay in memory until explicitly freed with SSL_SESSION_free(3), - regardless of its state. */ - - Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, - sockindex)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } - - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */, sockindex); - if(result) { - Curl_ssl_sessionid_unlock(conn); - failf(data, "failed to store ssl session"); - return result; - } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); - } - Curl_ssl_sessionid_unlock(conn); - } - /* * We check certificates to authenticate the server; otherwise we risk * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to @@ -3709,7 +3773,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ static size_t Curl_ossl_version(char *buffer, size_t size) { #ifdef OPENSSL_IS_BORINGSSL - return snprintf(buffer, size, OSSL_PACKAGE); + return msnprintf(buffer, size, OSSL_PACKAGE); #else /* OPENSSL_IS_BORINGSSL */ char sub[3]; unsigned long ssleay_value; @@ -3736,12 +3800,12 @@ static size_t Curl_ossl_version(char *buffer, size_t size) sub[0]='\0'; } - return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", - OSSL_PACKAGE, - (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); + return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s", + OSSL_PACKAGE, + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); #endif /* OPENSSL_IS_BORINGSSL */ } diff --git a/libs/libcurl/src/vtls/polarssl.c b/libs/libcurl/src/vtls/polarssl.c index 27af0ccf3e..6ecabe94b5 100644 --- a/libs/libcurl/src/vtls/polarssl.c +++ b/libs/libcurl/src/vtls/polarssl.c @@ -497,7 +497,7 @@ polarssl_connect_step2(struct connectdata *conn, if(ret & BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); - return CURLE_SSL_CACERT; + return CURLE_PEER_FAILED_VERIFICATION; } if(ret & BADCERT_CN_MISMATCH) @@ -716,9 +716,9 @@ static void Curl_polarssl_session_free(void *ptr) static size_t Curl_polarssl_version(char *buffer, size_t size) { unsigned int version = version_get_number(); - return snprintf(buffer, size, "%s/%d.%d.%d", - version >= 0x01030A00?"mbedTLS":"PolarSSL", - version>>24, (version>>16)&0xff, (version>>8)&0xff); + return msnprintf(buffer, size, "%s/%d.%d.%d", + version >= 0x01030A00?"mbedTLS":"PolarSSL", + version>>24, (version>>16)&0xff, (version>>8)&0xff); } static CURLcode diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c index e4426924bc..56fd93e1e5 100644 --- a/libs/libcurl/src/vtls/schannel.c +++ b/libs/libcurl/src/vtls/schannel.c @@ -23,9 +23,8 @@ ***************************************************************************/ /* - * Source file for all SChannel-specific code for the TLS/SSL layer. No code + * Source file for all Schannel-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. - * */ /* @@ -196,7 +195,7 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "Schannel: TLS 1.3 is not yet supported"); + failf(data, "schannel: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; } } @@ -434,7 +433,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, VERSION_LESS_THAN_EQUAL)) { - /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and + /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and algorithms that may not be supported by all servers. */ infof(data, "schannel: WinSSL version is old and may not be able to " "connect to some servers due to lack of SNI, algorithms, etc.\n"); @@ -1114,13 +1113,68 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) #ifdef HAS_MANUAL_VERIFY_API if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) { - return verify_certificate(conn, sockindex); + return Curl_verify_certificate(conn, sockindex); } #endif return CURLE_OK; } +static bool +valid_cert_encoding(const CERT_CONTEXT *cert_context) +{ + return (cert_context != NULL) && + ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (cert_context->pbCertEncoded != NULL) && + (cert_context->cbCertEncoded > 0); +} + +typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg); + +static void +traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func, + void *arg) +{ + const CERT_CONTEXT *current_context = NULL; + bool should_continue = true; + while(should_continue && + (current_context = CertEnumCertificatesInStore( + context->hCertStore, + current_context)) != NULL) + should_continue = func(current_context, arg); + + if(current_context) + CertFreeCertificateContext(current_context); +} + +static bool +cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count) +{ + if(valid_cert_encoding(ccert_context)) + (*(int *)certs_count)++; + return true; +} + +struct Adder_args +{ + struct connectdata *conn; + CURLcode result; + int idx; +}; + +static bool +add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg) +{ + struct Adder_args *args = (struct Adder_args*)raw_arg; + args->result = CURLE_OK; + if(valid_cert_encoding(ccert_context)) { + const char *beg = (const char *) ccert_context->pbCertEncoded; + const char *end = beg + ccert_context->cbCertEncoded; + args->result = Curl_extract_certinfo(args->conn, (args->idx)++, beg, end); + } + return args->result == CURLE_OK; +} + static CURLcode schannel_connect_step3(struct connectdata *conn, int sockindex) { @@ -1230,6 +1284,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } if(data->set.ssl.certinfo) { + int certs_count = 0; sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); @@ -1238,15 +1293,15 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) return CURLE_PEER_FAILED_VERIFICATION; } - result = Curl_ssl_init_certinfo(data, 1); - if(!result) { - if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && - (ccert_context->cbCertEncoded > 0)) { + traverse_cert_store(ccert_context, cert_counter_callback, &certs_count); - const char *beg = (const char *) ccert_context->pbCertEncoded; - const char *end = beg + ccert_context->cbCertEncoded; - result = Curl_extract_certinfo(conn, 0, beg, end); - } + result = Curl_ssl_init_certinfo(data, certs_count); + if(!result) { + struct Adder_args args; + args.conn = conn; + args.idx = 0; + traverse_cert_store(ccert_context, add_cert_to_certinfo, &args); + result = args.result; } CertFreeCertificateContext(ccert_context); if(result) @@ -1994,7 +2049,7 @@ static void Curl_schannel_cleanup(void) static size_t Curl_schannel_version(char *buffer, size_t size) { - size = snprintf(buffer, size, "WinSSL"); + size = msnprintf(buffer, size, "WinSSL"); return size; } diff --git a/libs/libcurl/src/vtls/schannel.h b/libs/libcurl/src/vtls/schannel.h index e491bd4318..ee8d7d47ac 100644 --- a/libs/libcurl/src/vtls/schannel.h +++ b/libs/libcurl/src/vtls/schannel.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al. - * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,7 +53,7 @@ extern const struct Curl_ssl Curl_ssl_schannel; -CURLcode verify_certificate(struct connectdata *conn, int sockindex); +CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex); /* structs to expose only in schannel.c and schannel_verify.c */ #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c index 2516f56657..8b21624ba4 100644 --- a/libs/libcurl/src/vtls/schannel_verify.c +++ b/libs/libcurl/src/vtls/schannel_verify.c @@ -23,7 +23,7 @@ ***************************************************************************/ /* - * Source file for SChannel-specific certificate verification. This code should + * Source file for Schannel-specific certificate verification. This code should * only be invoked by code in schannel.c. */ @@ -406,7 +406,7 @@ cleanup: return result; } -CURLcode verify_certificate(struct connectdata *conn, int sockindex) +CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) { SECURITY_STATUS status; struct Curl_easy *data = conn->data; diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c index 6af39feab9..5e75f92e99 100644 --- a/libs/libcurl/src/vtls/vtls.c +++ b/libs/libcurl/src/vtls/vtls.c @@ -700,7 +700,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; /* sprintf the label and colon */ - snprintf(output, outlen, "%s:", label); + msnprintf(output, outlen, "%s:", label); /* memcpy the value (it might not be zero terminated) */ memcpy(&output[labellen + 1], value, valuelen); @@ -1170,8 +1170,6 @@ static const struct Curl_ssl Curl_ssl_multi = { const struct Curl_ssl *Curl_ssl = #if defined(CURL_WITH_MULTI_SSL) &Curl_ssl_multi; -#elif defined(USE_AXTLS) - &Curl_ssl_axtls; #elif defined(USE_CYASSL) &Curl_ssl_cyassl; #elif defined(USE_DARWINSSL) @@ -1197,9 +1195,6 @@ const struct Curl_ssl *Curl_ssl = #endif static const struct Curl_ssl *available_backends[] = { -#if defined(USE_AXTLS) - &Curl_ssl_axtls, -#endif #if defined(USE_CYASSL) &Curl_ssl_cyassl, #endif @@ -1318,7 +1313,14 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, *avail = (const curl_ssl_backend **)&available_backends; if(Curl_ssl != &Curl_ssl_multi) - return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE; + return id == Curl_ssl->info.id || + (name && strcasecompare(name, Curl_ssl->info.name)) ? + CURLSSLSET_OK : +#if defined(CURL_WITH_MULTI_SSL) + CURLSSLSET_TOO_LATE; +#else + CURLSSLSET_UNKNOWN_BACKEND; +#endif for(i = 0; available_backends[i]; i++) { if(available_backends[i]->info.id == id || diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h index 5cd11602e7..1f163631f7 100644 --- a/libs/libcurl/src/vtls/vtls.h +++ b/libs/libcurl/src/vtls/vtls.h @@ -103,7 +103,6 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, #include "nssg.h" /* NSS versions */ #include "gskit.h" /* Global Secure ToolKit versions */ #include "polarssl.h" /* PolarSSL versions */ -#include "axtls.h" /* axTLS versions */ #include "cyassl.h" /* CyaSSL versions */ #include "schannel.h" /* Schannel SSPI version */ #include "darwinssl.h" /* SecureTransport (Darwin) version */ diff --git a/libs/libcurl/src/x509asn1.c b/libs/libcurl/src/x509asn1.c index a576fc703b..746e1e8e8d 100644 --- a/libs/libcurl/src/x509asn1.c +++ b/libs/libcurl/src/x509asn1.c @@ -209,7 +209,7 @@ static const char *octet2str(const char *beg, const char *end) buf = malloc(3 * n + 1); if(buf) for(n = 0; beg < end; n += 3) - snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); + msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); } return buf; } |