lib: TLS session ticket caching reworked
—
$ git checkout -f fa0ccd9f1fbbbd77bf50b26e3ba231ea6c729474
Previous HEAD position was 37fb50a858 examples/complicated: fix warnings, bump deprecated callback, tidy up
HEAD is now at fa0ccd9f1f lib: TLS session ticket caching reworked
$ git clean -fdx
Removing Makefile
Removing Makefile.in
Removing aclocal.m4
Removing autom4te.cache/
Removing buildinfo.txt
Removing compile
Removing config.guess
Removing config.log
Removing config.status
Removing config.sub
Removing configure
Removing curl-config
Removing depcomp
Removing docs/Makefile
Removing docs/Makefile.in
Removing docs/cmdline-opts/Makefile
Removing docs/cmdline-opts/Makefile.in
Removing docs/examples/.deps/
Removing docs/examples/Makefile
Removing docs/examples/Makefile.in
Removing docs/libcurl/Makefile
Removing docs/libcurl/Makefile.in
Removing docs/libcurl/opts/Makefile
Removing docs/libcurl/opts/Makefile.in
Removing include/Makefile
Removing include/Makefile.in
Removing include/curl/Makefile
Removing include/curl/Makefile.in
Removing install-sh
Removing lib/.deps/
Removing lib/.dirstamp
Removing lib/.libs/
Removing lib/Makefile
Removing lib/Makefile.in
Removing lib/base64.o
Removing lib/curl_config.h
Removing lib/curl_config.h.in
Removing lib/curl_multibyte.o
Removing lib/dynbuf.o
Removing lib/libcurl.la
Removing lib/libcurl.vers
Removing lib/libcurl_la-altsvc.lo
Removing lib/libcurl_la-altsvc.o
Removing lib/libcurl_la-amigaos.lo
Removing lib/libcurl_la-amigaos.o
Removing lib/libcurl_la-asyn-ares.lo
Removing lib/libcurl_la-asyn-ares.o
Removing lib/libcurl_la-asyn-thread.lo
Removing lib/libcurl_la-asyn-thread.o
Removing lib/libcurl_la-base64.lo
Removing lib/libcurl_la-base64.o
Removing lib/libcurl_la-bufq.lo
Removing lib/libcurl_la-bufq.o
Removing lib/libcurl_la-bufref.lo
Removing lib/libcurl_la-bufref.o
Removing lib/libcurl_la-c-hyper.lo
Removing lib/libcurl_la-c-hyper.o
Removing lib/libcurl_la-cf-h1-proxy.lo
Removing lib/libcurl_la-cf-h1-proxy.o
Removing lib/libcurl_la-cf-h2-proxy.lo
Removing lib/libcurl_la-cf-h2-proxy.o
Removing lib/libcurl_la-cf-haproxy.lo
Removing lib/libcurl_la-cf-haproxy.o
Removing lib/libcurl_la-cf-https-connect.lo
Removing lib/libcurl_la-cf-https-connect.o
Removing lib/libcurl_la-cf-socket.lo
Removing lib/libcurl_la-cf-socket.o
Removing lib/libcurl_la-cfilters.lo
Removing lib/libcurl_la-cfilters.o
Removing lib/libcurl_la-conncache.lo
Removing lib/libcurl_la-conncache.o
Removing lib/libcurl_la-connect.lo
Removing lib/libcurl_la-connect.o
Removing lib/libcurl_la-content_encoding.lo
Removing lib/libcurl_la-content_encoding.o
Removing lib/libcurl_la-cookie.lo
Removing lib/libcurl_la-cookie.o
Removing lib/libcurl_la-curl_addrinfo.lo
Removing lib/libcurl_la-curl_addrinfo.o
Removing lib/libcurl_la-curl_des.lo
Removing lib/libcurl_la-curl_des.o
Removing lib/libcurl_la-curl_endian.lo
Removing lib/libcurl_la-curl_endian.o
Removing lib/libcurl_la-curl_fnmatch.lo
Removing lib/libcurl_la-curl_fnmatch.o
Removing lib/libcurl_la-curl_get_line.lo
Removing lib/libcurl_la-curl_get_line.o
Removing lib/libcurl_la-curl_gethostname.lo
Removing lib/libcurl_la-curl_gethostname.o
Removing lib/libcurl_la-curl_gssapi.lo
Removing lib/libcurl_la-curl_gssapi.o
Removing lib/libcurl_la-curl_memrchr.lo
Removing lib/libcurl_la-curl_memrchr.o
Removing lib/libcurl_la-curl_multibyte.lo
Removing lib/libcurl_la-curl_multibyte.o
Removing lib/libcurl_la-curl_ntlm_core.lo
Removing lib/libcurl_la-curl_ntlm_core.o
Removing lib/libcurl_la-curl_range.lo
Removing lib/libcurl_la-curl_range.o
Removing lib/libcurl_la-curl_rtmp.lo
Removing lib/libcurl_la-curl_rtmp.o
Removing lib/libcurl_la-curl_sasl.lo
Removing lib/libcurl_la-curl_sasl.o
Removing lib/libcurl_la-curl_sha512_256.lo
Removing lib/libcurl_la-curl_sha512_256.o
Removing lib/libcurl_la-curl_sspi.lo
Removing lib/libcurl_la-curl_sspi.o
Removing lib/libcurl_la-curl_threads.lo
Removing lib/libcurl_la-curl_threads.o
Removing lib/libcurl_la-curl_trc.lo
Removing lib/libcurl_la-curl_trc.o
Removing lib/libcurl_la-cw-out.lo
Removing lib/libcurl_la-cw-out.o
Removing lib/libcurl_la-dict.lo
Removing lib/libcurl_la-dict.o
Removing lib/libcurl_la-dllmain.lo
Removing lib/libcurl_la-dllmain.o
Removing lib/libcurl_la-doh.lo
Removing lib/libcurl_la-doh.o
Removing lib/libcurl_la-dynbuf.lo
Removing lib/libcurl_la-dynbuf.o
Removing lib/libcurl_la-dynhds.lo
Removing lib/libcurl_la-dynhds.o
Removing lib/libcurl_la-easy.lo
Removing lib/libcurl_la-easy.o
Removing lib/libcurl_la-easygetopt.lo
Removing lib/libcurl_la-easygetopt.o
Removing lib/libcurl_la-easyoptions.lo
Removing lib/libcurl_la-easyoptions.o
Removing lib/libcurl_la-escape.lo
Removing lib/libcurl_la-escape.o
Removing lib/libcurl_la-file.lo
Removing lib/libcurl_la-file.o
Removing lib/libcurl_la-fileinfo.lo
Removing lib/libcurl_la-fileinfo.o
Removing lib/libcurl_la-fopen.lo
Removing lib/libcurl_la-fopen.o
Removing lib/libcurl_la-formdata.lo
Removing lib/libcurl_la-formdata.o
Removing lib/libcurl_la-ftp.lo
Removing lib/libcurl_la-ftp.o
Removing lib/libcurl_la-ftplistparser.lo
Removing lib/libcurl_la-ftplistparser.o
Removing lib/libcurl_la-getenv.lo
Removing lib/libcurl_la-getenv.o
Removing lib/libcurl_la-getinfo.lo
Removing lib/libcurl_la-getinfo.o
Removing lib/libcurl_la-gopher.lo
Removing lib/libcurl_la-gopher.o
Removing lib/libcurl_la-hash.lo
Removing lib/libcurl_la-hash.o
Removing lib/libcurl_la-headers.lo
Removing lib/libcurl_la-headers.o
Removing lib/libcurl_la-hmac.lo
Removing lib/libcurl_la-hmac.o
Removing lib/libcurl_la-hostasyn.lo
Removing lib/libcurl_la-hostasyn.o
Removing lib/libcurl_la-hostip.lo
Removing lib/libcurl_la-hostip.o
Removing lib/libcurl_la-hostip4.lo
Removing lib/libcurl_la-hostip4.o
Removing lib/libcurl_la-hostip6.lo
Removing lib/libcurl_la-hostip6.o
Removing lib/libcurl_la-hostsyn.lo
Removing lib/libcurl_la-hostsyn.o
Removing lib/libcurl_la-hsts.lo
Removing lib/libcurl_la-hsts.o
Removing lib/libcurl_la-http.lo
Removing lib/libcurl_la-http.o
Removing lib/libcurl_la-http1.lo
Removing lib/libcurl_la-http1.o
Removing lib/libcurl_la-http2.lo
Removing lib/libcurl_la-http2.o
Removing lib/libcurl_la-http_aws_sigv4.lo
Removing lib/libcurl_la-http_aws_sigv4.o
Removing lib/libcurl_la-http_chunks.lo
Removing lib/libcurl_la-http_chunks.o
Removing lib/libcurl_la-http_digest.lo
Removing lib/libcurl_la-http_digest.o
Removing lib/libcurl_la-http_negotiate.lo
Removing lib/libcurl_la-http_negotiate.o
Removing lib/libcurl_la-http_ntlm.lo
Removing lib/libcurl_la-http_ntlm.o
Removing lib/libcurl_la-http_proxy.lo
Removing lib/libcurl_la-http_proxy.o
Removing lib/libcurl_la-idn.lo
Removing lib/libcurl_la-idn.o
Removing lib/libcurl_la-if2ip.lo
Removing lib/libcurl_la-if2ip.o
Removing lib/libcurl_la-imap.lo
Removing lib/libcurl_la-imap.o
Removing lib/libcurl_la-inet_ntop.lo
Removing lib/libcurl_la-inet_ntop.o
Removing lib/libcurl_la-inet_pton.lo
Removing lib/libcurl_la-inet_pton.o
Removing lib/libcurl_la-krb5.lo
Removing lib/libcurl_la-krb5.o
Removing lib/libcurl_la-ldap.lo
Removing lib/libcurl_la-ldap.o
Removing lib/libcurl_la-llist.lo
Removing lib/libcurl_la-llist.o
Removing lib/libcurl_la-macos.lo
Removing lib/libcurl_la-macos.o
Removing lib/libcurl_la-md4.lo
Removing lib/libcurl_la-md4.o
Removing lib/libcurl_la-md5.lo
Removing lib/libcurl_la-md5.o
Removing lib/libcurl_la-memdebug.lo
Removing lib/libcurl_la-memdebug.o
Removing lib/libcurl_la-mime.lo
Removing lib/libcurl_la-mime.o
Removing lib/libcurl_la-mprintf.lo
Removing lib/libcurl_la-mprintf.o
Removing lib/libcurl_la-mqtt.lo
Removing lib/libcurl_la-mqtt.o
Removing lib/libcurl_la-multi.lo
Removing lib/libcurl_la-multi.o
Removing lib/libcurl_la-netrc.lo
Removing lib/libcurl_la-netrc.o
Removing lib/libcurl_la-nonblock.lo
Removing lib/libcurl_la-nonblock.o
Removing lib/libcurl_la-noproxy.lo
Removing lib/libcurl_la-noproxy.o
Removing lib/libcurl_la-openldap.lo
Removing lib/libcurl_la-openldap.o
Removing lib/libcurl_la-parsedate.lo
Removing lib/libcurl_la-parsedate.o
Removing lib/libcurl_la-pingpong.lo
Removing lib/libcurl_la-pingpong.o
Removing lib/libcurl_la-pop3.lo
Removing lib/libcurl_la-pop3.o
Removing lib/libcurl_la-progress.lo
Removing lib/libcurl_la-progress.o
Removing lib/libcurl_la-psl.lo
Removing lib/libcurl_la-psl.o
Removing lib/libcurl_la-rand.lo
Removing lib/libcurl_la-rand.o
Removing lib/libcurl_la-rename.lo
Removing lib/libcurl_la-rename.o
Removing lib/libcurl_la-request.lo
Removing lib/libcurl_la-request.o
Removing lib/libcurl_la-rtsp.lo
Removing lib/libcurl_la-rtsp.o
Removing lib/libcurl_la-select.lo
Removing lib/libcurl_la-select.o
Removing lib/libcurl_la-sendf.lo
Removing lib/libcurl_la-sendf.o
Removing lib/libcurl_la-setopt.lo
Removing lib/libcurl_la-setopt.o
Removing lib/libcurl_la-sha256.lo
Removing lib/libcurl_la-sha256.o
Removing lib/libcurl_la-share.lo
Removing lib/libcurl_la-share.o
Removing lib/libcurl_la-slist.lo
Removing lib/libcurl_la-slist.o
Removing lib/libcurl_la-smb.lo
Removing lib/libcurl_la-smb.o
Removing lib/libcurl_la-smtp.lo
Removing lib/libcurl_la-smtp.o
Removing lib/libcurl_la-socketpair.lo
Removing lib/libcurl_la-socketpair.o
Removing lib/libcurl_la-socks.lo
Removing lib/libcurl_la-socks.o
Removing lib/libcurl_la-socks_gssapi.lo
Removing lib/libcurl_la-socks_gssapi.o
Removing lib/libcurl_la-socks_sspi.lo
Removing lib/libcurl_la-socks_sspi.o
Removing lib/libcurl_la-speedcheck.lo
Removing lib/libcurl_la-speedcheck.o
Removing lib/libcurl_la-splay.lo
Removing lib/libcurl_la-splay.o
Removing lib/libcurl_la-strcase.lo
Removing lib/libcurl_la-strcase.o
Removing lib/libcurl_la-strdup.lo
Removing lib/libcurl_la-strdup.o
Removing lib/libcurl_la-strerror.lo
Removing lib/libcurl_la-strerror.o
Removing lib/libcurl_la-strparse.lo
Removing lib/libcurl_la-strparse.o
Removing lib/libcurl_la-strtok.lo
Removing lib/libcurl_la-strtok.o
Removing lib/libcurl_la-strtoofft.lo
Removing lib/libcurl_la-strtoofft.o
Removing lib/libcurl_la-system_win32.lo
Removing lib/libcurl_la-system_win32.o
Removing lib/libcurl_la-telnet.lo
Removing lib/libcurl_la-telnet.o
Removing lib/libcurl_la-tftp.lo
Removing lib/libcurl_la-tftp.o
Removing lib/libcurl_la-timediff.lo
Removing lib/libcurl_la-timediff.o
Removing lib/libcurl_la-timeval.lo
Removing lib/libcurl_la-timeval.o
Removing lib/libcurl_la-transfer.lo
Removing lib/libcurl_la-transfer.o
Removing lib/libcurl_la-url.lo
Removing lib/libcurl_la-url.o
Removing lib/libcurl_la-urlapi.lo
Removing lib/libcurl_la-urlapi.o
Removing lib/libcurl_la-version.lo
Removing lib/libcurl_la-version.o
Removing lib/libcurl_la-version_win32.lo
Removing lib/libcurl_la-version_win32.o
Removing lib/libcurl_la-warnless.lo
Removing lib/libcurl_la-warnless.o
Removing lib/libcurl_la-ws.lo
Removing lib/libcurl_la-ws.o
Removing lib/nonblock.o
Removing lib/stamp-h1
Removing lib/strtoofft.o
Removing lib/timediff.o
Removing lib/vauth/.deps/
Removing lib/vauth/.dirstamp
Removing lib/vauth/libcurl_la-cleartext.lo
Removing lib/vauth/libcurl_la-cleartext.o
Removing lib/vauth/libcurl_la-cram.lo
Removing lib/vauth/libcurl_la-cram.o
Removing lib/vauth/libcurl_la-digest.lo
Removing lib/vauth/libcurl_la-digest.o
Removing lib/vauth/libcurl_la-digest_sspi.lo
Removing lib/vauth/libcurl_la-digest_sspi.o
Removing lib/vauth/libcurl_la-gsasl.lo
Removing lib/vauth/libcurl_la-gsasl.o
Removing lib/vauth/libcurl_la-krb5_gssapi.lo
Removing lib/vauth/libcurl_la-krb5_gssapi.o
Removing lib/vauth/libcurl_la-krb5_sspi.lo
Removing lib/vauth/libcurl_la-krb5_sspi.o
Removing lib/vauth/libcurl_la-ntlm.lo
Removing lib/vauth/libcurl_la-ntlm.o
Removing lib/vauth/libcurl_la-ntlm_sspi.lo
Removing lib/vauth/libcurl_la-ntlm_sspi.o
Removing lib/vauth/libcurl_la-oauth2.lo
Removing lib/vauth/libcurl_la-oauth2.o
Removing lib/vauth/libcurl_la-spnego_gssapi.lo
Removing lib/vauth/libcurl_la-spnego_gssapi.o
Removing lib/vauth/libcurl_la-spnego_sspi.lo
Removing lib/vauth/libcurl_la-spnego_sspi.o
Removing lib/vauth/libcurl_la-vauth.lo
Removing lib/vauth/libcurl_la-vauth.o
Removing lib/version_win32.o
Removing lib/vquic/.deps/
Removing lib/vquic/.dirstamp
Removing lib/vquic/libcurl_la-curl_msh3.lo
Removing lib/vquic/libcurl_la-curl_msh3.o
Removing lib/vquic/libcurl_la-curl_ngtcp2.lo
Removing lib/vquic/libcurl_la-curl_ngtcp2.o
Removing lib/vquic/libcurl_la-curl_osslq.lo
Removing lib/vquic/libcurl_la-curl_osslq.o
Removing lib/vquic/libcurl_la-curl_quiche.lo
Removing lib/vquic/libcurl_la-curl_quiche.o
Removing lib/vquic/libcurl_la-vquic-tls.lo
Removing lib/vquic/libcurl_la-vquic-tls.o
Removing lib/vquic/libcurl_la-vquic.lo
Removing lib/vquic/libcurl_la-vquic.o
Removing lib/vssh/.deps/
Removing lib/vssh/.dirstamp
Removing lib/vssh/libcurl_la-curl_path.lo
Removing lib/vssh/libcurl_la-curl_path.o
Removing lib/vssh/libcurl_la-libssh.lo
Removing lib/vssh/libcurl_la-libssh.o
Removing lib/vssh/libcurl_la-libssh2.lo
Removing lib/vssh/libcurl_la-libssh2.o
Removing lib/vssh/libcurl_la-wolfssh.lo
Removing lib/vssh/libcurl_la-wolfssh.o
Removing lib/vtls/.deps/
Removing lib/vtls/.dirstamp
Removing lib/vtls/libcurl_la-bearssl.lo
Removing lib/vtls/libcurl_la-bearssl.o
Removing lib/vtls/libcurl_la-cipher_suite.lo
Removing lib/vtls/libcurl_la-cipher_suite.o
Removing lib/vtls/libcurl_la-gtls.lo
Removing lib/vtls/libcurl_la-gtls.o
Removing lib/vtls/libcurl_la-hostcheck.lo
Removing lib/vtls/libcurl_la-hostcheck.o
Removing lib/vtls/libcurl_la-keylog.lo
Removing lib/vtls/libcurl_la-keylog.o
Removing lib/vtls/libcurl_la-mbedtls.lo
Removing lib/vtls/libcurl_la-mbedtls.o
Removing lib/vtls/libcurl_la-mbedtls_threadlock.lo
Removing lib/vtls/libcurl_la-mbedtls_threadlock.o
Removing lib/vtls/libcurl_la-openssl.lo
Removing lib/vtls/libcurl_la-openssl.o
Removing lib/vtls/libcurl_la-rustls.lo
Removing lib/vtls/libcurl_la-rustls.o
Removing lib/vtls/libcurl_la-schannel.lo
Removing lib/vtls/libcurl_la-schannel.o
Removing lib/vtls/libcurl_la-schannel_verify.lo
Removing lib/vtls/libcurl_la-schannel_verify.o
Removing lib/vtls/libcurl_la-sectransp.lo
Removing lib/vtls/libcurl_la-sectransp.o
Removing lib/vtls/libcurl_la-vtls.lo
Removing lib/vtls/libcurl_la-vtls.o
Removing lib/vtls/libcurl_la-vtls_scache.lo
Removing lib/vtls/libcurl_la-vtls_scache.o
Removing lib/vtls/libcurl_la-wolfssl.lo
Removing lib/vtls/libcurl_la-wolfssl.o
Removing lib/vtls/libcurl_la-x509asn1.lo
Removing lib/vtls/libcurl_la-x509asn1.o
Removing lib/warnless.o
Removing libcurl.pc
Removing libtool
Removing ltmain.sh
Removing m4/libtool.m4
Removing m4/ltoptions.m4
Removing m4/ltsugar.m4
Removing m4/ltversion.m4
Removing m4/lt~obsolete.m4
Removing missing
Removing packages/Makefile
Removing packages/Makefile.in
Removing packages/vms/Makefile
Removing packages/vms/Makefile.in
Removing scripts/Makefile
Removing scripts/Makefile.in
Removing src/.deps/
Removing src/.libs/
Removing src/Makefile
Removing src/Makefile.in
Removing src/curl
Removing src/slist_wc.o
Removing src/terminal.o
Removing src/tool_binmode.o
Removing src/tool_bname.o
Removing src/tool_ca_embed.c
Removing src/tool_ca_embed.o
Removing src/tool_cb_dbg.o
Removing src/tool_cb_hdr.o
Removing src/tool_cb_prg.o
Removing src/tool_cb_rea.o
Removing src/tool_cb_see.o
Removing src/tool_cb_soc.o
Removing src/tool_cb_wrt.o
Removing src/tool_cfgable.o
Removing src/tool_dirhie.o
Removing src/tool_doswin.o
Removing src/tool_easysrc.o
Removing src/tool_filetime.o
Removing src/tool_findfile.o
Removing src/tool_formparse.o
Removing src/tool_getparam.o
Removing src/tool_getpass.o
Removing src/tool_help.o
Removing src/tool_helpers.o
Removing src/tool_hugehelp.c
Removing src/tool_hugehelp.o
Removing src/tool_ipfs.o
Removing src/tool_libinfo.o
Removing src/tool_listhelp.o
Removing src/tool_main.o
Removing src/tool_msgs.o
Removing src/tool_operate.o
Removing src/tool_operhlp.o
Removing src/tool_paramhlp.o
Removing src/tool_parsecfg.o
Removing src/tool_progress.o
Removing src/tool_setopt.o
Removing src/tool_sleep.o
Removing src/tool_stderr.o
Removing src/tool_strdup.o
Removing src/tool_urlglob.o
Removing src/tool_util.o
Removing src/tool_vms.o
Removing src/tool_writeout.o
Removing src/tool_writeout_json.o
Removing src/tool_xattr.o
Removing src/var.o
Removing tests/Makefile
Removing tests/Makefile.in
Removing tests/certs/Makefile
Removing tests/certs/Makefile.in
Removing tests/certs/scripts/Makefile
Removing tests/certs/scripts/Makefile.in
Removing tests/config
Removing tests/configurehelp.pm
Removing tests/data/Makefile
Removing tests/data/Makefile.in
Removing tests/http/Makefile
Removing tests/http/Makefile.in
Removing tests/http/clients/.deps/
Removing tests/http/clients/Makefile
Removing tests/http/clients/Makefile.in
Removing tests/http/config.ini
Removing tests/libtest/.deps/
Removing tests/libtest/Makefile
Removing tests/libtest/Makefile.in
Removing tests/server/.deps/
Removing tests/server/Makefile
Removing tests/server/Makefile.in
Removing tests/unit/.deps/
Removing tests/unit/Makefile
Removing tests/unit/Makefile.in
$ autoreconf -fi
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
libtoolize: Remember to add 'LT_INIT' to configure.ac.
configure.ac:125: installing './compile'
configure.ac:429: installing './config.guess'
configure.ac:429: installing './config.sub'
configure.ac:125: installing './install-sh'
configure.ac:131: installing './missing'
docs/examples/Makefile.am: installing './depcomp'
$ bash -c find . -name config.guess -exec cp /usr/share/misc/config.guess {} \;
$ bash -c find . -name config.sub -exec cp /usr/share/misc/config.sub {} \;
$ chmod +x configure
$ ./configure --disable-shared --without-ssl --disable-docs
checking whether to enable maintainer-specific portions of Makefiles... no
checking whether make supports nested variables... yes
checking whether to enable debug build options... no
checking whether to enable compiler optimizer... (assumed) yes
checking whether to enable strict compiler warnings... no
checking whether to enable compiler warnings as errors... no
checking whether to enable curl debug memory tracking... no
checking whether to enable hiding of library internal symbols... yes
checking whether to enable c-ares for DNS lookups... no
checking whether to disable dependency on -lrt... (assumed no)
checking whether to enable HTTPSRR support... no
checking whether to enable ECH support... no
checking for path separator... :
checking for sed... /usr/bin/sed
checking for grep... /usr/bin/grep
checking that grep -E works... yes
checking for ar... /usr/bin/ar
checking for a BSD-compatible install... /usr/bin/install -c
checking for gcc... ccache gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether ccache gcc accepts -g... yes
checking for ccache gcc option to enable C11 features... none needed
checking whether ccache gcc understands -c and -o together... yes
checking how to run the C preprocessor... ccache gcc -E
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... yes
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... yes
checking for stdatomic.h... yes
checking if _Atomic is available... yes
checking for a sed that does not truncate output... (cached) /usr/bin/sed
checking for code coverage support... no
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports the include directive... yes (GNU style)
checking dependency style of ccache gcc... gcc3
checking curl version... 8.11.2-DEV
checking for httpd... no
checking for apache2... no
checking for apachectl... no
checking for apxs... no
configure: httpd/apache2 not in PATH, http tests disabled
configure: apxs not in PATH, http tests disabled
checking for nghttpx... no
checking for caddy... /usr/bin/caddy
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for grep that handles long lines and -e... (cached) /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking if OS is AIX (to define _ALL_SOURCE)... no
checking if _THREAD_SAFE is already defined... no
checking if _THREAD_SAFE is actually needed... no
checking if _THREAD_SAFE is onwards defined... no
checking if _REENTRANT is already defined... no
checking if _REENTRANT is actually needed... no
checking if _REENTRANT is onwards defined... no
checking for special C compiler options needed for large files... no
checking for _FILE_OFFSET_BITS value needed for large files... no
checking how to print strings... printf
checking for a sed that does not truncate output... (cached) /usr/bin/sed
checking for fgrep... /usr/bin/grep -F
checking for ld used by ccache gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking command to parse /usr/bin/nm -B output from ccache gcc object... ok
checking for sysroot... no
checking for a working dd... /usr/bin/dd
checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
checking for mt... mt
checking if mt is a manifest tool... no
checking for dlfcn.h... yes
checking for objdir... .libs
checking if ccache gcc supports -fno-rtti -fno-exceptions... no
checking for ccache gcc option to produce PIC... -fPIC -DPIC
checking if ccache gcc PIC flag -fPIC -DPIC works... yes
checking if ccache gcc static flag -static works... yes
checking if ccache gcc supports -c -o file.o... yes
checking if ccache gcc supports -c -o file.o... (cached) yes
checking whether the ccache gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... no
checking whether to build static libraries... yes
checking whether to build shared libraries with -version-info... yes
checking whether to build shared libraries with -no-undefined... no
checking whether to build shared libraries with -mimpure-text... no
checking whether to build shared libraries with PIC... yes
checking whether to build static libraries with PIC... yes
checking whether to build shared libraries only... no
checking whether to build static libraries only... yes
checking for windres... no
checking if cpp -P is needed... yes
checking if cpp -P works... yes
checking if compiler is DEC/Compaq/HP C... no
checking if compiler is HP-UX C... no
checking if compiler is IBM C... no
checking if compiler is Intel C... no
checking if compiler is clang... no
checking if compiler is GNU C... yes
checking compiler version... gcc '1100' (raw: '11')
checking if compiler is SunPro C... no
checking if compiler is Tiny C... no
checking whether build target is a native Windows one... no
checking if compiler accepts some basic options... yes
configure: compiler options added: -Werror-implicit-function-declaration
checking if compiler optimizer assumed setting might be used... yes
checking if compiler accepts optimizer enabling options... yes
configure: compiler options added: -O2
checking if compiler accepts strict warning options... yes
configure: compiler options added: -Wno-system-headers
checking if compiler halts on compilation errors... yes
checking if compiler halts on negative sized arrays... yes
checking if compiler halts on function prototype mismatch... yes
checking if compiler supports hiding library internal symbols... yes
checking whether build target supports Win32 file API... no
checking whether build target supports Win32 crypto API... no
checking for good-to-use Darwin CFLAGS... no
checking whether to build libcurl and curl in "unity" mode... no
checking whether to build tests into single-binary bundles... no
checking whether to support http... yes
checking whether to support ftp... yes
checking whether to support file... yes
checking whether to support IPFS... yes
checking whether to support ldap... yes
checking whether to support ldaps... yes
checking whether to support rtsp... yes
checking whether to support proxies... yes
checking whether to support dict... yes
checking whether to support telnet... yes
checking whether to support tftp... yes
checking whether to support pop3... yes
checking whether to support imap... yes
checking whether to support smb... yes
checking whether to support smtp... yes
checking whether to support gopher... yes
checking whether to support mqtt... no
checking whether to provide built-in manual... yes
checking whether to build documentation... no
checking whether to enable generation of C code... yes
checking whether to use libgcc... no
checking if X/Open network library is required... no
checking for gethostbyname... yes
checking whether build target is a native Windows one... (cached) no
checking for proto/bsdsocket.h... no
checking for connect in libraries... yes
checking for sys/types.h... (cached) yes
checking for sys/time.h... yes
checking for monotonic clock_gettime... yes
checking for clock_gettime in libraries... no additional lib required
checking if monotonic clock_gettime works... yes
checking for sys/types.h... (cached) yes
checking for sys/time.h... (cached) yes
checking for raw monotonic clock_gettime... yes
checking for pkg-config... /usr/bin/pkg-config
checking for zlib options with pkg-config... found
checking for zlib.h... yes
configure: found both libz and libz.h header
checking for BrotliDecoderDecompress in -lbrotlidec... no
checking for brotli/decode.h... no
checking for ZSTD_createDStream in -lzstd... no
checking for zstd.h... no
checking for lber.h... no
checking for ldap.h... no
checking for ldap_ssl.h... no
checking for LDAP libraries... cannot find LDAP libraries
checking whether to enable IPv6... yes
checking if struct sockaddr_in6 has sin6_scope_id member... yes
checking if argv can be written to... yes
checking if GSS-API support is requested... no
checking whether to enable Windows native SSL/TLS... no
checking whether to enable Secure Transport... no
checking whether to enable Amiga native SSL/TLS (AmiSSL v5)... no
checking for pkg-config... (cached) /usr/bin/pkg-config
checking for libpsl options with pkg-config... found
checking for psl_builtin in -lpsl... yes
checking for libpsl.h... yes
checking for library containing gsasl_init... no
checking for RTMP_Init in -lrtmp... no
checking whether versioned symbols are wanted... no
checking whether to build with libidn2... (assumed) yes
checking for pkg-config... (cached) /usr/bin/pkg-config
checking for libidn2 options with pkg-config... no
configure: IDN_LIBS: "-lidn2"
configure: IDN_LDFLAGS: ""
configure: IDN_CPPFLAGS: ""
configure: IDN_DIR: ""
checking if idn2_lookup_ul can be linked... no
checking for idn2.h... no
checking for pkg-config... (cached) /usr/bin/pkg-config
checking for libnghttp2 options with pkg-config... no
checking for nghttp2_session_get_stream_local_window_size in -lnghttp2... no
checking for sys/types.h... (cached) yes
checking for sys/time.h... (cached) yes
checking for sys/select.h... yes
checking for sys/socket.h... yes
checking for sys/ioctl.h... yes
checking for unistd.h... (cached) yes
checking for stdlib.h... (cached) yes
checking for arpa/inet.h... yes
checking for net/if.h... yes
checking for netinet/in.h... yes
checking for netinet/in6.h... no
checking for sys/un.h... yes
checking for linux/tcp.h... yes
checking for netinet/tcp.h... yes
checking for netinet/udp.h... yes
checking for netdb.h... yes
checking for sys/sockio.h... no
checking for sys/stat.h... (cached) yes
checking for sys/param.h... yes
checking for termios.h... yes
checking for termio.h... yes
checking for fcntl.h... yes
checking for io.h... no
checking for pwd.h... yes
checking for utime.h... yes
checking for sys/utime.h... no
checking for sys/poll.h... yes
checking for poll.h... yes
checking for sys/resource.h... yes
checking for libgen.h... yes
checking for locale.h... yes
checking for stdbool.h... yes
checking for sys/filio.h... no
checking for sys/eventfd.h... yes
checking for setjmp.h... yes
checking for an ANSI C-conforming const... yes
checking for size_t... yes
checking for sys/types.h... (cached) yes
checking for sys/time.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for struct timeval... yes
checking run-time libs availability... fine
checking size of size_t... 8
checking size of long... 8
checking size of int... 4
checking size of time_t... 8
checking size of off_t... 8
checking size of curl_off_t... 8
checking size of curl_socket_t... 4
checking for long long... yes
checking for ssize_t... yes
checking for bool... yes
checking for sa_family_t... yes
checking for suseconds_t... yes
checking if time_t is unsigned... no
checking for in_addr_t... yes
checking for struct sockaddr_storage... yes
checking for sys/select.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for select... yes
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for recv... yes
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for send... yes
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for MSG_NOSIGNAL... yes
checking for sys/types.h... (cached) yes
checking for unistd.h... (cached) yes
checking if alarm can be linked... yes
checking if alarm is prototyped... yes
checking if alarm is compilable... yes
checking if alarm usage allowed... yes
checking if alarm might be used... yes
checking for sys/types.h... (cached) yes
checking for strings.h... (cached) yes
checking for sys/types.h... (cached) yes
checking for libgen.h... (cached) yes
checking if basename can be linked... yes
checking if basename is prototyped... yes
checking if basename is compilable... yes
checking if basename usage allowed... yes
checking if basename might be used... yes
checking if closesocket can be linked... no
checking if closesocket might be used... no
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking if CloseSocket can be linked... no
checking if CloseSocket might be used... no
checking for sys/types.h... (cached) yes
checking for unistd.h... (cached) yes
checking for fcntl.h... (cached) yes
checking if fcntl can be linked... yes
checking if fcntl is prototyped... yes
checking if fcntl is compilable... yes
checking if fcntl usage allowed... yes
checking if fcntl might be used... yes
checking if fcntl O_NONBLOCK is compilable... yes
checking if fcntl O_NONBLOCK usage allowed... yes
checking if fcntl O_NONBLOCK might be used... yes
checking whether build target is a native Windows one... (cached) no
checking for sys/types.h... (cached) yes
checking for netdb.h... (cached) yes
checking if freeaddrinfo can be linked... yes
checking if freeaddrinfo is prototyped... yes
checking if freeaddrinfo is compilable... yes
checking if freeaddrinfo usage allowed... yes
checking if freeaddrinfo might be used... yes
checking for sys/types.h... (cached) yes
checking for sys/xattr.h... yes
checking if fsetxattr can be linked... yes
checking if fsetxattr is prototyped... yes
checking if fsetxattr takes 5 args.... yes
checking if fsetxattr is compilable... yes
checking if fsetxattr usage allowed... yes
checking if fsetxattr might be used... yes
checking if ftruncate can be linked... yes
checking if ftruncate is prototyped... yes
checking if ftruncate is compilable... yes
checking if ftruncate usage allowed... yes
checking if ftruncate might be used... yes
checking for sys/types.h... (cached) yes
checking if getaddrinfo can be linked... yes
checking if getaddrinfo is prototyped... yes
checking if getaddrinfo is compilable... yes
checking if getaddrinfo seems to work... yes
checking if getaddrinfo usage allowed... yes
checking if getaddrinfo might be used... yes
checking if getaddrinfo is threadsafe... yes
checking if gethostbyname_r can be linked... yes
checking if gethostbyname_r is prototyped... yes
checking if gethostbyname_r takes 3 args.... no
checking if gethostbyname_r takes 5 args.... no
checking if gethostbyname_r takes 6 args.... yes
checking if gethostbyname_r is compilable... yes
checking if gethostbyname_r usage allowed... yes
checking if gethostbyname_r might be used... yes
checking if gethostname can be linked... yes
checking if gethostname is prototyped... yes
checking if gethostname is compilable... yes
checking for gethostname arg 2 data type... size_t
checking if gethostname usage allowed... yes
checking if gethostname might be used... yes
checking if getpeername can be linked... yes
checking if getpeername is prototyped... yes
checking if getpeername is compilable... yes
checking if getpeername usage allowed... yes
checking if getpeername might be used... yes
checking if getsockname can be linked... yes
checking if getsockname is prototyped... yes
checking if getsockname is compilable... yes
checking if getsockname usage allowed... yes
checking if getsockname might be used... yes
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for netinet/in.h... (cached) yes
checking for ifaddrs.h... yes
checking if getifaddrs can be linked... yes
checking if getifaddrs is prototyped... yes
checking if getifaddrs is compilable... yes
checking if getifaddrs seems to work... yes
checking if getifaddrs usage allowed... yes
checking if getifaddrs might be used... yes
checking for sys/types.h... (cached) yes
checking for sys/time.h... (cached) yes
checking if gmtime_r can be linked... yes
checking if gmtime_r is prototyped... yes
checking if gmtime_r is compilable... yes
checking if gmtime_r seems to work... yes
checking if gmtime_r usage allowed... yes
checking if gmtime_r might be used... yes
checking for sys/types.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for netinet/in.h... (cached) yes
checking for arpa/inet.h... (cached) yes
checking if inet_ntop can be linked... yes
checking if inet_ntop is prototyped... yes
checking if inet_ntop is compilable... yes
checking if inet_ntop seems to work... yes
checking if inet_ntop usage allowed... yes
checking if inet_ntop might be used... yes
checking if inet_pton can be linked... yes
checking if inet_pton is prototyped... yes
checking if inet_pton is compilable... yes
checking if inet_pton seems to work... yes
checking if inet_pton usage allowed... yes
checking if inet_pton might be used... yes
checking for sys/types.h... (cached) yes
checking for unistd.h... (cached) yes
checking for sys/socket.h... (cached) yes
checking for sys/ioctl.h... (cached) yes
checking for stropts.h... no
checking if ioctl can be linked... yes
checking if ioctl is prototyped... yes
checking if ioctl is compilable... yes
checking if ioctl usage allowed... yes
checking if ioctl might be used... yes
checking if ioctl FIONBIO is compilable... yes
checking if ioctl FIONBIO usage allowed... yes
checking if ioctl FIONBIO might be used... yes
checking if ioctl SIOCGIFADDR is compilable... yes
checking if ioctl SIOCGIFADDR usage allowed... yes
checking if ioctl SIOCGIFADDR might be used... yes
checking if ioctlsocket can be linked... no
checking if ioctlsocket might be used... no
checking if IoctlSocket can be linked... no
checking if IoctlSocket might be used... no
checking if memrchr can be linked... yes
checking if memrchr is prototyped... yes
checking if memrchr is compilable... yes
checking if memrchr usage allowed... yes
checking if memrchr might be used... yes
checking for sys/types.h... (cached) yes
checking if sigaction can be linked... yes
checking if sigaction is prototyped... yes
checking if sigaction is compilable... yes
checking if sigaction usage allowed... yes
checking if sigaction might be used... yes
checking if siginterrupt can be linked... yes
checking if siginterrupt is prototyped... yes
checking if siginterrupt is compilable... yes
checking if siginterrupt usage allowed... yes
checking if siginterrupt might be used... yes
checking if signal can be linked... yes
checking if signal is prototyped... yes
checking if signal is compilable... yes
checking if signal usage allowed... yes
checking if signal might be used... yes
checking for sys/types.h... (cached) yes
checking if sigsetjmp can be linked... no
checking if sigsetjmp seems a macro... yes
checking if sigsetjmp is compilable... yes
checking if sigsetjmp usage allowed... yes
checking if sigsetjmp might be used... yes
checking if socket can be linked... yes
checking if socket is prototyped... yes
checking if socket is compilable... yes
checking if socket usage allowed... yes
checking if socket might be used... yes
checking if socketpair can be linked... yes
checking if socketpair is prototyped... yes
checking if socketpair is compilable... yes
checking if socketpair usage allowed... yes
checking if socketpair might be used... yes
checking if strcasecmp can be linked... yes
checking if strcasecmp is prototyped... yes
checking if strcasecmp is compilable... yes
checking if strcasecmp usage allowed... yes
checking if strcasecmp might be used... yes
checking if strcmpi can be linked... no
checking if strcmpi might be used... no
checking if strdup can be linked... yes
checking if strdup is prototyped... yes
checking if strdup is compilable... yes
checking if strdup usage allowed... yes
checking if strdup might be used... yes
checking if strerror_r can be linked... yes
checking if strerror_r is prototyped... yes
checking if strerror_r is compilable... yes
checking if strerror_r is glibc like... yes
checking if strerror_r seems to work... yes
checking if strerror_r usage allowed... yes
checking if strerror_r might be used... yes
checking if stricmp can be linked... no
checking if stricmp might be used... no
checking if strtok_r can be linked... yes
checking if strtok_r is prototyped... yes
checking if strtok_r is compilable... yes
checking if strtok_r usage allowed... yes
checking if strtok_r might be used... yes
checking if strtoll can be linked... yes
checking if strtoll is prototyped... yes
checking if strtoll is compilable... yes
checking if strtoll usage allowed... yes
checking if strtoll might be used... yes
checking for ccache gcc options needed to detect all undeclared functions... none needed
checking whether getpwuid_r is declared... yes
checking for eventfd... yes
checking for fnmatch... yes
checking for geteuid... yes
checking for getpass_r... no
checking for getppid... yes
checking for getpwuid... yes
checking for getpwuid_r... yes
checking for getrlimit... yes
checking for gettimeofday... yes
checking for if_nametoindex... yes
checking for mach_absolute_time... no
checking for pipe... yes
checking for poll... yes
checking for sched_yield... yes
checking for sendmsg... yes
checking for sendmmsg... yes
checking for setlocale... yes
checking for setmode... no
checking for setrlimit... yes
checking for snprintf... yes
checking for utime... yes
checking for utimes... yes
checking for arc4random... no
checking for fseeko... yes
checking whether fseeko is declared... yes
checking how to set a socket into non-blocking mode... fcntl O_NONBLOCK
checking for perl... /usr/bin/perl
checking whether to enable the threaded resolver... yes
checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks... no
checking whether to use POSIX threads for threaded resolver... auto
checking for pthread.h... yes
checking for pthread_create... yes
checking for dirent.h... yes
checking for opendir... yes
checking convert -I options to -isystem... yes
checking whether to enable verbose strings... yes
checking whether to enable SSPI support (Windows native builds only)... no
checking whether to enable basic authentication method... yes
checking whether to enable bearer authentication method... yes
checking whether to enable digest authentication method... yes
checking whether to enable kerberos authentication method... yes
checking whether to enable negotiate authentication method... yes
checking whether to enable aws sig methods... yes
checking whether to support NTLM... yes
checking whether to enable TLS-SRP authentication... yes
checking whether to enable Unix domain sockets... auto
checking for struct sockaddr_un.sun_path... yes
checking whether to support cookies... yes
checking whether to support socketpair... yes
checking whether to support HTTP authentication... yes
checking whether to support DoH... yes
checking whether to support the MIME API... yes
checking whether to support binding connections locally... yes
checking whether to support the form API... yes
checking whether to support date parsing... yes
checking whether to support netrc parsing... yes
checking whether to support progress-meter... yes
checking whether to support the SHA-512/256 hash algorithm... yes
checking whether to support DNS shuffling... yes
checking whether to support curl_easy_option*... yes
checking whether to support alt-svc... yes
checking whether to support headers-api... yes
configure: disables HSTS due to lack of SSL
checking whether to support WebSockets... yes
checking whether hiding of library internal symbols will actually happen... yes
checking if this build supports HTTPS-proxy... no
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating docs/Makefile
config.status: creating docs/examples/Makefile
config.status: creating docs/libcurl/Makefile
config.status: creating docs/libcurl/opts/Makefile
config.status: creating docs/cmdline-opts/Makefile
config.status: creating include/Makefile
config.status: creating include/curl/Makefile
config.status: creating src/Makefile
config.status: creating lib/Makefile
config.status: creating scripts/Makefile
config.status: creating lib/libcurl.vers
config.status: creating tests/Makefile
config.status: creating tests/config
config.status: creating tests/configurehelp.pm
config.status: creating tests/certs/Makefile
config.status: creating tests/certs/scripts/Makefile
config.status: creating tests/data/Makefile
config.status: creating tests/server/Makefile
config.status: creating tests/libtest/Makefile
config.status: creating tests/unit/Makefile
config.status: creating tests/http/config.ini
config.status: creating tests/http/Makefile
config.status: creating tests/http/clients/Makefile
config.status: creating packages/Makefile
config.status: creating packages/vms/Makefile
config.status: creating curl-config
config.status: creating libcurl.pc
config.status: creating lib/curl_config.h
config.status: executing depfiles commands
config.status: executing libtool commands
configure: Configured to build curl/libcurl:
Host setup: x86_64-pc-linux-gnu
Install prefix: /usr/local
Compiler: ccache gcc
CFLAGS: -Werror-implicit-function-declaration -O2 -Wno-system-headers
CFLAGS extras:
CPPFLAGS: -D_GNU_SOURCE
LDFLAGS:
curl-config:
LIBS: -lpsl -lz
curl version: 8.11.2-DEV
SSL: no (--with-{openssl,gnutls,mbedtls,wolfssl,schannel,secure-transport,amissl,bearssl,rustls} )
SSH: no (--with-{libssh,libssh2})
zlib: enabled
brotli: no (--with-brotli)
zstd: no (--with-zstd)
GSS-API: no (--with-gssapi)
GSASL: no (libgsasl not found)
TLS-SRP: no (--enable-tls-srp)
resolver: POSIX threaded
IPv6: enabled
Unix sockets: enabled
IDN: no (--with-{libidn2,winidn})
Build docs: no
Build libcurl: Shared=no, Static=yes
Built-in manual: no (--enable-manual)
--libcurl option: enabled (--disable-libcurl-option)
Verbose errors: enabled (--disable-verbose)
Code coverage: disabled
SSPI: no (--enable-sspi)
ca cert bundle: no
ca cert path:
ca cert embed: no
ca fallback:
LDAP: no (--enable-ldap / --with-ldap-lib / --with-lber-lib)
LDAPS: no (--enable-ldaps)
IPFS/IPNS: enabled
RTSP: enabled
RTMP: no (--with-librtmp)
PSL: enabled
Alt-svc: enabled (--disable-alt-svc)
Headers API: enabled (--disable-headers-api)
HSTS: no (--enable-hsts)
HTTP1: enabled (internal)
HTTP2: no (--with-nghttp2)
HTTP3: no (--with-ngtcp2 --with-nghttp3, --with-quiche, --with-openssl-quic, --with-msh3)
ECH: no (--enable-ech)
Protocols: dict file ftp gopher http imap ipfs ipns mqtt pop3 rtsp smtp telnet tftp ws
Features: alt-svc AsynchDNS IPv6 Largefile libz PSL threadsafe UnixSockets
configure: WARNING: Cannot find libraries for LDAP support: LDAP disabled
configure: WARNING: libgsasl was not found
configure: WARNING: Cannot find libidn2
$ make -j3
Making all in lib
make[1]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/lib'
make all-am
make[2]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/lib'
CC libcurl_la-altsvc.lo
CC libcurl_la-amigaos.lo
CC libcurl_la-asyn-ares.lo
CC libcurl_la-asyn-thread.lo
CC libcurl_la-base64.lo
CC libcurl_la-bufq.lo
CC libcurl_la-bufref.lo
CC libcurl_la-c-hyper.lo
CC libcurl_la-cf-h1-proxy.lo
CC libcurl_la-cf-h2-proxy.lo
CC libcurl_la-cf-haproxy.lo
CC libcurl_la-cf-https-connect.lo
CC libcurl_la-cf-socket.lo
CC libcurl_la-conncache.lo
CC libcurl_la-cfilters.lo
CC libcurl_la-connect.lo
CC libcurl_la-content_encoding.lo
CC libcurl_la-cookie.lo
CC libcurl_la-curl_addrinfo.lo
CC libcurl_la-curl_des.lo
CC libcurl_la-curl_endian.lo
CC libcurl_la-curl_fnmatch.lo
CC libcurl_la-curl_get_line.lo
CC libcurl_la-curl_gethostname.lo
CC libcurl_la-curl_gssapi.lo
CC libcurl_la-curl_memrchr.lo
CC libcurl_la-curl_multibyte.lo
CC libcurl_la-curl_ntlm_core.lo
CC libcurl_la-curl_range.lo
CC libcurl_la-curl_rtmp.lo
CC libcurl_la-curl_sasl.lo
CC libcurl_la-curl_sha512_256.lo
CC libcurl_la-curl_sspi.lo
CC libcurl_la-curl_threads.lo
CC libcurl_la-curl_trc.lo
CC libcurl_la-cw-out.lo
CC libcurl_la-dict.lo
CC libcurl_la-dllmain.lo
CC libcurl_la-doh.lo
CC libcurl_la-dynbuf.lo
CC libcurl_la-dynhds.lo
CC libcurl_la-easy.lo
CC libcurl_la-easygetopt.lo
CC libcurl_la-easyoptions.lo
CC libcurl_la-escape.lo
CC libcurl_la-file.lo
CC libcurl_la-fileinfo.lo
CC libcurl_la-fopen.lo
CC libcurl_la-formdata.lo
CC libcurl_la-ftp.lo
CC libcurl_la-ftplistparser.lo
CC libcurl_la-getenv.lo
CC libcurl_la-getinfo.lo
CC libcurl_la-gopher.lo
CC libcurl_la-hash.lo
CC libcurl_la-headers.lo
CC libcurl_la-hmac.lo
CC libcurl_la-hostasyn.lo
CC libcurl_la-hostip.lo
CC libcurl_la-hostip4.lo
CC libcurl_la-hostip6.lo
CC libcurl_la-hostsyn.lo
CC libcurl_la-hsts.lo
CC libcurl_la-http.lo
CC libcurl_la-http1.lo
CC libcurl_la-http2.lo
CC libcurl_la-http_aws_sigv4.lo
CC libcurl_la-http_chunks.lo
CC libcurl_la-http_digest.lo
CC libcurl_la-http_negotiate.lo
CC libcurl_la-http_ntlm.lo
CC libcurl_la-http_proxy.lo
CC libcurl_la-idn.lo
CC libcurl_la-if2ip.lo
CC libcurl_la-imap.lo
CC libcurl_la-inet_ntop.lo
CC libcurl_la-inet_pton.lo
CC libcurl_la-krb5.lo
CC libcurl_la-ldap.lo
CC libcurl_la-llist.lo
CC libcurl_la-macos.lo
CC libcurl_la-md4.lo
CC libcurl_la-md5.lo
CC libcurl_la-memdebug.lo
CC libcurl_la-mime.lo
CC libcurl_la-mprintf.lo
CC libcurl_la-mqtt.lo
CC libcurl_la-multi.lo
CC libcurl_la-netrc.lo
CC libcurl_la-nonblock.lo
CC libcurl_la-noproxy.lo
CC libcurl_la-openldap.lo
CC libcurl_la-parsedate.lo
CC libcurl_la-pingpong.lo
CC libcurl_la-pop3.lo
CC libcurl_la-progress.lo
CC libcurl_la-psl.lo
CC libcurl_la-rand.lo
CC libcurl_la-rename.lo
CC libcurl_la-request.lo
CC libcurl_la-rtsp.lo
CC libcurl_la-select.lo
CC libcurl_la-sendf.lo
CC libcurl_la-setopt.lo
CC libcurl_la-sha256.lo
CC libcurl_la-share.lo
CC libcurl_la-slist.lo
CC libcurl_la-smb.lo
CC libcurl_la-smtp.lo
CC libcurl_la-socketpair.lo
CC libcurl_la-socks.lo
CC libcurl_la-socks_gssapi.lo
CC libcurl_la-speedcheck.lo
CC libcurl_la-socks_sspi.lo
CC libcurl_la-splay.lo
CC libcurl_la-strcase.lo
CC libcurl_la-strdup.lo
CC libcurl_la-strerror.lo
CC libcurl_la-strparse.lo
CC libcurl_la-strtok.lo
CC libcurl_la-system_win32.lo
CC libcurl_la-strtoofft.lo
CC libcurl_la-telnet.lo
CC libcurl_la-tftp.lo
CC libcurl_la-timediff.lo
CC libcurl_la-timeval.lo
CC libcurl_la-transfer.lo
CC libcurl_la-url.lo
CC libcurl_la-urlapi.lo
CC libcurl_la-version.lo
CC libcurl_la-version_win32.lo
CC libcurl_la-warnless.lo
CC libcurl_la-ws.lo
CC vauth/libcurl_la-cleartext.lo
CC vauth/libcurl_la-cram.lo
CC vauth/libcurl_la-digest.lo
CC vauth/libcurl_la-digest_sspi.lo
CC vauth/libcurl_la-gsasl.lo
CC vauth/libcurl_la-krb5_gssapi.lo
CC vauth/libcurl_la-krb5_sspi.lo
CC vauth/libcurl_la-ntlm.lo
CC vauth/libcurl_la-ntlm_sspi.lo
CC vauth/libcurl_la-oauth2.lo
CC vauth/libcurl_la-spnego_gssapi.lo
CC vauth/libcurl_la-spnego_sspi.lo
CC vauth/libcurl_la-vauth.lo
CC vtls/libcurl_la-bearssl.lo
CC vtls/libcurl_la-cipher_suite.lo
CC vtls/libcurl_la-gtls.lo
CC vtls/libcurl_la-hostcheck.lo
CC vtls/libcurl_la-keylog.lo
CC vtls/libcurl_la-mbedtls.lo
CC vtls/libcurl_la-mbedtls_threadlock.lo
CC vtls/libcurl_la-openssl.lo
CC vtls/libcurl_la-rustls.lo
CC vtls/libcurl_la-schannel.lo
CC vtls/libcurl_la-schannel_verify.lo
CC vtls/libcurl_la-sectransp.lo
CC vtls/libcurl_la-vtls.lo
CC vtls/libcurl_la-vtls_scache.lo
CC vtls/libcurl_la-wolfssl.lo
CC vtls/libcurl_la-x509asn1.lo
CC vquic/libcurl_la-curl_msh3.lo
CC vquic/libcurl_la-curl_ngtcp2.lo
CC vquic/libcurl_la-curl_osslq.lo
CC vquic/libcurl_la-curl_quiche.lo
CC vquic/libcurl_la-vquic.lo
CC vquic/libcurl_la-vquic-tls.lo
CC vssh/libcurl_la-libssh.lo
CC vssh/libcurl_la-libssh2.lo
CC vssh/libcurl_la-curl_path.lo
CC vssh/libcurl_la-wolfssh.lo
CCLD libcurl.la
make[2]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/lib'
make[1]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/lib'
Making all in docs
make[1]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs'
Making all in .
make[2]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs'
make[2]: Nothing to be done for 'all-am'.
make[2]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs'
Making all in cmdline-opts
make[2]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs/cmdline-opts'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs/cmdline-opts'
Making all in libcurl
make[2]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl'
Making all in opts
make[3]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl/opts'
make[3]: Nothing to be done for 'all'.
make[3]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl/opts'
make[3]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl'
make[3]: Nothing to be done for 'all-am'.
make[3]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl'
make[2]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs/libcurl'
make[1]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/docs'
Making all in src
make[1]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/src'
CC slist_wc.o
CC terminal.o
CC tool_binmode.o
CC tool_bname.o
CC tool_cb_dbg.o
CC tool_cb_hdr.o
CC tool_cb_prg.o
CC tool_cb_rea.o
CC tool_cb_see.o
CC tool_cb_soc.o
CC tool_cb_wrt.o
CC tool_cfgable.o
CC tool_dirhie.o
CC tool_doswin.o
CC tool_easysrc.o
CC tool_filetime.o
CC tool_findfile.o
CC tool_formparse.o
CC tool_getparam.o
CC tool_getpass.o
CC tool_help.o
CC tool_helpers.o
echo '#include "tool_hugehelp.h"' >> tool_hugehelp.c
CC tool_ipfs.o
CC tool_libinfo.o
CC tool_listhelp.o
CC tool_main.o
CC tool_msgs.o
CC tool_operate.o
CC tool_operhlp.o
CC tool_paramhlp.o
CC tool_parsecfg.o
CC tool_progress.o
CC tool_setopt.o
CC tool_sleep.o
CC tool_stderr.o
CC tool_strdup.o
CC tool_urlglob.o
CC tool_util.o
CC tool_vms.o
CC tool_writeout.o
CC tool_writeout_json.o
CC tool_xattr.o
CC var.o
echo 'extern const void *curl_ca_embed; const void *curl_ca_embed;' > tool_ca_embed.c
CC tool_hugehelp.o
CC tool_ca_embed.o
CC ../lib/base64.o
CC ../lib/curl_multibyte.o
CC ../lib/dynbuf.o
CC ../lib/nonblock.o
CC ../lib/strtoofft.o
CC ../lib/timediff.o
CC ../lib/version_win32.o
CC ../lib/warnless.o
CCLD curl
make[1]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/src'
Making all in scripts
make[1]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0/scripts'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0/scripts'
make[1]: Entering directory '/root/asi_db/builds/curl/_worktrees/w0'
make[1]: Nothing to be done for 'all-am'.
make[1]: Leaving directory '/root/asi_db/builds/curl/_worktrees/w0'
| @@ -57,6 +57,7 @@ INTERNALDOCS = \ | |
| internals/README.md \ | |
| internals/SPLAY.md \ | |
| internals/STRPARSE.md \ | |
| + | internals/TLS-SESSIONS.md \ |
| internals/WEBSOCKET.md | |
| EXTRA_DIST = \ | |
| @@ -132,3 +132,14 @@ CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t len); | |
| Sets the new shorter length of the buffer in number of bytes. Keeps the | |
| leftmost set number of bytes, discards the rest. To instead keep the tail part | |
| of the buffer, see `Curl_dyn_tail()`. | |
| + | |
| + | ## `Curl_dyn_take` |
| + | |
| + | ```c |
| + | char *Curl_dyn_take(struct dynbuf *s, size_t *plen); |
| + | ``` |
| + | |
| + | Transfers ownership of the internal buffer to the caller. The dynbuf |
| + | resets to its initial state. The returned pointer may be `NULL` if the |
| + | dynbuf never allocated memory. The returned length is the amount of |
| + | data written to the buffer. The actual allocated memory might be larger. |
| @@ -64,7 +64,13 @@ See also `Curl_llist_insert_next`. | |
| ## Remove a node | |
| - | Remove a node again from a list by calling `Curl_llist_remove()`. |
| + | Remove a node again from a list by calling `Curl_llist_remove()`. This |
| + | will destroy the node's `elem` (e.g. calling a registered free function). |
| + | |
| + | To remove a node without destroying it's `elem`, use |
| + | `Curl_node_take_elem()` which returns the `elem` pointer and |
| + | removes the node from the list. The caller then owns this pointer |
| + | and has to take care of it. |
| ## Iterate | |
| @@ -0,0 +1,168 @@ | |
| + | <!-- |
| + | Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | |
| + | SPDX-License-Identifier: curl |
| + | --> |
| + | |
| + | # TLS Sessions and Tickets |
| + | |
| + | The TLS protocol offers methods of "resuming" a previous "session". A |
| + | TLS "session" is a negotiated security context across a connection |
| + | (which may be via TCP or UDP or other transports.) |
| + | |
| + | By "resuming", the TLS protocol means that the security context from |
| + | before can be fully or partially resurrected when the TLS client presents |
| + | the proper crypto stuff to the server. This saves on the amount of |
| + | TLS packets that need to be sent back and forth, reducing amount |
| + | of data and even latency. In the case of QUIC, resumption may send |
| + | application data without having seen any reply from the server, hence |
| + | this is named 0-RTT data. |
| + | |
| + | The exact mechanism of session tickets in TLSv1.2 (and earlier) and |
| + | TLSv1.3 differs. TLSv1.2 tickets have several weaknesses (that can |
| + | be exploited by attackers) which TLSv1.3 then fixed. See |
| + | [Session Tickets in the real world](https://words.filippo.io/we-need-to-talk-about-session-tickets/) |
| + | for an insight into this topic. |
| + | |
| + | These difference between TLS protocol versions are reflected in curl's |
| + | handling of session tickets. More below. |
| + | |
| + | ## Curl's `ssl_peer_key` |
| + | |
| + | In order to find a ticket from a previous TLS session, curl |
| + | needs a name for TLS sessions that uniquely identifies the peer |
| + | it talks to. |
| + | |
| + | This name has to reflect also the various TLS parameters that can |
| + | be configured in curl for a connection. We do not want to use |
| + | a ticket from an different configuration. Example: when setting |
| + | the maximum TLS version to 1.2, we do not want to reuse a ticket |
| + | we got from a TLSv1.3 session, although we are talking to the |
| + | same host. |
| + | |
| + | Internally, we call this name a `ssl_peer_key`. It is a printable |
| + | string that carries hostname and port and any non-default TLS |
| + | parameters involved in the connection. |
| + | |
| + | Examples: |
| + | - `curl.se:443:CA-/etc/ssl/cert.pem:IMPL-GnuTLS/3.8.7` is a peer key for |
| + | a connection to `curl.se:443` using `/etc/ssl/cert.pem` as CA |
| + | trust anchors and GnuTLS/3.8.7 as TLS backend. |
| + | - `curl.se:443:TLSVER-6-6:CA-/etc/ssl/cert.pem:IMPL-GnuTLS/3.8.7` is the |
| + | same as the previous, except it is configured to use TLSv1.2 as |
| + | min and max versions. |
| + | |
| + | Different configurations produce different keys which is just what |
| + | curl needs when handling SSL session tickets. |
| + | |
| + | One important thing: peer keys do not contain confidential |
| + | information. If you configure a client certificate or SRP authentication |
| + | with username/password, these will not be part of the peer key. |
| + | |
| + | However, peer keys carry the hostnames you use curl for. The *do* |
| + | leak the privacy of your communication. We recommend to *not* persist |
| + | peer keys for this reason. |
| + | |
| + | **Caveat**: The key may contain file names or paths. It does not |
| + | reflect the *contents* in the filesystem. If you change `/etc/ssl/cert.pem` |
| + | and reuse a previous ticket, curl might trust a server which no |
| + | longer has a root certificate in the file. |
| + | |
| + | |
| + | ## Session Cache Access |
| + | |
| + | #### Lookups |
| + | |
| + | When a new connection is being established, each SSL connection filter creates |
| + | its own peer_key and calls into the cache. The cache then looks for a ticket |
| + | with exactly this peer_key. Peer keys between proxy SSL filters and SSL |
| + | filters talking through a tunnel will differ, as they talk to different |
| + | peers. |
| + | |
| + | If the connection filter wants to use a client certificate or SRP |
| + | authentication, the cache will check those as well. If the cache peer |
| + | carries client cert or SRP auth, the connection filter must have |
| + | those with the same values (and vice versa). |
| + | |
| + | On a match, the connection filter gets the session ticket and feeds that |
| + | to the TLS implementation which, on accepting it, will try to resume it |
| + | for a shorter handshake. In addition, the filter gets the ALPN used |
| + | before and the amount of 0-RTT data that the server announced to be |
| + | willing to accept. The filter can then decide if it wants to attempt |
| + | 0-RTT or not. (The ALPN is needed to know if the server speaks the |
| + | protocol you want to send in 0-RTT. It makes no sense to send HTTP/2 |
| + | requests to a server that only knows HTTP/1.1.) |
| + | |
| + | #### Updates |
| + | |
| + | When a new TLS session ticket is received by a filter, it adds it to the |
| + | cache using its peer_key and SSL configuration. The cache looks for |
| + | a matching entry and, should it find one, adds the ticket for this |
| + | peer. |
| + | |
| + | ### Put, Take and Return |
| + | |
| + | when a filter accesses the session cache, it *takes* |
| + | a ticket from the cache, meaning a returned ticket is removed. The filter |
| + | then configures its TLS backend and *returns* the ticket to the cache. |
| + | |
| + | The cache needs to treat tickets from TLSv1.2 and 1.3 differently. |
| + | 1.2 tickets should be reused, but 1.3 tickets SHOULD NOT (RFC 8446). |
| + | The session cache will simply drop 1.3 tickets when they are returned |
| + | after use, but keep a 1.2 ticket. |
| + | |
| + | When a ticket is *put* into the cache, there is also a difference. There |
| + | can be several 1.3 tickets at the same time, but only a single 1.2 ticket. |
| + | TLSv1.2 tickets replace any other. 1.3 tickets accumulate up to a max |
| + | amount. |
| + | |
| + | By having a "put/take/return" we reflect the 1.3 use case nicely. Two |
| + | concurrent connections will not reuse the same ticket. |
| + | |
| + | ## Session Ticket Persistence |
| + | |
| + | #### Privacy and Security |
| + | |
| + | As mentioned above, ssl peer keys are not intended for storage in a |
| + | file system. They'll clearly show which hosts the user talked to. This |
| + | maybe "just" privacy relevant, but has security implications as an |
| + | attacker might find worthy targets among your peer keys. |
| + | |
| + | Also, we do not recommend to persist TLSv1.2 tickets. |
| + | |
| + | ### Salted Hashes |
| + | |
| + | The TLS session cache offers an alternative to storing peer keys: |
| + | it provides a salted SHA256 hash of the peer key for import and export. |
| + | |
| + | #### Export |
| + | |
| + | The salt is generated randomly for each peer key on export. The |
| + | SHA256 makes sure that the peer key cannot be reversed and that |
| + | a slightly different key still produces a very different result. |
| + | |
| + | This means an attacker cannot just "grep" a session file for a |
| + | particular entry, e.g. if they want to know if you accessed a |
| + | specific host. They *can* however compute the SHA256 hashes for |
| + | all salts in the file and find a specific entry. But they *cannot* |
| + | find a hostname they do not know. They'd have to brute force by |
| + | guessing. |
| + | |
| + | #### Import |
| + | |
| + | When session tickets are imported from a file, curl only gets the |
| + | salted hashes. The tickets imported will belong to an *unknown* |
| + | peer key. |
| + | |
| + | When a connection filter tries to *take* a session ticket, it will |
| + | pass its peer key. This peer key will initially not match any |
| + | tickets in the cache. The cache then checks all entries with |
| + | unknown peer keys if the passed key matches their salted hash. If |
| + | it does, the peer key is recovered and remembered at the cache |
| + | entry. |
| + | |
| + | This is a performance penalty in the order of "unknown" peer keys |
| + | which will diminish over time when keys are rediscovered. Note that |
| + | this also works for putting a new ticket into the cache: when no |
| + | present entry matches, a new one with peer key is created. This |
| + | peer key will then no longer bear the cost of hash computes. |
| @@ -56,6 +56,7 @@ LIB_VTLS_CFILES = \ | |
| vtls/schannel_verify.c \ | |
| vtls/sectransp.c \ | |
| vtls/vtls.c \ | |
| + | vtls/vtls_scache.c \ |
| vtls/wolfssl.c \ | |
| vtls/x509asn1.c | |
| @@ -74,6 +75,7 @@ LIB_VTLS_HFILES = \ | |
| vtls/sectransp.h \ | |
| vtls/vtls.h \ | |
| vtls/vtls_int.h \ | |
| + | vtls/vtls_scache.h \ |
| vtls/wolfssl.h \ | |
| vtls/x509asn1.h | |
| @@ -244,6 +244,18 @@ char *Curl_dyn_ptr(const struct dynbuf *s) | |
| return s->bufr; | |
| } | |
| + | char *Curl_dyn_take(struct dynbuf *s, size_t *plen) |
| + | { |
| + | char *ptr = s->bufr; |
| + | DEBUGASSERT(s); |
| + | DEBUGASSERT(s->init == DYNINIT); |
| + | *plen = s->leng; |
| + | s->bufr = NULL; |
| + | s->leng = 0; |
| + | s->allc = 0; |
| + | return ptr; |
| + | } |
| + | |
| /* | |
| * Returns an unsigned pointer to the buffer. | |
| */ | |
| @@ -39,6 +39,7 @@ | |
| #define Curl_dyn_uptr(a) curlx_dyn_uptr(a) | |
| #define Curl_dyn_len(a) curlx_dyn_len(a) | |
| #define Curl_dyn_reset(a) curlx_dyn_reset(a) | |
| + | #define Curl_dyn_take(a,b) curlx_dyn_take(a,b) |
| #define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b) | |
| #define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b) | |
| #define curlx_dynbuf dynbuf /* for the struct name */ | |
| @@ -75,6 +76,10 @@ size_t Curl_dyn_len(const struct dynbuf *s); | |
| /* The implementation of this function exists in mprintf.c */ | |
| int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save); | |
| + | /* Take the buffer out of the dynbuf. Caller has ownership and |
| + | * dynbuf resets to initial state. */ |
| + | char *Curl_dyn_take(struct dynbuf *s, size_t *plen); |
| + | |
| /* Dynamic buffer max sizes */ | |
| #define DYN_DOH_RESPONSE 3000 | |
| #define DYN_DOH_CNAME 256 | |
| @@ -134,16 +134,12 @@ Curl_llist_append(struct Curl_llist *list, const void *p, | |
| Curl_llist_insert_next(list, list->_tail, p, ne); | |
| } | |
| - | /* |
| - | * @unittest: 1300 |
| - | */ |
| - | void |
| - | Curl_node_uremove(struct Curl_llist_node *e, void *user) |
| + | void *Curl_node_take_elem(struct Curl_llist_node *e) |
| { | |
| void *ptr; | |
| struct Curl_llist *list; | |
| if(!e) | |
| - | return; |
| + | return NULL; |
| list = e->_list; | |
| DEBUGASSERT(list); | |
| @@ -179,8 +175,23 @@ Curl_node_uremove(struct Curl_llist_node *e, void *user) | |
| #endif | |
| --list->_size; | |
| + | return ptr; |
| + | } |
| + | |
| + | /* |
| + | * @unittest: 1300 |
| + | */ |
| + | void |
| + | Curl_node_uremove(struct Curl_llist_node *e, void *user) |
| + | { |
| + | struct Curl_llist *list; |
| + | void *ptr; |
| + | if(!e) |
| + | return; |
| - | /* call the dtor() last for when it actually frees the 'e' memory itself */ |
| + | list = e->_list; |
| + | DEBUGASSERT(list); |
| + | ptr = Curl_node_take_elem(e); |
| if(list->_dtor) | |
| list->_dtor(user, ptr); | |
| } | |
| @@ -75,6 +75,10 @@ size_t Curl_llist_count(struct Curl_llist *list); | |
| /* Curl_node_elem() returns the custom data from a Curl_llist_node */ | |
| void *Curl_node_elem(struct Curl_llist_node *n); | |
| + | /* Remove the node from the list and return the custom data |
| + | * from a Curl_llist_node. Will NOT incoke a registered `dtor`. */ |
| + | void *Curl_node_take_elem(struct Curl_llist_node *); |
| + | |
| /* Curl_node_next() returns the next element in a list from a given | |
| Curl_llist_node */ | |
| struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n); | |
| @@ -1588,8 +1588,8 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, | |
| data->hsts = NULL; | |
| #endif | |
| #ifdef USE_SSL | |
| - | if(data->share->sslsession == data->state.session) |
| - | data->state.session = NULL; |
| + | if(data->share->ssl_scache == data->state.ssl_scache) |
| + | data->state.ssl_scache = NULL; |
| #endif | |
| #ifdef USE_LIBPSL | |
| if(data->psl == &data->share->psl) | |
| @@ -1632,10 +1632,8 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, | |
| } | |
| #endif | |
| #ifdef USE_SSL | |
| - | if(data->share->sslsession) { |
| - | data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; |
| - | data->state.session = data->share->sslsession; |
| - | } |
| + | if(data->share->ssl_scache) |
| + | data->state.ssl_scache = data->share->ssl_scache; |
| #endif | |
| #ifdef USE_LIBPSL | |
| if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) | |
| @@ -30,6 +30,7 @@ | |
| #include "share.h" | |
| #include "psl.h" | |
| #include "vtls/vtls.h" | |
| + | #include "vtls/vtls_scache.h" |
| #include "hsts.h" | |
| #include "url.h" | |
| @@ -108,12 +109,8 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) | |
| case CURL_LOCK_DATA_SSL_SESSION: | |
| #ifdef USE_SSL | |
| - | if(!share->sslsession) { |
| - | share->max_ssl_sessions = 8; |
| - | share->sslsession = calloc(share->max_ssl_sessions, |
| - | sizeof(struct Curl_ssl_session)); |
| - | share->sessionage = 0; |
| - | if(!share->sslsession) |
| + | if(!share->ssl_scache) { |
| + | if(Curl_ssl_scache_create(8, 2, &share->ssl_scache)) |
| res = CURLSHE_NOMEM; | |
| } | |
| #else | |
| @@ -174,7 +171,10 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) | |
| case CURL_LOCK_DATA_SSL_SESSION: | |
| #ifdef USE_SSL | |
| - | Curl_safefree(share->sslsession); |
| + | if(share->ssl_scache) { |
| + | Curl_ssl_scache_destroy(share->ssl_scache); |
| + | share->ssl_scache = NULL; |
| + | } |
| #else | |
| res = CURLSHE_NOT_BUILT_IN; | |
| #endif | |
| @@ -245,11 +245,9 @@ curl_share_cleanup(CURLSH *sh) | |
| #endif | |
| #ifdef USE_SSL | |
| - | if(share->sslsession) { |
| - | size_t i; |
| - | for(i = 0; i < share->max_ssl_sessions; i++) |
| - | Curl_ssl_kill_session(&(share->sslsession[i])); |
| - | free(share->sslsession); |
| + | if(share->ssl_scache) { |
| + | Curl_ssl_scache_destroy(share->ssl_scache); |
| + | share->ssl_scache = NULL; |
| } | |
| #endif | |
| @@ -31,6 +31,8 @@ | |
| #include "urldata.h" | |
| #include "conncache.h" | |
| + | struct Curl_ssl_scache; |
| + | |
| #define CURL_GOOD_SHARE 0x7e117a1e | |
| #define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE) | |
| @@ -58,9 +60,7 @@ struct Curl_share { | |
| struct hsts *hsts; | |
| #endif | |
| #ifdef USE_SSL | |
| - | struct Curl_ssl_session *sslsession; |
| - | size_t max_ssl_sessions; |
| - | long sessionage; |
| + | struct Curl_ssl_scache *ssl_scache; |
| #endif | |
| }; | |
| @@ -68,4 +68,9 @@ CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, | |
| curl_lock_access); | |
| CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data); | |
| + | /* convenience macro to check if this handle is using a shared SSL spool */ |
| + | #define CURL_SHARE_ssl_scache(data) (data->share && \ |
| + | (data->share->specifier & \ |
| + | (1<<CURL_LOCK_DATA_SSL_SESSION))) |
| + | |
| #endif /* HEADER_CURL_SHARE_H */ | |
| @@ -72,6 +72,7 @@ | |
| #include "url.h" | |
| #include "getinfo.h" | |
| #include "vtls/vtls.h" | |
| + | #include "vtls/vtls_scache.h" |
| #include "vquic/vquic.h" | |
| #include "select.h" | |
| #include "multiif.h" | |
| @@ -538,7 +539,7 @@ void Curl_init_CONNECT(struct Curl_easy *data) | |
| */ | |
| CURLcode Curl_pretransfer(struct Curl_easy *data) | |
| { | |
| - | CURLcode result; |
| + | CURLcode result = CURLE_OK; |
| if(!data->state.url && !data->set.uh) { | |
| /* we cannot do anything without URL */ | |
| @@ -577,12 +578,14 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) | |
| data->state.httpreq = data->set.method; | |
| data->state.url = data->set.str[STRING_SET_URL]; | |
| - | /* Init the SSL session ID cache here. We do it here since we want to do it |
| - | after the *_setopt() calls (that could specify the size of the cache) but |
| - | before any transfer takes place. */ |
| - | result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); |
| - | if(result) |
| - | return result; |
| + | #ifdef USE_SSL |
| + | if(!data->state.ssl_scache) { |
| + | result = Curl_ssl_scache_create(data->set.general_ssl.max_ssl_sessions, |
| + | 2, &data->state.ssl_scache); |
| + | if(result) |
| + | return result; |
| + | } |
| + | #endif |
| data->state.requests = 0; | |
| data->state.followlocation = 0; /* reset the location-follow counter */ | |
| @@ -271,21 +271,7 @@ enum protection_level { | |
| /* SSL backend-specific data; declared differently by each SSL backend */ | |
| struct ssl_backend_data; | |
| - | |
| - | typedef enum { |
| - | CURL_SSL_PEER_DNS, |
| - | CURL_SSL_PEER_IPV4, |
| - | CURL_SSL_PEER_IPV6 |
| - | } ssl_peer_type; |
| - | |
| - | struct ssl_peer { |
| - | char *hostname; /* hostname for verification */ |
| - | char *dispname; /* display version of hostname */ |
| - | char *sni; /* SNI version of hostname or NULL if not usable */ |
| - | ssl_peer_type type; /* type of the peer information */ |
| - | int port; /* port we are talking to */ |
| - | int transport; /* one of TRNSPRT_* defines */ |
| - | }; |
| + | struct Curl_ssl_scache_entry; |
| struct ssl_primary_config { | |
| char *CApath; /* certificate dir (does not work on Windows) */ | |
| @@ -341,24 +327,6 @@ struct ssl_general_config { | |
| int ca_cache_timeout; /* Certificate store cache timeout (seconds) */ | |
| }; | |
| - | typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize); |
| - | |
| - | /* information stored about one single SSL session */ |
| - | struct Curl_ssl_session { |
| - | char *name; /* hostname for which this ID was used */ |
| - | char *conn_to_host; /* hostname for the connection (may be NULL) */ |
| - | const char *scheme; /* protocol scheme used */ |
| - | char *alpn; /* APLN TLS negotiated protocol string */ |
| - | void *sessionid; /* as returned from the SSL layer */ |
| - | size_t idsize; /* if known, otherwise 0 */ |
| - | Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */ |
| - | long age; /* just a number, the higher the more recent */ |
| - | int remote_port; /* remote port */ |
| - | int conn_to_port; /* remote port for the connection (may be -1) */ |
| - | int transport; /* TCP or QUIC */ |
| - | struct ssl_primary_config ssl_config; /* setup for this session */ |
| - | }; |
| - | |
| #ifdef USE_WINDOWS_SSPI | |
| #include "curl_sspi.h" | |
| #endif | |
| @@ -1232,8 +1200,7 @@ struct UrlState { | |
| curl_prot_t first_remote_protocol; | |
| int retrycount; /* number of retries on a new connection */ | |
| - | struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ |
| - | long sessionage; /* number of the most recent session */ |
| + | struct Curl_ssl_scache *ssl_scache; /* TLS session pool */ |
| int os_errno; /* filled in with errno whenever an error occurs */ | |
| long followlocation; /* redirect counter */ | |
| int requests; /* request counter: redirects + authentication retakes */ | |
| @@ -2131,7 +2131,8 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) | |
| ctx = cf ? cf->ctx : NULL; | |
| data = cf ? CF_DATA_CURRENT(cf) : NULL; | |
| if(cf && data && ctx) { | |
| - | Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid); |
| + | Curl_ossl_add_session(cf, data, ctx->peer.scache_key, ssl_sessionid, |
| + | SSL_version(ssl), "h3"); |
| return 1; | |
| } | |
| return 0; | |
| @@ -2158,7 +2159,8 @@ static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype, | |
| } | |
| switch(htype) { | |
| case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: { | |
| - | (void)Curl_gtls_update_session_id(cf, data, session, &ctx->peer, "h3"); |
| + | (void)Curl_gtls_cache_session(cf, data, ctx->peer.scache_key, |
| + | session, -1, "h3"); |
| break; | |
| } | |
| default: | |
| @@ -2181,7 +2183,8 @@ static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) | |
| struct Curl_easy *data = CF_DATA_CURRENT(cf); | |
| DEBUGASSERT(data); | |
| if(data && ctx) { | |
| - | (void)wssl_cache_session(cf, data, &ctx->peer, session); |
| + | (void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key, |
| + | session, wolfSSL_version(ssl), "h3"); |
| } | |
| } | |
| return 0; | |
| @@ -2258,10 +2261,6 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, | |
| int qfd; | |
| DEBUGASSERT(ctx->initialized); | |
| - | result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); |
| - | if(result) |
| - | return result; |
| - | |
| #define H3_ALPN "\x2h3\x5h3-29" | |
| result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, | |
| H3_ALPN, sizeof(H3_ALPN) - 1, | |
| @@ -1162,9 +1162,6 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, | |
| BIO_ADDR *baddr = NULL; | |
| DEBUGASSERT(ctx->initialized); | |
| - | result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); |
| - | if(result) |
| - | goto out; |
| #define H3_ALPN "\x2h3" | |
| result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, | |
| @@ -1278,10 +1278,6 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, | |
| if(result) | |
| return result; | |
| - | result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); |
| - | if(result) |
| - | return result; |
| - | |
| ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION); | |
| if(!ctx->cfg) { | |
| failf(data, "cannot create quiche config"); | |
| @@ -50,6 +50,7 @@ | |
| #include "multiif.h" | |
| #include "vtls/keylog.h" | |
| #include "vtls/vtls.h" | |
| + | #include "vtls/vtls_scache.h" |
| #include "vquic-tls.h" | |
| /* The last 3 #include files should be in this order */ | |
| @@ -221,7 +222,7 @@ static CURLcode wssl_init_ssl(struct curl_tls_ctx *ctx, | |
| } | |
| if(ssl_config->primary.cache_session) { | |
| - | (void)wssl_setup_session(cf, data, &ctx->wssl, peer); |
| + | (void)Curl_wssl_setup_session(cf, data, &ctx->wssl, peer->scache_key); |
| } | |
| return CURLE_OK; | |
| @@ -236,11 +237,26 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx, | |
| Curl_vquic_tls_ctx_setup *cb_setup, | |
| void *cb_user_data, void *ssl_user_data) | |
| { | |
| + | char tls_id[80]; |
| CURLcode result; | |
| + | #ifdef USE_OPENSSL |
| + | Curl_ossl_version(tls_id, sizeof(tls_id)); |
| + | #elif defined(USE_GNUTLS) |
| + | Curl_gtls_version(tls_id, sizeof(tls_id)); |
| + | #elif defined(USE_WOLFSSL) |
| + | Curl_wssl_version(tls_id, sizeof(tls_id)); |
| + | #else |
| + | #error "no TLS lib in used, should not happen" |
| + | return CURLE_FAILED_INIT; |
| + | #endif |
| + | result = Curl_ssl_peer_init(peer, cf, tls_id, TRNSPRT_QUIC); |
| + | if(result) |
| + | return result; |
| + | |
| #ifdef USE_OPENSSL | |
| (void)result; | |
| - | return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, TRNSPRT_QUIC, |
| + | return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, |
| (const unsigned char *)alpn, alpn_len, | |
| cb_setup, cb_user_data, NULL, ssl_user_data); | |
| #elif defined(USE_GNUTLS) | |
| @@ -346,6 +362,9 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, | |
| } | |
| #endif | |
| + | /* on error, remove any session we might have in the pool */ |
| + | if(result) |
| + | Curl_ssl_scache_remove_all(cf, data, peer->scache_key); |
| return result; | |
| } | |
| @@ -26,6 +26,7 @@ | |
| #include "curl_setup.h" | |
| #include "bufq.h" | |
| + | #include "vtls/vtls.h" |
| #include "vtls/openssl.h" | |
| #if defined(USE_HTTP3) && \ | |
| @@ -33,6 +34,8 @@ | |
| #include "vtls/wolfssl.h" | |
| + | struct ssl_peer; |
| + | |
| struct curl_tls_ctx { | |
| #ifdef USE_OPENSSL | |
| struct ossl_ctx ossl; | |
| @@ -34,6 +34,7 @@ | |
| #include "inet_pton.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "connect.h" | |
| #include "select.h" | |
| #include "multiif.h" | |
| @@ -609,20 +610,19 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, | |
| br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); | |
| if(ssl_config->primary.cache_session) { | |
| - | void *sdata; |
| - | size_t slen; |
| + | struct Curl_ssl_session *sc_session = NULL; |
| const br_ssl_session_parameters *session; | |
| - | CURL_TRC_CF(data, cf, "connect_step1, check session cache"); |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &sdata, &slen, NULL) && |
| - | slen == sizeof(*session)) { |
| - | session = sdata; |
| + | ret = Curl_ssl_scache_take(cf, data, connssl->peer.scache_key, |
| + | &sc_session); |
| + | if(!ret && sc_session && sc_session->sdata && sc_session->sdata_len) { |
| + | session = (br_ssl_session_parameters *)(void *)sc_session->sdata; |
| br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); | |
| session_set = 1; | |
| infof(data, "BearSSL: reusing session ID"); | |
| + | /* single use of sessions */ |
| + | Curl_ssl_scache_return(cf, data, connssl->peer.scache_key, sc_session); |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| } | |
| if(connssl->alpn) { | |
| @@ -804,12 +804,6 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, | |
| return ret; | |
| } | |
| - | static void bearssl_session_free(void *sessionid, size_t idsize) |
| - | { |
| - | (void)idsize; |
| - | free(sessionid); |
| - | } |
| - | |
| static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, | |
| struct Curl_easy *data) | |
| { | |
| @@ -832,17 +826,22 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, | |
| } | |
| if(ssl_config->primary.cache_session) { | |
| + | struct Curl_ssl_session *sc_session; |
| br_ssl_session_parameters *session; | |
| session = malloc(sizeof(*session)); | |
| if(!session) | |
| return CURLE_OUT_OF_MEMORY; | |
| br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); | |
| - | Curl_ssl_sessionid_lock(data); |
| - | ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL, |
| - | session, sizeof(*session), |
| - | bearssl_session_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | ret = Curl_ssl_session_create((unsigned char *)session, sizeof(*session), |
| + | (int)session->version, |
| + | connssl->negotiated.alpn, |
| + | 0, -1, &sc_session); |
| + | if(!ret) { |
| + | ret = Curl_ssl_scache_put(cf, data, connssl->peer.scache_key, |
| + | sc_session); |
| + | /* took ownership of `sc_session` */ |
| + | } |
| if(ret) | |
| return ret; | |
| } | |
| @@ -47,6 +47,7 @@ | |
| #include "gtls.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "vauth/vauth.h" | |
| #include "parsedate.h" | |
| #include "connect.h" /* for the connect timeout */ | |
| @@ -714,21 +715,17 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf, | |
| return CURLE_OK; | |
| } | |
| - | static void gtls_sessionid_free(void *sessionid, size_t idsize) |
| - | { |
| - | (void)idsize; |
| - | free(sessionid); |
| - | } |
| - | |
| - | CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | gnutls_session_t session, |
| - | struct ssl_peer *peer, |
| - | const char *alpn) |
| + | CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | gnutls_session_t session, |
| + | int lifetime_secs, |
| + | const char *alpn) |
| { | |
| struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | |
| - | void *connect_sessionid; |
| - | size_t connect_idsize = 0; |
| + | struct Curl_ssl_session *sc_session; |
| + | unsigned char *sdata; |
| + | size_t sdata_len = 0; |
| CURLcode result = CURLE_OK; | |
| if(!ssl_config->primary.cache_session) | |
| @@ -740,35 +737,57 @@ CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf, | |
| detect that. */ | |
| /* get the session ID data size */ | |
| - | gnutls_session_get_data(session, NULL, &connect_idsize); |
| - | if(!connect_idsize) /* gnutls does this for some version combinations */ |
| + | gnutls_session_get_data(session, NULL, &sdata_len); |
| + | if(!sdata_len) /* gnutls does this for some version combinations */ |
| return CURLE_OK; | |
| - | connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ |
| - | if(!connect_sessionid) |
| + | sdata = malloc(sdata_len); /* get a buffer for it */ |
| + | if(!sdata) |
| return CURLE_OUT_OF_MEMORY; | |
| /* extract session ID to the allocated buffer */ | |
| - | gnutls_session_get_data(session, connect_sessionid, &connect_idsize); |
| + | gnutls_session_get_data(session, sdata, &sdata_len); |
| CURL_TRC_CF(data, cf, "get session id (len=%zu, alpn=%s) and store in cache", | |
| - | connect_idsize, alpn ? alpn : "-"); |
| - | Curl_ssl_sessionid_lock(data); |
| - | /* store this session id, takes ownership */ |
| - | result = Curl_ssl_set_sessionid(cf, data, peer, alpn, |
| - | connect_sessionid, connect_idsize, |
| - | gtls_sessionid_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | sdata_len, alpn ? alpn : "-"); |
| + | result = Curl_ssl_session_create(sdata, sdata_len, |
| + | Curl_glts_get_ietf_proto(session), |
| + | alpn, 0, lifetime_secs, |
| + | &sc_session); |
| + | /* call took ownership of `sdata`*/ |
| + | if(!result) { |
| + | result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session); |
| + | /* took ownership of `sc_session` */ |
| + | } |
| return result; | |
| } | |
| + | int Curl_glts_get_ietf_proto(gnutls_session_t session) |
| + | { |
| + | switch(gnutls_protocol_get_version(session)) { |
| + | case GNUTLS_SSL3: |
| + | return CURL_IETF_PROTO_SSL3; |
| + | case GNUTLS_TLS1_0: |
| + | return CURL_IETF_PROTO_TLS1; |
| + | case GNUTLS_TLS1_1: |
| + | return CURL_IETF_PROTO_TLS1_1; |
| + | case GNUTLS_TLS1_2: |
| + | return CURL_IETF_PROTO_TLS1_2; |
| + | case GNUTLS_TLS1_3: |
| + | return CURL_IETF_PROTO_TLS1_3; |
| + | default: |
| + | return CURL_IETF_PROTO_UNKNOWN; |
| + | } |
| + | } |
| + | |
| static CURLcode cf_gtls_update_session_id(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| gnutls_session_t session) | |
| { | |
| struct ssl_connect_data *connssl = cf->ctx; | |
| - | return Curl_gtls_update_session_id(cf, data, session, &connssl->peer, |
| - | connssl->alpn_negotiated); |
| + | return Curl_gtls_cache_session(cf, data, connssl->peer.scache_key, |
| + | session, -1, |
| + | connssl->negotiated.alpn); |
| } | |
| static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype, | |
| @@ -1058,9 +1077,11 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, | |
| { | |
| struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); | |
| struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | |
| + | struct Curl_ssl_session *scs = NULL; |
| gnutls_datum_t gtls_alpns[5]; | |
| size_t gtls_alpns_count = 0; | |
| CURLcode result; | |
| + | int rc; |
| DEBUGASSERT(gctx); | |
| @@ -1085,29 +1106,23 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, | |
| /* This might be a reconnect, so we check for a session ID in the cache | |
| to speed up things */ | |
| if(conn_config->cache_session) { | |
| - | void *ssl_sessionid; |
| - | size_t ssl_idsize; |
| - | char *session_alpn; |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, peer, |
| - | &ssl_sessionid, &ssl_idsize, &session_alpn)) { |
| - | /* we got a session id, use it! */ |
| - | int rc; |
| - | |
| - | rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize); |
| - | if(rc < 0) |
| - | infof(data, "SSL failed to set session ID"); |
| + | result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs); |
| + | if(result) |
| + | goto out; |
| + | |
| + | if(scs && scs->sdata && scs->sdata_len) { |
| + | /* we got a cached session, use it! */ |
| + | rc = gnutls_session_set_data(gctx->session, scs->sdata, scs->sdata_len); |
| + | if(rc < 0) { |
| + | infof(data, "SSL session not accepted by GnuTLS, continuing without"); |
| + | } |
| else { | |
| - | infof(data, "SSL reusing session ID (size=%zu, alpn=%s)", |
| - | ssl_idsize, session_alpn ? session_alpn : "-"); |
| - | #ifdef DEBUGBUILD |
| - | if((ssl_config->earlydata || !!getenv("CURL_USE_EARLYDATA")) && |
| - | #else |
| + | infof(data, "SSL reusing session with ALPN '%s'", |
| + | scs->alpn ? scs->alpn : "-"); |
| if(ssl_config->earlydata && | |
| - | #endif |
| !cf->conn->connect_only && connssl && | |
| (gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3) && | |
| - | Curl_alpn_contains_proto(connssl->alpn, session_alpn)) { |
| + | Curl_alpn_contains_proto(connssl->alpn, scs->alpn)) { |
| connssl->earlydata_max = | |
| gnutls_record_get_max_early_data_size(gctx->session); | |
| if((!connssl->earlydata_max || | |
| @@ -1118,24 +1133,32 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, | |
| else { | |
| CURL_TRC_CF(data, cf, "TLS session allows %zu earlydata bytes, " | |
| "reusing ALPN '%s'", | |
| - | connssl->earlydata_max, session_alpn); |
| + | connssl->earlydata_max, scs->alpn); |
| connssl->earlydata_state = ssl_earlydata_use; | |
| connssl->state = ssl_connection_deferred; | |
| result = Curl_alpn_set_negotiated(cf, data, connssl, | |
| - | (const unsigned char *)session_alpn, |
| - | session_alpn ? strlen(session_alpn) : 0); |
| + | (const unsigned char *)scs->alpn, |
| + | scs->alpn ? strlen(scs->alpn) : 0); |
| if(result) | |
| - | return result; |
| + | goto out; |
| /* We only try the ALPN protocol the session used before, | |
| * otherwise we might send early data for the wrong protocol */ | |
| - | gtls_alpns[0].data = (unsigned char *)session_alpn; |
| - | gtls_alpns[0].size = (unsigned)strlen(session_alpn); |
| - | gtls_alpns_count = 1; |
| + | gtls_alpns[0].data = (unsigned char *)scs->alpn; |
| + | gtls_alpns[0].size = (unsigned)strlen(scs->alpn); |
| + | if(gnutls_alpn_set_protocols(gctx->session, |
| + | gtls_alpns, 1, |
| + | GNUTLS_ALPN_MANDATORY)) { |
| + | failf(data, "failed setting ALPN"); |
| + | result = CURLE_SSL_CONNECT_ERROR; |
| + | goto out; |
| + | } |
| + | /* don't set again below */ |
| + | gtls_alpns_count = 0; |
| + | alpn = NULL; |
| } | |
| } | |
| } | |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| } | |
| /* convert the ALPN string from our arguments to a list of strings that | |
| @@ -1143,19 +1166,21 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, | |
| * to the server. nice. */ | |
| if(!gtls_alpns_count && alpn && alpn_len) { | |
| size_t i, alen = alpn_len; | |
| - | unsigned char *s = (unsigned char *)alpn; |
| + | unsigned char *salpn = (unsigned char *)alpn; |
| unsigned char slen; | |
| for(i = 0; (i < ARRAYSIZE(gtls_alpns)) && alen; ++i) { | |
| - | slen = s[0]; |
| + | slen = salpn[0]; |
| if(slen >= alen) | |
| return CURLE_FAILED_INIT; | |
| - | gtls_alpns[i].data = s + 1; |
| + | gtls_alpns[i].data = salpn + 1; |
| gtls_alpns[i].size = slen; | |
| - | s += slen + 1; |
| + | salpn += slen + 1; |
| alen -= (size_t)slen + 1; | |
| } | |
| - | if(alen) /* not all alpn chars used, wrong format or too many */ |
| - | return CURLE_FAILED_INIT; |
| + | if(alen) { /* not all alpn chars used, wrong format or too many */ |
| + | result = CURLE_FAILED_INIT; |
| + | goto out; |
| + | } |
| gtls_alpns_count = i; | |
| } | |
| @@ -1164,10 +1189,12 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, | |
| gtls_alpns, (unsigned int)gtls_alpns_count, | |
| GNUTLS_ALPN_MANDATORY)) { | |
| failf(data, "failed setting ALPN"); | |
| - | return CURLE_SSL_CONNECT_ERROR; |
| + | result = CURLE_SSL_CONNECT_ERROR; |
| } | |
| - | return CURLE_OK; |
| + | out: |
| + | Curl_ssl_scache_return(cf, data, peer->scache_key, scs); |
| + | return result; |
| } | |
| static CURLcode | |
| @@ -1197,7 +1224,8 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| } | |
| result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer, | |
| - | proto.data, proto.len, connssl, NULL, NULL, cf); |
| + | proto.data, proto.len, |
| + | connssl, NULL, NULL, cf); |
| if(result) | |
| return result; | |
| @@ -2213,7 +2241,7 @@ out: | |
| return ret; | |
| } | |
| - | static size_t gtls_version(char *buffer, size_t size) |
| + | size_t Curl_gtls_version(char *buffer, size_t size) |
| { | |
| return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); | |
| } | |
| @@ -2268,7 +2296,7 @@ const struct Curl_ssl Curl_ssl_gnutls = { | |
| gtls_init, /* init */ | |
| gtls_cleanup, /* cleanup */ | |
| - | gtls_version, /* version */ |
| + | Curl_gtls_version, /* version */ |
| gtls_shutdown, /* shutdown */ | |
| gtls_data_pending, /* data_pending */ | |
| gtls_random, /* random */ | |
| @@ -47,6 +47,8 @@ struct ssl_config_data; | |
| struct ssl_peer; | |
| struct ssl_connect_data; | |
| + | int Curl_glts_get_ietf_proto(gnutls_session_t session); |
| + | |
| struct gtls_shared_creds { | |
| gnutls_certificate_credentials_t creds; | |
| char *CAfile; /* CAfile path used to generate X509 store */ | |
| @@ -70,6 +72,8 @@ struct gtls_ctx { | |
| BIT(sent_shutdown); | |
| }; | |
| + | size_t Curl_gtls_version(char *buffer, size_t size); |
| + | |
| typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| void *user_data); | |
| @@ -96,11 +100,12 @@ CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, | |
| const char *pinned_key); | |
| /* Extract TLS session and place in cache, if configured. */ | |
| - | CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | gnutls_session_t session, |
| - | struct ssl_peer *peer, |
| - | const char *alpn); |
| + | CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | gnutls_session_t session, |
| + | int lifetime_secs, |
| + | const char *alpn); |
| extern const struct Curl_ssl Curl_ssl_gnutls; | |
| @@ -64,6 +64,7 @@ | |
| #include "mbedtls.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "x509asn1.h" | |
| #include "parsedate.h" | |
| #include "connect.h" /* for the connect timeout */ | |
| @@ -875,29 +876,30 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* Check if there is a cached ID we can/should use here! */ | |
| if(ssl_config->primary.cache_session) { | |
| - | void *sdata = NULL; |
| - | size_t slen = 0; |
| + | struct Curl_ssl_session *sc_session = NULL; |
| + | CURLcode result; |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, |
| - | &sdata, &slen, NULL) && slen) { |
| + | result = Curl_ssl_scache_take(cf, data, connssl->peer.scache_key, |
| + | &sc_session); |
| + | if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) { |
| mbedtls_ssl_session session; | |
| mbedtls_ssl_session_init(&session); | |
| - | ret = mbedtls_ssl_session_load(&session, sdata, slen); |
| + | ret = mbedtls_ssl_session_load(&session, sc_session->sdata, |
| + | sc_session->sdata_len); |
| if(ret) { | |
| - | failf(data, "error loading cached session: -0x%x", -ret); |
| + | failf(data, "SSL session error loading: -0x%x", -ret); |
| } | |
| else { | |
| ret = mbedtls_ssl_set_session(&backend->ssl, &session); | |
| if(ret) | |
| - | failf(data, "error setting session: -0x%x", -ret); |
| + | failf(data, "SSL session error setting: -0x%x", -ret); |
| else | |
| infof(data, "SSL reusing session ID"); | |
| } | |
| mbedtls_ssl_session_free(&session); | |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_return(cf, data, connssl->peer.scache_key, sc_session); |
| } | |
| mbedtls_ssl_conf_ca_chain(&backend->config, | |
| @@ -1115,12 +1117,6 @@ pinnedpubkey_error: | |
| return CURLE_OK; | |
| } | |
| - | static void mbedtls_session_free(void *session, size_t slen) |
| - | { |
| - | (void)slen; |
| - | free(session); |
| - | } |
| - | |
| static CURLcode | |
| mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| { | |
| @@ -1128,48 +1124,64 @@ mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| struct mbed_ssl_backend_data *backend = | |
| (struct mbed_ssl_backend_data *)connssl->backend; | |
| struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | |
| + | mbedtls_ssl_session session; |
| + | bool msession_alloced = FALSE; |
| + | struct Curl_ssl_session *sc_session = NULL; |
| + | unsigned char *sdata = NULL; |
| + | size_t slen = 0; |
| + | int ietf_tls_id; |
| CURLcode result = CURLE_OK; | |
| + | int ret; |
| DEBUGASSERT(backend); | |
| - | if(ssl_config->primary.cache_session) { |
| - | int ret; |
| - | mbedtls_ssl_session session; |
| - | unsigned char *sdata = NULL; |
| - | size_t slen = 0; |
| + | if(!ssl_config->primary.cache_session) |
| + | return CURLE_OK; |
| - | mbedtls_ssl_session_init(&session); |
| - | ret = mbedtls_ssl_get_session(&backend->ssl, &session); |
| - | if(ret) { |
| - | if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) |
| - | mbedtls_ssl_session_free(&session); |
| - | failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); |
| - | return CURLE_SSL_CONNECT_ERROR; |
| - | } |
| + | mbedtls_ssl_session_init(&session); |
| + | ret = mbedtls_ssl_get_session(&backend->ssl, &session); |
| + | msession_alloced = (ret != MBEDTLS_ERR_SSL_ALLOC_FAILED); |
| + | if(ret) { |
| + | failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); |
| + | result = CURLE_SSL_CONNECT_ERROR; |
| + | goto out; |
| + | } |
| - | mbedtls_ssl_session_save(&session, NULL, 0, &slen); |
| - | if(!slen) { |
| - | failf(data, "failed to serialize session: length is 0"); |
| - | } |
| - | else { |
| - | sdata = malloc(slen); |
| - | if(sdata) { |
| - | ret = mbedtls_ssl_session_save(&session, sdata, slen, &slen); |
| - | if(ret) { |
| - | failf(data, "failed to serialize session: -0x%x", -ret); |
| - | } |
| - | else { |
| - | Curl_ssl_sessionid_lock(data); |
| - | result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL, |
| - | sdata, slen, mbedtls_session_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| - | if(!result) |
| - | sdata = NULL; |
| - | } |
| - | } |
| - | } |
| - | mbedtls_ssl_session_free(&session); |
| - | free(sdata); |
| + | mbedtls_ssl_session_save(&session, NULL, 0, &slen); |
| + | if(!slen) { |
| + | failf(data, "failed to serialize session: length is 0"); |
| + | goto out; |
| + | } |
| + | |
| + | sdata = malloc(slen); |
| + | if(!sdata) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto out; |
| + | } |
| + | |
| + | ret = mbedtls_ssl_session_save(&session, sdata, slen, &slen); |
| + | if(ret) { |
| + | failf(data, "failed to serialize session: -0x%x", -ret); |
| + | goto out; |
| } | |
| + | |
| + | #if MBEDTLS_VERSION_NUMBER >= 0x03020000 |
| + | ietf_tls_id = mbedtls_ssl_get_version_number(&backend->ssl); |
| + | #else |
| + | ietf_tls_id = CURL_IETF_PROTO_UNKNOWN; |
| + | #endif |
| + | result = Curl_ssl_session_create(sdata, slen, |
| + | ietf_tls_id, |
| + | connssl->negotiated.alpn, 0, -1, |
| + | &sc_session); |
| + | sdata = NULL; /* call took ownership */ |
| + | if(!result) |
| + | result = Curl_ssl_scache_put(cf, data, connssl->peer.scache_key, |
| + | sc_session); |
| + | |
| + | out: |
| + | if(msession_alloced) |
| + | mbedtls_ssl_session_free(&session); |
| + | free(sdata); |
| return result; | |
| } | |
| @@ -56,6 +56,7 @@ | |
| #include "select.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "vauth/vauth.h" | |
| #include "keylog.h" | |
| #include "strcase.h" | |
| @@ -960,8 +961,6 @@ static const char *SSL_ERROR_to_str(int err) | |
| } | |
| } | |
| - | static size_t ossl_version(char *buffer, size_t size); |
| - | |
| /* Return error string for last OpenSSL error | |
| */ | |
| static char *ossl_strerror(unsigned long error, char *buf, size_t size) | |
| @@ -970,7 +969,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) | |
| DEBUGASSERT(size); | |
| *buf = '\0'; | |
| - | len = ossl_version(buf, size); |
| + | len = Curl_ossl_version(buf, size); |
| DEBUGASSERT(len < (size - 2)); | |
| if(len < (size - 2)) { | |
| buf += len; | |
| @@ -2013,13 +2012,6 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| } | |
| } | |
| - | static void ossl_session_free(void *sessionid, size_t idsize) |
| - | { |
| - | /* free the ID */ |
| - | (void)idsize; |
| - | free(sessionid); |
| - | } |
| - | |
| /* | |
| * This function is called when the 'data' struct is going away. Close | |
| * down everything and free all resources! | |
| @@ -2873,20 +2865,23 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, | |
| CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| - | const struct ssl_peer *peer, |
| - | SSL_SESSION *session) |
| + | const char *ssl_peer_key, |
| + | SSL_SESSION *session, |
| + | int ietf_tls_id, |
| + | const char *alpn) |
| { | |
| const struct ssl_config_data *config; | |
| + | unsigned char *der_session_buf = NULL; |
| CURLcode result = CURLE_OK; | |
| - | size_t der_session_size; |
| - | unsigned char *der_session_buf; |
| - | unsigned char *der_session_ptr; |
| if(!cf || !data) | |
| goto out; | |
| config = Curl_ssl_cf_get_config(cf, data); | |
| if(config->primary.cache_session) { | |
| + | struct Curl_ssl_session *sc_session = NULL; |
| + | size_t der_session_size; |
| + | unsigned char *der_session_ptr; |
| der_session_size = i2d_SSL_SESSION(session, NULL); | |
| if(der_session_size == 0) { | |
| @@ -2903,17 +2898,22 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, | |
| der_session_size = i2d_SSL_SESSION(session, &der_session_ptr); | |
| if(der_session_size == 0) { | |
| result = CURLE_OUT_OF_MEMORY; | |
| - | free(der_session_buf); |
| goto out; | |
| } | |
| - | Curl_ssl_sessionid_lock(data); |
| - | result = Curl_ssl_set_sessionid(cf, data, peer, NULL, der_session_buf, |
| - | der_session_size, ossl_session_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | result = Curl_ssl_session_create(der_session_buf, der_session_size, |
| + | ietf_tls_id, alpn, 0, |
| + | SSL_SESSION_get_timeout(session), |
| + | &sc_session); |
| + | der_session_buf = NULL; /* took ownership of sdata */ |
| + | if(!result) { |
| + | result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session); |
| + | /* took ownership of `sc_session` */ |
| + | } |
| } | |
| out: | |
| + | free(der_session_buf); |
| return result; | |
| } | |
| @@ -2929,7 +2929,9 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) | |
| cf = (struct Curl_cfilter*) SSL_get_app_data(ssl); | |
| connssl = cf ? cf->ctx : NULL; | |
| data = connssl ? CF_DATA_CURRENT(cf) : NULL; | |
| - | Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid); |
| + | if(data && connssl) |
| + | Curl_ossl_add_session(cf, data, connssl->peer.scache_key, ssl_sessionid, |
| + | SSL_version(ssl), connssl->negotiated.alpn); |
| return 0; | |
| } | |
| @@ -3468,7 +3470,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| struct ssl_peer *peer, | |
| - | int transport, /* TCP or QUIC */ |
| const unsigned char *alpn, size_t alpn_len, | |
| Curl_ossl_ctx_setup_cb *cb_setup, | |
| void *cb_user_data, | |
| @@ -3479,9 +3480,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| const char *ciphers; | |
| SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; | |
| ctx_option_t ctx_options = 0; | |
| - | SSL_SESSION *ssl_session = NULL; |
| - | const unsigned char *der_sessionid = NULL; |
| - | size_t der_sessionid_size = 0; |
| struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); | |
| struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | |
| const long int ssl_version_min = conn_config->version; | |
| @@ -3498,7 +3496,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| ssl_config->certverifyresult = !X509_V_OK; | |
| - | switch(transport) { |
| + | switch(peer->transport) { |
| case TRNSPRT_TCP: | |
| /* check to see if we have been told to use an explicit SSL/TLS version */ | |
| switch(ssl_version_min) { | |
| @@ -3542,7 +3540,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| #endif | |
| break; | |
| default: | |
| - | failf(data, "unsupported transport %d in SSL init", transport); |
| + | failf(data, "unsupported transport %d in SSL init", peer->transport); |
| return CURLE_SSL_CONNECT_ERROR; | |
| } | |
| @@ -3965,32 +3963,36 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| octx->reused_session = FALSE; | |
| if(ssl_config->primary.cache_session) { | |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid, |
| - | &der_sessionid_size, NULL)) { |
| - | /* we got a session id, use it! */ |
| + | struct Curl_ssl_session *sc_session = NULL; |
| + | |
| + | result = Curl_ssl_scache_take(cf, data, peer->scache_key, &sc_session); |
| + | if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) { |
| + | const unsigned char *der_sessionid = sc_session->sdata; |
| + | size_t der_sessionid_size = sc_session->sdata_len; |
| + | SSL_SESSION *ssl_session = NULL; |
| + | |
| + | /* If OpenSSL does not accept the session from the cache, this |
| + | * is not an error. We just continue without it. */ |
| ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid, | |
| - | (long)der_sessionid_size); |
| + | (long)der_sessionid_size); |
| if(ssl_session) { | |
| if(!SSL_set_session(octx->ssl, ssl_session)) { | |
| - | Curl_ssl_sessionid_unlock(data); |
| - | SSL_SESSION_free(ssl_session); |
| - | failf(data, "SSL: SSL_set_session failed: %s", |
| + | infof(data, "SSL: SSL_set_session not accepted, " |
| + | "continuing without: %s", |
| ossl_strerror(ERR_get_error(), error_buffer, | |
| sizeof(error_buffer))); | |
| - | return CURLE_SSL_CONNECT_ERROR; |
| + | } |
| + | else { |
| + | infof(data, "SSL reusing session"); |
| + | octx->reused_session = TRUE; |
| } | |
| SSL_SESSION_free(ssl_session); | |
| - | /* Informational message */ |
| - | infof(data, "SSL reusing session ID"); |
| - | octx->reused_session = TRUE; |
| } | |
| else { | |
| - | Curl_ssl_sessionid_unlock(data); |
| - | return CURLE_SSL_CONNECT_ERROR; |
| + | infof(data, "SSL session not accepted by OpenSSL, continuing without"); |
| } | |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_return(cf, data, peer->scache_key, sc_session); |
| } | |
| return CURLE_OK; | |
| @@ -4018,7 +4020,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, | |
| } | |
| #endif | |
| - | result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, TRNSPRT_TCP, |
| + | result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, |
| proto.data, proto.len, NULL, NULL, | |
| ossl_new_session_cb, cf); | |
| if(result) | |
| @@ -4693,21 +4695,6 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, | |
| /* do not do this after Session ID reuse */ | |
| result = verifystatus(cf, data, octx); | |
| if(result) { | |
| - | /* when verifystatus failed, remove the session id from the cache again |
| - | if present */ |
| - | if(!Curl_ssl_cf_is_proxy(cf)) { |
| - | void *old_ssl_sessionid = NULL; |
| - | bool incache; |
| - | Curl_ssl_sessionid_lock(data); |
| - | incache = !(Curl_ssl_getsessionid(cf, data, peer, |
| - | &old_ssl_sessionid, NULL, NULL)); |
| - | if(incache) { |
| - | infof(data, "Remove session ID again from cache"); |
| - | Curl_ssl_delsessionid(data, old_ssl_sessionid); |
| - | } |
| - | Curl_ssl_sessionid_unlock(data); |
| - | } |
| - | |
| X509_free(octx->server_cert); | |
| octx->server_cert = NULL; | |
| return result; | |
| @@ -4757,6 +4744,9 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf, | |
| result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer); | |
| if(!result) | |
| connssl->connecting_state = ssl_connect_done; | |
| + | else |
| + | /* on error, remove sessions we might have in the pool */ |
| + | Curl_ssl_scache_remove_all(cf, data, connssl->peer.scache_key); |
| return result; | |
| } | |
| @@ -5172,7 +5162,7 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, | |
| #endif | |
| } | |
| - | static size_t ossl_version(char *buffer, size_t size) |
| + | size_t Curl_ossl_version(char *buffer, size_t size) |
| { | |
| #ifdef LIBRESSL_VERSION_NUMBER | |
| #ifdef HAVE_OPENSSL_VERSION | |
| @@ -5336,7 +5326,7 @@ const struct Curl_ssl Curl_ssl_openssl = { | |
| ossl_init, /* init */ | |
| ossl_cleanup, /* cleanup */ | |
| - | ossl_version, /* version */ |
| + | Curl_ossl_version, /* version */ |
| ossl_shutdown, /* shutdown */ | |
| ossl_data_pending, /* data_pending */ | |
| ossl_random, /* random */ | |
| @@ -36,6 +36,8 @@ | |
| #include "urldata.h" | |
| + | struct ssl_peer; |
| + | |
| /* Struct to hold a Curl OpenSSL instance */ | |
| struct ossl_ctx { | |
| /* these ones requires specific SSL-types */ | |
| @@ -53,6 +55,8 @@ struct ossl_ctx { | |
| BIT(reused_session); /* session-ID was reused for this */ | |
| }; | |
| + | size_t Curl_ossl_version(char *buffer, size_t size); |
| + | |
| typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| void *user_data); | |
| @@ -63,7 +67,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, | |
| struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| struct ssl_peer *peer, | |
| - | int transport, /* TCP or QUIC */ |
| const unsigned char *alpn, size_t alpn_len, | |
| Curl_ossl_ctx_setup_cb *cb_setup, | |
| void *cb_user_data, | |
| @@ -94,8 +97,10 @@ CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf, | |
| */ | |
| CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| - | const struct ssl_peer *peer, |
| - | SSL_SESSION *ssl_sessionid); |
| + | const char *ssl_peer_key, |
| + | SSL_SESSION *ssl_sessionid, |
| + | int ietf_tls_id, |
| + | const char *alpn); |
| /* | |
| * Get the server cert, verify it and show it, etc., only call failf() if | |
| @@ -41,6 +41,7 @@ | |
| #include "schannel_int.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "strcase.h" | |
| #include "sendf.h" | |
| #include "connect.h" /* for the connect timeout */ | |
| @@ -954,9 +955,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* check for an existing reusable credential handle */ | |
| if(ssl_config->primary.cache_session) { | |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, |
| - | (void **)&old_cred, NULL, NULL)) { |
| + | Curl_ssl_scache_lock(data); |
| + | if(Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key, |
| + | (void **)&old_cred)) { |
| backend->cred = old_cred; | |
| DEBUGF(infof(data, "schannel: reusing existing credential handle")); | |
| @@ -966,7 +967,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| "schannel: incremented credential handle refcount = %d", | |
| backend->cred->refcount)); | |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_unlock(data); |
| } | |
| if(!backend->cred) { | |
| @@ -1501,12 +1502,11 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order, | |
| return args->result == CURLE_OK; | |
| } | |
| - | static void schannel_session_free(void *sessionid, size_t idsize) |
| + | static void schannel_session_free(void *sessionid) |
| { | |
| /* this is expected to be called under sessionid lock */ | |
| struct Curl_schannel_cred *cred = sessionid; | |
| - | (void)idsize; |
| if(cred) { | |
| cred->refcount--; | |
| if(cred->refcount == 0) { | |
| @@ -1599,14 +1599,12 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* save the current session data for possible reuse */ | |
| if(ssl_config->primary.cache_session) { | |
| - | Curl_ssl_sessionid_lock(data); |
| + | Curl_ssl_scache_lock(data); |
| /* Up ref count since call takes ownership */ | |
| backend->cred->refcount++; | |
| - | result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL, |
| - | backend->cred, |
| - | sizeof(struct Curl_schannel_cred), |
| - | schannel_session_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | result = Curl_ssl_scache_add_obj(cf, data, connssl->peer.scache_key, |
| + | backend->cred, schannel_session_free); |
| + | Curl_ssl_scache_unlock(data); |
| if(result) | |
| return result; | |
| } | |
| @@ -2445,9 +2443,9 @@ static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* free SSPI Schannel API credential handle */ | |
| if(backend->cred) { | |
| - | Curl_ssl_sessionid_lock(data); |
| - | schannel_session_free(backend->cred, 0); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_lock(data); |
| + | schannel_session_free(backend->cred); |
| + | Curl_ssl_scache_unlock(data); |
| backend->cred = NULL; | |
| } | |
| @@ -38,6 +38,7 @@ | |
| #include "multiif.h" | |
| #include "strcase.h" | |
| #include "x509asn1.h" | |
| + | #include "vtls_scache.h" |
| #include "strerror.h" | |
| #include "cipher_suite.h" | |
| @@ -1020,7 +1021,7 @@ failed: | |
| return ret; | |
| } | |
| - | static void sectransp_session_free(void *sessionid, size_t idsize) |
| + | static void sectransp_session_free(void *sessionid) |
| { | |
| /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a | |
| cached session ID inside the Security framework. There is a private | |
| @@ -1028,7 +1029,6 @@ static void sectransp_session_free(void *sessionid, size_t idsize) | |
| got your application rejected from the App Store due to the use of a | |
| private API, so the best we can do is free up our own char array that we | |
| created way back in sectransp_connect_step1... */ | |
| - | (void)idsize; |
| Curl_safefree(sessionid); | |
| } | |
| @@ -1337,19 +1337,19 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, | |
| char *ssl_sessionid; | |
| size_t ssl_sessionid_len; | |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, |
| - | (void **)&ssl_sessionid, &ssl_sessionid_len, |
| - | NULL)) { |
| + | Curl_ssl_scache_lock(data); |
| + | if(Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key, |
| + | (void **)&ssl_sessionid)) { |
| /* we got a session id, use it! */ | |
| - | err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); |
| - | Curl_ssl_sessionid_unlock(data); |
| + | err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, |
| + | strlen(ssl_sessionid)); |
| + | Curl_ssl_scache_unlock(data); |
| if(err != noErr) { | |
| failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); | |
| return CURLE_SSL_CONNECT_ERROR; | |
| } | |
| - | /* Informational message */ |
| - | infof(data, "SSL reusing session ID"); |
| + | else |
| + | infof(data, "SSL reusing session ID"); |
| } | |
| /* If there is not one, then let's make one up! This has to be done prior | |
| to starting the handshake. */ | |
| @@ -1363,15 +1363,17 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, | |
| err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); | |
| if(err != noErr) { | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_unlock(data); |
| failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); | |
| return CURLE_SSL_CONNECT_ERROR; | |
| } | |
| - | result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL, |
| - | ssl_sessionid, ssl_sessionid_len, |
| + | /* This is all a bit weird, as we have not handshaked yet. |
| + | * I hope this backend will go away soon. */ |
| + | result = Curl_ssl_scache_add_obj(cf, data, connssl->peer.scache_key, |
| + | (void *)ssl_sessionid, |
| sectransp_session_free); | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_unlock(data); |
| if(result) | |
| return result; | |
| } | |
| @@ -55,6 +55,7 @@ | |
| #include "vtls.h" /* generic SSL protos etc */ | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "openssl.h" /* OpenSSL versions */ | |
| #include "gtls.h" /* GnuTLS versions */ | |
| @@ -74,6 +75,7 @@ | |
| #include "multiif.h" | |
| #include "timeval.h" | |
| #include "curl_md5.h" | |
| + | #include "curl_sha256.h" |
| #include "warnless.h" | |
| #include "curl_base64.h" | |
| #include "curl_printf.h" | |
| @@ -88,11 +90,6 @@ | |
| #include "memdebug.h" | |
| - | /* convenience macro to check if this handle is using a shared SSL session */ |
| - | #define SSLSESSION_SHARED(data) (data->share && \ |
| - | (data->share->specifier & \ |
| - | (1<<CURL_LOCK_DATA_SSL_SESSION))) |
| - | |
| #define CLONE_STRING(var) \ | |
| do { \ | |
| if(source->var) { \ | |
| @@ -465,9 +462,10 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, | |
| if(!ctx) | |
| return NULL; | |
| + | ctx->ssl_impl = Curl_ssl; |
| ctx->alpn = alpn; | |
| Curl_bufq_init2(&ctx->earlydata, CURL_SSL_EARLY_MAX, 1, BUFQ_OPT_NO_SPARES); | |
| - | ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); |
| + | ctx->backend = calloc(1, ctx->ssl_impl->sizeof_ssl_backend_data); |
| if(!ctx->backend) { | |
| free(ctx); | |
| return NULL; | |
| @@ -478,7 +476,7 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, | |
| static void cf_ctx_free(struct ssl_connect_data *ctx) | |
| { | |
| if(ctx) { | |
| - | Curl_safefree(ctx->alpn_negotiated); |
| + | Curl_safefree(ctx->negotiated.alpn); |
| Curl_bufq_free(&ctx->earlydata); | |
| free(ctx->backend); | |
| free(ctx); | |
| @@ -496,7 +494,7 @@ static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* mark this is being ssl-enabled from here on. */ | |
| connssl->state = ssl_connection_negotiating; | |
| - | result = Curl_ssl->connect_blocking(cf, data); |
| + | result = connssl->ssl_impl->connect_blocking(cf, data); |
| if(!result) { | |
| DEBUGASSERT(connssl->state == ssl_connection_complete); | |
| @@ -509,275 +507,13 @@ static CURLcode | |
| ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data, | |
| bool *done) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| + | |
| if(!ssl_prefs_check(data)) | |
| return CURLE_SSL_CONNECT_ERROR; | |
| /* mark this is being ssl requested from here on. */ | |
| - | return Curl_ssl->connect_nonblocking(cf, data, done); |
| - | } |
| - | |
| - | /* |
| - | * Lock shared SSL session data |
| - | */ |
| - | void Curl_ssl_sessionid_lock(struct Curl_easy *data) |
| - | { |
| - | if(SSLSESSION_SHARED(data)) |
| - | Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); |
| - | } |
| - | |
| - | /* |
| - | * Unlock shared SSL session data |
| - | */ |
| - | void Curl_ssl_sessionid_unlock(struct Curl_easy *data) |
| - | { |
| - | if(SSLSESSION_SHARED(data)) |
| - | Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); |
| - | } |
| - | |
| - | /* |
| - | * Check if there is a session ID for the given connection in the cache, and if |
| - | * there is one suitable, it is provided. Returns TRUE when no entry matched. |
| - | */ |
| - | bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | const struct ssl_peer *peer, |
| - | void **ssl_sessionid, |
| - | size_t *idsize, /* set 0 if unknown */ |
| - | char **palpn) |
| - | { |
| - | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| - | struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
| - | struct Curl_ssl_session *check; |
| - | size_t i; |
| - | long *general_age; |
| - | bool no_match = TRUE; |
| - | |
| - | *ssl_sessionid = NULL; |
| - | if(palpn) |
| - | *palpn = NULL; |
| - | if(!ssl_config) |
| - | return TRUE; |
| - | |
| - | DEBUGASSERT(ssl_config->primary.cache_session); |
| - | |
| - | if(!ssl_config->primary.cache_session || !data->state.session) |
| - | /* session ID reuse is disabled or the session cache has not been |
| - | setup */ |
| - | return TRUE; |
| - | |
| - | /* Lock if shared */ |
| - | if(SSLSESSION_SHARED(data)) |
| - | general_age = &data->share->sessionage; |
| - | else |
| - | general_age = &data->state.sessionage; |
| - | |
| - | for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { |
| - | check = &data->state.session[i]; |
| - | if(!check->sessionid) |
| - | /* not session ID means blank entry */ |
| - | continue; |
| - | if(strcasecompare(peer->hostname, check->name) && |
| - | ((!cf->conn->bits.conn_to_host && !check->conn_to_host) || |
| - | (cf->conn->bits.conn_to_host && check->conn_to_host && |
| - | strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) && |
| - | ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) || |
| - | (cf->conn->bits.conn_to_port && check->conn_to_port != -1 && |
| - | cf->conn->conn_to_port == check->conn_to_port)) && |
| - | (peer->port == check->remote_port) && |
| - | (peer->transport == check->transport) && |
| - | strcasecompare(cf->conn->handler->scheme, check->scheme) && |
| - | match_ssl_primary_config(data, conn_config, &check->ssl_config)) { |
| - | /* yes, we have a session ID! */ |
| - | (*general_age)++; /* increase general age */ |
| - | check->age = *general_age; /* set this as used in this age */ |
| - | *ssl_sessionid = check->sessionid; |
| - | if(idsize) |
| - | *idsize = check->idsize; |
| - | if(palpn) |
| - | *palpn = check->alpn; |
| - | no_match = FALSE; |
| - | break; |
| - | } |
| - | } |
| - | |
| - | CURL_TRC_CF(data, cf, "%s cached session ID for %s://%s:%d", |
| - | no_match ? "No" : "Found", |
| - | cf->conn->handler->scheme, peer->hostname, peer->port); |
| - | return no_match; |
| - | } |
| - | |
| - | /* |
| - | * Kill a single session ID entry in the cache. |
| - | */ |
| - | void Curl_ssl_kill_session(struct Curl_ssl_session *session) |
| - | { |
| - | if(session->sessionid) { |
| - | /* defensive check */ |
| - | |
| - | /* free the ID the SSL-layer specific way */ |
| - | session->sessionid_free(session->sessionid, session->idsize); |
| - | |
| - | session->sessionid = NULL; |
| - | session->sessionid_free = NULL; |
| - | session->age = 0; /* fresh */ |
| - | |
| - | free_primary_ssl_config(&session->ssl_config); |
| - | |
| - | Curl_safefree(session->name); |
| - | Curl_safefree(session->conn_to_host); |
| - | Curl_safefree(session->alpn); |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * Delete the given session ID from the cache. |
| - | */ |
| - | void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid) |
| - | { |
| - | size_t i; |
| - | |
| - | for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { |
| - | struct Curl_ssl_session *check = &data->state.session[i]; |
| - | |
| - | if(check->sessionid == ssl_sessionid) { |
| - | Curl_ssl_kill_session(check); |
| - | break; |
| - | } |
| - | } |
| - | } |
| - | |
| - | CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | const struct ssl_peer *peer, |
| - | const char *alpn, |
| - | void *ssl_sessionid, |
| - | size_t idsize, |
| - | Curl_ssl_sessionid_dtor *sessionid_free_cb) |
| - | { |
| - | struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
| - | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| - | size_t i; |
| - | struct Curl_ssl_session *store; |
| - | long oldest_age; |
| - | char *clone_host = NULL; |
| - | char *clone_conn_to_host = NULL; |
| - | char *clone_alpn = NULL; |
| - | int conn_to_port; |
| - | long *general_age; |
| - | void *old_sessionid; |
| - | size_t old_size; |
| - | CURLcode result = CURLE_OUT_OF_MEMORY; |
| - | |
| - | DEBUGASSERT(ssl_sessionid); |
| - | DEBUGASSERT(sessionid_free_cb); |
| - | |
| - | if(!data->state.session) { |
| - | sessionid_free_cb(ssl_sessionid, idsize); |
| - | return CURLE_OK; |
| - | } |
| - | |
| - | if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size, NULL)) { |
| - | if((old_size == idsize) && |
| - | ((old_sessionid == ssl_sessionid) || |
| - | (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) { |
| - | /* the very same */ |
| - | sessionid_free_cb(ssl_sessionid, idsize); |
| - | return CURLE_OK; |
| - | } |
| - | Curl_ssl_delsessionid(data, old_sessionid); |
| - | } |
| - | |
| - | store = &data->state.session[0]; |
| - | oldest_age = data->state.session[0].age; /* zero if unused */ |
| - | DEBUGASSERT(ssl_config->primary.cache_session); |
| - | (void)ssl_config; |
| - | |
| - | clone_host = strdup(peer->hostname); |
| - | if(!clone_host) |
| - | goto out; |
| - | |
| - | if(cf->conn->bits.conn_to_host) { |
| - | clone_conn_to_host = strdup(cf->conn->conn_to_host.name); |
| - | if(!clone_conn_to_host) |
| - | goto out; |
| - | } |
| - | |
| - | clone_alpn = alpn ? strdup(alpn) : NULL; |
| - | if(alpn && !clone_alpn) |
| - | goto out; |
| - | |
| - | if(cf->conn->bits.conn_to_port) |
| - | conn_to_port = cf->conn->conn_to_port; |
| - | else |
| - | conn_to_port = -1; |
| - | |
| - | /* Now we should add the session ID and the hostname to the cache, (remove |
| - | the oldest if necessary) */ |
| - | |
| - | /* If using shared SSL session, lock! */ |
| - | if(SSLSESSION_SHARED(data)) { |
| - | general_age = &data->share->sessionage; |
| - | } |
| - | else { |
| - | general_age = &data->state.sessionage; |
| - | } |
| - | |
| - | /* find an empty slot for us, or find the oldest */ |
| - | for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && |
| - | data->state.session[i].sessionid; i++) { |
| - | if(data->state.session[i].age < oldest_age) { |
| - | oldest_age = data->state.session[i].age; |
| - | store = &data->state.session[i]; |
| - | } |
| - | } |
| - | if(i == data->set.general_ssl.max_ssl_sessions) |
| - | /* cache is full, we must "kill" the oldest entry! */ |
| - | Curl_ssl_kill_session(store); |
| - | else |
| - | store = &data->state.session[i]; /* use this slot */ |
| - | |
| - | /* now init the session struct wisely */ |
| - | if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) { |
| - | free_primary_ssl_config(&store->ssl_config); |
| - | store->sessionid = NULL; /* let caller free sessionid */ |
| - | goto out; |
| - | } |
| - | store->sessionid = ssl_sessionid; |
| - | store->idsize = idsize; |
| - | store->sessionid_free = sessionid_free_cb; |
| - | store->age = *general_age; /* set current age */ |
| - | /* free it if there is one already present */ |
| - | free(store->name); |
| - | free(store->conn_to_host); |
| - | store->name = clone_host; /* clone hostname */ |
| - | clone_host = NULL; |
| - | store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */ |
| - | clone_conn_to_host = NULL; |
| - | store->conn_to_port = conn_to_port; /* connect to port number */ |
| - | store->alpn = clone_alpn; |
| - | clone_alpn = NULL; |
| - | /* port number */ |
| - | store->remote_port = peer->port; |
| - | store->scheme = cf->conn->handler->scheme; |
| - | store->transport = peer->transport; |
| - | |
| - | result = CURLE_OK; |
| - | |
| - | out: |
| - | free(clone_host); |
| - | free(clone_conn_to_host); |
| - | free(clone_alpn); |
| - | if(result) { |
| - | failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]", |
| - | store->scheme, store->name, store->remote_port, |
| - | Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"); |
| - | sessionid_free_cb(ssl_sessionid, idsize); |
| - | return result; |
| - | } |
| - | CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]", |
| - | store->scheme, store->name, store->remote_port, |
| - | Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"); |
| - | return CURLE_OK; |
| + | return connssl->ssl_impl->connect_nonblocking(cf, data, done); |
| } | |
| CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex, | |
| @@ -791,14 +527,9 @@ CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex, | |
| void Curl_ssl_close_all(struct Curl_easy *data) | |
| { | |
| /* kill the session ID cache if not shared */ | |
| - | if(data->state.session && !SSLSESSION_SHARED(data)) { |
| - | size_t i; |
| - | for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) |
| - | /* the single-killer function handles empty table slots */ |
| - | Curl_ssl_kill_session(&data->state.session[i]); |
| - | |
| - | /* free the cache data */ |
| - | Curl_safefree(data->state.session); |
| + | if(data->state.ssl_scache && !CURL_SHARE_ssl_scache(data)) { |
| + | Curl_ssl_scache_destroy(data->state.ssl_scache); |
| + | data->state.ssl_scache = NULL; |
| } | |
| if(Curl_ssl->close_all) | |
| @@ -853,29 +584,6 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) | |
| return NULL; | |
| } | |
| - | /* |
| - | * This sets up a session ID cache to the specified size. Make sure this code |
| - | * is agnostic to what underlying SSL technology we use. |
| - | */ |
| - | CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) |
| - | { |
| - | struct Curl_ssl_session *session; |
| - | |
| - | if(data->state.session) |
| - | /* this is just a precaution to prevent multiple inits */ |
| - | return CURLE_OK; |
| - | |
| - | session = calloc(amount, sizeof(struct Curl_ssl_session)); |
| - | if(!session) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | |
| - | /* store the info in the SSL section */ |
| - | data->set.general_ssl.max_ssl_sessions = amount; |
| - | data->state.session = session; |
| - | data->state.sessionage = 1; /* this is brand new */ |
| - | return CURLE_OK; |
| - | } |
| - | |
| static size_t multissl_version(char *buffer, size_t size); | |
| void Curl_ssl_version(char *buffer, size_t size) | |
| @@ -1494,11 +1202,12 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, | |
| void Curl_ssl_peer_cleanup(struct ssl_peer *peer) | |
| { | |
| + | Curl_safefree(peer->sni); |
| if(peer->dispname != peer->hostname) | |
| free(peer->dispname); | |
| - | free(peer->sni); |
| - | free(peer->hostname); |
| - | peer->hostname = peer->sni = peer->dispname = NULL; |
| + | peer->dispname = NULL; |
| + | Curl_safefree(peer->hostname); |
| + | Curl_safefree(peer->scache_key); |
| peer->type = CURL_SSL_PEER_DNS; | |
| } | |
| @@ -1506,7 +1215,7 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| { | |
| struct ssl_connect_data *connssl = cf->ctx; | |
| if(connssl) { | |
| - | Curl_ssl->close(cf, data); |
| + | connssl->ssl_impl->close(cf, data); |
| connssl->state = ssl_connection_none; | |
| Curl_ssl_peer_cleanup(&connssl->peer); | |
| } | |
| @@ -1532,7 +1241,9 @@ static ssl_peer_type get_peer_type(const char *hostname) | |
| return CURL_SSL_PEER_DNS; | |
| } | |
| - | CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf, |
| + | CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, |
| + | struct Curl_cfilter *cf, |
| + | const char *tls_id, |
| int transport) | |
| { | |
| const char *ehostname, *edispname; | |
| @@ -1594,7 +1305,8 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf, | |
| peer->sni[len] = 0; | |
| } | |
| } | |
| - | result = CURLE_OK; |
| + | |
| + | result = Curl_ssl_peer_key_make(cf, peer, tls_id, &peer->scache_key); |
| out: | |
| if(result) | |
| @@ -1657,7 +1369,9 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, | |
| *done = FALSE; | |
| if(!connssl->peer.hostname) { | |
| - | result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP); |
| + | char tls_id[80]; |
| + | connssl->ssl_impl->version(tls_id, sizeof(tls_id) - 1); |
| + | result = Curl_ssl_peer_init(&connssl->peer, cf, tls_id, TRNSPRT_TCP); |
| if(result) | |
| goto out; | |
| } | |
| @@ -1686,11 +1400,13 @@ out: | |
| static bool ssl_cf_data_pending(struct Curl_cfilter *cf, | |
| const struct Curl_easy *data) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| struct cf_call_data save; | |
| bool result; | |
| CF_DATA_SAVE(save, cf, data); | |
| - | if(Curl_ssl->data_pending && Curl_ssl->data_pending(cf, data)) |
| + | if(connssl->ssl_impl->data_pending && |
| + | connssl->ssl_impl->data_pending(cf, data)) |
| result = TRUE; | |
| else | |
| result = cf->next->cft->has_data_pending(cf->next, data); | |
| @@ -1702,6 +1418,7 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, const void *buf, size_t len, | |
| bool eos, CURLcode *err) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| struct cf_call_data save; | |
| ssize_t nwritten = 0; | |
| @@ -1710,7 +1427,7 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, | |
| *err = CURLE_OK; | |
| if(len > 0) { | |
| CF_DATA_SAVE(save, cf, data); | |
| - | nwritten = Curl_ssl->send_plain(cf, data, buf, len, err); |
| + | nwritten = connssl->ssl_impl->send_plain(cf, data, buf, len, err); |
| CF_DATA_RESTORE(cf, save); | |
| } | |
| return nwritten; | |
| @@ -1720,12 +1437,13 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, char *buf, size_t len, | |
| CURLcode *err) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| struct cf_call_data save; | |
| ssize_t nread; | |
| CF_DATA_SAVE(save, cf, data); | |
| *err = CURLE_OK; | |
| - | nread = Curl_ssl->recv_plain(cf, data, buf, len, err); |
| + | nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err); |
| if(nread > 0) { | |
| DEBUGASSERT((size_t)nread <= len); | |
| } | |
| @@ -1743,6 +1461,7 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| bool *done) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| CURLcode result = CURLE_OK; | |
| *done = TRUE; | |
| @@ -1750,7 +1469,7 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf, | |
| struct cf_call_data save; | |
| CF_DATA_SAVE(save, cf, data); | |
| - | result = Curl_ssl->shut_down(cf, data, TRUE, done); |
| + | result = connssl->ssl_impl->shut_down(cf, data, TRUE, done); |
| CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done); | |
| CF_DATA_RESTORE(cf, save); | |
| cf->shutdown = (result || *done); | |
| @@ -1762,10 +1481,11 @@ static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| struct easy_pollset *ps) | |
| { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| struct cf_call_data save; | |
| CF_DATA_SAVE(save, cf, data); | |
| - | Curl_ssl->adjust_pollset(cf, data, ps); |
| + | connssl->ssl_impl->adjust_pollset(cf, data, ps); |
| CF_DATA_RESTORE(cf, save); | |
| } | |
| @@ -1971,9 +1691,10 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, | |
| /* get first SSL filter in chain, if any is present */ | |
| cf = get_ssl_filter(data->conn->cfilter[sockindex]); | |
| if(cf) { | |
| + | struct ssl_connect_data *connssl = cf->ctx; |
| struct cf_call_data save; | |
| CF_DATA_SAVE(save, cf, data); | |
| - | result = Curl_ssl->get_internals(cf->ctx, info); |
| + | result = connssl->ssl_impl->get_internals(cf->ctx, info); |
| CF_DATA_RESTORE(cf, save); | |
| } | |
| } | |
| @@ -2006,7 +1727,7 @@ static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf, | |
| return CURLE_OPERATION_TIMEDOUT; | |
| } | |
| - | result = Curl_ssl->shut_down(cf, data, send_shutdown, done); |
| + | result = connssl->ssl_impl->shut_down(cf, data, send_shutdown, done); |
| if(result ||*done) | |
| goto out; | |
| @@ -2158,28 +1879,28 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, | |
| #endif | |
| ; | |
| - | if(connssl->alpn_negotiated) { |
| + | if(connssl->negotiated.alpn) { |
| /* When we ask for a specific ALPN protocol, we need the confirmation | |
| * of it by the server, as we have installed protocol handler and | |
| * connection filter chain for exactly this protocol. */ | |
| if(!proto_len) { | |
| failf(data, "ALPN: asked for '%s' from previous session, " | |
| "but server did not confirm it. Refusing to continue.", | |
| - | connssl->alpn_negotiated); |
| + | connssl->negotiated.alpn); |
| result = CURLE_SSL_CONNECT_ERROR; | |
| goto out; | |
| } | |
| - | else if((strlen(connssl->alpn_negotiated) != proto_len) || |
| - | memcmp(connssl->alpn_negotiated, proto, proto_len)) { |
| + | else if((strlen(connssl->negotiated.alpn) != proto_len) || |
| + | memcmp(connssl->negotiated.alpn, proto, proto_len)) { |
| failf(data, "ALPN: asked for '%s' from previous session, but server " | |
| "selected '%.*s'. Refusing to continue.", | |
| - | connssl->alpn_negotiated, (int)proto_len, proto); |
| + | connssl->negotiated.alpn, (int)proto_len, proto); |
| result = CURLE_SSL_CONNECT_ERROR; | |
| goto out; | |
| } | |
| /* ALPN is exactly what we asked for, done. */ | |
| infof(data, "ALPN: server confirmed to use '%s'", | |
| - | connssl->alpn_negotiated); |
| + | connssl->negotiated.alpn); |
| goto out; | |
| } | |
| @@ -2190,11 +1911,11 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, | |
| result = CURLE_SSL_CONNECT_ERROR; | |
| goto out; | |
| } | |
| - | connssl->alpn_negotiated = malloc(proto_len + 1); |
| - | if(!connssl->alpn_negotiated) |
| + | connssl->negotiated.alpn = malloc(proto_len + 1); |
| + | if(!connssl->negotiated.alpn) |
| return CURLE_OUT_OF_MEMORY; | |
| - | memcpy(connssl->alpn_negotiated, proto, proto_len); |
| - | connssl->alpn_negotiated[proto_len] = 0; |
| + | memcpy(connssl->negotiated.alpn, proto, proto_len); |
| + | connssl->negotiated.alpn[proto_len] = 0; |
| } | |
| if(proto && proto_len) { | |
| @@ -28,7 +28,9 @@ | |
| struct connectdata; | |
| struct ssl_config_data; | |
| struct ssl_primary_config; | |
| - | struct Curl_ssl_session; |
| + | struct Curl_cfilter; |
| + | struct Curl_easy; |
| + | struct dynbuf; |
| #define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */ | |
| #define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */ | |
| @@ -63,9 +65,31 @@ struct Curl_ssl_session; | |
| #define VTLS_INFOF_ALPN_DEFERRED \ | |
| "ALPN: deferred handshake for early data using '%.*s'." | |
| - | /* Curl_multi SSL backend-specific data; declared differently by each SSL |
| - | backend */ |
| - | struct Curl_cfilter; |
| + | /* IETF defined version numbers used in TLS protocol negotiation */ |
| + | #define CURL_IETF_PROTO_UNKNOWN 0x0 |
| + | #define CURL_IETF_PROTO_SSL3 0x0300 |
| + | #define CURL_IETF_PROTO_TLS1 0x0301 |
| + | #define CURL_IETF_PROTO_TLS1_1 0x0302 |
| + | #define CURL_IETF_PROTO_TLS1_2 0x0303 |
| + | #define CURL_IETF_PROTO_TLS1_3 0x0304 |
| + | #define CURL_IETF_PROTO_DTLS1 0xFEFF |
| + | #define CURL_IETF_PROTO_DTLS1_2 0xFEFD |
| + | |
| + | typedef enum { |
| + | CURL_SSL_PEER_DNS, |
| + | CURL_SSL_PEER_IPV4, |
| + | CURL_SSL_PEER_IPV6 |
| + | } ssl_peer_type; |
| + | |
| + | struct ssl_peer { |
| + | char *hostname; /* hostname for verification */ |
| + | char *dispname; /* display version of hostname */ |
| + | char *sni; /* SNI version of hostname or NULL if not usable */ |
| + | char *scache_key; /* for lookups in session cache */ |
| + | ssl_peer_type type; /* type of the peer information */ |
| + | int port; /* port we are talking to */ |
| + | int transport; /* one of TRNSPRT_* defines */ |
| + | }; |
| CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, | |
| const curl_ssl_backend ***avail); | |
| @@ -121,7 +145,9 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy); | |
| * Init SSL peer information for filter. Can be called repeatedly. | |
| */ | |
| CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, | |
| - | struct Curl_cfilter *cf, int transport); |
| + | struct Curl_cfilter *cf, |
| + | const char *tls_id, |
| + | int transport); |
| /** | |
| * Free all allocated data and reset peer information. | |
| */ | |
| @@ -138,8 +164,6 @@ CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); | |
| CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); | |
| struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); | |
| - | /* init the SSL session ID cache */ |
| - | CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); |
| void Curl_ssl_version(char *buffer, size_t size); | |
| /* Certificate information list handling. */ | |
| @@ -155,33 +179,6 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, | |
| /* Functions to be used by SSL library adaptation functions */ | |
| - | /* Lock session cache mutex. |
| - | * Call this before calling other Curl_ssl_*session* functions |
| - | * Caller should unlock this mutex as soon as possible, as it may block |
| - | * other SSL connection from making progress. |
| - | * The purpose of explicitly locking SSL session cache data is to allow |
| - | * individual SSL engines to manage session lifetime in their specific way. |
| - | */ |
| - | void Curl_ssl_sessionid_lock(struct Curl_easy *data); |
| - | |
| - | /* Unlock session cache mutex */ |
| - | void Curl_ssl_sessionid_unlock(struct Curl_easy *data); |
| - | |
| - | /* Kill a single session ID entry in the cache |
| - | * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). |
| - | * This will call engine-specific curlssl_session_free function, which must |
| - | * take sessionid object ownership from sessionid cache |
| - | * (e.g. decrement refcount). |
| - | */ |
| - | void Curl_ssl_kill_session(struct Curl_ssl_session *session); |
| - | /* delete a session from the cache |
| - | * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). |
| - | * This will call engine-specific curlssl_session_free function, which must |
| - | * take sessionid object ownership from sessionid cache |
| - | * (e.g. decrement refcount). |
| - | */ |
| - | void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid); |
| - | |
| /* get N random bytes into the buffer */ | |
| CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, | |
| size_t length); | |
| @@ -273,9 +270,7 @@ extern struct Curl_cftype Curl_cft_ssl_proxy; | |
| #define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN | |
| #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN | |
| #define Curl_ssl_engines_list(x) NULL | |
| - | #define Curl_ssl_initsessions(x,y) CURLE_OK |
| #define Curl_ssl_free_certinfo(x) Curl_nop_stmt | |
| - | #define Curl_ssl_kill_session(x) Curl_nop_stmt |
| #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) | |
| #define Curl_ssl_cert_status_request() FALSE | |
| #define Curl_ssl_false_start() FALSE | |
| @@ -26,9 +26,11 @@ | |
| #include "curl_setup.h" | |
| #include "cfilters.h" | |
| #include "urldata.h" | |
| + | #include "vtls.h" |
| #ifdef USE_SSL | |
| + | struct Curl_ssl; |
| struct ssl_connect_data; | |
| /* see https://www.iana.org/assignments/tls-extensiontype-values/ */ | |
| @@ -103,12 +105,15 @@ typedef enum { | |
| /* Information in each SSL cfilter context: cf->ctx */ | |
| struct ssl_connect_data { | |
| - | struct ssl_peer peer; |
| + | const struct Curl_ssl *ssl_impl; /* TLS backend for this filter */ |
| + | struct ssl_peer peer; /* peer the filter talks to */ |
| const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ | |
| void *backend; /* vtls backend specific props */ | |
| struct cf_call_data call_data; /* data handle used in current call */ | |
| struct curltime handshake_done; /* time when handshake finished */ | |
| - | char *alpn_negotiated; /* negotiated ALPN value or NULL */ |
| + | struct { |
| + | char *alpn; /* ALPN value or NULL */ |
| + | } negotiated; |
| struct bufq earlydata; /* earlydata to be send to peer */ | |
| size_t earlydata_max; /* max earlydata allowed by peer */ | |
| size_t earlydata_skip; /* sending bytes to skip when earlydata | |
| @@ -193,43 +198,6 @@ void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, | |
| */ | |
| bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf); | |
| - | /* extract a session ID |
| - | * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). |
| - | * Caller must make sure that the ownership of returned sessionid object |
| - | * is properly taken (e.g. its refcount is incremented |
| - | * under sessionid mutex). |
| - | * @param cf the connection filter wanting to use it |
| - | * @param data the transfer involved |
| - | * @param peer the peer the filter wants to talk to |
| - | * @param sessionid on return the TLS session |
| - | * @param idsize on return the size of the TLS session data |
| - | * @param palpn on return the ALPN string used by the session, |
| - | * set to NULL when not interested |
| - | */ |
| - | bool Curl_ssl_getsessionid(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | const struct ssl_peer *peer, |
| - | void **ssl_sessionid, |
| - | size_t *idsize, /* set 0 if unknown */ |
| - | char **palpn); |
| - | |
| - | /* Set a TLS session ID for `peer`. Replaces an existing session ID if |
| - | * not already the same. |
| - | * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). |
| - | * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb` |
| - | * to deallocate it. Is called in all outcomes, either right away or |
| - | * later when the session cache is cleaned up. |
| - | * Caller must ensure that it has properly shared ownership of this sessionid |
| - | * object with cache (e.g. incrementing refcount on success) |
| - | */ |
| - | CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | const struct ssl_peer *peer, |
| - | const char *alpn, |
| - | void *sessionid, |
| - | size_t sessionid_size, |
| - | Curl_ssl_sessionid_dtor *sessionid_free_cb); |
| - | |
| #endif /* USE_SSL */ | |
| #endif /* HEADER_CURL_VTLS_INT_H */ | |
| @@ -0,0 +1,876 @@ | |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * Project ___| | | | _ \| | |
| + | * / __| | | | |_) | | |
| + | * | (__| |_| | _ <| |___ |
| + | * \___|\___/|_| \_\_____| |
| + | * |
| + | * Copyright (C) Daniel Stenberg, <[email protected]>, 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.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. |
| + | * |
| + | * SPDX-License-Identifier: curl |
| + | * |
| + | ***************************************************************************/ |
| + | |
| + | /* This file is for implementing all "generic" SSL functions that all libcurl |
| + | internals should use. It is then responsible for calling the proper |
| + | "backend" function. |
| + | |
| + | SSL-functions in libcurl should call functions in this source file, and not |
| + | to any specific SSL-layer. |
| + | |
| + | Curl_ssl_ - prefix for generic ones |
| + | |
| + | Note that this source code uses the functions of the configured SSL |
| + | backend via the global Curl_ssl instance. |
| + | |
| + | "SSL/TLS Strong Encryption: An Introduction" |
| + | https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html |
| + | */ |
| + | |
| + | #include "curl_setup.h" |
| + | |
| + | #ifdef USE_SSL |
| + | |
| + | #ifdef HAVE_SYS_TYPES_H |
| + | #include <sys/types.h> |
| + | #endif |
| + | #ifdef HAVE_SYS_STAT_H |
| + | #include <sys/stat.h> |
| + | #endif |
| + | #ifdef HAVE_FCNTL_H |
| + | #include <fcntl.h> |
| + | #endif |
| + | |
| + | #include "urldata.h" |
| + | #include "cfilters.h" |
| + | |
| + | #include "vtls.h" /* generic SSL protos etc */ |
| + | #include "vtls_int.h" |
| + | #include "vtls_scache.h" |
| + | |
| + | #include "strcase.h" |
| + | #include "url.h" |
| + | #include "llist.h" |
| + | #include "share.h" |
| + | #include "curl_trc.h" |
| + | #include "curl_sha256.h" |
| + | #include "warnless.h" |
| + | #include "curl_printf.h" |
| + | #include "strdup.h" |
| + | |
| + | /* The last #include files should be: */ |
| + | #include "curl_memory.h" |
| + | #include "memdebug.h" |
| + | |
| + | /* a peer+tls-config we cache sessions for */ |
| + | struct Curl_ssl_scache_peer { |
| + | char *ssl_peer_key; /* id for peer + relevant TLS configuration */ |
| + | char *clientcert; |
| + | char *srp_username; |
| + | char *srp_password; |
| + | struct Curl_llist sessions; |
| + | void *sobj; /* object instance or NULL */ |
| + | Curl_ssl_scache_obj_dtor *sobj_free; /* free `sobj` callback */ |
| + | unsigned char key_salt[CURL_SHA256_DIGEST_LENGTH]; /* for entry export */ |
| + | unsigned char key_hmac[CURL_SHA256_DIGEST_LENGTH]; /* for entry export */ |
| + | size_t max_sessions; |
| + | long age; /* just a number, the higher the more recent */ |
| + | BIT(hmac_set); /* if key_salt and key_hmac are present */ |
| + | }; |
| + | |
| + | struct Curl_ssl_scache { |
| + | struct Curl_ssl_scache_peer *peers; |
| + | size_t peer_count; |
| + | int default_lifetime_secs; |
| + | long age; |
| + | }; |
| + | |
| + | static void cf_ssl_scache_clear_session(struct Curl_ssl_session *s) |
| + | { |
| + | if(s->sdata) { |
| + | free((void *)s->sdata); |
| + | s->sdata = NULL; |
| + | } |
| + | s->sdata_len = 0; |
| + | s->ietf_tls_id = 0; |
| + | s->time_received = 0; |
| + | s->lifetime_secs = 0; |
| + | Curl_safefree(s->alpn); |
| + | } |
| + | |
| + | static void cf_ssl_scache_sesssion_ldestroy(void *udata, void *s) |
| + | { |
| + | (void)udata; |
| + | cf_ssl_scache_clear_session(s); |
| + | free(s); |
| + | } |
| + | |
| + | CURLcode |
| + | Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len, |
| + | int ietf_tls_id, const char *alpn, |
| + | curl_off_t time_received, long lifetime_secs, |
| + | struct Curl_ssl_session **psession) |
| + | { |
| + | struct Curl_ssl_session *s; |
| + | |
| + | if(!sdata || !sdata_len) { |
| + | free(sdata); |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | } |
| + | |
| + | *psession = NULL; |
| + | s = calloc(1, sizeof(*s)); |
| + | if(!s) { |
| + | free(sdata); |
| + | return CURLE_OUT_OF_MEMORY; |
| + | } |
| + | |
| + | s->ietf_tls_id = ietf_tls_id; |
| + | s->time_received = time_received; |
| + | if(lifetime_secs < 0) |
| + | lifetime_secs = -1; /* unknown */ |
| + | else if((s->ietf_tls_id == CURL_IETF_PROTO_TLS1_3) && |
| + | (lifetime_secs > CURL_SCACHE_MAX_13_LIFETIME_SEC)) |
| + | lifetime_secs = CURL_SCACHE_MAX_13_LIFETIME_SEC; |
| + | else if(lifetime_secs > CURL_SCACHE_MAX_12_LIFETIME_SEC) |
| + | lifetime_secs = CURL_SCACHE_MAX_12_LIFETIME_SEC; |
| + | |
| + | s->lifetime_secs = (int)lifetime_secs; |
| + | s->sdata = sdata; |
| + | s->sdata_len = sdata_len; |
| + | if(alpn) { |
| + | s->alpn = strdup(alpn); |
| + | if(!s->alpn) { |
| + | cf_ssl_scache_sesssion_ldestroy(NULL, s); |
| + | return CURLE_OUT_OF_MEMORY; |
| + | } |
| + | } |
| + | *psession = s; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | void Curl_ssl_session_destroy(struct Curl_ssl_session *s) |
| + | { |
| + | if(s) { |
| + | /* if in the list, the list destructor takes care of it */ |
| + | if(Curl_node_llist(&s->list)) |
| + | Curl_node_remove(&s->list); |
| + | else { |
| + | cf_ssl_scache_sesssion_ldestroy(NULL, s); |
| + | } |
| + | } |
| + | } |
| + | |
| + | static void cf_ssl_scache_clear_peer(struct Curl_ssl_scache_peer *peer) |
| + | { |
| + | Curl_llist_destroy(&peer->sessions, NULL); |
| + | if(peer->sobj) { |
| + | DEBUGASSERT(peer->sobj_free); |
| + | if(peer->sobj_free) |
| + | peer->sobj_free(peer->sobj); |
| + | peer->sobj = NULL; |
| + | } |
| + | peer->sobj_free = NULL; |
| + | Curl_safefree(peer->clientcert); |
| + | #ifdef USE_TLS_SRP |
| + | Curl_safefree(peer->srp_username); |
| + | Curl_safefree(peer->srp_password); |
| + | #endif |
| + | Curl_safefree(peer->ssl_peer_key); |
| + | peer->age = 0; |
| + | peer->hmac_set = FALSE; |
| + | } |
| + | |
| + | static void cf_ssl_scache_peer_set_obj(struct Curl_ssl_scache_peer *peer, |
| + | void *sobj, |
| + | Curl_ssl_scache_obj_dtor *sobj_free) |
| + | { |
| + | DEBUGASSERT(peer); |
| + | if(peer->sobj_free) { |
| + | peer->sobj_free(peer->sobj); |
| + | } |
| + | peer->sobj = sobj; |
| + | peer->sobj_free = sobj_free; |
| + | } |
| + | |
| + | static CURLcode cf_ssl_scache_peer_init(struct Curl_ssl_scache_peer *peer, |
| + | const char *ssl_peer_key, |
| + | const char *clientcert, |
| + | const char *srp_username, |
| + | const char *srp_password) |
| + | { |
| + | CURLcode result = CURLE_OUT_OF_MEMORY; |
| + | |
| + | DEBUGASSERT(!peer->ssl_peer_key); |
| + | peer->ssl_peer_key = strdup(ssl_peer_key); |
| + | if(!peer->ssl_peer_key) |
| + | goto out; |
| + | if(clientcert) { |
| + | peer->clientcert = strdup(clientcert); |
| + | if(!peer->clientcert) |
| + | goto out; |
| + | } |
| + | if(srp_username) { |
| + | peer->srp_username = strdup(srp_username); |
| + | if(!peer->srp_username) |
| + | goto out; |
| + | } |
| + | if(srp_password) { |
| + | peer->srp_password = strdup(srp_password); |
| + | if(!peer->srp_password) |
| + | goto out; |
| + | } |
| + | result = CURLE_OK; |
| + | out: |
| + | if(result) |
| + | cf_ssl_scache_clear_peer(peer); |
| + | return result; |
| + | } |
| + | |
| + | static void cf_scache_session_remove(struct Curl_ssl_scache_peer *peer, |
| + | struct Curl_ssl_session *s) |
| + | { |
| + | (void)peer; |
| + | DEBUGASSERT(Curl_node_llist(&s->list) == &peer->sessions); |
| + | Curl_ssl_session_destroy(s); |
| + | } |
| + | |
| + | static bool cf_scache_session_expired(struct Curl_ssl_session *s, |
| + | curl_off_t now) |
| + | { |
| + | return (s->lifetime_secs > 0 && |
| + | (s->time_received + s->lifetime_secs) < now); |
| + | } |
| + | |
| + | static void cf_scache_peer_remove_expired(struct Curl_ssl_scache_peer *peer, |
| + | curl_off_t now) |
| + | { |
| + | struct Curl_llist_node *n = Curl_llist_head(&peer->sessions); |
| + | while(n) { |
| + | struct Curl_ssl_session *s = Curl_node_elem(n); |
| + | n = Curl_node_next(n); |
| + | if(cf_scache_session_expired(s, now)) |
| + | cf_scache_session_remove(peer, s); |
| + | } |
| + | } |
| + | |
| + | static void cf_scache_peer_remove_non13(struct Curl_ssl_scache_peer *peer) |
| + | { |
| + | struct Curl_llist_node *n = Curl_llist_head(&peer->sessions); |
| + | while(n) { |
| + | struct Curl_ssl_session *s = Curl_node_elem(n); |
| + | n = Curl_node_next(n); |
| + | if(s->ietf_tls_id != CURL_IETF_PROTO_TLS1_3) |
| + | cf_scache_session_remove(peer, s); |
| + | } |
| + | } |
| + | |
| + | CURLcode Curl_ssl_scache_create(size_t max_peers, |
| + | size_t max_sessions_per_peer, |
| + | struct Curl_ssl_scache **pscache) |
| + | { |
| + | struct Curl_ssl_scache *scache; |
| + | struct Curl_ssl_scache_peer *peers; |
| + | size_t i; |
| + | |
| + | *pscache = NULL; |
| + | peers = calloc(max_peers, sizeof(*peers)); |
| + | if(!peers) |
| + | return CURLE_OUT_OF_MEMORY; |
| + | |
| + | scache = calloc(1, sizeof(*scache)); |
| + | if(!scache) { |
| + | free(peers); |
| + | return CURLE_OUT_OF_MEMORY; |
| + | } |
| + | |
| + | scache->default_lifetime_secs = (24*60*60); /* 1 day */ |
| + | scache->peer_count = max_peers; |
| + | scache->peers = peers; |
| + | scache->age = 1; |
| + | for(i = 0; i < scache->peer_count; ++i) { |
| + | scache->peers[i].max_sessions = max_sessions_per_peer; |
| + | Curl_llist_init(&scache->peers[i].sessions, |
| + | cf_ssl_scache_sesssion_ldestroy); |
| + | } |
| + | |
| + | *pscache = scache; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | void Curl_ssl_scache_destroy(struct Curl_ssl_scache *scache) |
| + | { |
| + | if(scache) { |
| + | size_t i; |
| + | for(i = 0; i < scache->peer_count; ++i) { |
| + | cf_ssl_scache_clear_peer(&scache->peers[i]); |
| + | } |
| + | free(scache->peers); |
| + | free(scache); |
| + | } |
| + | } |
| + | |
| + | /* Lock shared SSL session data */ |
| + | void Curl_ssl_scache_lock(struct Curl_easy *data) |
| + | { |
| + | if(CURL_SHARE_ssl_scache(data)) |
| + | Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); |
| + | } |
| + | |
| + | /* Unlock shared SSL session data */ |
| + | void Curl_ssl_scache_unlock(struct Curl_easy *data) |
| + | { |
| + | if(CURL_SHARE_ssl_scache(data)) |
| + | Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); |
| + | } |
| + | |
| + | static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf, |
| + | const char *name, |
| + | char *path) |
| + | { |
| + | if(path && path[0]) { |
| + | /* We try to add absolute paths, so that the session key can stay |
| + | * valid when used in another process with different CWD. However, |
| + | * when a path does not exist, this does not work. Then, we add |
| + | * the path as is. */ |
| + | #ifdef _WIN32 |
| + | char abspath[_MAX_PATH]; |
| + | if(_fullpath(abspath, path, _MAX_PATH)) |
| + | return Curl_dyn_addf(buf, ":%s-%s", name, abspath); |
| + | #else |
| + | if(path[0] != '/') { |
| + | char *abspath = realpath(path, NULL); |
| + | if(abspath) { |
| + | CURLcode r = Curl_dyn_addf(buf, ":%s-%s", name, abspath); |
| + | (free)(abspath); /* allocated by libc, free without memdebug */ |
| + | return r; |
| + | } |
| + | } |
| + | #endif |
| + | return Curl_dyn_addf(buf, ":%s-%s", name, path); |
| + | } |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf, |
| + | const char *name, |
| + | struct curl_blob *blob) |
| + | { |
| + | CURLcode r = CURLE_OK; |
| + | if(blob && blob->len) { |
| + | unsigned char hash[CURL_SHA256_DIGEST_LENGTH]; |
| + | size_t i; |
| + | |
| + | r = Curl_dyn_addf(buf, ":%s-", name); |
| + | if(r) |
| + | goto out; |
| + | r = Curl_sha256it(hash, blob->data, blob->len); |
| + | if(r) |
| + | goto out; |
| + | for(i = 0; i < CURL_SHA256_DIGEST_LENGTH; ++i) { |
| + | r = Curl_dyn_addf(buf, "%02x", hash[i]); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | } |
| + | out: |
| + | return r; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf, |
| + | const struct ssl_peer *peer, |
| + | const char *tls_id, |
| + | char **ppeer_key) |
| + | { |
| + | struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf); |
| + | struct dynbuf buf; |
| + | size_t key_len; |
| + | CURLcode r; |
| + | |
| + | *ppeer_key = NULL; |
| + | Curl_dyn_init(&buf, 10 * 1024); |
| + | |
| + | r = Curl_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port); |
| + | if(r) |
| + | goto out; |
| + | |
| + | switch(peer->transport) { |
| + | case TRNSPRT_TCP: |
| + | break; |
| + | case TRNSPRT_UDP: |
| + | r = Curl_dyn_add(&buf, ":UDP"); |
| + | break; |
| + | case TRNSPRT_QUIC: |
| + | r = Curl_dyn_add(&buf, ":QUIC"); |
| + | break; |
| + | case TRNSPRT_UNIX: |
| + | r = Curl_dyn_add(&buf, ":UNIX"); |
| + | break; |
| + | default: |
| + | r = Curl_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport); |
| + | break; |
| + | } |
| + | if(r) |
| + | goto out; |
| + | |
| + | if(!ssl->verifypeer) { |
| + | r = Curl_dyn_add(&buf, ":NO-VRFY-PEER"); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(!ssl->verifyhost) { |
| + | r = Curl_dyn_add(&buf, ":NO-VRFY-HOST"); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->verifystatus) { |
| + | r = Curl_dyn_add(&buf, ":VRFY-STATUS"); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(!ssl->verifypeer || !ssl->verifyhost) { |
| + | if(cf->conn->bits.conn_to_host) { |
| + | r = Curl_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(cf->conn->bits.conn_to_port) { |
| + | r = Curl_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | } |
| + | |
| + | if(ssl->version || ssl->version_max) { |
| + | r = Curl_dyn_addf(&buf, ":TLSVER-%d-%d", ssl->version, |
| + | (ssl->version_max >> 16)); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->ssl_options) { |
| + | r = Curl_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->cipher_list) { |
| + | r = Curl_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->cipher_list13) { |
| + | r = Curl_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->curves) { |
| + | r = Curl_dyn_addf(&buf, ":CURVES-%s", ssl->curves); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->verifypeer) { |
| + | r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile); |
| + | if(r) |
| + | goto out; |
| + | r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath); |
| + | if(r) |
| + | goto out; |
| + | r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile); |
| + | if(r) |
| + | goto out; |
| + | r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert); |
| + | if(r) |
| + | goto out; |
| + | if(ssl->cert_blob) { |
| + | r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->ca_info_blob) { |
| + | r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(ssl->issuercert_blob) { |
| + | r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | } |
| + | if(ssl->pinned_key && ssl->pinned_key[0]) { |
| + | r = Curl_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | |
| + | if(ssl->clientcert && ssl->clientcert[0]) { |
| + | r = Curl_dyn_add(&buf, ":CCERT"); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | #ifdef USE_TLS_SRP |
| + | if(ssl->username || ssl->password) { |
| + | r = Curl_dyn_add(&buf, ":SRP-AUTH"); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | #endif |
| + | |
| + | if(!tls_id || !tls_id[0]) { |
| + | r = CURLE_FAILED_INIT; |
| + | goto out; |
| + | } |
| + | r = Curl_dyn_addf(&buf, ":IMPL-%s", tls_id); |
| + | if(r) |
| + | goto out; |
| + | |
| + | *ppeer_key = Curl_dyn_take(&buf, &key_len); |
| + | /* we just added printable char, and dynbuf always 0 terminates, |
| + | * no need to track length */ |
| + | |
| + | |
| + | out: |
| + | Curl_dyn_free(&buf); |
| + | return r; |
| + | } |
| + | |
| + | static bool cf_ssl_scache_match_auth(struct Curl_ssl_scache_peer *peer, |
| + | struct ssl_primary_config *conn_config) |
| + | { |
| + | if(!Curl_safecmp(peer->clientcert, conn_config->clientcert)) |
| + | return FALSE; |
| + | #ifdef USE_TLS_SRP |
| + | if(Curl_timestrcmp(peer->srp_username, conn_config->username) || |
| + | Curl_timestrcmp(peer->srp_password, conn_config->password)) |
| + | return FALSE; |
| + | #endif |
| + | return TRUE; |
| + | } |
| + | |
| + | static CURLcode cf_ssl_find_peer(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | struct Curl_ssl_scache *scache, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_scache_peer **ppeer) |
| + | { |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| + | struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
| + | size_t i, peer_key_len = 0; |
| + | CURLcode result = CURLE_OK; |
| + | |
| + | *ppeer = NULL; |
| + | if(!ssl_config || !ssl_config->primary.cache_session) |
| + | goto out; |
| + | |
| + | /* check for entries with known peer_key */ |
| + | for(i = 0; scache && i < scache->peer_count; i++) { |
| + | if(scache->peers[i].ssl_peer_key && |
| + | strcasecompare(ssl_peer_key, scache->peers[i].ssl_peer_key) && |
| + | cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) { |
| + | /* yes, we have a cached session for this! */ |
| + | *ppeer = &scache->peers[i]; |
| + | goto out; |
| + | } |
| + | } |
| + | /* check for entries with HMAC set but no known peer_key */ |
| + | for(i = 0; scache && i < scache->peer_count; i++) { |
| + | if(!scache->peers[i].ssl_peer_key && |
| + | scache->peers[i].hmac_set && |
| + | cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) { |
| + | /* possible entry with unknown peer_key, check hmac */ |
| + | unsigned char my_hmac[CURL_SHA256_DIGEST_LENGTH]; |
| + | if(!peer_key_len) /* we are lazy */ |
| + | peer_key_len = strlen(ssl_peer_key); |
| + | (void)Curl_hmacit(&Curl_HMAC_SHA256, |
| + | scache->peers[i].key_salt, |
| + | sizeof(scache->peers[i].key_salt), |
| + | (const unsigned char *)ssl_peer_key, |
| + | peer_key_len, |
| + | my_hmac); |
| + | if(!memcmp(scache->peers[i].key_hmac, my_hmac, sizeof(my_hmac))) { |
| + | /* remember peer_key for future lookups */ |
| + | scache->peers[i].ssl_peer_key = strdup(ssl_peer_key); |
| + | if(!scache->peers[i].ssl_peer_key) { |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | goto out; |
| + | } |
| + | *ppeer = &scache->peers[i]; |
| + | goto out; |
| + | } |
| + | } |
| + | } |
| + | out: |
| + | if(result) |
| + | CURL_TRC_CF(data, cf, "[SACHE] failure finding scache peer: %d", result); |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode cf_ssl_add_peer(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | struct Curl_ssl_scache *scache, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_scache_peer **ppeer) |
| + | { |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | size_t i; |
| + | CURLcode result; |
| + | |
| + | *ppeer = NULL; |
| + | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(result || !scache->peer_count) |
| + | return result; |
| + | |
| + | if(peer) { |
| + | *ppeer = peer; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | /* not there, find empty or oldest peer */ |
| + | for(i = 0; i < scache->peer_count; ++i) { |
| + | /* free peer entry? */ |
| + | if(!scache->peers[i].ssl_peer_key && !scache->peers[i].hmac_set) { |
| + | peer = &scache->peers[i]; |
| + | break; |
| + | } |
| + | /* peer without sessions and obj */ |
| + | if(!scache->peers[i].sobj && |
| + | !Curl_llist_count(&scache->peers[i].sessions)) { |
| + | peer = &scache->peers[i]; |
| + | break; |
| + | } |
| + | /* remember "oldest" peer */ |
| + | if(!peer || (scache->peers[i].age < peer->age)) { |
| + | peer = &scache->peers[i]; |
| + | } |
| + | } |
| + | DEBUGASSERT(peer); |
| + | if(!peer) |
| + | return CURLE_OK; |
| + | /* clear previous peer and reinit */ |
| + | cf_ssl_scache_clear_peer(peer); |
| + | result = cf_ssl_scache_peer_init(peer, ssl_peer_key, |
| + | conn_config->clientcert, |
| + | #ifdef USE_TLS_SRP |
| + | conn_config->username, |
| + | conn_config->password); |
| + | #else |
| + | NULL, NULL); |
| + | #endif |
| + | if(result) |
| + | goto out; |
| + | /* all ready */ |
| + | *ppeer = peer; |
| + | result = CURLE_OK; |
| + | |
| + | out: |
| + | if(result) { |
| + | cf_ssl_scache_clear_peer(peer); |
| + | CURL_TRC_CF(data, cf, "[SACHE] failure adding peer: %d", result); |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode cf_scache_peer_add_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | struct Curl_ssl_scache *scache, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session *s) |
| + | { |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | CURLcode result = CURLE_OUT_OF_MEMORY; |
| + | curl_off_t now = (curl_off_t)time(NULL); |
| + | |
| + | if(!scache || !scache->peer_count) { |
| + | Curl_ssl_session_destroy(s); |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | if(!s->time_received) |
| + | s->time_received = now; |
| + | if(s->lifetime_secs < 0) |
| + | s->lifetime_secs = scache->default_lifetime_secs; |
| + | |
| + | if(cf_scache_session_expired(s, now)) { |
| + | CURL_TRC_CF(data, cf, "[SCACHE] add, session already expired"); |
| + | Curl_ssl_session_destroy(s); |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | result = cf_ssl_add_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(result || !peer) { |
| + | CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result); |
| + | Curl_ssl_session_destroy(s); |
| + | goto out; |
| + | } |
| + | |
| + | /* A session not from TLSv1.3 replaces all other. */ |
| + | if(s->ietf_tls_id != CURL_IETF_PROTO_TLS1_3) { |
| + | Curl_llist_destroy(&peer->sessions, NULL); |
| + | Curl_llist_append(&peer->sessions, s, &s->list); |
| + | } |
| + | else { |
| + | /* Expire existing, append, trim from head to obey max_sessions */ |
| + | cf_scache_peer_remove_expired(peer, now); |
| + | cf_scache_peer_remove_non13(peer); |
| + | Curl_llist_append(&peer->sessions, s, &s->list); |
| + | while(Curl_llist_count(&peer->sessions) > peer->max_sessions) { |
| + | Curl_node_remove(Curl_llist_head(&peer->sessions)); |
| + | } |
| + | } |
| + | |
| + | out: |
| + | if(result) { |
| + | failf(data, "[SCACHE] failed to add session for %s, error=%d", |
| + | ssl_peer_key, result); |
| + | } |
| + | else |
| + | CURL_TRC_CF(data, cf, "[SCACHE] added session for %s [proto=0x%x, " |
| + | "lifetime=%d, alpn=%s], peer has %zu sessions now", |
| + | ssl_peer_key, s->ietf_tls_id, s->lifetime_secs, s->alpn, |
| + | Curl_llist_count(&peer->sessions)); |
| + | return result; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session *s) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | CURLcode result; |
| + | |
| + | Curl_ssl_scache_lock(data); |
| + | result = cf_scache_peer_add_session(cf, data, scache, ssl_peer_key, s); |
| + | Curl_ssl_scache_unlock(data); |
| + | return result; |
| + | } |
| + | |
| + | void Curl_ssl_scache_return(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session *s) |
| + | { |
| + | /* See RFC 8446 C.4: |
| + | * "Clients SHOULD NOT reuse a ticket for multiple connections." */ |
| + | if(s && s->ietf_tls_id < 0x304) |
| + | (void)Curl_ssl_scache_put(cf, data, ssl_peer_key, s); |
| + | else |
| + | Curl_ssl_session_destroy(s); |
| + | } |
| + | |
| + | CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session **ps) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | struct Curl_llist_node *n; |
| + | CURLcode result; |
| + | |
| + | *ps = NULL; |
| + | if(!scache) |
| + | return CURLE_OK; |
| + | |
| + | Curl_ssl_scache_lock(data); |
| + | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(!result && peer) { |
| + | cf_scache_peer_remove_expired(peer, (curl_off_t)time(NULL)); |
| + | n = Curl_llist_head(&peer->sessions); |
| + | if(n) { |
| + | *ps = Curl_node_take_elem(n); |
| + | (scache->age)++; /* increase general age */ |
| + | peer->age = scache->age; /* set this as used in this age */ |
| + | } |
| + | } |
| + | Curl_ssl_scache_unlock(data); |
| + | |
| + | CURL_TRC_CF(data, cf, "[SCACHE] %s cached session for '%s'", |
| + | *ps ? "Found" : "No", ssl_peer_key); |
| + | return result; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | void *sobj, |
| + | Curl_ssl_scache_obj_dtor *sobj_free) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | CURLcode result; |
| + | |
| + | DEBUGASSERT(sobj); |
| + | DEBUGASSERT(sobj_free); |
| + | |
| + | result = cf_ssl_add_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(result || !peer) { |
| + | CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result); |
| + | goto out; |
| + | } |
| + | |
| + | cf_ssl_scache_peer_set_obj(peer, sobj, sobj_free); |
| + | sobj = NULL; /* peer took ownership */ |
| + | |
| + | out: |
| + | if(sobj && sobj_free) |
| + | sobj_free(sobj); |
| + | return result; |
| + | } |
| + | |
| + | bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | void **sobj) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | CURLcode result; |
| + | |
| + | *sobj = NULL; |
| + | if(!scache) |
| + | return FALSE; |
| + | |
| + | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(result) |
| + | return FALSE; |
| + | |
| + | if(peer) |
| + | *sobj = peer->sobj; |
| + | |
| + | CURL_TRC_CF(data, cf, "[SACHE] %s cached session for '%s'", |
| + | *sobj ? "Found" : "No", ssl_peer_key); |
| + | return !!*sobj; |
| + | } |
| + | |
| + | void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | CURLcode result; |
| + | |
| + | (void)cf; |
| + | if(!scache) |
| + | return; |
| + | |
| + | Curl_ssl_scache_lock(data); |
| + | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | if(!result && peer) |
| + | cf_ssl_scache_clear_peer(peer); |
| + | Curl_ssl_scache_unlock(data); |
| + | } |
| + | |
| + | #endif /* USE_SSL */ |
| @@ -0,0 +1,196 @@ | |
| + | #ifndef HEADER_CURL_VTLS_SCACHE_H |
| + | #define HEADER_CURL_VTLS_SCACHE_H |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * Project ___| | | | _ \| | |
| + | * / __| | | | |_) | | |
| + | * | (__| |_| | _ <| |___ |
| + | * \___|\___/|_| \_\_____| |
| + | * |
| + | * Copyright (C) Daniel Stenberg, <[email protected]>, 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.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. |
| + | * |
| + | * SPDX-License-Identifier: curl |
| + | * |
| + | ***************************************************************************/ |
| + | #include "curl_setup.h" |
| + | #include "cfilters.h" |
| + | #include "urldata.h" |
| + | |
| + | #ifdef USE_SSL |
| + | |
| + | struct Curl_cfilter; |
| + | struct Curl_easy; |
| + | struct Curl_ssl_scache; |
| + | struct Curl_ssl_session; |
| + | struct ssl_peer; |
| + | |
| + | /* RFC 8446 (TLSv1.3) restrict lifetime to one week max, for |
| + | * other, less secure versions, we restrict it to a day */ |
| + | #define CURL_SCACHE_MAX_13_LIFETIME_SEC (60*60*24*7) |
| + | #define CURL_SCACHE_MAX_12_LIFETIME_SEC (60*60*24) |
| + | |
| + | /* Create a session cache for up to max_peers endpoints with a total |
| + | * of up to max_sessions SSL sessions per peer */ |
| + | CURLcode Curl_ssl_scache_create(size_t max_peers, |
| + | size_t max_sessions_per_peer, |
| + | struct Curl_ssl_scache **pscache); |
| + | |
| + | void Curl_ssl_scache_destroy(struct Curl_ssl_scache *scache); |
| + | |
| + | /* Create a key from peer and TLS configuration information that is |
| + | * unique for how the connection filter wants to establish a TLS |
| + | * connection to the peer. |
| + | * If the filter is a TLS proxy filter, it will use the proxy relevant |
| + | * information. |
| + | * @param cf the connection filter wanting to use it |
| + | * @param peer the peer the filter wants to talk to |
| + | * @param tls_id identifier of TLS implementation for sessions. Should |
| + | * include full version if session data from other versions |
| + | * is to be avoided. |
| + | * @param ppeer_key on successful return, the key generated |
| + | */ |
| + | CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf, |
| + | const struct ssl_peer *peer, |
| + | const char *tls_id, |
| + | char **ppeer_key); |
| + | |
| + | /* Lock session cache mutex. |
| + | * Call this before calling other Curl_ssl_*session* functions |
| + | * Caller should unlock this mutex as soon as possible, as it may block |
| + | * other SSL connection from making progress. |
| + | * The purpose of explicitly locking SSL session cache data is to allow |
| + | * individual SSL engines to manage session lifetime in their specific way. |
| + | */ |
| + | void Curl_ssl_scache_lock(struct Curl_easy *data); |
| + | |
| + | /* Unlock session cache mutex */ |
| + | void Curl_ssl_scache_unlock(struct Curl_easy *data); |
| + | |
| + | /* Get TLS session object from the cache for the ssl_peer_ey. |
| + | * scache mutex must be locked (see Curl_ssl_scache_lock). |
| + | * Caller must make sure that the ownership of returned session object |
| + | * is properly taken (e.g. its refcount is incremented |
| + | * under scache mutex). |
| + | * @param cf the connection filter wanting to use it |
| + | * @param data the transfer involved |
| + | * @param ssl_peer_key the key for lookup |
| + | * @param sobj on return, the object for the peer key or NULL |
| + | */ |
| + | bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | void **sobj); |
| + | |
| + | typedef void Curl_ssl_scache_obj_dtor(void *sobj); |
| + | |
| + | /* Add a TLS session related object to the cache. |
| + | * Replaces an existing object with the same peer_key. |
| + | * scache mutex must be locked (see Curl_ssl_scache_lock). |
| + | * Call takes ownership of `sobj`, using `sobj_dtor_cb` |
| + | * to deallocate it. Is called in all outcomes, either right away or |
| + | * later when the session cache is cleaned up. |
| + | * Caller must ensure that it has properly shared ownership of `sobj` |
| + | * with cache (e.g. incrementing refcount on success) |
| + | * @param cf the connection filter wanting to use it |
| + | * @param data the transfer involved |
| + | * @param ssl_peer_key the key for lookup |
| + | * @param sobj the TLS session object |
| + | * @param sobj_free_cb callback to free the session objectt |
| + | */ |
| + | CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | void *sobj, |
| + | Curl_ssl_scache_obj_dtor *sobj_dtor_cb); |
| + | |
| + | /* All about a SSL session ticket */ |
| + | struct Curl_ssl_session { |
| + | const unsigned char *sdata; /* session ticket data, plain bytes */ |
| + | size_t sdata_len; /* number of bytes in sdata */ |
| + | curl_off_t time_received; /* seconds since EPOCH ticket was received */ |
| + | int lifetime_secs; /* ticket lifetime (-1 unknown) */ |
| + | int ietf_tls_id; /* TLS protocol identifier negotiated */ |
| + | char *alpn; /* APLN TLS negotiated protocol string */ |
| + | struct Curl_llist_node list; /* internal storage handling */ |
| + | }; |
| + | |
| + | /* Create a `session` instance. Does NOT need locking. |
| + | * Takes ownership of `sdata` and `sobj` regardless of return code. |
| + | * @param sdata bytes of SSL session data or NULL (sobj then required) |
| + | * @param sdata_len amount of session data bytes |
| + | * @param ietf_tls_id IETF protocol version, e.g. 0x304 for TLSv1.3 |
| + | * @param alpn ALPN protocol selected or NULL |
| + | * @param time_received seconds since EPOCH session was received, pass 0 |
| + | * to have the value set to time of call |
| + | * @param lifetime_secs seconds of announced lifetime, <0 if unknown. |
| + | * values longer than 1 week will be capped as |
| + | * required by RFC 8446 |
| + | * @param psession on return the scached session instance created |
| + | */ |
| + | CURLcode |
| + | Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len, |
| + | int ietf_tls_id, const char *alpn, |
| + | curl_off_t time_received, long lifetime_secs, |
| + | struct Curl_ssl_session **psession); |
| + | |
| + | /* Destroy a `session` instance. Can be called with NULL. |
| + | * Does NOT need locking. */ |
| + | void Curl_ssl_session_destroy(struct Curl_ssl_session *s); |
| + | |
| + | /* Put the scache session into the cache. Does NOT need locking. |
| + | * Call takes ownership of `s` in all outcomes. |
| + | * @param cf the connection filter wanting to use it |
| + | * @param data the transfer involved |
| + | * @param ssl_peer_key the key for lookup |
| + | * @param s the scache session object |
| + | */ |
| + | CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session *s); |
| + | |
| + | /* Take a matching scache session from the cache. Does NOT need locking. |
| + | * @param cf the connection filter wanting to use it |
| + | * @param data the transfer involved |
| + | * @param ssl_peer_key the key for lookup |
| + | * @param s on return, the scache session object or NULL |
| + | */ |
| + | CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session **ps); |
| + | |
| + | /* Return a taken scache session to the cache. Does NOT need locking. |
| + | * Depending on TLS version and other criteria, it may cache it again |
| + | * or destroy it. Maybe called with a NULL session. |
| + | */ |
| + | void Curl_ssl_scache_return(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | struct Curl_ssl_session *s); |
| + | |
| + | /* Remove all sessions and obj for the peer_key. Does NOT need locking. */ |
| + | void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key); |
| + | |
| + | |
| + | #else /* USE_SSL */ |
| + | |
| + | #define Curl_ssl_scache_create(x,y) CURLE_OK |
| + | #define Curl_ssl_scache_destroy(x) CURLE_OK |
| + | |
| + | #endif /* USE_SSL (else) */ |
| + | |
| + | #endif /* HEADER_CURL_VTLS_SCACHE_H */ |
| @@ -60,6 +60,7 @@ | |
| #include "inet_pton.h" | |
| #include "vtls.h" | |
| #include "vtls_int.h" | |
| + | #include "vtls_scache.h" |
| #include "keylog.h" | |
| #include "parsedate.h" | |
| #include "connect.h" /* for the connect timeout */ | |
| @@ -395,57 +396,53 @@ static void wolfssl_bio_cf_free_methods(void) | |
| #endif /* !USE_BIO_CHAIN */ | |
| - | static void wolfssl_session_free(void *sdata, size_t slen) |
| - | { |
| - | (void)slen; |
| - | free(sdata); |
| - | } |
| - | |
| - | CURLcode wssl_cache_session(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | struct ssl_peer *peer, |
| - | WOLFSSL_SESSION *session) |
| + | CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | WOLFSSL_SESSION *session, |
| + | int ietf_tls_id, |
| + | const char *alpn) |
| { | |
| CURLcode result = CURLE_OK; | |
| + | struct Curl_ssl_session *sc_session = NULL; |
| unsigned char *sdata = NULL; | |
| - | unsigned int slen; |
| + | unsigned int sdata_len; |
| if(!session) | |
| goto out; | |
| - | slen = wolfSSL_i2d_SSL_SESSION(session, NULL); |
| - | if(slen <= 0) { |
| - | CURL_TRC_CF(data, cf, "fail to assess session length: %u", slen); |
| + | sdata_len = wolfSSL_i2d_SSL_SESSION(session, NULL); |
| + | if(sdata_len <= 0) { |
| + | CURL_TRC_CF(data, cf, "fail to assess session length: %u", sdata_len); |
| result = CURLE_FAILED_INIT; | |
| goto out; | |
| } | |
| - | sdata = calloc(1, slen); |
| + | sdata = calloc(1, sdata_len); |
| if(!sdata) { | |
| - | failf(data, "unable to allocate session buffer of %u bytes", slen); |
| + | failf(data, "unable to allocate session buffer of %u bytes", sdata_len); |
| result = CURLE_OUT_OF_MEMORY; | |
| goto out; | |
| } | |
| - | slen = wolfSSL_i2d_SSL_SESSION(session, &sdata); |
| - | if(slen <= 0) { |
| - | CURL_TRC_CF(data, cf, "fail to serialize session: %u", slen); |
| + | sdata_len = wolfSSL_i2d_SSL_SESSION(session, &sdata); |
| + | if(sdata_len <= 0) { |
| + | CURL_TRC_CF(data, cf, "fail to serialize session: %u", sdata_len); |
| result = CURLE_FAILED_INIT; | |
| goto out; | |
| } | |
| - | Curl_ssl_sessionid_lock(data); |
| - | result = Curl_ssl_set_sessionid(cf, data, peer, NULL, |
| - | sdata, slen, wolfssl_session_free); |
| - | Curl_ssl_sessionid_unlock(data); |
| - | if(result) |
| - | failf(data, "failed to add new ssl session to cache (%d)", result); |
| - | else { |
| - | CURL_TRC_CF(data, cf, "added new session to cache"); |
| - | sdata = NULL; |
| + | result = Curl_ssl_session_create(sdata, sdata_len, |
| + | ietf_tls_id, alpn, 0, |
| + | wolfSSL_SESSION_get_timeout(session), |
| + | &sc_session); |
| + | sdata = NULL; /* took ownership of sdata */ |
| + | if(!result) { |
| + | result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session); |
| + | /* took ownership of `sc_session` */ |
| } | |
| out: | |
| free(sdata); | |
| - | return 0; |
| + | return result; |
| } | |
| static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) | |
| @@ -460,32 +457,35 @@ static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) | |
| DEBUGASSERT(connssl); | |
| DEBUGASSERT(data); | |
| if(connssl && data) { | |
| - | (void)wssl_cache_session(cf, data, &connssl->peer, session); |
| + | (void)Curl_wssl_cache_session(cf, data, connssl->peer.scache_key, |
| + | session, wolfSSL_version(ssl), |
| + | connssl->negotiated.alpn); |
| } | |
| } | |
| return 0; | |
| } | |
| - | CURLcode wssl_setup_session(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | struct wolfssl_ctx *wss, |
| - | struct ssl_peer *peer) |
| + | CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | struct wolfssl_ctx *wss, |
| + | const char *ssl_peer_key) |
| { | |
| - | void *psdata; |
| - | const unsigned char *sdata = NULL; |
| - | size_t slen = 0; |
| - | CURLcode result = CURLE_OK; |
| + | struct Curl_ssl_session *sc_session = NULL; |
| + | CURLcode result; |
| - | Curl_ssl_sessionid_lock(data); |
| - | if(!Curl_ssl_getsessionid(cf, data, peer, &psdata, &slen, NULL)) { |
| + | result = Curl_ssl_scache_take(cf, data, ssl_peer_key, &sc_session); |
| + | if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) { |
| WOLFSSL_SESSION *session; | |
| - | sdata = psdata; |
| - | session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)slen); |
| + | /* wolfSSL changes the passed pointer for whatever reasons, yikes */ |
| + | const unsigned char *sdata = sc_session->sdata; |
| + | session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, |
| + | (long)sc_session->sdata_len); |
| if(session) { | |
| int ret = wolfSSL_set_session(wss->handle, session); | |
| if(ret != WOLFSSL_SUCCESS) { | |
| - | Curl_ssl_delsessionid(data, psdata); |
| - | infof(data, "previous session not accepted (%d), " |
| + | Curl_ssl_session_destroy(sc_session); |
| + | sc_session = NULL; |
| + | infof(data, "cached session not accepted (%d), " |
| "removing from cache", ret); | |
| } | |
| else | |
| @@ -496,7 +496,7 @@ CURLcode wssl_setup_session(struct Curl_cfilter *cf, | |
| failf(data, "could not decode previous session"); | |
| } | |
| } | |
| - | Curl_ssl_sessionid_unlock(data); |
| + | Curl_ssl_scache_return(cf, data, ssl_peer_key, sc_session); |
| return result; | |
| } | |
| @@ -1188,7 +1188,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | |
| /* Check if there is a cached ID we can/should use here! */ | |
| if(ssl_config->primary.cache_session) { | |
| /* Set session from cache if there is one */ | |
| - | (void)wssl_setup_session(cf, data, backend, &connssl->peer); |
| + | (void)Curl_wssl_setup_session(cf, data, backend, connssl->peer.scache_key); |
| /* Register to get notified when a new session is received */ | |
| wolfSSL_set_app_data(backend->handle, cf); | |
| wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb); | |
| @@ -1792,7 +1792,7 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, | |
| } | |
| - | static size_t wolfssl_version(char *buffer, size_t size) |
| + | size_t Curl_wssl_version(char *buffer, size_t size) |
| { | |
| #if LIBWOLFSSL_VERSION_HEX >= 0x03006000 | |
| return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); | |
| @@ -2030,7 +2030,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = { | |
| wolfssl_init, /* init */ | |
| wolfssl_cleanup, /* cleanup */ | |
| - | wolfssl_version, /* version */ |
| + | Curl_wssl_version, /* version */ |
| wolfssl_shutdown, /* shutdown */ | |
| wolfssl_data_pending, /* data_pending */ | |
| wolfssl_random, /* random */ | |
| @@ -47,19 +47,23 @@ struct wolfssl_ctx { | |
| BIT(shutting_down); /* TLS is being shut down */ | |
| }; | |
| + | size_t Curl_wssl_version(char *buffer, size_t size); |
| + | |
| CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| struct wolfssl_ctx *wssl); | |
| - | CURLcode wssl_setup_session(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | struct wolfssl_ctx *wss, |
| - | struct ssl_peer *peer); |
| + | CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | struct wolfssl_ctx *wss, |
| + | const char *ssl_peer_key); |
| - | CURLcode wssl_cache_session(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data, |
| - | struct ssl_peer *peer, |
| - | WOLFSSL_SESSION *session); |
| + | CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | WOLFSSL_SESSION *session, |
| + | int ietf_tls_id, |
| + | const char *alpn); |
| #endif /* USE_WOLFSSL */ | |
| @@ -617,7 +617,7 @@ class TestDownload: | |
| earlydata = {} | |
| reused_session = False | |
| for line in r.trace_lines: | |
| - | m = re.match(r'^\[t-(\d+)] EarlyData: (\d+)', line) |
| + | m = re.match(r'^\[t-(\d+)] EarlyData: (-?\d+)', line) |
| if m: | |
| earlydata[int(m.group(1))] = int(m.group(2)) | |
| continue | |
| @@ -134,4 +134,4 @@ class TestAuth: | |
| # Depending on protocol, we might have an error sending or | |
| # the server might shutdown the connection and we see the error | |
| # on receiving | |
| - | assert r.exit_code in [55, 56], f'{self.dump_logs()}' |
| + | assert r.exit_code in [55, 56], f'{r.dump_logs()}' |