diff options
author | Haibo Huang <hhb@google.com> | 2020-04-30 00:42:15 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-04-30 00:42:15 +0000 |
commit | 0c66739b05f29c81b6a0a6814929e1e6a51c6995 (patch) | |
tree | e932df98deeb78b7fe8615fe094739eda91b8956 /lib | |
parent | 710432084ddcf1503bd3f13a633df9f9af772a7f (diff) | |
parent | ea155d05e764c6543c0d6be01edf12dda123ed99 (diff) | |
download | external_curl-0c66739b05f29c81b6a0a6814929e1e6a51c6995.tar.gz external_curl-0c66739b05f29c81b6a0a6814929e1e6a51c6995.tar.bz2 external_curl-0c66739b05f29c81b6a0a6814929e1e6a51c6995.zip |
Merge "Upgrade curl to curl-7_70_0" am: 47cd0cac1b am: ea155d05e7
Change-Id: I487c81955205e3bb979e2f0d41b53c68ab72dd17
Diffstat (limited to 'lib')
74 files changed, 2719 insertions, 1348 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e73efb90..1d71e149 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, 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. +# +########################################################################### set(LIB_NAME libcurl) if(BUILD_SHARED_LIBS) @@ -71,6 +92,11 @@ add_library( ${HHEADERS} ${CSOURCES} ) +add_library( + ${PROJECT_NAME}::${LIB_NAME} + ALIAS ${LIB_NAME} + ) + if(MSVC AND NOT BUILD_SHARED_LIBS) set_target_properties(${LIB_NAME} PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) endif() @@ -122,5 +148,5 @@ install(TARGETS ${LIB_NAME} export(TARGETS ${LIB_NAME} APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake - NAMESPACE CURL:: + NAMESPACE ${PROJECT_NAME}:: ) diff --git a/lib/Makefile.Watcom b/lib/Makefile.Watcom index 942cd0c7..6ea975b5 100644 --- a/lib/Makefile.Watcom +++ b/lib/Makefile.Watcom @@ -6,7 +6,7 @@ # \___|\___/|_| \_\_____| # # Copyright (C) 2005 - 2009, Gisle Vanem <gvanem@yahoo.no>. -# Copyright (C) 2005 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 2005 - 2020, 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 diff --git a/lib/Makefile.am b/lib/Makefile.am index 516a2394..f2886ec6 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2020, 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 @@ -29,7 +29,8 @@ EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h \ makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \ config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \ config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ - firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl + firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \ + setup-win32.h lib_LTLIBRARIES = libcurl.la diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 46ded90b..e3cf4189 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -20,71 +20,66 @@ # ########################################################################### -LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ - vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ - vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ - vauth/spnego_gssapi.c vauth/spnego_sspi.c +LIB_VAUTH_CFILES = vauth/cleartext.c vauth/cram.c vauth/digest.c \ + vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c vauth/ntlm.c \ + vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \ + vauth/vauth.c -LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h +LIB_VAUTH_HFILES = vauth/digest.h vauth/ntlm.h vauth/vauth.h -LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ - vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ - vtls/mesalink.c vtls/bearssl.c +LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/mbedtls.c \ + vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c vtls/openssl.c \ + vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c vtls/vtls.c \ + vtls/wolfssl.c -LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ - vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ - vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ - vtls/bearssl.h +LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/mbedtls.h \ + vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h vtls/openssl.h \ + vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h -LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c +LIB_VSSH_CFILES = vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h -LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ - cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ - ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ - fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ - strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ - http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ - strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ - inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - curl_addrinfo.c socks_gssapi.c socks_sspi.c \ - curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ - pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ - openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ - http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ - curl_multibyte.c hostcheck.c conncache.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ - mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ - doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c +LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c \ + conncache.c connect.c content_encoding.c cookie.c curl_addrinfo.c \ + curl_ctype.c curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c \ + curl_gethostname.c curl_gssapi.c curl_memrchr.c curl_multibyte.c \ + curl_ntlm_core.c curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c \ + curl_sasl.c curl_sspi.c curl_threads.c dict.c dotdot.c easy.c escape.c \ + file.c fileinfo.c formdata.c ftp.c url.c ftplistparser.c getenv.c getinfo.c \ + gopher.c hash.c hmac.c hostasyn.c hostcheck.c hostip.c hostip4.c hostip6.c \ + hostsyn.c http.c http2.c http_chunks.c http_digest.c http_negotiate.c \ + http_ntlm.c http_proxy.c idn_win32.c if2ip.c imap.c inet_ntop.c inet_pton.c \ + krb5.c ldap.c llist.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c \ + multi.c netrc.c non-ascii.c nonblock.c openldap.c parsedate.c pingpong.c \ + pop3.c progress.c psl.c doh.c rand.c rename.c rtsp.c security.c select.c \ + sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \ + socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c \ + strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c \ + transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c -LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ - formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ - speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ - wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ - hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ - http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ - inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ - easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h curl_base64.h curl_addrinfo.h curl_sspi.h \ - slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ - rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ - curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ - curl_setup_once.h multihandle.h setup-vms.h dotdot.h \ - x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ - curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ - curl_get_line.h altsvc.h quic.h socketpair.h rename.h +LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \ + content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h \ + curl_des.h curl_endian.h curl_fnmatch.h curl_get_line.h curl_gethostname.h \ + curl_gssapi.h curl_hmac.h curl_ldap.h curl_md4.h curl_md5.h curl_memory.h \ + curl_memrchr.h curl_multibyte.h curl_ntlm_core.h curl_ntlm_wb.h curl_path.h \ + curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h curl_sec.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h curlx.h dict.h \ + dotdot.h easyif.h escape.h file.h fileinfo.h formdata.h ftp.h url.h \ + ftplistparser.h getinfo.h gopher.h hash.h hostcheck.h hostip.h http.h \ + http2.h http_chunks.h http_digest.h http_negotiate.h http_ntlm.h \ + http_proxy.h if2ip.h imap.h inet_ntop.h inet_pton.h llist.h memdebug.h \ + mime.h mqtt.h multihandle.h multiif.h netrc.h non-ascii.h nonblock.h \ + parsedate.h pingpong.h pop3.h progress.h psl.h doh.h quic.h rand.h rename.h \ + rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h slist.h \ + smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \ + strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \ + timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h \ + x509asn1.h LIB_RCFILES = libcurl.rc diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 index ac6b3de6..fe8701bd 100644 --- a/lib/Makefile.m32 +++ b/lib/Makefile.m32 @@ -99,7 +99,7 @@ LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_DLL) -s AR = $(CURL_AR) RANLIB = $(CURL_RANLIB) RC = $(CROSSPREFIX)windres -RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF +RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O coff STRIP = $(CROSSPREFIX)strip -g # Set environment var ARCH to your architecture to override autodetection. diff --git a/lib/Makefile.netware b/lib/Makefile.netware index 752d3d6f..2c16adba 100644 --- a/lib/Makefile.netware +++ b/lib/Makefile.netware @@ -669,8 +669,6 @@ endif @echo $(DL)#endif$(DL) >> $@ ifdef CABUNDLE @echo $(DL)#define CURL_CA_BUNDLE "$(CABUNDLE)"$(DL) >> $@ -else - @echo $(DL)#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")$(DL) >> $@ endif $(EXPORTF): $(CURL_INC)/curl/curl.h $(CURL_INC)/curl/easy.h $(CURL_INC)/curl/multi.h $(CURL_INC)/curl/mprintf.h diff --git a/lib/Makefile.vxworks b/lib/Makefile.vxworks index 7ff197f0..ada87fbd 100644 --- a/lib/Makefile.vxworks +++ b/lib/Makefile.vxworks @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, 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. +# +########################################################################### #***************************************************************************** # # diff --git a/lib/checksrc.pl b/lib/checksrc.pl index e1bb1a63..b074f274 100755 --- a/lib/checksrc.pl +++ b/lib/checksrc.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 2011 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 2011 - 2020, 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 @@ -80,6 +80,7 @@ my %warnings = ( 'MULTISPACE' => 'multiple spaces used when not suitable', 'SIZEOFNOPAREN' => 'use of sizeof without parentheses', 'SNPRINTF' => 'use of snprintf', + 'ONELINECONDITION' => 'conditional block on the same line as the if()', ); sub readwhitelist { @@ -457,13 +458,34 @@ sub scanfile { } } - if($nostr =~ /^((.*)(if) *\()(.*)\)/) { + if($nostr =~ /^((.*\s)(if) *\()(.*)\)(.*)/) { my $pos = length($1); - if($4 =~ / = /) { + my $postparen = $5; + my $cond = $4; + if($cond =~ / = /) { checkwarn("ASSIGNWITHINCONDITION", $line, $pos+1, $file, $l, "assignment within conditional expression"); } + my $temp = $cond; + $temp =~ s/\(//g; # remove open parens + my $openc = length($cond) - length($temp); + + $temp = $cond; + $temp =~ s/\)//g; # remove close parens + my $closec = length($cond) - length($temp); + my $even = $openc == $closec; + + if($l =~ / *\#/) { + # this is a #if, treat it differently + } + elsif($even && $postparen && + ($postparen !~ /^ *$/) && ($postparen !~ /^ *[,{&|\\]+/)) { + print STDERR "5: '$postparen'\n"; + checkwarn("ONELINECONDITION", + $line, length($l)-length($postparen), $file, $l, + "conditional block on the same line"); + } } # check spaces after open parentheses if($l =~ /^(.*[a-z])\( /i) { diff --git a/lib/config-dos.h b/lib/config-dos.h index aa83c4be..349e7563 100644 --- a/lib/config-dos.h +++ b/lib/config-dos.h @@ -151,8 +151,6 @@ #define ssize_t int #endif -#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") - /* Target HAVE_x section */ #if defined(DJGPP) diff --git a/lib/config-os400.h b/lib/config-os400.h index a302828e..7beb81fa 100644 --- a/lib/config-os400.h +++ b/lib/config-os400.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -97,9 +97,6 @@ /* Define if you have the <crypto.h> header file. */ #undef HAVE_CRYPTO_H -/* Define if you have the <des.h> header file. */ -#undef HAVE_DES_H - /* Define if you have the <errno.h> header file. */ #define HAVE_ERRNO_H diff --git a/lib/config-riscos.h b/lib/config-riscos.h index 4af94981..0ddf487e 100644 --- a/lib/config-riscos.h +++ b/lib/config-riscos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -98,9 +98,6 @@ /* Define if you have the <crypto.h> header file. */ #undef HAVE_CRYPTO_H -/* Define if you have the <des.h> header file. */ -#undef HAVE_DES_H - /* Define if you have the <errno.h> header file. */ #define HAVE_ERRNO_H diff --git a/lib/config-symbian.h b/lib/config-symbian.h index 82a27bfe..7f17dce2 100644 --- a/lib/config-symbian.h +++ b/lib/config-symbian.h @@ -122,9 +122,6 @@ /* Define to 1 if you have the <crypto.h> header file. */ /* #undef HAVE_CRYPTO_H */ -/* Define to 1 if you have the <des.h> header file. */ -/* #undef HAVE_DES_H */ - /* Define to 1 if you have the <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 diff --git a/lib/config-tpf.h b/lib/config-tpf.h index a79afae6..199dfbcd 100644 --- a/lib/config-tpf.h +++ b/lib/config-tpf.h @@ -115,10 +115,6 @@ /* #undef HAVE_CRYPTO_H */ #define HAVE_CRYPTO_H 1 -/* Define to 1 if you have the <des.h> header file. */ -/* #undef HAVE_DES_H */ -#define HAVE_DES_H 1 - /* Define to 1 if you have the <errno.h> header file. */ #define HAVE_ERRNO_H 1 diff --git a/lib/config-vxworks.h b/lib/config-vxworks.h index 2769cdfd..14bf0be4 100644 --- a/lib/config-vxworks.h +++ b/lib/config-vxworks.h @@ -137,9 +137,6 @@ /* Define to 1 if you have the <crypto.h> header file. */ /* #undef HAVE_CRYPTO_H */ -/* Define to 1 if you have the <des.h> header file. */ -/* #undef HAVE_DES_H */ - /* Define to 1 if you have the <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 diff --git a/lib/config-win32.h b/lib/config-win32.h index d19665d7..516baca0 100644 --- a/lib/config-win32.h +++ b/lib/config-win32.h @@ -719,12 +719,15 @@ Vista #endif /* Define to use Unix sockets. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -/* sdkddkver.h first shipped with Platform SDK v6.0A included with VS2008 */ -#include <sdkddkver.h> -#if defined(NTDDI_WIN10_RS4) #define USE_UNIX_SOCKETS -#endif +#if !defined(UNIX_PATH_MAX) + /* Replicating logic present in afunix.h of newer Windows 10 SDK versions */ +# define UNIX_PATH_MAX 108 +# include <ws2tcpip.h> + typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; + } SOCKADDR_UN, *PSOCKADDR_UN; #endif /* ---------------------------------------------------------------- */ diff --git a/lib/connect.c b/lib/connect.c index 0a7475cb..421f9041 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -167,11 +167,12 @@ tcpkeepalive(struct Curl_easy *data, static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, /* start connecting to this */ - int sockindex); /* 0 or 1 among the temp ones */ + int tempindex); /* 0 or 1 among the temp ones */ /* * Curl_timeleft() returns the amount of milliseconds left allowed for the - * transfer/connection. If the value is negative, the timeout time has already + * transfer/connection. If the value is 0, there's no timeout (ie there's + * infinite time left). If the value is negative, the timeout time has already * elapsed. * * The start time is stored in progress.t_startsingle - as set with @@ -555,13 +556,27 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) return rc; } +/* update tempaddr[tempindex] (to the next entry), makes sure to stick + to the correct family */ +static Curl_addrinfo *ainext(struct connectdata *conn, + int tempindex, + bool next) /* use current or next entry */ +{ + Curl_addrinfo *ai = conn->tempaddr[tempindex]; + if(ai && next) + ai = ai->ai_next; + while(ai && (ai->ai_family != conn->tempfamily[tempindex])) + ai = ai->ai_next; + conn->tempaddr[tempindex] = ai; + return ai; +} + /* Used within the multi interface. Try next IP address, return TRUE if no more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { - const int other = tempindex ^ 1; CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. @@ -572,38 +587,15 @@ static CURLcode trynextip(struct connectdata *conn, conn->tempsock[tempindex] = CURL_SOCKET_BAD; if(sockindex == FIRSTSOCKET) { - Curl_addrinfo *ai = NULL; - int family = AF_UNSPEC; - - if(conn->tempaddr[tempindex]) { - /* find next address in the same protocol family */ - family = conn->tempaddr[tempindex]->ai_family; - ai = conn->tempaddr[tempindex]->ai_next; - } -#ifdef ENABLE_IPV6 - else if(conn->tempaddr[0]) { - /* happy eyeballs - try the other protocol family */ - int firstfamily = conn->tempaddr[0]->ai_family; - family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; - ai = conn->tempaddr[0]->ai_next; - } -#endif + Curl_addrinfo *ai = conn->tempaddr[tempindex]; while(ai) { - if(conn->tempaddr[other]) { - /* we can safely skip addresses of the other protocol family */ - while(ai && ai->ai_family != family) - ai = ai->ai_next; - } - if(ai) { result = singleipconnect(conn, ai, tempindex); if(result == CURLE_COULDNT_CONNECT) { - ai = ai->ai_next; + ai = ainext(conn, tempindex, TRUE); continue; } - - conn->tempaddr[tempindex] = ai; } break; } @@ -688,58 +680,56 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - if(conn->transport != TRNSPRT_TCP) - /* there's no TCP connection! */ - return; - + if(conn->transport == TRNSPRT_TCP) { #if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME) - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - struct Curl_easy *data = conn->data; - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssrem; - struct Curl_sockaddr_storage ssloc; - curl_socklen_t plen; - curl_socklen_t slen; + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { + struct Curl_easy *data = conn->data; + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + struct Curl_sockaddr_storage ssloc; + curl_socklen_t plen; + curl_socklen_t slen; #ifdef HAVE_GETPEERNAME - plen = sizeof(struct Curl_sockaddr_storage); - if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + plen = sizeof(struct Curl_sockaddr_storage); + if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETSOCKNAME - slen = sizeof(struct Curl_sockaddr_storage); - memset(&ssloc, 0, sizeof(ssloc)); - if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { - int error = SOCKERRNO; - failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } + slen = sizeof(struct Curl_sockaddr_storage); + memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { + int error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } #endif #ifdef HAVE_GETPEERNAME - if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, - conn->primary_ip, &conn->primary_port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } - memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + conn->primary_ip, &conn->primary_port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } + memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); #endif #ifdef HAVE_GETSOCKNAME - if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, - conn->local_ip, &conn->local_port)) { - failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } + if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, + conn->local_ip, &conn->local_port)) { + failf(data, "ssloc inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } #endif - } + } #else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */ - (void)sockfd; /* unused */ + (void)sockfd; /* unused */ #endif + } /* end of TCP-only section */ /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -816,6 +806,7 @@ static void post_SOCKS(struct connectdata *conn, Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */ Curl_updateconninfo(conn, conn->sock[sockindex]); Curl_verboseconnect(conn); + conn->data->info.numconnects++; /* to track the number of connections made */ } /* @@ -880,6 +871,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; + post_SOCKS(conn, sockindex, connected); connkeep(conn, "HTTP/3 default"); } return result; @@ -905,9 +897,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, } /* should we try another protocol family? */ - if(i == 0 && conn->tempaddr[1] == NULL && + if(i == 0 && !conn->parallel_connect && (Curl_timediff(now, conn->connecttime) >= data->set.happy_eyeballs_timeout)) { + conn->parallel_connect = TRUE; /* starting now */ trynextip(conn, sockindex, 1); } } @@ -967,7 +960,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; - + ainext(conn, i, TRUE); status = trynextip(conn, sockindex, i); if((status != CURLE_COULDNT_CONNECT) || conn->tempsock[other] == CURL_SOCKET_BAD) @@ -984,7 +977,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ - if(conn->tempaddr[1] == NULL) { + { result = trynextip(conn, sockindex, 1); if(!result) return result; @@ -1113,7 +1106,7 @@ void Curl_sndbufset(curl_socket_t sockfd) */ static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, - int sockindex) + int tempindex) { struct Curl_sockaddr_ex addr; int rc = -1; @@ -1129,15 +1122,12 @@ static CURLcode singleipconnect(struct connectdata *conn, int optval = 1; #endif char buffer[STRERROR_LEN]; - curl_socket_t *sockp = &conn->tempsock[sockindex]; + curl_socket_t *sockp = &conn->tempsock[tempindex]; *sockp = CURL_SOCKET_BAD; result = Curl_socket(conn, ai, &addr, &sockfd); if(result) - /* Failed to create the socket, but still return OK since we signal the - lack of socket as well. This allows the parent function to keep looping - over alternative addresses/socket families etc. */ - return CURLE_OK; + return result; /* store remote address and port used in this connection attempt */ if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen, @@ -1257,7 +1247,7 @@ static CURLcode singleipconnect(struct connectdata *conn, else if(conn->transport == TRNSPRT_QUIC) { /* pass in 'sockfd' separately since it hasn't been put into the tempsock array at this point */ - result = Curl_quic_connect(conn, sockfd, sockindex, + result = Curl_quic_connect(conn, sockfd, tempindex, &addr.sa_addr, addr.addrlen); if(result) error = SOCKERRNO; @@ -1315,7 +1305,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ struct Curl_easy *data = conn->data; struct curltime before = Curl_now(); CURLcode result = CURLE_COULDNT_CONNECT; - + int i; timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { @@ -1325,30 +1315,35 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } conn->num_addr = Curl_num_addresses(remotehost->addr); - conn->tempaddr[0] = remotehost->addr; - conn->tempaddr[1] = NULL; - conn->tempsock[0] = CURL_SOCKET_BAD; - conn->tempsock[1] = CURL_SOCKET_BAD; + conn->tempaddr[0] = conn->tempaddr[1] = remotehost->addr; + conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD; /* Max time for the next connection attempt */ conn->timeoutms_per_addr = conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; - /* start connecting to first IP */ - while(conn->tempaddr[0]) { - result = singleipconnect(conn, conn->tempaddr[0], 0); - if(!result) - break; - conn->tempaddr[0] = conn->tempaddr[0]->ai_next; - } + conn->tempfamily[0] = conn->tempaddr[0]? + conn->tempaddr[0]->ai_family:0; + conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ? + AF_INET : AF_INET6; + ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */ - if(conn->tempsock[0] == CURL_SOCKET_BAD) { - if(!result) - result = CURLE_COULDNT_CONNECT; - return result; + DEBUGF(infof(data, "family0 == %s, family1 == %s\n", + conn->tempfamily[0] == AF_INET ? "v4" : "v6", + conn->tempfamily[1] == AF_INET ? "v4" : "v6")); + + /* get through the list in family order in case of quick failures */ + for(i = 0; (i < 2) && result; i++) { + while(conn->tempaddr[i]) { + result = singleipconnect(conn, conn->tempaddr[i], i); + if(!result) + break; + ainext(conn, i, TRUE); + } } + if(result) + return result; - data->info.numconnects++; /* to track the number of connections made */ Curl_expire(conn->data, data->set.happy_eyeballs_timeout, EXPIRE_HAPPY_EYEBALLS); diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 16c4779c..b2dd8342 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -50,10 +50,6 @@ # define in_addr_t unsigned long #endif -#if defined(WIN32) && defined(USE_UNIX_SOCKETS) -#include <afunix.h> -#endif - #include <stddef.h> #include "curl_addrinfo.h" diff --git a/lib/curl_config.h b/lib/curl_config.h index e5b99a79..21cd2f89 100644 --- a/lib/curl_config.h +++ b/lib/curl_config.h @@ -97,6 +97,9 @@ /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ +/* to enable MQTT */ +/* #undef CURL_ENABLE_MQTT */ + /* Definition to make a library symbol externally visible. */ #define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ ("default"))) @@ -299,16 +302,6 @@ /* Define to 1 if you have a working gmtime_r function. */ #define HAVE_GMTIME_R 1 -/* Define to 1 if you have the `gnutls_alpn_set_protocols' function. */ -/* #undef HAVE_GNUTLS_ALPN_SET_PROTOCOLS */ - -/* Define to 1 if you have the `gnutls_certificate_set_x509_key_file2' - function. */ -/* #undef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 */ - -/* Define to 1 if you have the `gnutls_ocsp_req_init' function. */ -/* #undef HAVE_GNUTLS_OCSP_REQ_INIT */ - /* if you have the function gnutls_srp_verifier */ /* #undef HAVE_GNUTLS_SRP */ @@ -503,6 +496,9 @@ */ /* #undef HAVE_OLD_GSSMIT */ +/* Define to 1 if using OpenSSL 3 or later. */ +/* #undef HAVE_OPENSSL3 */ + /* Define to 1 if you have the <openssl/crypto.h> header file. */ #define HAVE_OPENSSL_CRYPTO_H 1 @@ -989,6 +985,9 @@ /* if ngtcp2 is in use */ /* #undef USE_NGTCP2 */ +/* if ngtcp2_crypto_gnutls is in use */ +/* #undef USE_NGTCP2_CRYPTO_GNUTLS */ + /* if ngtcp2_crypto_openssl is in use */ /* #undef USE_NGTCP2_CRYPTO_OPENSSL */ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 98cdf514..57a86e50 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -1,3 +1,24 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, 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. + * + ***************************************************************************/ /* lib/curl_config.h.in. Generated somehow by cmake. */ /* when building libcurl itself */ @@ -42,6 +63,9 @@ /* to disable LDAPS */ #cmakedefine CURL_DISABLE_LDAPS 1 +/* to enable MQTT */ +#undef CURL_ENABLE_MQTT + /* to disable POP3 */ #cmakedefine CURL_DISABLE_POP3 1 @@ -145,9 +169,6 @@ /* Define to 1 if you have the <crypto.h> header file. */ #cmakedefine HAVE_CRYPTO_H 1 -/* Define to 1 if you have the <des.h> header file. */ -#cmakedefine HAVE_DES_H 1 - /* Define to 1 if you have the <dlfcn.h> header file. */ #cmakedefine HAVE_DLFCN_H 1 @@ -945,6 +966,9 @@ ${SIZEOF_TIME_T_CODE} /* if BearSSL is enabled */ #cmakedefine USE_BEARSSL 1 +/* if WolfSSL is enabled */ +#cmakedefine USE_WOLFSSL 1 + /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in index 8f29f51c..abb6c078 100644 --- a/lib/curl_config.h.in +++ b/lib/curl_config.h.in @@ -96,6 +96,9 @@ /* to disable verbose strings */ #undef CURL_DISABLE_VERBOSE_STRINGS +/* to enable MQTT */ +#undef CURL_ENABLE_MQTT + /* Definition to make a library symbol externally visible. */ #undef CURL_EXTERN_SYMBOL @@ -298,16 +301,6 @@ /* Define to 1 if you have a working gmtime_r function. */ #undef HAVE_GMTIME_R -/* Define to 1 if you have the `gnutls_alpn_set_protocols' function. */ -#undef HAVE_GNUTLS_ALPN_SET_PROTOCOLS - -/* Define to 1 if you have the `gnutls_certificate_set_x509_key_file2' - function. */ -#undef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 - -/* Define to 1 if you have the `gnutls_ocsp_req_init' function. */ -#undef HAVE_GNUTLS_OCSP_REQ_INIT - /* if you have the function gnutls_srp_verifier */ #undef HAVE_GNUTLS_SRP @@ -502,6 +495,9 @@ */ #undef HAVE_OLD_GSSMIT +/* Define to 1 if using OpenSSL 3 or later. */ +#undef HAVE_OPENSSL3 + /* Define to 1 if you have the <openssl/crypto.h> header file. */ #undef HAVE_OPENSSL_CRYPTO_H @@ -1006,6 +1002,9 @@ /* if ngtcp2 is in use */ #undef USE_NGTCP2 +/* if ngtcp2_crypto_gnutls is in use */ +#undef USE_NGTCP2_CRYPTO_GNUTLS + /* if ngtcp2_crypto_openssl is in use */ #undef USE_NGTCP2_CRYPTO_OPENSSL diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c index f9b823b4..32e29a93 100644 --- a/lib/curl_ntlm_core.c +++ b/lib/curl_ntlm_core.c @@ -342,7 +342,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, /* Acquire the crypto provider */ if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return FALSE; /* Setup the key blob structure */ diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 4ecda6a9..56e6db83 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -231,64 +231,20 @@ #endif /* - * Use getaddrinfo to resolve the IPv4 address literal. If the current network - * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, - * performing this task will result in a synthesized IPv6 address. - */ -#ifdef __APPLE__ -#define USE_RESOLVE_ON_IPS 1 -#endif - -/* - * Include header files for windows builds before redefining anything. - * Use this preprocessor block only to include or exclude windows.h, - * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs - * to any other further and independent block. Under Cygwin things work - * just as under linux (e.g. <sys/socket.h>) and the winsock headers should - * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, - * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + * Windows setup file includes some system headers. */ #ifdef HAVE_WINDOWS_H -# if defined(UNICODE) && !defined(_UNICODE) -# define _UNICODE -# endif -# if defined(_UNICODE) && !defined(UNICODE) -# define UNICODE -# endif -# include <winerror.h> -# include <windows.h> -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# ifdef HAVE_WS2TCPIP_H -# include <ws2tcpip.h> -# endif -# else -# ifdef HAVE_WINSOCK_H -# include <winsock.h> -# endif -# endif -# include <tchar.h> -# ifdef UNICODE - typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); -# endif +# include "setup-win32.h" #endif /* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * define USE_WINSOCK to 1 if we have and use WINSOCK API, else - * undefine USE_WINSOCK. + * Use getaddrinfo to resolve the IPv4 address literal. If the current network + * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, + * performing this task will result in a synthesized IPv6 address. */ - -#undef USE_WINSOCK - -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# define USE_WINSOCK 1 -# endif +#ifdef __APPLE__ +#define USE_RESOLVE_ON_IPS 1 #endif #ifdef USE_LWIPSOCK @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -46,6 +46,8 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #include "urldata.h" @@ -174,7 +174,7 @@ UNITTEST DOHcode doh_encode(const char *host, } static size_t -doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp) +doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct dohresponse *mem = (struct dohresponse *)userp; @@ -318,6 +318,9 @@ static CURLcode dohprobe(struct Curl_easy *data, } if(data->set.proxy_ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); + else if(data->set.proxy_ssl.revoke_best_effort) + ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, + CURLSSLOPT_REVOKE_BEST_EFFORT); if(data->set.str[STRING_SSL_CAPATH_PROXY]) { ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH, data->set.str[STRING_SSL_CAPATH_PROXY]); @@ -351,6 +354,8 @@ static CURLcode dohprobe(struct Curl_easy *data, } if(data->set.ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); + else if(data->set.ssl.revoke_best_effort) + ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT); if(data->set.ssl.fsslctx) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) @@ -434,7 +439,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn, return NULL; } -static DOHcode skipqname(unsigned char *doh, size_t dohlen, +static DOHcode skipqname(const unsigned char *doh, size_t dohlen, unsigned int *indexp) { unsigned char length; @@ -458,12 +463,12 @@ static DOHcode skipqname(unsigned char *doh, size_t dohlen, return DOH_OK; } -static unsigned short get16bit(unsigned char *doh, int index) +static unsigned short get16bit(const unsigned char *doh, int index) { return (unsigned short)((doh[index] << 8) | doh[index + 1]); } -static unsigned int get32bit(unsigned char *doh, int index) +static unsigned int get32bit(const unsigned char *doh, int index) { /* make clang and gcc optimize this to bswap by incrementing the pointer first. */ @@ -475,7 +480,7 @@ static unsigned int get32bit(unsigned char *doh, int index) return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3]; } -static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) +static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { @@ -487,7 +492,9 @@ static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) return DOH_OK; } -static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d) +static DOHcode store_aaaa(const unsigned char *doh, + int index, + struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { @@ -500,7 +507,7 @@ static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d) } static DOHcode cnameappend(struct cnamestore *c, - unsigned char *src, + const unsigned char *src, size_t len) { if(!c->alloc) { @@ -525,7 +532,7 @@ static DOHcode cnameappend(struct cnamestore *c, return DOH_OK; } -static DOHcode store_cname(unsigned char *doh, +static DOHcode store_cname(const unsigned char *doh, size_t dohlen, unsigned int index, struct dohentry *d) @@ -580,7 +587,7 @@ static DOHcode store_cname(unsigned char *doh, return DOH_OK; } -static DOHcode rdata(unsigned char *doh, +static DOHcode rdata(const unsigned char *doh, size_t dohlen, unsigned short rdlength, unsigned short type, @@ -630,7 +637,7 @@ static void init_dohentry(struct dohentry *de) } -UNITTEST DOHcode doh_decode(unsigned char *doh, +UNITTEST DOHcode doh_decode(const unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d) @@ -770,12 +777,12 @@ UNITTEST DOHcode doh_decode(unsigned char *doh, #ifndef CURL_DISABLE_VERBOSE_STRINGS static void showdoh(struct Curl_easy *data, - struct dohentry *d) + const struct dohentry *d) { int i; infof(data, "TTL: %u seconds\n", d->ttl); for(i = 0; i < d->numaddr; i++) { - struct dohaddr *a = &d->addr[i]; + const struct dohaddr *a = &d->addr[i]; if(a->type == DNS_TYPE_A) { infof(data, "DOH A: %u.%u.%u.%u\n", a->ip.v4[0], a->ip.v4[1], @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2018 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2020, 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 @@ -99,7 +99,7 @@ DOHcode doh_encode(const char *host, unsigned char *dnsp, /* buffer */ size_t len, /* buffer size */ size_t *olen); /* output length */ -DOHcode doh_decode(unsigned char *doh, +DOHcode doh_decode(const unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d); @@ -884,14 +884,25 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) goto fail; #ifdef USE_ARES - if(Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS])) - goto fail; - if(Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE])) - goto fail; - if(Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4])) - goto fail; - if(Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6])) - goto fail; + { + CURLcode rc; + + rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + } #endif /* USE_ARES */ Curl_convert_setup(outcurl); @@ -136,7 +136,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; - int fd = -1; + int fd; #ifdef DOS_FILESYSTEM size_t i; char *actual_path; @@ -181,9 +181,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) return CURLE_URL_MALFORMAT; } - if(strncmp("\\\\", actual_path, 2)) - /* refuse to open path that starts with two backslashes */ - fd = open_readonly(actual_path, O_RDONLY|O_BINARY); + fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else if(memchr(real_path, 0, real_path_len)) { diff --git a/lib/firefox-db2pem.sh b/lib/firefox-db2pem.sh index 45489324..ee820261 100644 --- a/lib/firefox-db2pem.sh +++ b/lib/firefox-db2pem.sh @@ -6,7 +6,7 @@ # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * -# * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. +# * Copyright (C) 1998 - 2020, 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 @@ -150,7 +150,6 @@ struct ftp_conn { connection to */ char *newhost; /* this is the pair to connect the DATA... */ unsigned short newport; /* connection to */ - }; #define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ diff --git a/lib/getinfo.c b/lib/getinfo.c index 2b8f2303..84d9fc1c 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -147,6 +147,33 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, long *to_long; } lptr; +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_LOCAL_PORT: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } + /* use another variable for this to allow different values */ + timestr = getenv("CURL_DEBUG_SIZE"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_HEADER_SIZE: + case CURLINFO_REQUEST_SIZE: + *param_longp = (long)val; + return CURLE_OK; + default: + break; + } + } +#endif + switch(info) { case CURLINFO_RESPONSE_CODE: *param_longp = data->info.httpcode; @@ -212,8 +239,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, *param_longp = data->info.conn_local_port; break; case CURLINFO_CONDITION_UNMET: - /* return if the condition prevented the document to get transferred */ - *param_longp = data->info.timecond ? 1L : 0L; + if(data->info.httpcode == 304) + *param_longp = 1L; + else + /* return if the condition prevented the document to get transferred */ + *param_longp = data->info.timecond ? 1L : 0L; break; case CURLINFO_RTSP_CLIENT_CSEQ: *param_longp = data->state.rtsp_next_client_CSeq; @@ -258,6 +288,27 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, curl_off_t *param_offt) { +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME_T: + case CURLINFO_NAMELOOKUP_TIME_T: + case CURLINFO_CONNECT_TIME_T: + case CURLINFO_APPCONNECT_TIME_T: + case CURLINFO_PRETRANSFER_TIME_T: + case CURLINFO_STARTTRANSFER_TIME_T: + case CURLINFO_REDIRECT_TIME_T: + case CURLINFO_SPEED_DOWNLOAD_T: + case CURLINFO_SPEED_UPLOAD_T: + *param_offt = (curl_off_t)val; + return CURLE_OK; + default: + break; + } + } +#endif switch(info) { case CURLINFO_FILETIME_T: *param_offt = (curl_off_t)data->info.filetime; @@ -282,7 +333,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? data->progress.size_ul:-1; break; - case CURLINFO_TOTAL_TIME_T: + case CURLINFO_TOTAL_TIME_T: *param_offt = data->progress.timespent; break; case CURLINFO_NAMELOOKUP_TIME_T: @@ -316,6 +367,27 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { +#ifdef DEBUGBUILD + char *timestr = getenv("CURL_TIME"); + if(timestr) { + unsigned long val = strtol(timestr, NULL, 10); + switch(info) { + case CURLINFO_TOTAL_TIME: + case CURLINFO_NAMELOOKUP_TIME: + case CURLINFO_CONNECT_TIME: + case CURLINFO_APPCONNECT_TIME: + case CURLINFO_PRETRANSFER_TIME: + case CURLINFO_STARTTRANSFER_TIME: + case CURLINFO_REDIRECT_TIME: + case CURLINFO_SPEED_DOWNLOAD: + case CURLINFO_SPEED_UPLOAD: + *param_doublep = (double)val; + return CURLE_OK; + default: + break; + } + } +#endif switch(info) { case CURLINFO_TOTAL_TIME: *param_doublep = DOUBLE_SECS(data->progress.timespent); diff --git a/lib/gopher.c b/lib/gopher.c index b296c62d..c48098f7 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -28,6 +28,7 @@ #include <curl/curl.h> #include "transfer.h" #include "sendf.h" +#include "connect.h" #include "progress.h" #include "gopher.h" #include "select.h" @@ -83,8 +84,10 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *query = data->state.up.query; char *sel = NULL; char *sel_org = NULL; + timediff_t timeout_ms; ssize_t amount, k; size_t len; + int what; *done = TRUE; /* unconditionally */ @@ -139,19 +142,29 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) else break; + timeout_ms = Curl_timeleft(conn->data, NULL, FALSE); + if(timeout_ms < 0) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't possible to send now will be sent in the doing function repeatedly until the entire request is sent. - - Wait a while for the socket to be writable. Note that this doesn't - acknowledge the timeout. */ - if(SOCKET_WRITABLE(sockfd, 100) < 0) { + what = SOCKET_WRITABLE(sockfd, timeout_ms); + if(what < 0) { result = CURLE_SEND_ERROR; break; } + else if(!what) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } } free(sel_org); @@ -1229,8 +1229,21 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, memcpy(data->state.ulbuf, ptr, sendsize); ptr = data->state.ulbuf; } - else + else { +#ifdef CURLDEBUG + /* Allow debug builds override this logic to force short initial sends */ + char *p = getenv("CURL_SMALLREQSEND"); + if(p) { + size_t altsize = (size_t)strtoul(p, NULL, 10); + if(altsize) + sendsize = CURLMIN(size, altsize); + else + sendsize = size; + } + else +#endif sendsize = size; + } result = Curl_write(conn, sockfd, ptr, sendsize, &amount); @@ -1320,7 +1333,6 @@ CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) { char *s; va_list ap; - Curl_send_buffer *in = *inp; va_start(ap, fmt); s = vaprintf(fmt, ap); /* this allocs a new string to append */ va_end(ap); @@ -1331,9 +1343,7 @@ CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) return result; } /* If we failed, we cleanup the whole buffer and return error */ - free(in->buffer); - free(in); - *inp = NULL; + Curl_add_buffer_free(inp); return CURLE_OUT_OF_MEMORY; } @@ -1350,9 +1360,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, /* If resulting used size of send buffer would wrap size_t, cleanup the whole buffer and return error. Otherwise the required buffer size will fit into a single allocatable memory chunk */ - Curl_safefree(in->buffer); - free(in); - *inp = NULL; + Curl_add_buffer_free(inp); return CURLE_OUT_OF_MEMORY; } @@ -2602,8 +2610,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) { altused = aprintf("Alt-Used: %s:%d\r\n", conn->conn_to_host.name, conn->conn_to_port); - if(!altused) + if(!altused) { + Curl_add_buffer_free(&req_buffer); return CURLE_OUT_OF_MEMORY; + } } #endif result = @@ -3044,7 +3054,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(result) return result; - if(!postsize) + if(!postsize && (http->sending != HTTPSEND_REQUEST)) data->req.upload_done = TRUE; if(data->req.writebytecount) { diff --git a/lib/http2.c b/lib/http2.c index 41d8db68..93dfbdb7 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1727,8 +1727,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, return retlen; } - /* If this stream is closed, return 0 to signal the http routine to close - the connection */ if(stream->closed) return 0; *err = CURLE_AGAIN; diff --git a/lib/if2ip.c b/lib/if2ip.c index d003de67..b283f67f 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -129,11 +129,11 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); if(ifscope != remote_scope) { - /* We are interested only in interface addresses whose - scope matches the remote address we want to - connect to: global for global, link-local for - link-local, etc... */ - if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; + /* We are interested only in interface addresses whose scope + matches the remote address we want to connect to: global + for global, link-local for link-local, etc... */ + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; continue; } diff --git a/lib/libcurl.plist b/lib/libcurl.plist index 0b521b0f..a02dfaa7 100644 --- a/lib/libcurl.plist +++ b/lib/libcurl.plist @@ -15,7 +15,7 @@ <string>se.haxx.curl.libcurl</string> <key>CFBundleVersion</key> - <string>7.69.1</string> + <string>7.70.0</string> <key>CFBundleName</key> <string>libcurl</string> @@ -27,9 +27,9 @@ <string>????</string> <key>CFBundleShortVersionString</key> - <string>libcurl 7.69.1</string> + <string>libcurl 7.70.0</string> <key>CFBundleGetInfoString</key> - <string>libcurl.plist 7.69.1</string> + <string>libcurl.plist 7.70.0</string> </dict> </plist> diff --git a/lib/makefile.amiga b/lib/makefile.amiga index 673b147c..29df6543 100644 --- a/lib/makefile.amiga +++ b/lib/makefile.amiga @@ -1,3 +1,24 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2020, 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. +# +########################################################################### # # libcurl Makefile for AmigaOS ... # diff --git a/lib/makefile.dj b/lib/makefile.dj index 941f8ce6..6ea79e4b 100644 --- a/lib/makefile.dj +++ b/lib/makefile.dj @@ -6,7 +6,7 @@ # \___|\___/|_| \_\_____| # # Copyright (C) 2003 - 2008, Gisle Vanem <gvanem@yahoo.no>. -# Copyright (C) 2003 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 2003 - 2020, 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 @@ -29,6 +29,10 @@ #ifdef USE_OPENSSL #include <openssl/opensslconf.h> +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */ +#define OPENSSL_NO_MD4 +#endif #endif /* USE_OPENSSL */ #ifdef USE_MBEDTLS @@ -146,7 +150,7 @@ static void MD4_Init(MD4_CTX *ctx) ctx->hHash = 0; if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash); } } @@ -186,8 +186,8 @@ typedef struct { static void MD5_Init(MD5_CTX *ctx) { - if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } } diff --git a/lib/memdebug.c b/lib/memdebug.c index ede60094..1c6b1514 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -328,7 +328,7 @@ void curl_dbg_free(void *ptr, int line, const char *source) (Curl_cfree)(mem); } - if(source) + if(source && ptr) curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr); } @@ -1778,6 +1778,23 @@ const char *Curl_mime_contenttype(const char *filename) return NULL; } +static bool content_type_match(const char *contenttype, const char *target) +{ + size_t len = strlen(target); + + if(contenttype && strncasecompare(contenttype, target, len)) + switch(contenttype[len]) { + case '\0': + case '\t': + case '\r': + case '\n': + case ' ': + case ';': + return TRUE; + } + return FALSE; +} + CURLcode Curl_mime_prepare_headers(curl_mimepart *part, const char *contenttype, const char *disposition, @@ -1829,7 +1846,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, boundary = mime->boundary; } else if(contenttype && !customct && - strcasecompare(contenttype, "text/plain")) + content_type_match(contenttype, "text/plain")) if(strategy == MIMESTRATEGY_MAIL || !part->filename) contenttype = NULL; @@ -1905,7 +1922,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, curl_mimepart *subpart; disposition = NULL; - if(strcasecompare(contenttype, "multipart/form-data")) + if(content_type_match(contenttype, "multipart/form-data")) disposition = "form-data"; for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy); diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl index 09e8e5b9..b9c7ed25 100755 --- a/lib/mk-ca-bundle.pl +++ b/lib/mk-ca-bundle.pl @@ -63,7 +63,7 @@ $opt_d = 'release'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.27'; +my $version = '1.28'; $opt_w = 76; # default base64 encoded lines length @@ -531,6 +531,11 @@ while (<TXT>) { } else { my $data = $cka_value; $cka_value = ""; + + if(!length($data)) { + # if empty, skip + next; + } my $encoded = MIME::Base64::encode_base64($data, ''); $encoded =~ s/(.{1,${opt_w}})/$1\n/g; my $pem = "-----BEGIN CERTIFICATE-----\n" diff --git a/lib/mk-ca-bundle.vbs b/lib/mk-ca-bundle.vbs index 8da27926..34871711 100755 --- a/lib/mk-ca-bundle.vbs +++ b/lib/mk-ca-bundle.vbs @@ -5,7 +5,7 @@ '* | (__| |_| | _ <| |___
'* \___|\___/|_| \_\_____|
'*
-'* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+'* Copyright (C) 1998 - 2020, 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
diff --git a/lib/mqtt.c b/lib/mqtt.c new file mode 100644 index 00000000..43a3b6e5 --- /dev/null +++ b/lib/mqtt.c @@ -0,0 +1,627 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019, Björn Stenberg, <bjorn@haxx.se> + * + * 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 CURL_ENABLE_MQTT + +#include "urldata.h" +#include <curl/curl.h> +#include "transfer.h" +#include "sendf.h" +#include "progress.h" +#include "mqtt.h" +#include "select.h" +#include "strdup.h" +#include "url.h" +#include "escape.h" +#include "warnless.h" +#include "curl_printf.h" +#include "curl_memory.h" +#include "multiif.h" +#include "rand.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +#define MQTT_MSG_CONNECT 0x10 +#define MQTT_MSG_CONNACK 0x20 +#define MQTT_MSG_PUBLISH 0x30 +#define MQTT_MSG_SUBSCRIBE 0x82 +#define MQTT_MSG_SUBACK 0x90 +#define MQTT_MSG_DISCONNECT 0xe0 + +#define MQTT_CONNACK_LEN 2 +#define MQTT_SUBACK_LEN 3 +#define MQTT_CLIENTID_LEN 12 /* "curl0123abcd" */ + +/* + * Forward declarations. + */ + +static CURLcode mqtt_do(struct connectdata *conn, bool *done); +static CURLcode mqtt_doing(struct connectdata *conn, bool *done); +static int mqtt_getsock(struct connectdata *conn, curl_socket_t *sock); +static CURLcode mqtt_setup_conn(struct connectdata *conn); + +/* + * MQTT protocol handler. + */ + +const struct Curl_handler Curl_handler_mqtt = { + "MQTT", /* scheme */ + mqtt_setup_conn, /* setup_connection */ + mqtt_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + mqtt_doing, /* doing */ + ZERO_NULL, /* proto_getsock */ + mqtt_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + PORT_MQTT, /* defport */ + CURLPROTO_MQTT, /* protocol */ + PROTOPT_NONE /* flags */ +}; + +static CURLcode mqtt_setup_conn(struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the Curl_easy, only to survive + during this request */ + struct MQTT *mq; + struct Curl_easy *data = conn->data; + DEBUGASSERT(data->req.protop == NULL); + + mq = calloc(1, sizeof(struct MQTT)); + if(!mq) + return CURLE_OUT_OF_MEMORY; + data->req.protop = mq; + return CURLE_OK; +} + +static CURLcode mqtt_send(struct connectdata *conn, + char *buf, size_t len) +{ + CURLcode result = CURLE_OK; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct Curl_easy *data = conn->data; + struct MQTT *mq = data->req.protop; + ssize_t n; + result = Curl_write(conn, sockfd, buf, len, &n); + if(!result && data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(len != (size_t)n) { + size_t nsend = len - n; + char *sendleftovers = Curl_memdup(&buf[n], nsend); + if(!sendleftovers) + return CURLE_OUT_OF_MEMORY; + mq->sendleftovers = sendleftovers; + mq->nsend = nsend; + } + return result; +} + +/* Generic function called by the multi interface to figure out what socket(s) + to wait for and for what actions during the DOING and PROTOCONNECT + states */ +static int mqtt_getsock(struct connectdata *conn, + curl_socket_t *sock) +{ + sock[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(FIRSTSOCKET); +} + +static CURLcode mqtt_connect(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + const size_t client_id_offset = 14; + const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN; + char client_id[MQTT_CLIENTID_LEN + 1] = "curl"; + const size_t curl_len = strlen("curl"); + char packet[32] = { + MQTT_MSG_CONNECT, /* packet type */ + 0x00, /* remaining length */ + 0x00, 0x04, /* protocol length */ + 'M','Q','T','T', /* protocol name */ + 0x04, /* protocol level */ + 0x02, /* CONNECT flag: CleanSession */ + 0x00, 0x3c, /* keep-alive 0 = disabled */ + 0x00, 0x00 /* payload1 length */ + }; + packet[1] = (packetlen - 2) & 0x7f; + packet[client_id_offset - 1] = MQTT_CLIENTID_LEN; + + result = Curl_rand_hex(conn->data, (unsigned char *)&client_id[curl_len], + MQTT_CLIENTID_LEN - curl_len + 1); + memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN); + infof(conn->data, "Using client id '%s'\n", client_id); + if(!result) + result = mqtt_send(conn, packet, packetlen); + return result; +} + +static CURLcode mqtt_disconnect(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + result = mqtt_send(conn, (char *)"\xe0\x00", 2); + return result; +} + +static CURLcode mqtt_verify_connack(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char readbuf[MQTT_CONNACK_LEN]; + ssize_t nread; + struct Curl_easy *data = conn->data; + + result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread); + if(result) + goto fail; + + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); + + /* fixme */ + if(nread < MQTT_CONNACK_LEN) { + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + + /* verify CONNACK */ + if(readbuf[0] != 0x00 || readbuf[1] != 0x00) { + failf(data, "Expected %02x%02x but got %02x%02x", + 0x00, 0x00, readbuf[0], readbuf[1]); + result = CURLE_WEIRD_SERVER_REPLY; + } + +fail: + return result; +} + +static CURLcode mqtt_get_topic(struct connectdata *conn, + char **topic, size_t *topiclen) +{ + CURLcode result = CURLE_OK; + char *path = conn->data->state.up.path; + + if(strlen(path) > 1) { + result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen, FALSE); + } + else { + failf(conn->data, "Error: No topic specified."); + result = CURLE_URL_MALFORMAT; + } + return result; +} + + +static int mqtt_encode_len(char *buf, size_t len) +{ + unsigned char encoded; + int i; + + for(i = 0; (len > 0) && (i<4); i++) { + encoded = len % 0x80; + len /= 0x80; + if(len) + encoded |= 0x80; + buf[i] = encoded; + } + + return i; +} + +static CURLcode mqtt_subscribe(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + char *topic = NULL; + size_t topiclen; + unsigned char *packet = NULL; + size_t packetlen; + char encodedsize[4]; + size_t n; + + result = mqtt_get_topic(conn, &topic, &topiclen); + if(result) + goto fail; + + conn->proto.mqtt.packetid++; + + packetlen = topiclen + 5; /* packetid + topic (has a two byte length field) + + 2 bytes topic length + QoS byte */ + n = mqtt_encode_len((char *)encodedsize, packetlen); + packetlen += n + 1; /* add one for the control packet type byte */ + + packet = malloc(packetlen); + if(!packet) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + packet[0] = MQTT_MSG_SUBSCRIBE; + memcpy(&packet[1], encodedsize, n); + packet[1 + n] = (conn->proto.mqtt.packetid >> 8) & 0xff; + packet[2 + n] = conn->proto.mqtt.packetid & 0xff; + packet[3 + n] = (topiclen >> 8) & 0xff; + packet[4 + n ] = topiclen & 0xff; + memcpy(&packet[5 + n], topic, topiclen); + packet[5 + n + topiclen] = 0; /* QoS zero */ + + result = mqtt_send(conn, (char *)packet, packetlen); + +fail: + free(topic); + free(packet); + return result; +} + +/* + * Called when the first byte was already read. + */ +static CURLcode mqtt_verify_suback(struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char readbuf[MQTT_SUBACK_LEN]; + ssize_t nread; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + + result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread); + if(result) + goto fail; + + if(conn->data->set.verbose) + Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); + + /* fixme */ + if(nread < MQTT_SUBACK_LEN) { + result = CURLE_WEIRD_SERVER_REPLY; + goto fail; + } + + /* verify SUBACK */ + if(readbuf[0] != ((mqtt->packetid >> 8) & 0xff) || + readbuf[1] != (mqtt->packetid & 0xff) || + readbuf[2] != 0x00) + result = CURLE_WEIRD_SERVER_REPLY; + +fail: + return result; +} + +static CURLcode mqtt_publish(struct connectdata *conn) +{ + CURLcode result; + char *payload = conn->data->set.postfields; + size_t payloadlen = (size_t)conn->data->set.postfieldsize; + char *topic = NULL; + size_t topiclen; + unsigned char *pkt = NULL; + size_t i = 0; + size_t remaininglength; + size_t encodelen; + char encodedbytes[4]; + + result = mqtt_get_topic(conn, &topic, &topiclen); + if(result) + goto fail; + + remaininglength = payloadlen + 2 + topiclen; + encodelen = mqtt_encode_len(encodedbytes, remaininglength); + + /* add the control byte and the encoded remaining length */ + pkt = malloc(remaininglength + 1 + encodelen); + if(!pkt) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + /* assemble packet */ + pkt[i++] = MQTT_MSG_PUBLISH; + memcpy(&pkt[i], encodedbytes, encodelen); + i += encodelen; + pkt[i++] = (topiclen >> 8) & 0xff; + pkt[i++] = (topiclen & 0xff); + memcpy(&pkt[i], topic, topiclen); + i += topiclen; + memcpy(&pkt[i], payload, payloadlen); + i += payloadlen; + result = mqtt_send(conn, (char *)pkt, i); + +fail: + free(pkt); + free(topic); + return result; +} + +static size_t mqtt_decode_len(unsigned char *buf, + size_t buflen, size_t *lenbytes) +{ + size_t len = 0; + size_t mult = 1; + size_t i; + unsigned char encoded = 128; + + for(i = 0; (i < buflen) && (encoded & 128); i++) { + encoded = buf[i]; + len += (encoded & 127) * mult; + mult *= 128; + } + + if(lenbytes) + *lenbytes = i; + + return len; +} + +#ifdef CURLDEBUG +static const char *statenames[]={ + "MQTT_FIRST", + "MQTT_REMAINING_LENGTH", + "MQTT_CONNACK", + "MQTT_SUBACK", + "MQTT_SUBACK_COMING", + "MQTT_PUBWAIT", + "MQTT_PUB_REMAIN", + + "NOT A STATE" +}; +#endif + +/* The only way to change state */ +static void mqstate(struct connectdata *conn, + enum mqttstate state, + enum mqttstate nextstate) /* used if state == FIRST */ +{ + struct mqtt_conn *mqtt = &conn->proto.mqtt; +#ifdef CURLDEBUG + infof(conn->data, "%s (from %s) (next is %s)\n", + statenames[state], + statenames[mqtt->state], + (state == MQTT_FIRST)? statenames[nextstate] : ""); +#endif + mqtt->state = state; + if(state == MQTT_FIRST) + mqtt->nextstate = nextstate; +} + + +/* for the publish packet */ +#define MQTT_HEADER_LEN 5 /* max 5 bytes */ + +static CURLcode mqtt_read_publish(struct connectdata *conn, + bool *done) +{ + CURLcode result = CURLE_OK; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + ssize_t nread; + struct Curl_easy *data = conn->data; + unsigned char *pkt = (unsigned char *)data->state.buffer; + size_t remlen; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct MQTT *mq = data->req.protop; + unsigned char packet; + + switch(mqtt->state) { + MQTT_SUBACK_COMING: + case MQTT_SUBACK_COMING: + result = mqtt_verify_suback(conn); + if(result) + break; + + mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT); + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + /* we are expecting PUBLISH or SUBACK */ + packet = mq->firstbyte & 0xf0; + if(packet == MQTT_MSG_PUBLISH) + mqstate(conn, MQTT_PUB_REMAIN, MQTT_NOSTATE); + else if(packet == MQTT_MSG_SUBACK) { + mqstate(conn, MQTT_SUBACK_COMING, MQTT_NOSTATE); + goto MQTT_SUBACK_COMING; + } + else if(packet == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT\n"); + *done = TRUE; + goto end; + } + else { + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + + /* -- switched state -- */ + remlen = mq->remaining_length; + infof(data, "Remaining length: %zd bytes\n", remlen); + Curl_pgrsSetDownloadSize(data, remlen); + data->req.bytecount = 0; + data->req.size = remlen; + mq->npacket = remlen; /* get this many bytes */ + /* FALLTHROUGH */ + case MQTT_PUB_REMAIN: { + /* read rest of packet, but no more. Cap to buffer size */ + struct SingleRequest *k = &data->req; + size_t rest = mq->npacket; + if(rest > (size_t)data->set.buffer_size) + rest = (size_t)data->set.buffer_size; + result = Curl_read(conn, sockfd, (char *)pkt, rest, &nread); + if(result) { + if(CURLE_AGAIN == result) { + infof(data, "EEEE AAAAGAIN\n"); + } + goto end; + } + if(!nread) { + infof(data, "server disconnected\n"); + result = CURLE_PARTIAL_FILE; + goto end; + } + if(data->set.verbose) + Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread); + + mq->npacket -= nread; + k->bytecount += nread; + Curl_pgrsSetDownloadCounter(data, k->bytecount); + + /* if QoS is set, message contains packet id */ + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)pkt, nread); + if(result) + goto end; + + if(!mq->npacket) + /* no more PUBLISH payload, back to subscribe wait state */ + mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT); + break; + } + default: + DEBUGASSERT(NULL); /* illegal state */ + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + end: + return result; +} + +static CURLcode mqtt_do(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + + *done = FALSE; /* unconditionally */ + + result = mqtt_connect(conn); + if(result) { + failf(data, "Error %d sending MQTT CONN request", result); + return result; + } + mqstate(conn, MQTT_FIRST, MQTT_CONNACK); + return CURLE_OK; +} + +static CURLcode mqtt_doing(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct mqtt_conn *mqtt = &conn->proto.mqtt; + struct Curl_easy *data = conn->data; + struct MQTT *mq = data->req.protop; + ssize_t nread; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + unsigned char *pkt = (unsigned char *)data->state.buffer; + unsigned char byte; + + *done = FALSE; + + if(mq->nsend) { + /* send the remainder of an outgoing packet */ + char *ptr = mq->sendleftovers; + result = mqtt_send(conn, mq->sendleftovers, mq->nsend); + free(ptr); + if(result) + return result; + } + + infof(data, "mqtt_doing: state [%d]\n", (int) mqtt->state); + switch(mqtt->state) { + case MQTT_FIRST: + /* Read the initial byte only */ + result = Curl_read(conn, sockfd, (char *)&mq->firstbyte, 1, &nread); + if(result) + break; + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1); + /* remember the first byte */ + mq->npacket = 0; + mqstate(conn, MQTT_REMAINING_LENGTH, MQTT_NOSTATE); + /* FALLTHROUGH */ + case MQTT_REMAINING_LENGTH: + do { + result = Curl_read(conn, sockfd, (char *)&byte, 1, &nread); + if(result) + break; + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1); + pkt[mq->npacket++] = byte; + } while((byte & 0x80) && (mq->npacket < 4)); + if(result) + break; + mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL); + mq->npacket = 0; + if(mq->remaining_length) { + mqstate(conn, mqtt->nextstate, MQTT_NOSTATE); + break; + } + mqstate(conn, MQTT_FIRST, MQTT_FIRST); + + if(mq->firstbyte == MQTT_MSG_DISCONNECT) { + infof(data, "Got DISCONNECT\n"); + *done = TRUE; + } + break; + case MQTT_CONNACK: + result = mqtt_verify_connack(conn); + if(result) + break; + + if(conn->data->set.httpreq == HTTPREQ_POST) { + result = mqtt_publish(conn); + if(!result) { + result = mqtt_disconnect(conn); + *done = TRUE; + } + mqtt->nextstate = MQTT_FIRST; + } + else { + result = mqtt_subscribe(conn); + if(!result) { + mqstate(conn, MQTT_FIRST, MQTT_SUBACK); + } + } + break; + + case MQTT_SUBACK: + case MQTT_PUBWAIT: + case MQTT_PUB_REMAIN: + result = mqtt_read_publish(conn, done); + break; + + default: + failf(conn->data, "State not handled yet"); + *done = TRUE; + break; + } + + if(result == CURLE_AGAIN) + result = CURLE_OK; + return result; +} + +#endif /* CURL_ENABLE_MQTT */ diff --git a/lib/mqtt.h b/lib/mqtt.h new file mode 100644 index 00000000..37463d58 --- /dev/null +++ b/lib/mqtt.h @@ -0,0 +1,59 @@ +#ifndef HEADER_CURL_MQTT_H +#define HEADER_CURL_MQTT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2019 - 2020, Björn Stenberg, <bjorn@haxx.se> + * + * 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 CURL_ENABLE_MQTT +extern const struct Curl_handler Curl_handler_mqtt; +#endif + +enum mqttstate { + MQTT_FIRST, /* 0 */ + MQTT_REMAINING_LENGTH, /* 1 */ + MQTT_CONNACK, /* 2 */ + MQTT_SUBACK, /* 3 */ + MQTT_SUBACK_COMING, /* 4 - the SUBACK remainder */ + MQTT_PUBWAIT, /* 5 - wait for publish */ + MQTT_PUB_REMAIN, /* 6 - wait for the remainder of the publish */ + + MQTT_NOSTATE /* 7 - never used an actual state */ +}; + +struct mqtt_conn { + enum mqttstate state; + enum mqttstate nextstate; /* switch to this after remaining length is + done */ + unsigned int packetid; +}; + +/* protocol-specific transfer-related data */ +struct MQTT { + char *sendleftovers; + size_t nsend; /* size of sendleftovers */ + + /* when receiving */ + size_t npacket; /* byte counter */ + unsigned char firstbyte; + size_t remaining_length; +}; + +#endif /* HEADER_CURL_MQTT_H */ diff --git a/lib/multi.c b/lib/multi.c index e10e7529..d4f03187 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -700,6 +700,10 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, if(!data->multi) return CURLM_OK; /* it is already removed so let's say it is fine! */ + /* Prevent users from trying to remove an easy handle from the wrong multi */ + if(data->multi != multi) + return CURLM_BAD_EASY_HANDLE; + if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; diff --git a/lib/select.c b/lib/select.c index b372efff..d91b20a4 100644 --- a/lib/select.c +++ b/lib/select.c @@ -24,6 +24,8 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) @@ -101,6 +103,82 @@ int Curl_wait_ms(int timeout_ms) } /* + * This is a wrapper around select() to aid in Windows compatibility. + * A negative timeout value makes this function wait indefinitely, + * unless no valid file descriptor is given, when this happens the + * negative timeout is ignored and the function times out immediately. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * N = number of signalled file descriptors + */ +int Curl_select(curl_socket_t maxfd, + fd_set *fds_read, + fd_set *fds_write, + fd_set *fds_err, + time_t timeout_ms) /* milliseconds to wait */ +{ + struct timeval pending_tv; + struct timeval *ptimeout; + int pending_ms; + int r; + +#if SIZEOF_TIME_T != SIZEOF_INT + /* wrap-around precaution */ + if(timeout_ms >= INT_MAX) + timeout_ms = INT_MAX; +#endif + +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment below. */ + if((!fds_read || fds_read->fd_count == 0) && + (!fds_write || fds_write->fd_count == 0) && + (!fds_err || fds_err->fd_count == 0)) { + r = Curl_wait_ms((int)timeout_ms); + return r; + } +#endif + + ptimeout = &pending_tv; + + if(timeout_ms < 0) { + ptimeout = NULL; + } + else if(timeout_ms > 0) { + pending_ms = (int)timeout_ms; + pending_tv.tv_sec = pending_ms / 1000; + pending_tv.tv_usec = (pending_ms % 1000) * 1000; + } + else if(!timeout_ms) { + pending_tv.tv_sec = 0; + pending_tv.tv_usec = 0; + } + +#ifdef USE_WINSOCK + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. + */ + r = select((int)maxfd + 1, + fds_read && fds_read->fd_count ? fds_read : NULL, + fds_write && fds_write->fd_count ? fds_write : NULL, + fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout); +#else + r = select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout); +#endif + + return r; +} + +/* * Wait for read or write events on a set of file descriptors. It uses poll() * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, * otherwise select() is used. An error is returned if select() is being used @@ -123,20 +201,18 @@ int Curl_wait_ms(int timeout_ms) int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t readfd1, curl_socket_t writefd, /* socket to write to */ - time_t timeout_ms) /* milliseconds to wait */ + timediff_t timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE struct pollfd pfd[3]; + int pending_ms; int num; #else - struct timeval pending_tv; - struct timeval *ptimeout; fd_set fds_read; fd_set fds_write; fd_set fds_err; curl_socket_t maxfd; #endif - int pending_ms = 0; int r; int ret; @@ -158,10 +234,6 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ - if(timeout_ms > 0) { - pending_ms = (int)timeout_ms; - } - #ifdef HAVE_POLL_FINE num = 0; @@ -184,9 +256,11 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ num++; } - if(timeout_ms < 0) + if(timeout_ms > 0) + pending_ms = (int)timeout_ms; + else if(timeout_ms < 0) pending_ms = -1; - else if(!timeout_ms) + else pending_ms = 0; r = poll(pfd, num, pending_ms); @@ -249,46 +323,17 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ maxfd = writefd; } - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - - /* WinSock select() must not be called with an fd_set that contains zero - fd flags, or it will return WSAEINVAL. But, it also can't be called - with no fd_sets at all! From the documentation: - - Any two of the parameters, readfds, writefds, or exceptfds, can be - given as null. At least one must be non-null, and any non-null - descriptor set must contain at least one handle to a socket. - - We know that we have at least one bit set in at least two fd_sets in + /* We know that we have at least one bit set in at least two fd_sets in this case, but we may have no bits set in either fds_read or fd_write, so check for that and handle it. Luckily, with WinSock, we can _also_ ask how many bits are set on an fd_set. - It is unclear why WinSock doesn't just handle this for us instead of - calling this an error. - Note also that WinSock ignores the first argument, so we don't worry about the fact that maxfd is computed incorrectly with WinSock (since curl_socket_t is unsigned in such cases and thus -1 is the largest value). */ -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - &fds_err, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif + r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, (time_t)timeout_ms); if(r < 0) return -1; @@ -336,9 +381,9 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ */ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) { -#ifndef HAVE_POLL_FINE - struct timeval pending_tv; - struct timeval *ptimeout; +#ifdef HAVE_POLL_FINE + int pending_ms; +#else fd_set fds_read; fd_set fds_write; fd_set fds_err; @@ -346,7 +391,6 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) #endif bool fds_none = TRUE; unsigned int i; - int pending_ms = 0; int r; if(ufds) { @@ -367,15 +411,13 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ - if(timeout_ms > 0) { - pending_ms = timeout_ms; - } - #ifdef HAVE_POLL_FINE - if(timeout_ms < 0) + if(timeout_ms > 0) + pending_ms = timeout_ms; + else if(timeout_ms < 0) pending_ms = -1; - else if(!timeout_ms) + else pending_ms = 0; r = poll(ufds, nfds, pending_ms); @@ -418,39 +460,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } -#ifdef USE_WINSOCK - /* WinSock select() can't handle zero events. See the comment about this in - Curl_check_socket(). */ - if(fds_read.fd_count == 0 && fds_write.fd_count == 0 - && fds_err.fd_count == 0) { - r = Curl_wait_ms(timeout_ms); - return r; - } -#endif - - ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; - - if(timeout_ms > 0) { - pending_tv.tv_sec = pending_ms / 1000; - pending_tv.tv_usec = (pending_ms % 1000) * 1000; - } - else if(!timeout_ms) { - pending_tv.tv_sec = 0; - pending_tv.tv_usec = 0; - } - -#ifdef USE_WINSOCK - r = select((int)maxfd + 1, - /* WinSock select() can't handle fd_sets with zero bits set, so - don't give it such arguments. See the comment about this in - Curl_check_socket(). - */ - fds_read.fd_count ? &fds_read : NULL, - fds_write.fd_count ? &fds_write : NULL, - fds_err.fd_count ? &fds_err : NULL, ptimeout); -#else - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); -#endif + r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); if(r < 0) return -1; diff --git a/lib/select.h b/lib/select.h index ec3021aa..0fd8ed51 100644 --- a/lib/select.h +++ b/lib/select.h @@ -72,13 +72,19 @@ struct pollfd therefore defined here */ #define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) +int Curl_select(curl_socket_t maxfd, + fd_set *fds_read, + fd_set *fds_write, + fd_set *fds_err, + time_t timeout_ms); + int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, - time_t timeout_ms); + timediff_t timeout_ms); #define SOCKET_READABLE(x,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, (time_t)z) + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) #define SOCKET_WRITABLE(x,z) \ - Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, (time_t)z) + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); int Curl_wait_ms(int timeout_ms); diff --git a/lib/setopt.c b/lib/setopt.c index 4648c872..04785a68 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2134,6 +2134,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); break; #ifndef CURL_DISABLE_PROXY @@ -2143,6 +2144,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.proxy_ssl.revoke_best_effort = + !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); break; #endif diff --git a/lib/setup-win32.h b/lib/setup-win32.h new file mode 100644 index 00000000..45b58476 --- /dev/null +++ b/lib/setup-win32.h @@ -0,0 +1,123 @@ +#ifndef HEADER_CURL_SETUP_WIN32_H +#define HEADER_CURL_SETUP_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, 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 header files for windows builds before redefining anything. + * Use this preprocessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. <sys/socket.h>) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# if defined(UNICODE) && !defined(_UNICODE) +# define _UNICODE +# endif +# if defined(_UNICODE) && !defined(UNICODE) +# define UNICODE +# endif +# include <winerror.h> +# include <windows.h> +# ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +# ifdef HAVE_WS2TCPIP_H +# include <ws2tcpip.h> +# endif +# else +# ifdef HAVE_WINSOCK_H +# include <winsock.h> +# endif +# endif +# include <tchar.h> +# ifdef UNICODE + typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have + * those symbols to compare against, and even those that do may be missing + * newer symbols. + */ + +#ifndef _WIN32_WINNT_NT4 +#define _WIN32_WINNT_NT4 0x0400 /* Windows NT 4.0 */ +#endif +#ifndef _WIN32_WINNT_WIN2K +#define _WIN32_WINNT_WIN2K 0x0500 /* Windows 2000 */ +#endif +#ifndef _WIN32_WINNT_WINXP +#define _WIN32_WINNT_WINXP 0x0501 /* Windows XP */ +#endif +#ifndef _WIN32_WINNT_WS03 +#define _WIN32_WINNT_WS03 0x0502 /* Windows Server 2003 */ +#endif +#ifndef _WIN32_WINNT_WIN6 +#define _WIN32_WINNT_WIN6 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_VISTA +#define _WIN32_WINNT_VISTA 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_WS08 +#define _WIN32_WINNT_WS08 0x0600 /* Windows Server 2008 */ +#endif +#ifndef _WIN32_WINNT_LONGHORN +#define _WIN32_WINNT_LONGHORN 0x0600 /* Windows Vista */ +#endif +#ifndef _WIN32_WINNT_WIN7 +#define _WIN32_WINNT_WIN7 0x0601 /* Windows 7 */ +#endif +#ifndef _WIN32_WINNT_WIN8 +#define _WIN32_WINNT_WIN8 0x0602 /* Windows 8 */ +#endif +#ifndef _WIN32_WINNT_WINBLUE +#define _WIN32_WINNT_WINBLUE 0x0603 /* Windows 8.1 */ +#endif +#ifndef _WIN32_WINNT_WINTHRESHOLD +#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 /* Windows 10 */ +#endif +#ifndef _WIN32_WINNT_WIN10 +#define _WIN32_WINNT_WIN10 0x0A00 /* Windows 10 */ +#endif + +#endif /* HEADER_CURL_SETUP_WIN32_H */ diff --git a/lib/sha256.c b/lib/sha256.c index 352d577e..00d98ce4 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -207,8 +207,8 @@ typedef struct { static void SHA256_Init(SHA256_CTX *ctx) { - if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, - PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); } } @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies - * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2020, 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 @@ -193,7 +193,6 @@ struct smb_nt_create_response { unsigned int ext_file_attributes; curl_off_t allocation_size; curl_off_t end_of_file; - } PACK; struct smb_read { @@ -625,8 +625,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) utf8 = TRUE; if(host.name) { - free(from); - from = aprintf("<%s@%s>", address, host.name); + auth = aprintf("<%s@%s>", address, host.name); Curl_free_idnconverted_hostname(&host); } @@ -636,8 +635,6 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) auth = aprintf("<%s>", address); free(address); - if(!from) - return CURLE_OUT_OF_MEMORY; } else /* Empty AUTH, RFC-2554, sect. 5 */ @@ -1741,10 +1738,10 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) * Notes: * * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor - * that convertion then we shall return success. This allow the caller to send + * that conversion then we shall return success. This allow the caller to send * the data to the server as a U-label (as per RFC-6531 sect. 3.2). * - * If an mailbox '@' seperator cannot be located then the mailbox is considered + * If an mailbox '@' separator cannot be located then the mailbox is considered * to be either a local mailbox or an invalid mailbox (depending on what the * calling function deems it to be) then the input will simply be returned in * the address part with the host name being NULL. @@ -1765,7 +1762,7 @@ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, if(dup[length - 1] == '>') dup[length - 1] = '\0'; - /* Extract the host name from the addresss (if we can) */ + /* Extract the host name from the address (if we can) */ host->name = strpbrk(dup, "@"); if(host->name) { *host->name = '\0'; diff --git a/lib/socks.c b/lib/socks.c index 37099130..18affbc9 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -62,13 +62,15 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ int result; *n = 0; for(;;) { - timediff_t timeleft = Curl_timeleft(conn->data, NULL, TRUE); - if(timeleft < 0) { + timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE); + if(timeout_ms < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(SOCKET_READABLE(sockfd, timeleft) <= 0) { + if(!timeout_ms) + timeout_ms = TIME_T_MAX; + if(SOCKET_READABLE(sockfd, timeout_ms) <= 0) { result = ~CURLE_OK; break; } diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 97ee7183..7f66675f 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -227,7 +227,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_recv_token); - if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; + if(gss_major_status != GSS_S_CONTINUE_NEEDED) + break; /* analyse response */ diff --git a/lib/transfer.c b/lib/transfer.c index e76834eb..b9581d7a 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -48,6 +48,8 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +#include <unistd.h> #endif #ifndef HAVE_SOCKET @@ -568,17 +570,20 @@ static CURLcode readwrite_data(struct Curl_easy *data, bool is_empty_data = FALSE; size_t buffersize = data->set.buffer_size; size_t bytestoread = buffersize; +#ifdef USE_NGHTTP2 + bool is_http2 = ((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (conn->httpversion == 20)); +#endif if( -#if defined(USE_NGHTTP2) +#ifdef USE_NGHTTP2 /* For HTTP/2, read data without caring about the content length. This is safe because body in HTTP/2 is always segmented thanks to its framing layer. Meanwhile, we have to call Curl_read to ensure that http2_handle_stream_close is called when we read all incoming bytes for a particular stream. */ - !((conn->handler->protocol & PROTO_FAMILY_HTTP) && - conn->httpversion == 20) && + !is_http2 && #endif k->size != -1 && !k->header) { /* make sure we don't read too much */ @@ -621,9 +626,14 @@ static CURLcode readwrite_data(struct Curl_easy *data, k->buf[nread] = 0; } else { - /* if we receive 0 or less here, the server closed the connection - and we bail out from this! */ - DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); + /* if we receive 0 or less here, either the http2 stream is closed or the + server closed the connection and we bail out from this! */ +#ifdef USE_NGHTTP2 + if(is_http2 && !nread) + DEBUGF(infof(data, "nread == 0, stream closed, bailing\n")); + else +#endif + DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); k->keepon &= ~KEEP_RECV; break; } @@ -1707,12 +1717,19 @@ CURLcode Curl_follow(struct Curl_easy *data, break; case 303: /* See Other */ - /* Disable both types of POSTs, unless the user explicitly - asks for POST after POST */ - if(data->set.httpreq != HTTPREQ_GET - && !(data->set.keep_post & CURL_REDIR_POST_303)) { - data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ - infof(data, "Disables POST, goes with %s\n", + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->set.httpreq != HTTPREQ_GET && + ((data->set.httpreq != HTTPREQ_POST && + data->set.httpreq != HTTPREQ_POST_FORM && + data->set.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->set.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s\n", data->set.opt_no_body?"HEAD":"GET"); } break; @@ -1779,6 +1796,12 @@ CURLcode Curl_retry_request(struct connectdata *conn, retry = TRUE; } if(retry) { +#define CONN_MAX_RETRIES 5 + if(conn->retrycount++ >= CONN_MAX_RETRIES) { + failf(data, "Connection died, tried %d times before giving up", + CONN_MAX_RETRIES); + return CURLE_SEND_ERROR; + } infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) @@ -1821,15 +1844,21 @@ Curl_setup_transfer( { struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; + struct HTTP *http = data->req.protop; + bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_REQUEST)); DEBUGASSERT(conn != NULL); DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - if(conn->bits.multiplex || conn->httpversion == 20) { + if(conn->bits.multiplex || conn->httpversion == 20 || httpsending) { /* when multiplexing, the read/write sockets need to be the same! */ conn->sockfd = sockindex == -1 ? ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : conn->sock[sockindex]; conn->writesockfd = conn->sockfd; + if(httpsending) + /* special and very HTTP-specific */ + writesockindex = FIRSTSOCKET; } else { conn->sockfd = sockindex == -1 ? @@ -1857,7 +1886,6 @@ Curl_setup_transfer( k->keepon |= KEEP_RECV; if(writesockindex != -1) { - struct HTTP *http = data->req.protop; /* HTTP 1.1 magic: Even if we require a 100-return code before uploading data, we might @@ -114,6 +114,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "http_ntlm.h" #include "curl_rtmp.h" #include "gopher.h" +#include "mqtt.h" #include "http_proxy.h" #include "conncache.h" #include "multihandle.h" @@ -232,6 +233,10 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_gopher, #endif +#ifdef CURL_ENABLE_MQTT + &Curl_handler_mqtt, +#endif + #ifdef USE_LIBRTMP &Curl_handler_rtmp, &Curl_handler_rtmpt, @@ -3040,7 +3045,14 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, #ifdef USE_ALTSVC if(data->asi && !host && (port == -1) && - (conn->handler->protocol == CURLPROTO_HTTPS)) { + ((conn->handler->protocol == CURLPROTO_HTTPS) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") +#else + 0 +#endif + )) { /* no connect_to match, try alt-svc! */ enum alpnid srcalpnid; bool hit; diff --git a/lib/urldata.h b/lib/urldata.h index fbb8b645..50d8b84a 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -49,6 +49,7 @@ #define PORT_RTMPT PORT_HTTP #define PORT_RTMPS PORT_HTTPS #define PORT_GOPHER 70 +#define PORT_MQTT 1883 #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" @@ -128,6 +129,7 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ #include "http.h" #include "rtsp.h" #include "smb.h" +#include "mqtt.h" #include "wildcard.h" #include "multihandle.h" #include "quic.h" @@ -258,6 +260,8 @@ struct ssl_config_data { BIT(enable_beast); /* allow this flaw for interoperability's sake*/ BIT(no_revoke); /* disable SSL certificate revocation checks */ BIT(no_partialchain); /* don't accept partial certificate chains */ + BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation + list errors */ }; struct ssl_general_config { @@ -957,6 +961,7 @@ struct connectdata { curl_socket_t sock[2]; /* two sockets, the second is used for the data transfer when doing FTP */ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ + int tempfamily[2]; /* family used for the temp sockets */ Curl_recv *recv[2]; Curl_send *send[2]; @@ -1078,6 +1083,7 @@ struct connectdata { struct smb_conn smbc; void *rtmp; struct ldapconninfo *ldapc; + struct mqtt_conn mqtt; } proto; int cselect_bits; /* bitmask of socket events */ @@ -1098,7 +1104,7 @@ struct connectdata { struct http_connect_state *connect_state; /* for HTTP CONNECT */ struct connectbundle *bundle; /* The bundle we are member of */ int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ - + int retrycount; /* number of retries on a new connection */ #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; BIT(abstract_unix_socket); @@ -1113,6 +1119,8 @@ struct connectdata { handle */ BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with accept() */ + BIT(parallel_connect); /* set TRUE when a parallel connect attempt has + started (happy eyeballs) */ }; /* The end of connectdata. */ @@ -1325,7 +1333,6 @@ struct urlpieces { }; struct UrlState { - /* Points to the connection cache */ struct conncache *conn_cache; diff --git a/lib/version.c b/lib/version.c index 8170106e..14e50960 100644 --- a/lib/version.c +++ b/lib/version.c @@ -85,14 +85,17 @@ static size_t brotli_version(char *buf, size_t bufsz) * generate the exact same string and never write any temporary data like * zeros in the data. */ + +#define VERSION_PARTS 14 /* number of substrings we can concatenate */ + char *curl_version(void) { - static char out[250]; + static char out[300]; char *outp; size_t outlen; - const char *src[14]; + const char *src[VERSION_PARTS]; #ifdef USE_SSL - char ssl_version[40]; + char ssl_version[200]; #endif #ifdef HAVE_LIBZ char z_version[40]; @@ -103,7 +106,7 @@ char *curl_version(void) #ifdef USE_ARES char cares_version[40]; #endif -#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) +#if defined(USE_LIBIDN2) char idn_version[40]; #endif #ifdef USE_LIBPSL @@ -127,6 +130,16 @@ char *curl_version(void) int i = 0; int j; +#ifdef DEBUGBUILD + /* Override version string when environment variable CURL_VERSION is set */ + const char *debugversion = getenv("CURL_VERSION"); + if(debugversion) { + strncpy(out, debugversion, sizeof(out)-1); + out[sizeof(out)-1] = '\0'; + return out; + } +#endif + src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; #ifdef USE_SSL Curl_ssl_version(ssl_version, sizeof(ssl_version)); @@ -146,14 +159,11 @@ char *curl_version(void) src[i++] = cares_version; #endif #ifdef USE_LIBIDN2 - if(idn2_check_version(IDN2_VERSION)) { - msnprintf(idn_version, sizeof(idn_version), - "libidn2/%s", idn2_check_version(NULL)); - src[i++] = idn_version; - } -#elif defined(USE_WIN32_IDN) - msnprintf(idn_version, sizeof(idn_version), "WinIDN"); + msnprintf(idn_version, sizeof(idn_version), + "libidn2/%s", idn2_check_version(NULL)); src[i++] = idn_version; +#elif defined(USE_WIN32_IDN) + src[i++] = (char *)"WinIDN"; #endif #ifdef USE_LIBPSL @@ -198,6 +208,8 @@ char *curl_version(void) } #endif + DEBUGASSERT(i <= VERSION_PARTS); + outp = &out[0]; outlen = sizeof(out); for(j = 0; j < i; j++) { @@ -261,6 +273,9 @@ static const char * const protocols[] = { "ldaps", #endif #endif +#ifdef CURL_ENABLE_MQTT + "mqtt", +#endif #ifndef CURL_DISABLE_POP3 "pop3", #endif @@ -377,9 +392,6 @@ static curl_version_info_data version_info = { #if defined(USE_ALTSVC) | CURL_VERSION_ALTSVC #endif -#ifdef USE_ESNI - | CURL_VERSION_ESNI -#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ @@ -394,7 +406,17 @@ static curl_version_info_data version_info = { NULL, /* brotli version */ 0, /* nghttp2 version number */ NULL, /* nghttp2 version string */ - NULL /* quic library string */ + NULL, /* quic library string */ +#ifdef CURL_CA_BUNDLE + CURL_CA_BUNDLE, /* cainfo */ +#else + NULL, +#endif +#ifdef CURL_CA_PATH + CURL_CA_PATH /* capath */ +#else + NULL +#endif }; curl_version_info_data *curl_version_info(CURLversion stamp) diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c index 2f6ee8bd..5f7b6e2e 100644 --- a/lib/vquic/ngtcp2.c +++ b/lib/vquic/ngtcp2.c @@ -26,7 +26,9 @@ #include <ngtcp2/ngtcp2.h> #include <ngtcp2/ngtcp2_crypto.h> #include <nghttp3/nghttp3.h> +#ifdef USE_OPENSSL #include <openssl/err.h> +#endif #include "urldata.h" #include "sendf.h" #include "strdup.h" @@ -69,10 +71,18 @@ struct h3out { #define QUIC_MAX_STREAMS (256*1024) #define QUIC_MAX_DATA (1*1024*1024) #define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */ + +#ifdef USE_OPENSSL #define QUIC_CIPHERS \ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:X25519:P-384:P-521" +#elif defined(USE_GNUTLS) +#define QUIC_PRIORITY \ + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \ + "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ + "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1" +#endif static CURLcode ng_process_ingress(struct connectdata *conn, curl_socket_t sockfd, @@ -101,6 +111,7 @@ static void quic_printf(void *user_data, const char *fmt, ...) } #endif +#ifdef USE_OPENSSL static ngtcp2_crypto_level quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) { @@ -117,14 +128,32 @@ quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) assert(0); } } +#elif defined(USE_GNUTLS) +static ngtcp2_crypto_level +quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level) +{ + switch(gtls_level) { + case GNUTLS_ENCRYPTION_LEVEL_INITIAL: + return NGTCP2_CRYPTO_LEVEL_INITIAL; + case GNUTLS_ENCRYPTION_LEVEL_EARLY: + return NGTCP2_CRYPTO_LEVEL_EARLY; + case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE: + return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + case GNUTLS_ENCRYPTION_LEVEL_APPLICATION: + return NGTCP2_CRYPTO_LEVEL_APP; + default: + assert(0); + } +} +#endif static int setup_initial_crypto_context(struct quicsocket *qs) { const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn); if(ngtcp2_crypto_derive_and_install_initial_key( - qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid, - NGTCP2_CRYPTO_SIDE_CLIENT) != 0) + qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + dcid) != 0) return -1; return 0; @@ -150,6 +179,7 @@ static void quic_settings(ngtcp2_settings *s, } static FILE *keylog_file; /* not thread-safe */ +#ifdef USE_OPENSSL static void keylog_callback(const SSL *ssl, const char *line) { (void)ssl; @@ -157,37 +187,52 @@ static void keylog_callback(const SSL *ssl, const char *line) fputc('\n', keylog_file); fflush(keylog_file); } - -static int init_ngh3_conn(struct quicsocket *qs); - -static int quic_set_encryption_secrets(SSL *ssl, - OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *rx_secret, - const uint8_t *tx_secret, - size_t secretlen) +#elif defined(USE_GNUTLS) +static int keylog_callback(gnutls_session_t session, const char *label, + const gnutls_datum_t *secret) { - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - int level = quic_from_ossl_level(ossl_level); + gnutls_datum_t crandom; + gnutls_datum_t srandom; + gnutls_datum_t crandom_hex = { NULL, 0 }; + gnutls_datum_t secret_hex = { NULL, 0 }; + int rc = 0; + + gnutls_session_get_random(session, &crandom, &srandom); + if(crandom.size != 32) { + return -1; + } - if(ngtcp2_crypto_derive_and_install_key( - qs->qconn, ssl, NULL, NULL, NULL, NULL, NULL, NULL, level, rx_secret, - tx_secret, secretlen, NGTCP2_CRYPTO_SIDE_CLIENT) != 0) - return 0; + rc = gnutls_hex_encode2(&crandom, &crandom_hex); + if(rc < 0) { + fprintf(stderr, "gnutls_hex_encode2 failed: %s\n", + gnutls_strerror(rc)); + goto out; + } - if(level == NGTCP2_CRYPTO_LEVEL_APP) { - if(init_ngh3_conn(qs) != CURLE_OK) - return 0; + rc = gnutls_hex_encode2(secret, &secret_hex); + if(rc < 0) { + fprintf(stderr, "gnutls_hex_encode2 failed: %s\n", + gnutls_strerror(rc)); + goto out; } - return 1; + fprintf(keylog_file, "%s %s %s\n", label, crandom_hex.data, secret_hex.data); + fflush(keylog_file); + + out: + gnutls_free(crandom_hex.data); + gnutls_free(secret_hex.data); + return rc; } +#endif -static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *data, size_t len) +static int init_ngh3_conn(struct quicsocket *qs); + +static int write_client_handshake(struct quicsocket *qs, + ngtcp2_crypto_level level, + const uint8_t *data, size_t len) { - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); struct quic_handshake *crypto_data; - ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); int rv; crypto_data = &qs->crypto_data[level]; @@ -216,6 +261,42 @@ static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, return 1; } +#ifdef USE_OPENSSL +static int quic_set_encryption_secrets(SSL *ssl, + OSSL_ENCRYPTION_LEVEL ossl_level, + const uint8_t *rx_secret, + const uint8_t *tx_secret, + size_t secretlen) +{ + struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); + int level = quic_from_ossl_level(ossl_level); + + if(level != NGTCP2_CRYPTO_LEVEL_EARLY && + ngtcp2_crypto_derive_and_install_rx_key( + qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) + return 0; + + if(ngtcp2_crypto_derive_and_install_tx_key( + qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) + return 0; + + if(level == NGTCP2_CRYPTO_LEVEL_APP) { + if(init_ngh3_conn(qs) != CURLE_OK) + return 0; + } + + return 1; +} + +static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, + const uint8_t *data, size_t len) +{ + struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); + ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); + + return write_client_handshake(qs, level, data, len); +} + static int quic_flush_flight(SSL *ssl) { (void)ssl; @@ -303,6 +384,193 @@ static int quic_init_ssl(struct quicsocket *qs) SSL_set_tlsext_host_name(qs->ssl, hostname); return 0; } +#elif defined(USE_GNUTLS) +static int secret_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + const void *rx_secret, + const void *tx_secret, size_t secretlen) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + int level = quic_from_gtls_level(gtls_level); + + if(level != NGTCP2_CRYPTO_LEVEL_EARLY && + ngtcp2_crypto_derive_and_install_rx_key( + qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) + return 0; + + if(ngtcp2_crypto_derive_and_install_tx_key( + qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) + return 0; + + if(level == NGTCP2_CRYPTO_LEVEL_APP) { + if(init_ngh3_conn(qs) != CURLE_OK) + return -1; + } + + return 0; +} + +static int read_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + gnutls_handshake_description_t htype, const void *data, + size_t len) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level); + int rv; + + if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) + return 0; + + rv = write_client_handshake(qs, level, data, len); + if(rv == 0) + return -1; + + return 0; +} + +static int alert_read_func(gnutls_session_t ssl, + gnutls_record_encryption_level_t gtls_level, + gnutls_alert_level_t alert_level, + gnutls_alert_description_t alert_desc) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + (void)gtls_level; + (void)alert_level; + + qs->tls_alert = alert_desc; + return 1; +} + +static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data, + size_t data_size) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + ngtcp2_transport_params params; + + if(ngtcp2_decode_transport_params( + ¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, + data, data_size) != 0) + return -1; + + if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0) + return -1; + + return 0; +} + +static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata) +{ + struct quicsocket *qs = gnutls_session_get_ptr(ssl); + uint8_t paramsbuf[64]; + ngtcp2_transport_params params; + ssize_t nwrite; + int rc; + + ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); + nwrite = ngtcp2_encode_transport_params( + paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, + ¶ms); + if(nwrite < 0) { + fprintf(stderr, "ngtcp2_encode_transport_params: %s\n", + ngtcp2_strerror((int)nwrite)); + return -1; + } + + rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite); + if(rc < 0) + return rc; + + return (int)nwrite; +} + +static int quic_init_ssl(struct quicsocket *qs) +{ + gnutls_datum_t alpn = {NULL, 0}; + /* this will need some attention when HTTPS proxy over QUIC get fixed */ + const char * const hostname = qs->conn->host.name; + const char *keylog_filename; + int rc; + + if(qs->ssl) + gnutls_deinit(qs->ssl); + + gnutls_init(&qs->ssl, GNUTLS_CLIENT); + gnutls_session_set_ptr(qs->ssl, qs); + + rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); + if(rc < 0) { + fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", + gnutls_strerror(rc)); + return 1; + } + + gnutls_handshake_set_secret_function(qs->ssl, secret_func); + gnutls_handshake_set_read_function(qs->ssl, read_func); + gnutls_alert_set_read_function(qs->ssl, alert_read_func); + + rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters", + 0xffa5, GNUTLS_EXT_TLS, + tp_recv_func, tp_send_func, + NULL, NULL, NULL, + GNUTLS_EXT_FLAG_TLS | + GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE); + if(rc < 0) { + fprintf(stderr, "gnutls_session_ext_register failed: %s\n", + gnutls_strerror(rc)); + return 1; + } + + keylog_filename = getenv("SSLKEYLOGFILE"); + if(keylog_filename) { + keylog_file = fopen(keylog_filename, "wb"); + if(keylog_file) { + gnutls_session_set_keylog_function(qs->ssl, keylog_callback); + } + } + + if(qs->cred) + gnutls_certificate_free_credentials(qs->cred); + + rc = gnutls_certificate_allocate_credentials(&qs->cred); + if(rc < 0) { + fprintf(stderr, "gnutls_certificate_allocate_credentials failed: %s\n", + gnutls_strerror(rc)); + return 1; + } + + rc = gnutls_certificate_set_x509_system_trust(qs->cred); + if(rc < 0) { + fprintf(stderr, "gnutls_certificate_set_x509_system_trust failed: %s\n", + gnutls_strerror(rc)); + return 1; + } + + rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred); + if(rc < 0) { + fprintf(stderr, "gnutls_credentials_set failed: %s\n", + gnutls_strerror(rc)); + return 1; + } + + switch(qs->version) { +#ifdef NGTCP2_PROTO_VER + case NGTCP2_PROTO_VER: + /* strip the first byte from NGTCP2_ALPN_H3 */ + alpn.data = (unsigned char *)NGTCP2_ALPN_H3 + 1; + alpn.size = sizeof(NGTCP2_ALPN_H3) - 2; + break; +#endif + } + if(alpn.data) + gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0); + + /* set SNI */ + gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); + return 0; +} +#endif static int cb_initial(ngtcp2_conn *quic, void *user_data) { @@ -556,9 +824,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, struct quicsocket *qs = &conn->hequic[sockindex]; char ipbuf[40]; long port; +#ifdef USE_OPENSSL uint8_t paramsbuf[64]; ngtcp2_transport_params params; ssize_t nwrite; +#endif qs->conn = conn; @@ -574,9 +844,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, sockfd, ipbuf, port); qs->version = NGTCP2_PROTO_VER; +#ifdef USE_OPENSSL qs->sslctx = quic_ssl_ctx(data); if(!qs->sslctx) return CURLE_QUIC_CONNECT_ERROR; +#endif if(quic_init_ssl(qs)) return CURLE_QUIC_CONNECT_ERROR; @@ -613,6 +885,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, if(rc) return CURLE_QUIC_CONNECT_ERROR; +#ifdef USE_OPENSSL ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); nwrite = ngtcp2_encode_transport_params( paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, @@ -625,6 +898,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite)) return CURLE_QUIC_CONNECT_ERROR; +#endif rc = setup_initial_crypto_context(qs); if(rc) @@ -676,12 +950,22 @@ static CURLcode ng_disconnect(struct connectdata *conn, struct quicsocket *qs = &conn->hequic[0]; (void)dead_connection; if(qs->ssl) +#ifdef USE_OPENSSL SSL_free(qs->ssl); +#elif defined(USE_GNUTLS) + gnutls_deinit(qs->ssl); +#endif +#ifdef USE_GNUTLS + if(qs->cred) + gnutls_certificate_free_credentials(qs->cred); +#endif for(i = 0; i < 3; i++) free(qs->crypto_data[i].buf); nghttp3_conn_del(qs->h3conn); ngtcp2_conn_del(qs->qconn); +#ifdef USE_OPENSSL SSL_CTX_free(qs->sslctx); +#endif return CURLE_OK; } diff --git a/lib/vquic/ngtcp2.h b/lib/vquic/ngtcp2.h index 30d442fd..06337f6f 100644 --- a/lib/vquic/ngtcp2.h +++ b/lib/vquic/ngtcp2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -28,7 +28,11 @@ #include <ngtcp2/ngtcp2.h> #include <nghttp3/nghttp3.h> +#ifdef USE_OPENSSL #include <openssl/ssl.h> +#elif defined(USE_GNUTLS) +#include <gnutls/gnutls.h> +#endif struct quic_handshake { char *buf; /* pointer to the buffer */ @@ -44,8 +48,13 @@ struct quicsocket { ngtcp2_cid scid; uint32_t version; ngtcp2_settings settings; +#ifdef USE_OPENSSL SSL_CTX *sslctx; SSL *ssl; +#elif defined(USE_GNUTLS) + gnutls_certificate_credentials_t cred; + gnutls_session_t ssl; +#endif struct quic_handshake crypto_data[3]; /* the last TLS alert description generated by the local endpoint */ uint8_t tls_alert; diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 08d9f9e0..8988e239 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -403,6 +403,9 @@ static int myssh_is_known(struct connectdata *conn) knownkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: knownkey.keytype = CURLKHTYPE_ECDSA; break; case SSH_KEYTYPE_ED25519: @@ -470,6 +473,11 @@ static int myssh_is_known(struct connectdata *conn) foundkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: +#endif foundkey.keytype = CURLKHTYPE_ECDSA; break; #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0) @@ -2141,6 +2149,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done) CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; + int rc; /* initialize per-handle data if not already */ if(!data->req.protop) @@ -2167,38 +2176,70 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done) return CURLE_FAILED_INIT; } - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); + if(rc != SSH_OK) { + failf(data, "Could not set remote host"); + return CURLE_FAILED_INIT; + } + + rc = ssh_options_parse_config(ssh->ssh_session, NULL); + if(rc != SSH_OK) { + infof(data, "Could not parse SSH configuration files"); + /* ignore */ + } + + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); + if(rc != SSH_OK) { + failf(data, "Could not set socket"); + return CURLE_FAILED_INIT; + } - if(conn->user) { + if(conn->user && conn->user[0] != '\0') { infof(data, "User: %s\n", conn->user); - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); + if(rc != SSH_OK) { + failf(data, "Could not set user"); + return CURLE_FAILED_INIT; + } } if(data->set.str[STRING_SSH_KNOWNHOSTS]) { infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]); - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, - data->set.str[STRING_SSH_KNOWNHOSTS]); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, + data->set.str[STRING_SSH_KNOWNHOSTS]); + if(rc != SSH_OK) { + failf(data, "Could not set known hosts file path"); + return CURLE_FAILED_INIT; + } } - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); - if(conn->remote_port) - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, - &conn->remote_port); + if(conn->remote_port) { + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, + &conn->remote_port); + if(rc != SSH_OK) { + failf(data, "Could not set remote port"); + return CURLE_FAILED_INIT; + } + } if(data->set.ssh_compression) { - ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, - "zlib,zlib@openssh.com,none"); + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, + "zlib,zlib@openssh.com,none"); + if(rc != SSH_OK) { + failf(data, "Could not set compression"); + return CURLE_FAILED_INIT; + } } ssh->privkey = NULL; ssh->pubkey = NULL; if(data->set.str[STRING_SSH_PUBLIC_KEY]) { - int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], - &ssh->pubkey); + rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], + &ssh->pubkey); if(rc != SSH_OK) { failf(data, "Could not load public key file"); - /* ignore */ + return CURLE_FAILED_INIT; } } diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c index 67f94583..1a6530c8 100644 --- a/lib/vtls/bearssl.c +++ b/lib/vtls/bearssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> + * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,8 +56,6 @@ struct ssl_backend_data { size_t pending_write; }; -#define BACKEND connssl->backend - struct cafile_parser { CURLcode err; bool in_cert; @@ -300,6 +298,7 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; @@ -343,7 +342,7 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) } if(ssl_cafile) { - ret = load_cafile(ssl_cafile, &BACKEND->anchors, &BACKEND->anchors_len); + ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { failf(data, "error setting certificate verify locations:\n" @@ -356,24 +355,24 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) } /* initialize SSL context */ - br_ssl_client_init_full(&BACKEND->ctx, &BACKEND->x509.minimal, - BACKEND->anchors, BACKEND->anchors_len); - br_ssl_engine_set_versions(&BACKEND->ctx.eng, version_min, version_max); - br_ssl_engine_set_buffer(&BACKEND->ctx.eng, BACKEND->buf, - sizeof(BACKEND->buf), 1); + br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, + backend->anchors, backend->anchors_len); + br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); + br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, + sizeof(backend->buf), 1); /* initialize X.509 context */ - BACKEND->x509.vtable = &x509_vtable; - BACKEND->x509.verifypeer = verifypeer; - BACKEND->x509.verifyhost = verifyhost; - br_ssl_engine_set_x509(&BACKEND->ctx.eng, &BACKEND->x509.vtable); + backend->x509.vtable = &x509_vtable; + backend->x509.verifypeer = verifypeer; + backend->x509.verifyhost = verifyhost; + br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); if(SSL_SET_OPTION(primary.sessionid)) { void *session; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { - br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); + br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); infof(data, "BearSSL: re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); @@ -389,16 +388,16 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { - BACKEND->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif - BACKEND->protocols[cur++] = ALPN_HTTP_1_1; + backend->protocols[cur++] = ALPN_HTTP_1_1; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - br_ssl_engine_set_protocol_names(&BACKEND->ctx.eng, - BACKEND->protocols, cur); + br_ssl_engine_set_protocol_names(&backend->ctx.eng, + backend->protocols, cur); } if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) @@ -414,9 +413,9 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) hostname = NULL; } - if(!br_ssl_client_reset(&BACKEND->ctx, hostname, 0)) + if(!br_ssl_client_reset(&backend->ctx, hostname, 0)) return CURLE_FAILED_INIT; - BACKEND->active = TRUE; + backend->active = TRUE; connssl->connecting_state = ssl_connect_2; @@ -428,6 +427,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; curl_socket_t sockfd = conn->sock[sockindex]; unsigned state; unsigned char *buf; @@ -436,9 +436,9 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, int err; for(;;) { - state = br_ssl_engine_current_state(&BACKEND->ctx.eng); + state = br_ssl_engine_current_state(&backend->ctx.eng); if(state & BR_SSL_CLOSED) { - err = br_ssl_engine_last_error(&BACKEND->ctx.eng); + err = br_ssl_engine_last_error(&backend->ctx.eng); switch(err) { case BR_ERR_OK: /* TLS close notify */ @@ -468,7 +468,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, if(state & target) return CURLE_OK; if(state & BR_SSL_SENDREC) { - buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); + buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len); ret = swrite(sockfd, buf, len); if(ret == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { @@ -478,10 +478,10 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, } return CURLE_WRITE_ERROR; } - br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); + br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); } else if(state & BR_SSL_RECVREC) { - buf = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &len); + buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len); ret = sread(sockfd, buf, len); if(ret == 0) { failf(data, "SSL: EOF without close notify"); @@ -495,7 +495,7 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, } return CURLE_READ_ERROR; } - br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); + br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); } } } @@ -504,13 +504,14 @@ static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode ret; ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP); if(ret == CURLE_AGAIN) return CURLE_OK; if(ret == CURLE_OK) { - if(br_ssl_engine_current_state(&BACKEND->ctx.eng) == BR_SSL_CLOSED) { + if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) { failf(data, "SSL: connection closed during handshake"); return CURLE_SSL_CONNECT_ERROR; } @@ -523,6 +524,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode ret; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -530,7 +532,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) if(conn->bits.tls_enable_alpn) { const char *protocol; - protocol = br_ssl_engine_get_selected_protocol(&BACKEND->ctx.eng); + protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); if(protocol) { infof(data, "ALPN, server accepted to use %s\n", protocol); @@ -558,7 +560,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) session = malloc(sizeof(*session)); if(!session) return CURLE_OUT_OF_MEMORY; - br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); + br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); if(incache) @@ -581,6 +583,7 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned char *app; size_t applen; @@ -588,23 +591,23 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex, *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP); if (*err != CURLE_OK) return -1; - app = br_ssl_engine_sendapp_buf(&BACKEND->ctx.eng, &applen); + app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen); if(!app) { failf(data, "SSL: connection closed during write"); *err = CURLE_SEND_ERROR; return -1; } - if(BACKEND->pending_write) { - applen = BACKEND->pending_write; - BACKEND->pending_write = 0; + if(backend->pending_write) { + applen = backend->pending_write; + backend->pending_write = 0; return applen; } if(applen > len) applen = len; memcpy(app, buf, applen); - br_ssl_engine_sendapp_ack(&BACKEND->ctx.eng, applen); - br_ssl_engine_flush(&BACKEND->ctx.eng, 0); - BACKEND->pending_write = applen; + br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen); + br_ssl_engine_flush(&backend->ctx.eng, 0); + backend->pending_write = applen; } } @@ -612,19 +615,20 @@ static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned char *app; size_t applen; *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP); if(*err != CURLE_OK) return -1; - app = br_ssl_engine_recvapp_buf(&BACKEND->ctx.eng, &applen); + app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen); if(!app) return 0; if(applen > len) applen = len; memcpy(buf, app, applen); - br_ssl_engine_recvapp_ack(&BACKEND->ctx.eng, applen); + br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen); return applen; } @@ -739,8 +743,8 @@ static bool Curl_bearssl_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - - return br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_RECVAPP; + struct ssl_backend_data *backend = connssl->backend; + return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; } static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, @@ -786,21 +790,23 @@ static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - return &BACKEND->ctx; + struct ssl_backend_data *backend = connssl->backend; + return &backend->ctx; } static void Curl_bearssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; size_t i; - if(BACKEND->active) { - br_ssl_engine_close(&BACKEND->ctx.eng); + if(backend->active) { + br_ssl_engine_close(&backend->ctx.eng); (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED); } - for(i = 0; i < BACKEND->anchors_len; ++i) - free(BACKEND->anchors[i].dn.data); - free(BACKEND->anchors); + for(i = 0; i < backend->anchors_len; ++i) + free(backend->anchors[i].dn.data); + free(backend->anchors); } static void Curl_bearssl_session_free(void *ptr) @@ -836,9 +842,7 @@ static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, const struct Curl_ssl Curl_ssl_bearssl = { { CURLSSLBACKEND_BEARSSL, "bearssl" }, - 0, - sizeof(struct ssl_backend_data), Curl_none_init, diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index 32153dd0..b0864b5f 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -524,7 +524,6 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, int m; int i; int ret = 0; - struct timeval tv = {0, 0}; char buf[CURL_MAX_WRITE_SIZE]; if(!connssl->use || !connproxyssl->use) @@ -544,7 +543,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, if(n < conn->sock[sockindex]) n = conn->sock[sockindex]; } - i = select(n + 1, &fds_read, &fds_write, NULL, &tv); + i = Curl_select(n + 1, &fds_read, &fds_write, NULL, 0); if(i < 0) return -1; /* Select error. */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 5f740eeb..4ed3ea5c 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -72,36 +72,11 @@ static void tls_log_func(int level, const char *str) #endif static bool gtls_inited = FALSE; -#if defined(GNUTLS_VERSION_NUMBER) -# if (GNUTLS_VERSION_NUMBER >= 0x020c00) -# undef gnutls_transport_set_lowat -# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt -# define USE_GNUTLS_PRIORITY_SET_DIRECT 1 -# endif -# if (GNUTLS_VERSION_NUMBER >= 0x020c03) -# define GNUTLS_MAPS_WINSOCK_ERRORS 1 -# endif - -# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS -# define HAS_ALPN -# endif - -# if HAVE_GNUTLS_OCSP_REQ_INIT -# define HAS_OCSP -# endif - -# if (GNUTLS_VERSION_NUMBER >= 0x030306) -# define HAS_CAPATH -# endif +#if !defined(GNUTLS_VERSION_NUMBER) || (GNUTLS_VERSION_NUMBER < 0x03010a) +#error "too old GnuTLS version" #endif -#if (GNUTLS_VERSION_NUMBER >= 0x030603) -#define HAS_TLS13 -#endif - -#ifdef HAS_OCSP # include <gnutls/ocsp.h> -#endif struct ssl_backend_data { gnutls_session_t session; @@ -111,58 +86,10 @@ struct ssl_backend_data { #endif }; -#define BACKEND connssl->backend - -/* - * Custom push and pull callback functions used by GNU TLS to read and write - * to the socket. These functions are simple wrappers to send() and recv() - * (although here using the sread/swrite macros as defined by - * curl_setup_once.h). - * We use custom functions rather than the GNU TLS defaults because it allows - * us to get specific about the fourth "flags" argument, and to use arbitrary - * private data with gnutls_transport_set_ptr if we wish. - * - * When these custom push and pull callbacks fail, GNU TLS checks its own - * session-specific error variable, and when not set also its own global - * errno variable, in order to take appropriate action. GNU TLS does not - * require that the transport is actually a socket. This implies that for - * Windows builds these callbacks should ideally set the session-specific - * error variable using function gnutls_transport_set_errno or as a last - * resort global errno variable using gnutls_transport_set_global_errno, - * with a transport agnostic error value. This implies that some winsock - * error translation must take place in these callbacks. - * - * Paragraph above applies to GNU TLS versions older than 2.12.3, since - * this version GNU TLS does its own internal winsock error translation - * using system_errno() function. - */ - -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) -# define gtls_EINTR 4 -# define gtls_EIO 5 -# define gtls_EAGAIN 11 -static int gtls_mapped_sockerrno(void) -{ - switch(SOCKERRNO) { - case WSAEWOULDBLOCK: - return gtls_EAGAIN; - case WSAEINTR: - return gtls_EINTR; - default: - break; - } - return gtls_EIO; -} -#endif - static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = swrite(sock, buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif return ret; } @@ -170,10 +97,6 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = sread(sock, buf, len); -#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif return ret; } @@ -284,7 +207,8 @@ static CURLcode handshake(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; curl_socket_t sockfd = conn->sock[sockindex]; for(;;) { @@ -383,51 +307,6 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) return -1; } -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT -static CURLcode -set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) -{ - struct Curl_easy *data = conn->data; - long ssl_version = SSL_CONN_CONFIG(version); - long ssl_version_max = SSL_CONN_CONFIG(version_max); - long i = ssl_version; - long protocol_priority_idx = 0; - - switch(ssl_version_max) { - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_DEFAULT: -#ifdef HAS_TLS13 - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; -#endif - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - break; - } - - for(; i <= (ssl_version_max >> 16) && - protocol_priority_idx < list_size; ++i) { - switch(i) { - case CURL_SSLVERSION_TLSv1_0: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; - break; - case CURL_SSLVERSION_TLSv1_1: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; - break; - case CURL_SSLVERSION_TLSv1_2: - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; - break; - case CURL_SSLVERSION_TLSv1_3: -#ifdef HAS_TLS13 - protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3; - break; -#else - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; -#endif - } - } - return CURLE_OK; -} -#else #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" /* If GnuTLS was compiled without support for SRP it will error out if SRP is requested in the priority string, so treat it specially @@ -445,77 +324,59 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; } switch(ssl_version | ssl_version_max) { - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: -#ifdef HAS_TLS13 - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.3:" GNUTLS_SRP; - return CURLE_OK; -#else - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; -#endif - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" -#ifdef HAS_TLS13 - "+VERS-TLS1.3:" -#endif - GNUTLS_SRP; - return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2" + ":+VERS-TLS1.3"; + return CURLE_OK; } failf(data, "GnuTLS: cannot set ssl protocol"); return CURLE_SSL_CONNECT_ERROR; } -#endif static CURLcode gtls_connect_step1(struct connectdata *conn, @@ -523,6 +384,7 @@ gtls_connect_step1(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; unsigned int init_flags; gnutls_session_t session; int rc; @@ -535,26 +397,8 @@ gtls_connect_step1(struct connectdata *conn, #else struct in_addr addr; #endif -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - static const int cipher_priority[] = { - /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, - but this code path is only ever used for ver. < 2.12.0. - GNUTLS_CIPHER_AES_128_GCM, - GNUTLS_CIPHER_AES_256_GCM, - */ - GNUTLS_CIPHER_AES_128_CBC, - GNUTLS_CIPHER_AES_256_CBC, - GNUTLS_CIPHER_CAMELLIA_128_CBC, - GNUTLS_CIPHER_CAMELLIA_256_CBC, - GNUTLS_CIPHER_3DES_CBC, - }; - static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - int protocol_priority[] = { 0, 0, 0, 0 }; -#else const char *prioritylist; const char *err = NULL; -#endif - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; @@ -574,7 +418,7 @@ gtls_connect_step1(struct connectdata *conn, sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&BACKEND->cred); + rc = gnutls_certificate_allocate_credentials(&backend->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -585,14 +429,14 @@ gtls_connect_step1(struct connectdata *conn, infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( - &BACKEND->srp_client_cred); + &backend->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_OUT_OF_MEMORY; } - rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, + rc = gnutls_srp_set_client_credentials(backend->srp_client_cred, SSL_SET_OPTION(username), SSL_SET_OPTION(password)); if(rc != GNUTLS_E_SUCCESS) { @@ -605,10 +449,10 @@ gtls_connect_step1(struct connectdata *conn, if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(BACKEND->cred, + gnutls_certificate_set_verify_flags(backend->cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, + rc = gnutls_certificate_set_x509_trust_file(backend->cred, SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -622,10 +466,9 @@ gtls_connect_step1(struct connectdata *conn, SSL_CONN_CONFIG(CAfile)); } -#ifdef HAS_CAPATH if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ - rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, + rc = gnutls_certificate_set_x509_trust_dir(backend->cred, SSL_CONN_CONFIG(CApath), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -638,19 +481,18 @@ gtls_connect_step1(struct connectdata *conn, infof(data, "found %d certificates in %s\n", rc, SSL_CONN_CONFIG(CApath)); } -#endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ if(SSL_CONN_CONFIG(verifypeer) && !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { - gnutls_certificate_set_x509_system_trust(BACKEND->cred); + gnutls_certificate_set_x509_system_trust(backend->cred); } #endif if(SSL_SET_OPTION(CRLfile)) { /* set the CRL list file */ - rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, + rc = gnutls_certificate_set_x509_crl_file(backend->cred, SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { @@ -675,14 +517,14 @@ gtls_connect_step1(struct connectdata *conn, init_flags |= GNUTLS_NO_TICKETS; #endif - rc = gnutls_init(&BACKEND->session, init_flags); + rc = gnutls_init(&backend->session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ - session = BACKEND->session; + session = backend->session; if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 @@ -699,62 +541,6 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; -#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT - rc = gnutls_cipher_set_priority(session, cipher_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - /* Sets the priority on the certificate types supported by gnutls. Priority - is higher for types specified before others. After specifying the types - you want, you must append a 0. */ - rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - if(SSL_CONN_CONFIG(cipher_list) != NULL) { - failf(data, "can't pass a custom cipher list to older GnuTLS" - " versions"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_SSLv3: - protocol_priority[0] = GNUTLS_SSL3; - break; - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - protocol_priority[0] = GNUTLS_TLS1_0; - protocol_priority[1] = GNUTLS_TLS1_1; - protocol_priority[2] = GNUTLS_TLS1_2; -#ifdef HAS_TLS13 - protocol_priority[3] = GNUTLS_TLS1_3; -#endif - break; - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - CURLcode result = set_ssl_version_min_max(protocol_priority, - sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - rc = gnutls_protocol_set_priority(session, protocol_priority); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "Did you pass a valid GnuTLS cipher list?"); - return CURLE_SSL_CONNECT_ERROR; - } - -#else /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ @@ -764,11 +550,11 @@ gtls_connect_step1(struct connectdata *conn, break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0" #ifdef HAS_TLS13 - "+VERS-TLS1.3:" + ":+VERS-TLS1.3" #endif - GNUTLS_SRP; + ; break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: @@ -787,32 +573,39 @@ gtls_connect_step1(struct connectdata *conn, failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } - rc = gnutls_priority_set_direct(session, prioritylist, &err); - if((rc == GNUTLS_E_INVALID_REQUEST) && err) { - if(!strcmp(err, GNUTLS_SRP)) { - /* This GnuTLS was probably compiled without support for SRP. - * Note that fact and try again without it. */ - int validprioritylen = curlx_uztosi(err - prioritylist); - char *prioritycopy = strdup(prioritylist); - if(!prioritycopy) - return CURLE_OUT_OF_MEMORY; +#ifdef USE_TLS_SRP + /* Only add SRP to the cipher list if SRP is requested. Otherwise + * GnuTLS will disable TLS 1.3 support. */ + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { + size_t len = strlen(prioritylist); + + char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); + if(!prioritysrp) + return CURLE_OUT_OF_MEMORY; + strcpy(prioritysrp, prioritylist); + strcpy(prioritysrp + len, ":" GNUTLS_SRP); + + rc = gnutls_priority_set_direct(session, prioritysrp, &err); + free(prioritysrp); + + if((rc == GNUTLS_E_INVALID_REQUEST) && err) { infof(data, "This GnuTLS does not support SRP\n"); - if(validprioritylen) - /* Remove the :+SRP */ - prioritycopy[validprioritylen - 1] = 0; - rc = gnutls_priority_set_direct(session, prioritycopy, &err); - free(prioritycopy); } } + else { +#endif + rc = gnutls_priority_set_direct(session, prioritylist, &err); +#ifdef USE_TLS_SRP + } +#endif + if(rc != GNUTLS_E_SUCCESS) { failf(data, "Error %d setting GnuTLS cipher list starting with %s", rc, err); return CURLE_SSL_CONNECT_ERROR; } -#endif -#ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; @@ -834,18 +627,16 @@ gtls_connect_step1(struct connectdata *conn, gnutls_alpn_set_protocols(session, protocols, cur, 0); } -#endif if(SSL_SET_OPTION(cert)) { if(SSL_SET_OPTION(key_passwd)) { -#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( - BACKEND->cred, + backend->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -858,14 +649,10 @@ gtls_connect_step1(struct connectdata *conn, gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } -#else - failf(data, "gnutls lacks support for encrypted key files"); - return CURLE_SSL_CONNECT_ERROR; -#endif } else { if(gnutls_certificate_set_x509_key_file( - BACKEND->cred, + backend->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), @@ -881,7 +668,7 @@ gtls_connect_step1(struct connectdata *conn, /* put the credentials to the current session */ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, - BACKEND->srp_client_cred); + backend->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -891,7 +678,7 @@ gtls_connect_step1(struct connectdata *conn, #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - BACKEND->cred); + backend->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; @@ -917,10 +704,6 @@ gtls_connect_step1(struct connectdata *conn, gnutls_transport_set_push_function(session, gnutls_transport_push); gnutls_transport_set_pull_function(session, gnutls_transport_pull); - /* lowat must be set to zero when using custom push and pull functions. */ - gnutls_transport_set_lowat(session, 0); - -#ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { @@ -928,7 +711,6 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } } -#endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ @@ -1020,17 +802,17 @@ gtls_connect_step3(struct connectdata *conn, unsigned int verify_status = 0; gnutls_x509_crt_t x509_cert, x509_issuer; gnutls_datum_t issuerp; - char certbuf[256] = ""; /* big enough? */ + gnutls_datum_t certfields; + char certname[65] = ""; /* limited to 64 chars by ASN.1 */ size_t size; time_t certclock; const char *ptr; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session_t session = BACKEND->session; + struct ssl_backend_data *backend = connssl->backend; + gnutls_session_t session = backend->session; int rc; -#ifdef HAS_ALPN gnutls_datum_t proto; -#endif CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS unsigned int algo; @@ -1127,7 +909,6 @@ gtls_connect_step3(struct connectdata *conn, else infof(data, "\t server certificate verification SKIPPED\n"); -#ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { gnutls_datum_t status_request; @@ -1230,7 +1011,6 @@ gtls_connect_step3(struct connectdata *conn, } else infof(data, "\t server certificate status verification SKIPPED\n"); -#endif /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); @@ -1257,11 +1037,11 @@ gtls_connect_step3(struct connectdata *conn, SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } - size = sizeof(certbuf); + size = sizeof(certname); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ FALSE, - certbuf, + certname, &size); if(rc) { infof(data, "error fetching CN from cert:%s\n", @@ -1322,16 +1102,16 @@ gtls_connect_step3(struct connectdata *conn, if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, dispname); + "target host name '%s'", certname, dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, dispname); + certname, dispname); } else - infof(data, "\t common name: %s (matched)\n", certbuf); + infof(data, "\t common name: %s (matched)\n", certname); /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1416,9 +1196,10 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_get_version(x509_cert)); - size = sizeof(certbuf); - gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); - infof(data, "\t subject: %s\n", certbuf); + rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); + if(rc != 0) + return CURLE_OUT_OF_MEMORY; + infof(data, "\t subject: %s\n", certfields.data); certclock = gnutls_x509_crt_get_activation_time(x509_cert); showtime(data, "start date", certclock); @@ -1426,14 +1207,14 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_expiration_time(x509_cert); showtime(data, "expire date", certclock); - size = sizeof(certbuf); - gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); - infof(data, "\t issuer: %s\n", certbuf); + rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); + if(rc != 0) + return CURLE_OUT_OF_MEMORY; + infof(data, "\t issuer: %s\n", certfields.data); #endif gnutls_x509_crt_deinit(x509_cert); -#ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { @@ -1459,7 +1240,6 @@ gtls_connect_step3(struct connectdata *conn, Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } -#endif conn->ssl[sockindex].state = ssl_connection_complete; conn->recv[sockindex] = gtls_recv; @@ -1577,13 +1357,14 @@ static bool Curl_gtls_data_pending(const struct connectdata *conn, { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; bool res = FALSE; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) + struct ssl_backend_data *backend = connssl->backend; + if(backend->session && + 0 != gnutls_record_check_pending(backend->session)) res = TRUE; connssl = &conn->proxy_ssl[connindex]; - if(BACKEND->session && - 0 != gnutls_record_check_pending(BACKEND->session)) + if(backend->session && + 0 != gnutls_record_check_pending(backend->session)) res = TRUE; return res; @@ -1596,7 +1377,8 @@ static ssize_t gtls_send(struct connectdata *conn, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); + struct ssl_backend_data *backend = connssl->backend; + ssize_t rc = gnutls_record_send(backend->session, mem, len); if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) @@ -1611,19 +1393,20 @@ static ssize_t gtls_send(struct connectdata *conn, static void close_one(struct ssl_connect_data *connssl) { - if(BACKEND->session) { - gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); - gnutls_deinit(BACKEND->session); - BACKEND->session = NULL; + struct ssl_backend_data *backend = connssl->backend; + if(backend->session) { + gnutls_bye(backend->session, GNUTLS_SHUT_WR); + gnutls_deinit(backend->session); + backend->session = NULL; } - if(BACKEND->cred) { - gnutls_certificate_free_credentials(BACKEND->cred); - BACKEND->cred = NULL; + if(backend->cred) { + gnutls_certificate_free_credentials(backend->cred); + backend->cred = NULL; } #ifdef USE_TLS_SRP - if(BACKEND->srp_client_cred) { - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); - BACKEND->srp_client_cred = NULL; + if(backend->srp_client_cred) { + gnutls_srp_free_client_credentials(backend->srp_client_cred); + backend->srp_client_cred = NULL; } #endif } @@ -1641,6 +1424,7 @@ static void Curl_gtls_close(struct connectdata *conn, int sockindex) static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int retval = 0; struct Curl_easy *data = conn->data; @@ -1651,10 +1435,10 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) we do not send one. Let's hope other servers do the same... */ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); + gnutls_bye(backend->session, GNUTLS_SHUT_WR); #endif - if(BACKEND->session) { + if(backend->session) { ssize_t result; bool done = FALSE; char buf[120]; @@ -1665,7 +1449,7 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ - result = gnutls_record_recv(BACKEND->session, + result = gnutls_record_recv(backend->session, buf, sizeof(buf)); switch(result) { case 0: @@ -1695,18 +1479,18 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) done = TRUE; } } - gnutls_deinit(BACKEND->session); + gnutls_deinit(backend->session); } - gnutls_certificate_free_credentials(BACKEND->cred); + gnutls_certificate_free_credentials(backend->cred); #ifdef USE_TLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP && SSL_SET_OPTION(username) != NULL) - gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); + gnutls_srp_free_client_credentials(backend->srp_client_cred); #endif - BACKEND->cred = NULL; - BACKEND->session = NULL; + backend->cred = NULL; + backend->session = NULL; return retval; } @@ -1718,9 +1502,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; ssize_t ret; - ret = gnutls_record_recv(BACKEND->session, buf, buffersize); + ret = gnutls_record_recv(backend->session, buf, buffersize); if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { *curlcode = CURLE_AGAIN; return -1; @@ -1836,18 +1621,15 @@ static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ static bool Curl_gtls_cert_status_request(void) { -#ifdef HAS_OCSP return TRUE; -#else - return FALSE; -#endif } static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->session; + return backend->session; } const struct Curl_ssl Curl_ssl_gnutls = { diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index f057315f..cbf3d3de 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -75,8 +75,6 @@ struct ssl_backend_data { const char *protocols[3]; }; -#define BACKEND connssl->backend - /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -196,6 +194,7 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; long ssl_version = SSL_CONN_CONFIG(version); @@ -227,9 +226,9 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_min); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_max); return result; @@ -241,6 +240,7 @@ mbed_connect_step1(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); @@ -261,9 +261,9 @@ mbed_connect_step1(struct connectdata *conn, #ifdef THREADING_SUPPORT entropy_init_mutex(&ts_entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex, + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, &ts_entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -273,11 +273,11 @@ mbed_connect_step1(struct connectdata *conn, -ret, errorbuf); } #else - mbedtls_entropy_init(&BACKEND->entropy); - mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); + mbedtls_entropy_init(&backend->entropy); + mbedtls_ctr_drbg_init(&backend->ctr_drbg); - ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func, - &BACKEND->entropy, NULL, 0); + ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, + &backend->entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -288,10 +288,10 @@ mbed_connect_step1(struct connectdata *conn, #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ - mbedtls_x509_crt_init(&BACKEND->cacert); + mbedtls_x509_crt_init(&backend->cacert); if(ssl_cafile) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile); + ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -306,7 +306,7 @@ mbed_connect_step1(struct connectdata *conn, } if(ssl_capath) { - ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath); + ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath); if(ret<0) { #ifdef MBEDTLS_ERROR_C @@ -321,10 +321,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client certificate */ - mbedtls_x509_crt_init(&BACKEND->clicert); + mbedtls_x509_crt_init(&backend->clicert); if(ssl_cert) { - ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert); + ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -338,13 +338,13 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the client private key */ - mbedtls_pk_init(&BACKEND->pk); + mbedtls_pk_init(&backend->pk); if(SSL_SET_OPTION(key)) { - ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key), + ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !(mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA) || - mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_ECKEY))) + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || + mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; if(ret) { @@ -359,10 +359,10 @@ mbed_connect_step1(struct connectdata *conn, } /* Load the CRL */ - mbedtls_x509_crl_init(&BACKEND->crl); + mbedtls_x509_crl_init(&backend->crl); if(ssl_crlfile) { - ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile); + ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile); if(ret) { #ifdef MBEDTLS_ERROR_C @@ -377,14 +377,14 @@ mbed_connect_step1(struct connectdata *conn, infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port); - mbedtls_ssl_config_init(&BACKEND->config); + mbedtls_ssl_config_init(&backend->config); - mbedtls_ssl_init(&BACKEND->ssl); - if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) { + mbedtls_ssl_init(&backend->ssl); + if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) { failf(data, "mbedTLS: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } - ret = mbedtls_ssl_config_defaults(&BACKEND->config, + ret = mbedtls_ssl_config_defaults(&backend->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); @@ -394,20 +394,20 @@ mbed_connect_step1(struct connectdata *conn, } /* new profile with RSA min key len = 1024 ... */ - mbedtls_ssl_conf_cert_profile(&BACKEND->config, + mbedtls_ssl_conf_cert_profile(&backend->config, &mbedtls_x509_crt_profile_fr); switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); break; case CURL_SSLVERSION_SSLv3: - mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); - mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); infof(data, "mbedTLS: Set SSL version to SSLv3\n"); break; @@ -426,25 +426,25 @@ mbed_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random, - &BACKEND->ctr_drbg); - mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex], + mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, + &backend->ctr_drbg); + mbedtls_ssl_set_bio(&backend->ssl, &conn->sock[sockindex], mbedtls_net_send, mbedtls_net_recv, NULL /* rev_timeout() */); - mbedtls_ssl_conf_ciphersuites(&BACKEND->config, + mbedtls_ssl_conf_ciphersuites(&backend->config, mbedtls_ssl_list_ciphersuites()); #if defined(MBEDTLS_SSL_RENEGOTIATION) - mbedtls_ssl_conf_renegotiation(&BACKEND->config, + mbedtls_ssl_conf_renegotiation(&backend->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) - mbedtls_ssl_conf_session_tickets(&BACKEND->config, + mbedtls_ssl_conf_session_tickets(&backend->config, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); #endif @@ -454,7 +454,7 @@ mbed_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { - ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); + ret = mbedtls_ssl_set_session(&backend->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); @@ -465,15 +465,15 @@ mbed_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_unlock(conn); } - mbedtls_ssl_conf_ca_chain(&BACKEND->config, - &BACKEND->cacert, - &BACKEND->crl); + mbedtls_ssl_conf_ca_chain(&backend->config, + &backend->cacert, + &backend->crl); if(SSL_SET_OPTION(key)) { - mbedtls_ssl_conf_own_cert(&BACKEND->config, - &BACKEND->clicert, &BACKEND->pk); + mbedtls_ssl_conf_own_cert(&backend->config, + &backend->clicert, &backend->pk); } - if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) { + if(mbedtls_ssl_set_hostname(&backend->ssl, hostname)) { /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ @@ -483,7 +483,7 @@ mbed_connect_step1(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char **p = &BACKEND->protocols[0]; + const char **p = &backend->protocols[0]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) *p++ = NGHTTP2_PROTO_VERSION_ID; @@ -492,19 +492,19 @@ mbed_connect_step1(struct connectdata *conn, *p = NULL; /* this function doesn't clone the protocols array, which is why we need to keep it around */ - if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config, - &BACKEND->protocols[0])) { + if(mbedtls_ssl_conf_alpn_protocols(&backend->config, + &backend->protocols[0])) { failf(data, "Failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } - for(p = &BACKEND->protocols[0]; *p; ++p) + for(p = &backend->protocols[0]; *p; ++p) infof(data, "ALPN, offering %s\n", *p); } #endif #ifdef MBEDTLS_DEBUG /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ - mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data); + mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); /* - 0 No debug * - 1 Error * - 2 State change @@ -516,7 +516,7 @@ mbed_connect_step1(struct connectdata *conn, /* give application a chance to interfere with mbedTLS set up. */ if(data->set.ssl.fsslctx) { - ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config, + ret = (*data->set.ssl.fsslctx)(data, &backend->config, data->set.ssl.fsslctxp); if(ret) { failf(data, "error signaled by ssl ctx callback"); @@ -536,15 +536,16 @@ mbed_connect_step2(struct connectdata *conn, int ret; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const mbedtls_x509_crt *peercert; const char * const pinnedpubkey = SSL_IS_PROXY() ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; - ret = mbedtls_ssl_handshake(&BACKEND->ssl); + ret = mbedtls_ssl_handshake(&backend->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; @@ -566,10 +567,10 @@ mbed_connect_step2(struct connectdata *conn, } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", - mbedtls_ssl_get_ciphersuite(&BACKEND->ssl) + mbedtls_ssl_get_ciphersuite(&backend->ssl) ); - ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl); + ret = mbedtls_ssl_get_verify_result(&backend->ssl); if(!SSL_CONN_CONFIG(verifyhost)) /* Ignore hostname errors if verifyhost is disabled */ @@ -594,7 +595,7 @@ mbed_connect_step2(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl); + peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; @@ -664,7 +665,7 @@ mbed_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl); + const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); @@ -701,6 +702,7 @@ mbed_connect_step3(struct connectdata *conn, { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -716,7 +718,7 @@ mbed_connect_step3(struct connectdata *conn, mbedtls_ssl_session_init(our_ssl_sessionid); - ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); + ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid); if(ret) { if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) mbedtls_ssl_session_free(our_ssl_sessionid); @@ -750,9 +752,10 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; int ret = -1; - ret = mbedtls_ssl_write(&BACKEND->ssl, + ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len); if(ret < 0) { @@ -772,15 +775,16 @@ static void Curl_mbedtls_close_all(struct Curl_easy *data) static void Curl_mbedtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - mbedtls_pk_free(&BACKEND->pk); - mbedtls_x509_crt_free(&BACKEND->clicert); - mbedtls_x509_crt_free(&BACKEND->cacert); - mbedtls_x509_crl_free(&BACKEND->crl); - mbedtls_ssl_config_free(&BACKEND->config); - mbedtls_ssl_free(&BACKEND->ssl); - mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg); + struct ssl_backend_data *backend = connssl->backend; + mbedtls_pk_free(&backend->pk); + mbedtls_x509_crt_free(&backend->clicert); + mbedtls_x509_crt_free(&backend->cacert); + mbedtls_x509_crl_free(&backend->crl); + mbedtls_ssl_config_free(&backend->config); + mbedtls_ssl_free(&backend->ssl); + mbedtls_ctr_drbg_free(&backend->ctr_drbg); #ifndef THREADING_SUPPORT - mbedtls_entropy_free(&BACKEND->entropy); + mbedtls_entropy_free(&backend->entropy); #endif /* THREADING_SUPPORT */ } @@ -789,11 +793,12 @@ static ssize_t mbed_recv(struct connectdata *conn, int num, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; int ret = -1; ssize_t len = -1; memset(buf, 0, buffersize); - ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf, + ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize); if(ret <= 0) { @@ -1029,7 +1034,8 @@ static bool Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0; + struct ssl_backend_data *backend = connssl->backend; + return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0; } static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input, @@ -1051,8 +1057,9 @@ static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input, static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return &BACKEND->ssl; + return &backend->ssl; } const struct Curl_ssl Curl_ssl_mbedtls = { diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index ef51b0d9..16ec409e 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -87,8 +87,6 @@ struct ssl_backend_data { PK11GenericObject *obj_clicert; }; -#define BACKEND connssl->backend - static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; static PRLock *nss_findslot_lock = NULL; @@ -462,6 +460,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl, const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); + struct ssl_backend_data *backend = connssl->backend; if(!slot_name) return CURLE_OUT_OF_MEMORY; @@ -495,14 +494,14 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl, if(!obj) return result; - if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) { + if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } if(!cacert && CKO_CERTIFICATE == obj_class) /* store reference to a client certificate */ - BACKEND->obj_clicert = obj; + backend->obj_clicert = obj; return CURLE_OK; } @@ -1084,7 +1083,8 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct Curl_easy *data = BACKEND->data; + struct ssl_backend_data *backend = connssl->backend; + struct Curl_easy *data = backend->data; CERTCertificate *cert; if(!pinnedpubkey) @@ -1092,7 +1092,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, return CURLE_OK; /* get peer certificate */ - cert = SSL_PeerCertificate(BACKEND->handle); + cert = SSL_PeerCertificate(backend->handle); if(cert) { /* extract public key from peer certificate */ SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); @@ -1136,11 +1136,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct Curl_easy *data = BACKEND->data; - const char *nickname = BACKEND->client_nickname; + struct ssl_backend_data *backend = connssl->backend; + struct Curl_easy *data = backend->data; + const char *nickname = backend->client_nickname; static const char pem_slotname[] = "PEM Token #1"; - if(BACKEND->obj_clicert) { + if(backend->obj_clicert) { /* use the cert/key provided by PEM reader */ SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); @@ -1153,7 +1154,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE, + if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE, &cert_der) != SECSuccess) { failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); PK11_FreeSlot(slot); @@ -1503,11 +1504,12 @@ static void Curl_nss_cleanup(void) static int Curl_nss_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + struct ssl_backend_data *backend = connssl->backend; int rc; char buf; rc = - PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK, + PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK, PR_SecondsToInterval(1)); if(rc > 0) return 1; /* connection still in place */ @@ -1521,26 +1523,27 @@ static int Curl_nss_check_cxn(struct connectdata *conn) static void nss_close(struct ssl_connect_data *connssl) { /* before the cleanup, check whether we are using a client certificate */ - const bool client_cert = (BACKEND->client_nickname != NULL) - || (BACKEND->obj_clicert != NULL); + struct ssl_backend_data *backend = connssl->backend; + const bool client_cert = (backend->client_nickname != NULL) + || (backend->obj_clicert != NULL); - free(BACKEND->client_nickname); - BACKEND->client_nickname = NULL; + free(backend->client_nickname); + backend->client_nickname = NULL; /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); - BACKEND->obj_clicert = NULL; + Curl_llist_destroy(&backend->obj_list, NULL); + backend->obj_clicert = NULL; - if(BACKEND->handle) { + if(backend->handle) { if(client_cert) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ - SSL_InvalidateSession(BACKEND->handle); + SSL_InvalidateSession(backend->handle); - PR_Close(BACKEND->handle); - BACKEND->handle = NULL; + PR_Close(backend->handle); + backend->handle = NULL; } } @@ -1551,15 +1554,16 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->handle || connssl_proxy->backend->handle) { + if(backend->handle || connssl_proxy->backend->handle) { /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } - if(BACKEND->handle) + if(backend->handle) /* nss_close(connssl) will transitively close also connssl_proxy->backend->handle if both are used. Clear it to avoid a double close leading to crash. */ @@ -1773,6 +1777,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, CURLcode curlerr) { PRErrorCode err = 0; + struct ssl_backend_data *backend = connssl->backend; if(is_nss_error(curlerr)) { /* read NSPR error code */ @@ -1788,7 +1793,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, } /* cleanup on connection failure */ - Curl_llist_destroy(&BACKEND->obj_list, NULL); + Curl_llist_destroy(&backend->obj_list, NULL); return curlerr; } @@ -1799,10 +1804,11 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, bool blocking) { static PRSocketOptionData sock_opt; + struct ssl_backend_data *backend = connssl->backend; sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = !blocking; - if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS) + if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS) return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); return CURLE_OK; @@ -1818,6 +1824,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CURLcode result; bool second_layer = FALSE; SSLVersionRange sslver_supported; @@ -1835,10 +1842,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif }; - BACKEND->data = data; + backend->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ - Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); + Curl_llist_init(&backend->obj_list, nss_destroy_object); PR_Lock(nss_initlock); result = nss_init(conn->data); @@ -1960,7 +1967,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ - BACKEND->obj_clicert = NULL; + backend->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), @@ -1973,10 +1980,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* store the nickname for SelectClientCert() called during handshake */ - BACKEND->client_nickname = nickname; + backend->client_nickname = nickname; } else - BACKEND->client_nickname = NULL; + backend->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { @@ -2017,8 +2024,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } /* import our model socket onto the current I/O stack */ - BACKEND->handle = SSL_ImportFD(model, nspr_io); - if(!BACKEND->handle) { + backend->handle = SSL_ImportFD(model, nspr_io); + if(!backend->handle) { if(!second_layer) PR_Close(nspr_io); goto error; @@ -2029,36 +2036,36 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* This is the password associated with the cert that we're using */ if(SSL_SET_OPTION(key_passwd)) { - SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd)); + SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd)); } #ifdef SSL_ENABLE_OCSP_STAPLING if(SSL_CONN_CONFIG(verifystatus)) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) goto error; } #endif #ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #ifdef SSL_ENABLE_ALPN - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ if(data->set.ssl.falsestart) { - if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE) != SECSuccess) goto error; - if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, + if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback, conn) != SECSuccess) goto error; } @@ -2082,24 +2089,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; - if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) + if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) goto error; } #endif /* Force handshake on next I/O */ - if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) + if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE) != SECSuccess) goto error; /* propagate hostname to the TLS layer */ - if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : + if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; /* prevent NSS from re-using the session for a different hostname */ - if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? + if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; @@ -2116,6 +2123,7 @@ error: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; @@ -2136,7 +2144,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) /* Force the handshake now */ timeout = PR_MillisecondsToInterval((PRUint32) time_left); - if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) { + if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) { if(PR_GetError() == PR_WOULD_BLOCK_ERROR) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; @@ -2147,7 +2155,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) goto error; } - result = display_conn_info(conn, BACKEND->handle); + result = display_conn_info(conn, backend->handle); if(result) goto error; @@ -2156,7 +2164,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); if(nickname) { /* we support only nicknames in case of issuercert for now */ - ret = check_issuer_cert(BACKEND->handle, nickname); + ret = check_issuer_cert(backend->handle, nickname); free(nickname); } @@ -2260,13 +2268,14 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ssize_t rc; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; + backend->data = conn->data; - rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); + rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); if(rc < 0) { PRInt32 err = PR_GetError(); if(err == PR_WOULD_BLOCK_ERROR) @@ -2297,13 +2306,14 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ssize_t nread; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ - BACKEND->data = conn->data; + backend->data = conn->data; - nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, + nread = PR_Recv(backend->handle, buf, (int)buffersize, 0, PR_INTERVAL_NO_WAIT); if(nread < 0) { /* failed SSL read */ @@ -2364,6 +2374,9 @@ static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */ PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); unsigned int MD5out; + if(!MD5pw) + return CURLE_NOT_BUILT_IN; + PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); PK11_DestroyContext(MD5pw, PR_TRUE); @@ -2379,6 +2392,9 @@ static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */ PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); unsigned int SHA256out; + if(!SHA256pw) + return CURLE_NOT_BUILT_IN; + PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); PK11_DestroyContext(SHA256pw, PR_TRUE); @@ -2407,8 +2423,9 @@ static bool Curl_nss_false_start(void) static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_nss = { diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 1d09cadc..176fa522 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -228,8 +228,6 @@ struct ssl_backend_data { #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 @@ -1269,19 +1267,19 @@ static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *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); + struct ssl_backend_data *backend = connssl->backend; + if(backend->handle) { + (void)SSL_shutdown(backend->handle); + SSL_set_connect_state(backend->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + SSL_free(backend->handle); + backend->handle = NULL; } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; + if(backend->ctx) { + SSL_CTX_free(backend->ctx); + backend->ctx = NULL; } } @@ -1310,6 +1308,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) int buffsize; int err; bool done = FALSE; + struct ssl_backend_data *backend = connssl->backend; #ifndef CURL_DISABLE_FTP /* This has only been tested on the proftpd server, and the mod_tls code @@ -1318,10 +1317,10 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) 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); + (void)SSL_shutdown(backend->handle); #endif - if(BACKEND->handle) { + if(backend->handle) { buffsize = (int)sizeof(buf); while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], @@ -1331,8 +1330,8 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) /* 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); + 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 */ @@ -1377,7 +1376,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(data->set.verbose) { #ifdef HAVE_SSL_GET_SHUTDOWN - switch(SSL_get_shutdown(BACKEND->handle)) { + switch(SSL_get_shutdown(backend->handle)) { case SSL_SENT_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); break; @@ -1392,8 +1391,8 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) #endif } - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -1712,13 +1711,13 @@ static CURLcode verifystatus(struct connectdata *conn, 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; + struct ssl_backend_data *backend = connssl->backend; - long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status); + long len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status); if(!status) { failf(data, "No OCSP response received"); @@ -1748,8 +1747,8 @@ static CURLcode verifystatus(struct connectdata *conn, goto end; } - ch = SSL_get_peer_cert_chain(BACKEND->handle); - st = SSL_CTX_get_cert_store(BACKEND->ctx); + 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) && \ @@ -1825,7 +1824,8 @@ static CURLcode verifystatus(struct connectdata *conn, } end: - if(br) OCSP_BASICRESP_free(br); + if(br) + OCSP_BASICRESP_free(br); OCSP_RESPONSE_free(rsp); return result; @@ -2270,7 +2270,7 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, #ifdef TLS1_3_VERSION { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION); *ctx_options |= SSL_OP_NO_TLSv1_2; } #else @@ -2419,6 +2419,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -2477,25 +2478,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); - if(!BACKEND->ctx) { + 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); + 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); + SSL_CTX_set_msg_callback(backend->ctx, ssl_tls_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); } #endif @@ -2561,8 +2562,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* "--sslv2" option means SSLv2 only, disable all others */ case CURL_SSLVERSION_SSLv2: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL2_VERSION); - SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL2_VERSION); + SSL_CTX_set_min_proto_version(backend->ctx, SSL2_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, SSL2_VERSION); #else ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; @@ -2579,8 +2580,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* "--sslv3" option means SSLv3 only, disable all others */ case CURL_SSLVERSION_SSLv3: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL3_VERSION); - SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL3_VERSION); + SSL_CTX_set_min_proto_version(backend->ctx, SSL3_VERSION); + SSL_CTX_set_max_proto_version(backend->ctx, SSL3_VERSION); #else ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_TLSv1; @@ -2607,7 +2608,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ctx_options |= SSL_OP_NO_SSLv3; #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ - result = set_ssl_version_min_max(BACKEND->ctx, conn); + result = set_ssl_version_min_max(backend->ctx, conn); #else result = set_ssl_version_min_max_legacy(&ctx_options, conn, sockindex); #endif @@ -2620,11 +2621,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } - SSL_CTX_set_options(BACKEND->ctx, ctx_options); + 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); + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN @@ -2652,12 +2653,12 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* expects length prefixed preference ordered list of protocols in wire * format */ - SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); + 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, + 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() */ @@ -2669,7 +2670,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -2680,7 +2681,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); if(ciphers13) { - if(!SSL_CTX_set_ciphersuites(BACKEND->ctx, ciphers13)) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); return CURLE_SSL_CIPHER; } @@ -2691,7 +2692,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ - SSL_CTX_set_post_handshake_auth(BACKEND->ctx, 1); + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); #endif #ifdef USE_TLS_SRP @@ -2700,18 +2701,18 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, "Using TLS-SRP username: %s\n", ssl_username); - if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { + if(!SSL_CTX_set_srp_password(backend->ctx, SSL_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")) { + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { failf(data, "failed setting SRP cipher list"); return CURLE_SSL_CIPHER; } @@ -2719,10 +2720,37 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile) { + if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + if(verifypeer) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verification is required. */ + infof(data, "error setting certificate file, continuing anyway\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile); + } + if(ssl_capath) { + if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + if(verifypeer) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verification is required. */ + infof(data, "error setting certificate path, continuing anyway\n"); + } + infof(data, " CApath: %s\n", ssl_capath); + } +#else 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(!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" @@ -2746,18 +2774,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ssl_cafile ? ssl_cafile : "none", ssl_capath ? ssl_capath : "none"); } +#endif + #ifdef CURL_CA_FALLBACK else if(verifypeer) { /* verifying 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); + 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), + 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)) ) { @@ -2766,7 +2796,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } /* Everything is fine. */ infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + 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); @@ -2781,7 +2811,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) 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) - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_TRUSTED_FIRST); #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN @@ -2790,7 +2820,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) trust-anchors, in the same way as self-signed root CA certificates are. This allows users to verify servers using the intermediate cert only, instead of needing the whole chain. */ - X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_PARTIAL_CHAIN); } #endif @@ -2800,13 +2830,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * 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, + 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_fp) { - SSL_CTX_set_keylog_callback(BACKEND->ctx, ossl_keylog_callback); + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); } #endif @@ -2814,14 +2844,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * callback. Use the "external storage" mode to avoid that OpenSSL creates * an internal session cache. */ - SSL_CTX_set_session_cache_mode(BACKEND->ctx, + 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); + 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) { Curl_set_in_callback(data, true); - result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, + result = (*data->set.ssl.fsslctx)(data, backend->ctx, data->set.ssl.fsslctxp); Curl_set_in_callback(data, false); if(result) { @@ -2831,10 +2861,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } /* Lets make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + 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; } @@ -2842,23 +2872,23 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #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); + 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); + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); #endif - SSL_set_connect_state(BACKEND->handle); + SSL_set_connect_state(backend->handle); - BACKEND->server_cert = 0x0; + 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)) + !SSL_set_tlsext_host_name(backend->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif @@ -2872,14 +2902,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) 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); + 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)) { /* we got a session id, use it! */ - if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { + 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, @@ -2899,9 +2929,9 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) DEBUGASSERT(handle != NULL); DEBUGASSERT(bio != NULL); BIO_set_ssl(bio, handle, FALSE); - SSL_set_bio(BACKEND->handle, bio, bio); + SSL_set_bio(backend->handle, bio, bio); } - else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { + 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))); @@ -2920,24 +2950,25 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + struct ssl_backend_data *backend = connssl->backend; 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); + 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); + 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); + int detail = SSL_get_error(backend->handle, err); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -2977,7 +3008,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_PEER_FAILED_VERIFICATION; - lerr = SSL_get_verify_result(BACKEND->handle); + lerr = SSL_get_verify_result(backend->handle); if(lerr != X509_V_OK) { *certverifyresult = lerr; msnprintf(error_buffer, sizeof(error_buffer), @@ -3026,8 +3057,8 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) /* Informational message */ infof(data, "SSL connection using %s / %s\n", - get_ssl_version_txt(BACKEND->handle), - SSL_get_cipher(BACKEND->handle)); + 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 @@ -3036,7 +3067,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) if(conn->bits.tls_enable_alpn) { const unsigned char *neg_protocol; unsigned int len; - SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &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); @@ -3171,8 +3202,9 @@ static CURLcode get_cert_chain(struct connectdata *conn, struct Curl_easy *data = conn->data; numcert_t numcerts; BIO *mem; + struct ssl_backend_data *backend = connssl->backend; - sk = SSL_get_peer_cert_chain(BACKEND->handle); + sk = SSL_get_peer_cert_chain(backend->handle); if(!sk) { return CURLE_OUT_OF_MEMORY; } @@ -3458,13 +3490,14 @@ static CURLcode servercert(struct connectdata *conn, long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; BIO *mem = BIO_new(BIO_s_mem()); + struct ssl_backend_data *backend = connssl->backend; 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) { + backend->server_cert = SSL_get_peer_certificate(backend->handle); + if(!backend->server_cert) { BIO_free(mem); if(!strict) return CURLE_OK; @@ -3475,19 +3508,19 @@ static CURLcode servercert(struct connectdata *conn, infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); - rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), + rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), buffer, sizeof(buffer)); infof(data, " subject: %s\n", rc?"[NONE]":buffer); #ifndef CURL_DISABLE_VERBOSE_STRINGS { long len; - ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert)); + 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)); + 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); @@ -3497,15 +3530,15 @@ static CURLcode servercert(struct connectdata *conn, BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { - result = verifyhost(conn, BACKEND->server_cert); + result = verifyhost(conn, backend->server_cert); if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return result; } } - rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), + rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert), buffer, sizeof(buffer)); if(rc) { if(strict) @@ -3527,8 +3560,8 @@ static CURLcode servercert(struct connectdata *conn, " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_OUT_OF_MEMORY; } @@ -3537,8 +3570,8 @@ static CURLcode servercert(struct connectdata *conn, failf(data, "SSL: Unable to open issuer cert (%s)", SSL_SET_OPTION(issuercert)); BIO_free(fp); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -3549,19 +3582,19 @@ static CURLcode servercert(struct connectdata *conn, SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { + 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)); BIO_free(fp); X509_free(issuer); - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -3571,7 +3604,7 @@ static CURLcode servercert(struct connectdata *conn, X509_free(issuer); } - lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); + lerr = *certverifyresult = SSL_get_verify_result(backend->handle); if(*certverifyresult != X509_V_OK) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -3596,8 +3629,8 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { - X509_free(BACKEND->server_cert); - BACKEND->server_cert = NULL; + X509_free(backend->server_cert); + backend->server_cert = NULL; return result; } } @@ -3610,13 +3643,13 @@ static CURLcode servercert(struct connectdata *conn, 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); + 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; + X509_free(backend->server_cert); + backend->server_cert = NULL; connssl->connecting_state = ssl_connect_done; return result; @@ -3810,14 +3843,15 @@ static ssize_t ossl_send(struct connectdata *conn, int memlen; int rc; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; ERR_clear_error(); memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(BACKEND->handle, mem, memlen); + rc = SSL_write(backend->handle, mem, memlen); if(rc <= 0) { - err = SSL_get_error(BACKEND->handle, rc); + err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -3884,14 +3918,15 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ ssize_t nread; int buffsize; struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; ERR_clear_error(); buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); + nread = (ssize_t)SSL_read(backend->handle, buf, buffsize); if(nread <= 0) { /* failed SSL_read */ - int err = SSL_get_error(BACKEND->handle, (int)nread); + int err = SSL_get_error(backend->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ @@ -4097,8 +4132,9 @@ static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, CURLINFO info) { /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + struct ssl_backend_data *backend = connssl->backend; return info == CURLINFO_TLS_SESSION ? - (void *)BACKEND->ctx : (void *)BACKEND->handle; + (void *)backend->ctx : (void *)backend->handle; } const struct Curl_ssl Curl_ssl_openssl = { diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index f665ee34..49659bb7 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -520,8 +520,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) DEBUGF(infof(data, "schannel: disabled server certificate revocation " "checks\n")); } + else if(data->set.ssl.revoke_best_effort) { + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, "schannel: ignore revocation offline errors")); + } else { schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; + DEBUGF(infof(data, "schannel: checking server certificate revocation\n")); } @@ -578,11 +585,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) /* client certificate */ if(data->set.ssl.cert) { DWORD cert_store_name; - TCHAR *cert_store_path; + TCHAR *cert_store_path = NULL; TCHAR *cert_thumbprint_str; CRYPT_HASH_BLOB cert_thumbprint; BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; HCERTSTORE cert_store; + FILE *fInCert = NULL; TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert); if(!cert_path) @@ -590,54 +598,143 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) result = get_cert_location(cert_path, &cert_store_name, &cert_store_path, &cert_thumbprint_str); - if(result != CURLE_OK) { - failf(data, "schannel: Failed to get certificate location for %s", - cert_path); + if((result != CURLE_OK) && (data->set.ssl.cert[0]!='\0')) + fInCert = fopen(data->set.ssl.cert, "rb"); + + if((result != CURLE_OK) && (fInCert == NULL)) { + failf(data, "schannel: Failed to get certificate location" + " or file for %s", + data->set.ssl.cert); Curl_unicodefree(cert_path); return result; } - cert_store = - CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, - (HCRYPTPROV)NULL, - CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, - cert_store_path); - if(!cert_store) { - failf(data, "schannel: Failed to open cert store %x %s, " - "last error is %x", - cert_store_name, cert_store_path, GetLastError()); - free(cert_store_path); + if(fInCert) { + /* Reading a .P12 or .pfx file, like the example at bottom of + https://social.msdn.microsoft.com/Forums/windowsdesktop/ + en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + */ + void *certdata = NULL; + long filesize = 0; + CRYPT_DATA_BLOB datablob; + WCHAR* pszPassword; + size_t pwd_len = 0; + int str_w_len = 0; + int continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + filesize = ftell(fInCert); + if(filesize < 0) + continue_reading = 0; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; + if(continue_reading) + certdata = malloc(((size_t)filesize) + 1); + if((certdata == NULL) || + ((int) fread(certdata, (size_t)filesize, 1, fInCert) != 1)) + continue_reading = 0; + fclose(fInCert); Curl_unicodefree(cert_path); - return CURLE_SSL_CERTPROBLEM; - } - free(cert_store_path); - cert_thumbprint.pbData = cert_thumbprint_data; - cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + if(!continue_reading) { + failf(data, "schannel: Failed to read cert file %s", + data->set.ssl.cert); + free(certdata); + return CURLE_SSL_CERTPROBLEM; + } - if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN, - CRYPT_STRING_HEX, - cert_thumbprint_data, &cert_thumbprint.cbData, - NULL, NULL)) { - Curl_unicodefree(cert_path); - return CURLE_SSL_CERTPROBLEM; - } + /* Convert key-pair data to the in-memory certificate store */ + datablob.pbData = (BYTE*)certdata; + datablob.cbData = (DWORD)filesize; + + if(data->set.ssl.key_passwd != NULL) + pwd_len = strlen(data->set.ssl.key_passwd); + pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); + if(pwd_len > 0) + str_w_len = + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + data->set.ssl.key_passwd, (int)pwd_len, + pszPassword, (int)(pwd_len + 1)); + + if((str_w_len >= 0) && (str_w_len <= (int)pwd_len)) + pszPassword[str_w_len] = 0; + else + pszPassword[0] = 0; + + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + free(pszPassword); + free(certdata); + if(cert_store == NULL) { + DWORD errorcode = GetLastError(); + if(errorcode == ERROR_INVALID_PASSWORD) + failf(data, "schannel: Failed to import cert file %s, " + "password is bad", data->set.ssl.cert); + else + failf(data, "schannel: Failed to import cert file %s, " + "last error is 0x%x", data->set.ssl.cert, errorcode); + return CURLE_SSL_CERTPROBLEM; + } - client_certs[0] = CertFindCertificateInStore( - cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, - CERT_FIND_HASH, &cert_thumbprint, NULL); + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_ANY, NULL, NULL); - Curl_unicodefree(cert_path); + if(client_certs[0] == NULL) { + failf(data, "schannel: Failed to get certificate from file %s" + ", last error is 0x%x", + data->set.ssl.cert, GetLastError()); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } - if(client_certs[0]) { schannel_cred.cCreds = 1; schannel_cred.paCred = client_certs; } else { - /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ - return CURLE_SSL_CERTPROBLEM; - } + cert_store = + CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, + (HCRYPTPROV)NULL, + CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, + cert_store_path); + if(!cert_store) { + failf(data, "schannel: Failed to open cert store %x %s, " + "last error is 0x%x", + cert_store_name, cert_store_path, GetLastError()); + free(cert_store_path); + Curl_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + free(cert_store_path); + + cert_thumbprint.pbData = cert_thumbprint_data; + cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + + if(!CryptStringToBinary(cert_thumbprint_str, + CERT_THUMBPRINT_STR_LEN, + CRYPT_STRING_HEX, + cert_thumbprint_data, + &cert_thumbprint.cbData, + NULL, NULL)) { + Curl_unicodefree(cert_path); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_HASH, &cert_thumbprint, NULL); + + Curl_unicodefree(cert_path); + if(client_certs[0]) { + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } + else { + /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + } CertCloseStore(cert_store, 0); } #else @@ -1534,13 +1631,13 @@ schannel_send(struct connectdata *conn, int sockindex, /* send entire message or fail */ while(len > (size_t)written) { ssize_t this_write; - timediff_t timeleft; + timediff_t timeout_ms; int what; this_write = 0; - timeleft = Curl_timeleft(conn->data, NULL, FALSE); - if(timeleft < 0) { + timeout_ms = Curl_timeleft(conn->data, NULL, FALSE); + if(timeout_ms < 0) { /* we already got the timeout */ failf(conn->data, "schannel: timed out sending data " "(bytes sent: %zd)", written); @@ -1548,8 +1645,9 @@ schannel_send(struct connectdata *conn, int sockindex, written = -1; break; } - - what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); + if(!timeout_ms) + timeout_ms = TIMEDIFF_T_MAX; + what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2203,7 +2301,7 @@ static void Curl_schannel_checksum(const unsigned char *input, memset(checksum, 0, checksumlen); if(!CryptAcquireContext(&hProv, NULL, NULL, provType, - CRYPT_VERIFYCONTEXT)) + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return; /* failed */ do { diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index e75132ca..3dbc11f0 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -636,6 +636,15 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; + + if(data->set.ssl.revoke_best_effort) { + /* Ignore errors when root certificates are missing the revocation + * list URL, or when the list could not be downloaded because the + * server is currently unreachable. */ + dwTrustErrorMask &= ~(DWORD)(CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION); + } + if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) failf(data, "schannel: CertGetCertificateChain trust error" diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index 7dd028fb..6b2d436f 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -138,8 +138,6 @@ struct ssl_backend_data { size_t ssl_write_buffered_length; }; -#define BACKEND connssl->backend - /* pinned public key support tests */ /* version 1 supports macOS 10.12+ and iOS 10+ */ @@ -201,7 +199,8 @@ static OSStatus SocketRead(SSLConnectionRef connection, UInt8 *currData = (UInt8 *)data; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; + struct ssl_backend_data *backend = connssl->backend; + int sock = backend->ssl_sockfd; OSStatus rtn = noErr; size_t bytesRead; ssize_t rrtn; @@ -230,7 +229,7 @@ static OSStatus SocketRead(SSLConnectionRef connection, break; case EAGAIN: rtn = errSSLWouldBlock; - BACKEND->ssl_direction = false; + backend->ssl_direction = false; break; default: rtn = ioErr; @@ -261,7 +260,8 @@ static OSStatus SocketWrite(SSLConnectionRef connection, size_t bytesSent = 0; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; - int sock = BACKEND->ssl_sockfd; + struct ssl_backend_data *backend = connssl->backend; + int sock = backend->ssl_sockfd; ssize_t length; size_t dataLen = *dataLength; const UInt8 *dataPtr = (UInt8 *)data; @@ -281,7 +281,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, theErr = errno; if(theErr == EAGAIN) { ortn = errSSLWouldBlock; - BACKEND->ssl_direction = true; + backend->ssl_direction = true; } else { ortn = ioErr; @@ -1276,6 +1276,7 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long max_supported_version_by_os; @@ -1326,30 +1327,30 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex) return result; } - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, darwin_ver_min); - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, darwin_ver_max); + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, darwin_ver_min); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, darwin_ver_max); return result; } else { #if CURL_SUPPORT_MAC_10_8 long i = ssl_version; - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); for(; i <= (ssl_version_max >> 16); i++) { switch(i) { case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol11, true); break; case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol12, true); break; @@ -1373,6 +1374,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); char * const ssl_cert = SSL_SET_OPTION(cert); @@ -1395,10 +1397,10 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) { /* use the newer API if available */ - if(BACKEND->ssl_ctx) - CFRelease(BACKEND->ssl_ctx); - BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); - if(!BACKEND->ssl_ctx) { + if(backend->ssl_ctx) + CFRelease(backend->ssl_ctx); + backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); + if(!backend->ssl_ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -1406,9 +1408,9 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, else { /* The old ST API does not exist under iOS, so don't compile it: */ #if CURL_SUPPORT_MAC_10_8 - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; @@ -1416,31 +1418,31 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - if(BACKEND->ssl_ctx) - (void)SSLDisposeContext(BACKEND->ssl_ctx); - err = SSLNewContext(false, &(BACKEND->ssl_ctx)); + if(backend->ssl_ctx) + (void)SSLDisposeContext(backend->ssl_ctx); + err = SSLNewContext(false, &(backend->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_write_buffered_length = 0UL; /* reset buffered write length */ + backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */ /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { switch(conn->ssl_config.version) { case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1); #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(__builtin_available(macOS 10.13, iOS 11.0, *)) { - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol13); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13); } else { - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); } #else - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12); #endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 */ break; @@ -1456,20 +1458,20 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol3); + err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol3); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol3); break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol2); + err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol2); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2); + (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol2); break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); @@ -1478,19 +1480,19 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol11, true); - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol12, true); break; @@ -1505,7 +1507,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1514,7 +1516,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1534,12 +1536,12 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, " SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true); break; @@ -1553,7 +1555,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, failf(data, "Your version of the OS does not support TLSv1.3"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { @@ -1562,7 +1564,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, + err = SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { @@ -1596,7 +1598,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* expects length prefixed preference ordered list of protocols in wire * format */ - err = SSLSetALPNProtocols(BACKEND->ssl_ctx, alpnArr); + err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); if(err != noErr) infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n", err); @@ -1657,7 +1659,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, certs_c[0] = cert_and_key; certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, &kCFTypeArrayCallBacks); - err = SSLSetCertificate(BACKEND->ssl_ctx, certs); + err = SSLSetCertificate(backend->ssl_ctx, certs); if(certs) CFRelease(certs); if(err != noErr) { @@ -1720,7 +1722,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; - err = SSLSetSessionOption(BACKEND->ssl_ctx, + err = SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, break_on_auth); if(err != noErr) { @@ -1730,7 +1732,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, + err = SSLSetEnableCertVerify(backend->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1739,7 +1741,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else - err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, + err = SSLSetEnableCertVerify(backend->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); @@ -1760,7 +1762,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, * Both hostname check and SNI require SSLSetPeerDomainName(). * Also: the verifyhost setting influences SNI usage */ if(conn->ssl_config.verifyhost) { - err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname, + err = SSLSetPeerDomainName(backend->ssl_ctx, hostname, strlen(hostname)); if(err != noErr) { @@ -1786,7 +1788,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, higher priority, but it's probably better that we not connect at all than to give the user a false sense of security if the server only supports insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ - err = SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count); + err = SSLGetNumberSupportedCiphers(backend->ssl_ctx, &all_ciphers_count); if(err != noErr) { failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d", err); @@ -1803,7 +1805,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, failf(data, "SSL: Failed to allocate memory for allowed ciphers"); return CURLE_OUT_OF_MEMORY; } - err = SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers, + err = SSLGetSupportedCiphers(backend->ssl_ctx, all_ciphers, &all_ciphers_count); if(err != noErr) { Curl_safefree(all_ciphers); @@ -1890,7 +1892,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, break; } } - err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers, + err = SSLSetEnabledCiphers(backend->ssl_ctx, allowed_ciphers, allowed_ciphers_count); Curl_safefree(all_ciphers); Curl_safefree(allowed_ciphers); @@ -1903,9 +1905,9 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord, + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !data->set.ssl.enable_beast); - SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart, + SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, data->set.ssl.falsestart); /* false start support */ } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ @@ -1919,7 +1921,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, &ssl_sessionid_len, sockindex)) { /* we got a session id, use it! */ - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); Curl_ssl_sessionid_unlock(conn); if(err != noErr) { failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); @@ -1937,7 +1939,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); ssl_sessionid_len = strlen(ssl_sessionid); - err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); if(err != noErr) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); @@ -1954,7 +1956,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, } } - err = SSLSetIOFuncs(BACKEND->ssl_ctx, SocketRead, SocketWrite); + err = SSLSetIOFuncs(backend->ssl_ctx, SocketRead, SocketWrite); if(err != noErr) { failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -1964,8 +1966,8 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn, /* We need to store the FD in a constant memory address, because * SSLSetConnection() will not copy that address. I've found that * conn->sock[sockindex] may change on its own. */ - BACKEND->ssl_sockfd = sockfd; - err = SSLSetConnection(BACKEND->ssl_ctx, connssl); + backend->ssl_sockfd = sockfd; + err = SSLSetConnection(backend->ssl_ctx, connssl); if(err != noErr) { failf(data, "SSL: SSLSetConnection() failed: %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -2346,6 +2348,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; @@ -2357,12 +2360,12 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ - err = SSLHandshake(BACKEND->ssl_ctx); + err = SSLHandshake(backend->ssl_ctx); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = BACKEND->ssl_direction ? + connssl->connecting_state = backend->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; @@ -2371,7 +2374,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data, - BACKEND->ssl_ctx); + backend->ssl_ctx); if(result) return result; } @@ -2580,7 +2583,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) #ifdef SECTRANSP_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { - CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx, + CURLcode result = pkp_pin_peer_pubkey(data, backend->ssl_ctx, data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); if(result) { failf(data, "SSL: public key does not match pinned public key!"); @@ -2590,8 +2593,8 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) #endif /* SECTRANSP_PINNEDPUBKEY */ /* Informational message */ - (void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher); - (void)SSLGetNegotiatedProtocolVersion(BACKEND->ssl_ctx, &protocol); + (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher); + (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol); switch(protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", @@ -2631,7 +2634,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex) if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { CFArrayRef alpnArr = NULL; CFStringRef chosenProtocol = NULL; - err = SSLCopyALPNProtocols(BACKEND->ssl_ctx, &alpnArr); + err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr); if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); @@ -2674,19 +2677,20 @@ show_verbose_server_cert(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; CFArrayRef server_certs = NULL; SecCertificateRef server_cert; OSStatus err; CFIndex i, count; SecTrustRef trust = NULL; - if(!BACKEND->ssl_ctx) + if(!backend->ssl_ctx) return; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS #pragma unused(server_certs) - err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); + err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return a null trust, so be on guard for that: */ if(err == noErr && trust) { @@ -2712,7 +2716,7 @@ show_verbose_server_cert(struct connectdata *conn, Lion or later. */ if(SecTrustEvaluateAsync != NULL) { #pragma unused(server_certs) - err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); + err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return a null trust, so be on guard for that: */ if(err == noErr && trust) { @@ -2732,7 +2736,7 @@ show_verbose_server_cert(struct connectdata *conn, } else { #if CURL_SUPPORT_MAC_10_8 - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); /* Just in case SSLCopyPeerCertificates() returns null too... */ if(err == noErr && server_certs) { count = CFArrayGetCount(server_certs); @@ -2754,7 +2758,7 @@ show_verbose_server_cert(struct connectdata *conn, #endif /* CURL_BUILD_IOS */ #else #pragma unused(trust) - err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); + err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); for(i = 0L ; i < count ; i++) { @@ -2933,34 +2937,36 @@ static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex) static void Curl_sectransp_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->ssl_ctx) { - (void)SSLClose(BACKEND->ssl_ctx); + if(backend->ssl_ctx) { + (void)SSLClose(backend->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) - CFRelease(BACKEND->ssl_ctx); + CFRelease(backend->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else - (void)SSLDisposeContext(BACKEND->ssl_ctx); + (void)SSLDisposeContext(backend->ssl_ctx); #endif /* CURL_SUPPORT_MAC_10_8 */ #else - (void)SSLDisposeContext(BACKEND->ssl_ctx); + (void)SSLDisposeContext(backend->ssl_ctx); #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - BACKEND->ssl_ctx = NULL; + backend->ssl_ctx = NULL; } - BACKEND->ssl_sockfd = 0; + backend->ssl_sockfd = 0; } static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; char buf[120]; - if(!BACKEND->ssl_ctx) + if(!backend->ssl_ctx) return 0; #ifndef CURL_DISABLE_FTP @@ -3033,11 +3039,12 @@ static size_t Curl_sectransp_version(char *buffer, size_t size) static int Curl_sectransp_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; SSLSessionState state; - if(BACKEND->ssl_ctx) { - err = SSLGetSessionState(BACKEND->ssl_ctx, &state); + if(backend->ssl_ctx) { + err = SSLGetSessionState(backend->ssl_ctx, &state); if(err == noErr) return state == kSSLConnected || state == kSSLHandshake; return -1; @@ -3049,11 +3056,12 @@ static bool Curl_sectransp_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + struct ssl_backend_data *backend = connssl->backend; OSStatus err; size_t buffer; - if(BACKEND->ssl_ctx) { /* SSL is in use */ - err = SSLGetBufferedReadSize(BACKEND->ssl_ctx, &buffer); + if(backend->ssl_ctx) { /* SSL is in use */ + err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer); if(err == noErr) return buffer > 0UL; return false; @@ -3119,6 +3127,7 @@ static ssize_t sectransp_send(struct connectdata *conn, { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; size_t processed = 0UL; OSStatus err; @@ -3137,15 +3146,15 @@ static ssize_t sectransp_send(struct connectdata *conn, over again with no new data until it quits returning errSSLWouldBlock. */ /* Do we have buffered data to write from the last time we were called? */ - if(BACKEND->ssl_write_buffered_length) { + if(backend->ssl_write_buffered_length) { /* Write the buffered data: */ - err = SSLWrite(BACKEND->ssl_ctx, NULL, 0UL, &processed); + err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed); switch(err) { case noErr: /* processed is always going to be 0 because we didn't write to the buffer, so return how much was written to the socket */ - processed = BACKEND->ssl_write_buffered_length; - BACKEND->ssl_write_buffered_length = 0UL; + processed = backend->ssl_write_buffered_length; + backend->ssl_write_buffered_length = 0UL; break; case errSSLWouldBlock: /* argh, try again */ *curlcode = CURLE_AGAIN; @@ -3158,13 +3167,13 @@ static ssize_t sectransp_send(struct connectdata *conn, } else { /* We've got new data to write: */ - err = SSLWrite(BACKEND->ssl_ctx, mem, len, &processed); + err = SSLWrite(backend->ssl_ctx, mem, len, &processed); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* Data was buffered but not sent, we have to tell the caller to try sending again, and remember how much was buffered */ - BACKEND->ssl_write_buffered_length = len; + backend->ssl_write_buffered_length = len; *curlcode = CURLE_AGAIN; return -1L; default: @@ -3185,11 +3194,12 @@ static ssize_t sectransp_recv(struct connectdata *conn, { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; size_t processed = 0UL; OSStatus err; again: - err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed); + err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { switch(err) { @@ -3215,7 +3225,7 @@ static ssize_t sectransp_recv(struct connectdata *conn, case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), conn->data, - BACKEND->ssl_ctx); + backend->ssl_ctx); if(result) return result; } @@ -3233,8 +3243,9 @@ static ssize_t sectransp_recv(struct connectdata *conn, static void *Curl_sectransp_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->ssl_ctx; + return backend->ssl_ctx; } const struct Curl_ssl Curl_ssl_sectransp = { diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index dfefa1bd..f1b52522 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -174,6 +174,9 @@ int Curl_ssl_init(void) return Curl_ssl->init(); } +#if defined(CURL_WITH_MULTI_SSL) +static const struct Curl_ssl Curl_ssl_multi; +#endif /* Global cleanup */ void Curl_ssl_cleanup(void) @@ -181,6 +184,9 @@ void Curl_ssl_cleanup(void) if(init_ssl) { /* only cleanup if we did a previous init */ Curl_ssl->cleanup(); +#if defined(CURL_WITH_MULTI_SSL) + Curl_ssl = &Curl_ssl_multi; +#endif init_ssl = FALSE; } } @@ -489,6 +495,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->scheme = conn->handler->scheme; if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { + Curl_free_primary_ssl_config(&store->ssl_config); store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 8c2d3f4a..5040b059 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -96,12 +96,9 @@ struct ssl_backend_data { SSL* handle; }; -#define BACKEND connssl->backend - static Curl_recv wolfssl_recv; static Curl_send wolfssl_send; - static int do_file_type(const char *type) { if(!type || !type[0]) @@ -124,6 +121,7 @@ wolfssl_connect_step1(struct connectdata *conn, char *ciphers; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI @@ -203,11 +201,11 @@ wolfssl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(BACKEND->ctx) - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = SSL_CTX_new(req_method); + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); - if(!BACKEND->ctx) { + if(!backend->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -222,11 +220,11 @@ wolfssl_connect_step1(struct connectdata *conn, * defaults to TLS 1.1) so we have this short circuit evaluation to find * the minimum supported TLS version. */ - if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) && - (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1) + if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) && + (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1) #ifdef WOLFSSL_TLS13 - && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1) + && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1) #endif ) { failf(data, "SSL: couldn't set the minimum protocol version"); @@ -238,7 +236,7 @@ wolfssl_connect_step1(struct connectdata *conn, ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { - if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } @@ -248,7 +246,7 @@ wolfssl_connect_step1(struct connectdata *conn, #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { - if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, + if(1 != SSL_CTX_load_verify_locations(backend->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -285,7 +283,7 @@ wolfssl_connect_step1(struct connectdata *conn, if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert), + if(SSL_CTX_use_certificate_file(backend->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); @@ -293,7 +291,7 @@ wolfssl_connect_step1(struct connectdata *conn, } file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), + if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; @@ -305,7 +303,7 @@ wolfssl_connect_step1(struct connectdata *conn, * 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, + SSL_CTX_set_verify(backend->ctx, SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: SSL_VERIFY_NONE, NULL); @@ -324,7 +322,7 @@ wolfssl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif - (wolfSSL_CTX_UseSNI(BACKEND->ctx, WOLFSSL_SNI_HOST_NAME, hostname, + (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -334,7 +332,7 @@ wolfssl_connect_step1(struct connectdata *conn, /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - CURLcode result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, + CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); @@ -352,10 +350,10 @@ wolfssl_connect_step1(struct connectdata *conn, #endif /* Let's make an SSL structure */ - if(BACKEND->handle) - SSL_free(BACKEND->handle); - BACKEND->handle = SSL_new(BACKEND->ctx); - if(!BACKEND->handle) { + 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; } @@ -378,7 +376,7 @@ wolfssl_connect_step1(struct connectdata *conn, strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); - if(wolfSSL_UseALPN(BACKEND->handle, protocols, + if(wolfSSL_UseALPN(backend->handle, protocols, (unsigned)strlen(protocols), WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { failf(data, "SSL: failed setting ALPN protocols"); @@ -394,11 +392,11 @@ wolfssl_connect_step1(struct connectdata *conn, 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)) { + if(!SSL_set_session(backend->handle, ssl_sessionid)) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(BACKEND->handle, 0), + ERR_error_string(SSL_get_error(backend->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } @@ -409,7 +407,7 @@ wolfssl_connect_step1(struct connectdata *conn, } /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { + if(!SSL_set_fd(backend->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -426,6 +424,7 @@ wolfssl_connect_step2(struct connectdata *conn, int ret = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? @@ -439,15 +438,15 @@ wolfssl_connect_step2(struct connectdata *conn, /* Enable RFC2818 checks */ if(SSL_CONN_CONFIG(verifyhost)) { - ret = wolfSSL_check_domain_name(BACKEND->handle, hostname); + ret = wolfSSL_check_domain_name(backend->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } - ret = SSL_connect(BACKEND->handle); + ret = SSL_connect(backend->handle); if(ret != 1) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int detail = SSL_get_error(BACKEND->handle, ret); + int detail = SSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -516,7 +515,7 @@ wolfssl_connect_step2(struct connectdata *conn, curl_asn1Element *pubkey; CURLcode result; - x509 = SSL_get_peer_certificate(BACKEND->handle); + x509 = SSL_get_peer_certificate(backend->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; @@ -558,7 +557,7 @@ wolfssl_connect_step2(struct connectdata *conn, char *protocol = NULL; unsigned short protocol_len = 0; - rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len); + rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); if(rc == SSL_SUCCESS) { infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, @@ -592,8 +591,8 @@ wolfssl_connect_step2(struct connectdata *conn, connssl->connecting_state = ssl_connect_3; #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) infof(data, "SSL connection using %s / %s\n", - wolfSSL_get_version(BACKEND->handle), - wolfSSL_get_cipher_name(BACKEND->handle)); + wolfSSL_get_version(backend->handle), + wolfSSL_get_cipher_name(backend->handle)); #else infof(data, "SSL connected\n"); #endif @@ -609,6 +608,7 @@ wolfssl_connect_step3(struct connectdata *conn, CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -617,7 +617,7 @@ wolfssl_connect_step3(struct connectdata *conn, SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; - our_ssl_sessionid = SSL_get_session(BACKEND->handle); + our_ssl_sessionid = SSL_get_session(backend->handle); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, @@ -655,12 +655,13 @@ static ssize_t wolfssl_send(struct connectdata *conn, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(BACKEND->handle, mem, memlen); + int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + int rc = SSL_write(backend->handle, mem, memlen); if(rc < 0) { - int err = SSL_get_error(BACKEND->handle, rc); + int err = SSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -682,31 +683,33 @@ static ssize_t wolfssl_send(struct connectdata *conn, static void Curl_wolfssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->handle) { - (void)SSL_shutdown(BACKEND->handle); - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + (void)SSL_shutdown(backend->handle); + SSL_free(backend->handle); + backend->handle = NULL; } - if(BACKEND->ctx) { - SSL_CTX_free(BACKEND->ctx); - BACKEND->ctx = NULL; + if(backend->ctx) { + SSL_CTX_free(backend->ctx); + backend->ctx = NULL; } } static ssize_t wolfssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; + struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(BACKEND->handle, buf, buffsize); + int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + int nread = SSL_read(backend->handle, buf, buffsize); if(nread < 0) { - int err = SSL_get_error(BACKEND->handle, nread); + int err = SSL_get_error(backend->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ @@ -758,11 +761,12 @@ static void Curl_wolfssl_cleanup(void) static bool Curl_wolfssl_data_pending(const struct connectdata* conn, - int connindex) + int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - if(BACKEND->handle) /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE; + struct ssl_backend_data *backend = connssl->backend; + if(backend->handle) /* SSL is in use */ + return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE; else return FALSE; } @@ -776,10 +780,11 @@ static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; - if(BACKEND->handle) { - SSL_free(BACKEND->handle); - BACKEND->handle = NULL; + if(backend->handle) { + SSL_free(backend->handle); + backend->handle = NULL; } return retval; } @@ -950,10 +955,11 @@ static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */ } static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info UNUSED_PARAM) { + struct ssl_backend_data *backend = connssl->backend; (void)info; - return BACKEND->handle; + return backend->handle; } const struct Curl_ssl Curl_ssl_wolfssl = { diff --git a/lib/warnless.h b/lib/warnless.h index ea4c4395..ab78f944 100644 --- a/lib/warnless.h +++ b/lib/warnless.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, 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 @@ -94,19 +94,6 @@ unsigned short curlx_htons(unsigned short usnum); unsigned short curlx_ntohs(unsigned short usnum); -#ifndef BUILDING_WARNLESS_C -# undef FD_ISSET -# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b)) -# undef FD_SET -# define FD_SET(a,b) curlx_FD_SET((a),(b)) -# undef FD_ZERO -# define FD_ZERO(a) curlx_FD_ZERO((a)) -# undef htons -# define htons(a) curlx_htons((a)) -# undef ntohs -# define ntohs(a) curlx_ntohs((a)) -#endif - #endif /* __INTEL_COMPILER && __unix__ */ #endif /* HEADER_CURL_WARNLESS_H */ |