vtls: feature ssls-export for SSL session im-/export
—
$ git checkout -f 515a21f350b89f0676e5df7f904c62c8f67be377
Previous HEAD position was 4e15605896 HTTP/2: strip TE request header
HEAD is now at 515a21f350 vtls: feature ssls-export for SSL session im-/export
$ 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_get_line.o
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-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-vtls_spack.lo
Removing lib/vtls/libcurl_la-vtls_spack.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_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_ssls.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:126: installing './compile'
configure.ac:430: installing './config.guess'
configure.ac:430: installing './config.sub'
configure.ac:126: installing './install-sh'
configure.ac:132: 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 whether to enable SSL session export 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.12.0-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 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 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 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 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 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 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 stricmp can be linked... no
checking if stricmp might be used... no
checking for arc4random... no
checking for fseeko... yes
checking for ccache gcc options needed to detect all undeclared functions... none needed
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.12.0-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)
SSLS-EXPORT: no (--enable-ssls-export)
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-asyn-ares.lo
CC libcurl_la-amigaos.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-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-cfilters.lo
CC libcurl_la-conncache.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-ftp.lo
CC libcurl_la-formdata.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-socks_sspi.lo
CC libcurl_la-speedcheck.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-strtoofft.lo
CC libcurl_la-system_win32.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-vtls_spack.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_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
echo '#include "tool_hugehelp.h"' >> tool_hugehelp.c
CC tool_helpers.o
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_ssls.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_get_line.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'
| @@ -779,6 +779,7 @@ src | |
| SRP | |
| SRWLOCK | |
| SSL | |
| + | SSLS |
| ssl | |
| SSLeay | |
| SSLKEYLOGFILE | |
| @@ -978,6 +978,15 @@ if(USE_ECH) | |
| endif() | |
| endif() | |
| + | option(USE_SSLS_EXPORT "Enable SSL session export support" OFF) |
| + | if(USE_SSLS_EXPORT) |
| + | if(_ssl_enabled) |
| + | message(STATUS "SSL export enabled.") |
| + | else() |
| + | message(FATAL_ERROR "SSL session export requires SSL enabled") |
| + | endif() |
| + | endif() |
| + | |
| option(USE_NGHTTP2 "Use nghttp2 library" ON) | |
| if(USE_NGHTTP2) | |
| find_package(NGHTTP2) | |
| @@ -2086,6 +2095,7 @@ curl_add_if("TrackMemory" ENABLE_CURLDEBUG) | |
| curl_add_if("ECH" _ssl_enabled AND HAVE_ECH) | |
| curl_add_if("PSL" USE_LIBPSL) | |
| curl_add_if("CAcert" CURL_CA_EMBED_SET) | |
| + | curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT) |
| if(_items) | |
| if(NOT CMAKE_VERSION VERSION_LESS 3.13) | |
| list(SORT _items CASE INSENSITIVE) | |
| @@ -54,6 +54,7 @@ CURL_CHECK_OPTION_ARES | |
| CURL_CHECK_OPTION_RT | |
| CURL_CHECK_OPTION_HTTPSRR | |
| CURL_CHECK_OPTION_ECH | |
| + | CURL_CHECK_OPTION_SSLS_EXPORT |
| XC_CHECK_PATH_SEPARATOR | |
| @@ -4946,6 +4947,26 @@ else | |
| CURL_DISABLE_WEBSOCKETS=1 | |
| fi | |
| + | dnl ************************************************************* |
| + | dnl check whether experimental SSL Session Im-/Export is enabled |
| + | dnl |
| + | if test "x$want_ssls_export" != "xno"; then |
| + | AC_MSG_CHECKING([whether SSL session export support is available]) |
| + | |
| + | dnl assume NOT and look for sufficient condition |
| + | SSLS_EXPORT_ENABLED=0 |
| + | SSLS_EXPORT_SUPPORT='' |
| + | |
| + | if test "x$SSL_ENABLED" != "x1"; then |
| + | AC_MSG_ERROR([--enable-ssls-export ignored: No SSL support]) |
| + | else |
| + | SSLS_EXPORT_ENABLED=1 |
| + | AC_DEFINE(USE_SSLS_EXPORT, 1, [if SSL session export support is available]) |
| + | AC_MSG_RESULT("SSL session im-/export enabled") |
| + | experimental="$experimental SSLS-EXPORT" |
| + | fi |
| + | fi |
| + | |
| dnl ************************************************************ | |
| dnl hiding of library internal symbols | |
| dnl | |
| @@ -5148,6 +5169,10 @@ if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then | |
| fi | |
| fi | |
| + | if test "x$SSLS_EXPORT_ENABLED" = "x1"; then |
| + | SUPPORT_FEATURES="$SUPPORT_FEATURES SSLS-EXPORT" |
| + | fi |
| + | |
| if test ${ac_cv_sizeof_curl_off_t} -gt 4; then | |
| if test ${ac_cv_sizeof_off_t} -gt 4 -o \ | |
| "$curl_win32_file_api" = "win32_large_files"; then | |
| @@ -5413,6 +5438,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: | |
| HTTP2: ${curl_h2_msg} | |
| HTTP3: ${curl_h3_msg} | |
| ECH: ${curl_ech_msg} | |
| + | SSLS-EXPORT: ${curl_ssls_export_msg} |
| Protocols: ${SUPPORT_PROTOCOLS_LOWER} | |
| Features: ${SUPPORT_FEATURES} | |
| ]) | |
| @@ -63,3 +63,15 @@ Graduation requirements: | |
| - it has been given time to mature, so no earlier than April 2025 (twelve | |
| months after being added here) | |
| + | |
| + | ## SSL session import/export |
| + | |
| + | Import/Export of SSL sessions tickets in libcurl and curl command line |
| + | option '--ssl-session <filename>' for faster TLS handshakes and use |
| + | of TLSv1.3/QUIC Early Data (0-RTT). |
| + | |
| + | Graduation requirements: |
| + | |
| + | - the implementation is considered safe |
| + | |
| + | - feedback from users saying that session export works for their use cases |
| @@ -191,6 +191,7 @@ assumes that CMake generates `Makefile`: | |
| - `USE_ECH`: Enable ECH support. Default: `OFF` | |
| - `USE_HTTPSRR`: Enable HTTPS RR support. Default: `OFF` | |
| - `USE_OPENSSL_QUIC`: Use OpenSSL and nghttp3 libraries for HTTP/3 support. Default: `OFF` | |
| + | - `USE_SSLS_EXPORT`: Enable experimental SSL session import/export. Default: `OFF` |
| ## Disabling features | |
| @@ -269,6 +269,7 @@ DPAGES = \ | |
| ssl-no-revoke.md \ | |
| ssl-reqd.md \ | |
| ssl-revoke-best-effort.md \ | |
| + | ssl-sessions.md \ |
| ssl.md \ | |
| sslv2.md \ | |
| sslv3.md \ | |
| @@ -0,0 +1,35 @@ | |
| + | --- |
| + | c: Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | SPDX-License-Identifier: curl |
| + | Long: ssl-sessions |
| + | Arg: <filename> |
| + | Protocols: TLS |
| + | Help: Load/save SSL session tickets from/to this file |
| + | Added: 8.12.0 |
| + | Category: tls |
| + | Multi: single |
| + | See-also: |
| + | - tls-earlydata |
| + | Example: |
| + | - --ssl-sessions sessions.txt $URL |
| + | --- |
| + | |
| + | # `--ssl-sessions` |
| + | |
| + | Use the given file to load SSL session tickets into curl's cache before |
| + | starting any transfers. At the end of a successful curl run, the cached |
| + | SSL sessions tickets are save to the file, replacing any previous content. |
| + | |
| + | The file does not have to exist, but curl reports an error if it is |
| + | unable to create it. Unused loaded tickets are saved again, unless they |
| + | get replaced or purged from the cache for space reasons. |
| + | |
| + | Using a session file allows `--tls-earlydata` to send the first request |
| + | in "0-RTT" mode, should an SSL session with the feature be found. Note that |
| + | a server may not support early data. Also note that early data does |
| + | not provide forward secrecy, e.g. is not as secure. |
| + | |
| + | The SSL session tickets are stored as base64 encoded text, each ticket on |
| + | its own line. The hostnames are cryptographically salted and hashed. While |
| + | this prevents someone to easily see the hosts you contacted, they could still |
| + | check if a specific hostname matches one of the values. |
| @@ -10,6 +10,7 @@ Multi: boolean | |
| See-also: | |
| - tlsv1.3 | |
| - tls-max | |
| + | - ssl-sessions |
| Example: | |
| - --tls-earlydata $URL | |
| --- | |
| @@ -41,6 +41,8 @@ man_MANS = \ | |
| curl_easy_reset.3 \ | |
| curl_easy_send.3 \ | |
| curl_easy_setopt.3 \ | |
| + | curl_easy_ssls_import.3 \ |
| + | curl_easy_ssls_export.3 \ |
| curl_easy_strerror.3 \ | |
| curl_easy_unescape.3 \ | |
| curl_easy_upkeep.3 \ | |
| @@ -0,0 +1,172 @@ | |
| + | --- |
| + | c: Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | SPDX-License-Identifier: curl |
| + | Title: curl_easy_ssls_export |
| + | Section: 3 |
| + | Source: libcurl |
| + | See-also: |
| + | - CURLOPT_SHARE (3) |
| + | - curl_share_setopt (3) |
| + | - curl_easy_ssls_import (3) |
| + | Protocol: |
| + | - All |
| + | TLS-backend: |
| + | - GnuTLS |
| + | - OpenSSL |
| + | - BearSSL |
| + | - wolfSSL |
| + | - mbedTLS |
| + | Added-in: 8.12.0 |
| + | --- |
| + | |
| + | # NAME |
| + | |
| + | curl_easy_ssls_export - export SSL sessions |
| + | |
| + | # SYNOPSIS |
| + | |
| + | ~~~c |
| + | #include <curl/curl.h> |
| + | |
| + | typedef CURLcode curl_ssls_export_function(CURL *handle, |
| + | void *userptr, |
| + | const char *session_key, |
| + | const unsigned char *shmac, |
| + | size_t shmac_len, |
| + | const unsigned char *sdata, |
| + | size_t sdata_len, |
| + | curl_off_t valid_until, |
| + | int ietf_tls_id, |
| + | const char *alpn, |
| + | size_t earlydata_max); |
| + | |
| + | CURLcode curl_easy_ssls_export(CURL *handle, |
| + | curl_ssls_export_function *export_fn, |
| + | void *userptr); |
| + | ~~~ |
| + | |
| + | # DESCRIPTION |
| + | |
| + | This function iterates over all SSL session tickets that belong to the |
| + | easy handle and invokes the **export_fn** callback on each of them, as |
| + | long as the callback returns **CURLE_OK**. |
| + | |
| + | The callback may then store this information and use curl_easy_ssls_import(3) |
| + | in another libcurl instance to add SSL session tickets again. Reuse of |
| + | SSL session tickets may result in faster handshakes and some connections |
| + | might be able to send request data in the initial packets (0-RTT). |
| + | |
| + | From all the parameters passed to the **export_fn** only two need to be |
| + | persisted: either **session_key** or **shamc** and always **sdata**. All |
| + | other parameters are informative, e.g. allow the callback to act only |
| + | on specific session tickets. |
| + | |
| + | Note that SSL sessions that involve a client certificate or SRP |
| + | username/password are not exported. |
| + | |
| + | # Export Function Parameter |
| + | |
| + | ## Session Key |
| + | |
| + | This is a printable, 0-terminated string that starts with **hostname:port** |
| + | the session ticket is originating from and also contains all relevant |
| + | SSL parameters used in the connection. The key also carries the name |
| + | and version number of the TLS backend used. |
| + | |
| + | It is recommended to only persist **session_key** when it can be protected |
| + | from outside access. Since the hostname appears in plain text, it would |
| + | allow any third party to see how curl has been used for. |
| + | |
| + | ## Salted Hash |
| + | |
| + | A binary blob of **shmac_len** bytes that contains a random salt and |
| + | a cryptographic hash of the salt and **session_key**. The salt is generated |
| + | for every session individually. Storing **shmac** is recommended when |
| + | placing session tickets in a file, for example. |
| + | |
| + | A third party may brute-force known hostnames, but cannot just "grep" for |
| + | them. |
| + | |
| + | ## Session Data |
| + | |
| + | A binary blob of **sdata_len** bytes, **sdata** contains all relevant |
| + | SSL session ticket information for a later import - apart from **session_key** |
| + | and **shmac**. |
| + | |
| + | ## valid_until |
| + | |
| + | Seconds since EPOCH (1970-01-01) until the session ticket is considered |
| + | valid. |
| + | |
| + | ## TLS Version |
| + | |
| + | The IETF assigned number for the TLS version the session ticket originates |
| + | from. This is **0x0304** for TLSv1.3, **0x0303** for 1.2, etc. Session |
| + | tickets from version 1.3 have better security properties, so an export |
| + | might store only those. |
| + | |
| + | ## ALPN |
| + | |
| + | The ALPN protocol that had been negotiated with the host. This may be |
| + | **NULL** if negotiation gave no result or had not been attempted. |
| + | |
| + | ## Early Data |
| + | |
| + | The maximum amount of bytes the server supports to receive in early data |
| + | (0-RTT). This is 0 unless the server explicitly indicates support. |
| + | |
| + | # %PROTOCOLS% |
| + | |
| + | # EXAMPLE |
| + | |
| + | ~~~c |
| + | CURLcode my_export_cb(CURL *handle, |
| + | void *userptr, |
| + | const char *session_key, |
| + | const unsigned char *shmac, |
| + | size_t shmac_len, |
| + | const unsigned char *sdata, |
| + | size_t sdata_len, |
| + | curl_off_t valid_until, |
| + | int ietf_tls_id, |
| + | const char *alpn, |
| + | size_t earlydata_max) |
| + | { |
| + | /* persist sdata */ |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | int main(void) |
| + | { |
| + | CURLSHcode sh; |
| + | CURLSH *share = curl_share_init(); |
| + | CURLcode rc; |
| + | CURL *curl; |
| + | |
| + | sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); |
| + | if(sh) |
| + | printf("Error: %s\n", curl_share_strerror(sh)); |
| + | |
| + | curl = curl_easy_init(); |
| + | if(curl) { |
| + | curl_easy_setopt(curl, CURLOPT_SHARE, share); |
| + | |
| + | rc = curl_easy_ssls_export(curl, my_export_cb, NULL); |
| + | |
| + | /* always cleanup */ |
| + | curl_easy_cleanup(curl); |
| + | } |
| + | curl_share_cleanup(share); |
| + | } |
| + | ~~~ |
| + | |
| + | # %AVAILABILITY% |
| + | |
| + | # RETURN VALUE |
| + | |
| + | This function returns a CURLcode indicating success or error. |
| + | |
| + | CURLE_OK (0) means everything was OK, non-zero means an error occurred, see |
| + | libcurl-errors(3). If CURLOPT_ERRORBUFFER(3) was set with curl_easy_setopt(3) |
| + | there can be an error message stored in the error buffer when non-zero is |
| + | returned. |
| @@ -0,0 +1,84 @@ | |
| + | --- |
| + | c: Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | SPDX-License-Identifier: curl |
| + | Title: curl_easy_ssls_import |
| + | Section: 3 |
| + | Source: libcurl |
| + | See-also: |
| + | - CURLOPT_SHARE (3) |
| + | - curl_share_setopt (3) |
| + | - curl_easy_ssls_export (3) |
| + | Protocol: |
| + | - All |
| + | Added-in: 8.12.0 |
| + | --- |
| + | |
| + | # NAME |
| + | |
| + | curl_easy_ssls_export - export SSL sessions |
| + | |
| + | # SYNOPSIS |
| + | |
| + | ~~~c |
| + | #include <curl/curl.h> |
| + | |
| + | CURLcode curl_easy_ssls_import(CURL *handle, |
| + | const char *session_key, |
| + | const unsigned char *shmac, size_t shmac_len, |
| + | const unsigned char *sdata, size_t sdata_len); |
| + | ~~~ |
| + | |
| + | # DESCRIPTION |
| + | |
| + | This function imports a previously exported SSL session ticket. **sdata** and |
| + | **sdata_len** must always be provided. If **session_key** is **NULL**, then |
| + | **shmac** and **shmac_len** must be given as received during the export. |
| + | See curl_easy_ssls_export(3) for a description of those. |
| + | |
| + | Import of session tickets from other curl versions may fail due to changes |
| + | in the handling of **shmac** or **sdata**. A session ticket which has |
| + | already expired is silently discarded. |
| + | |
| + | # %PROTOCOLS% |
| + | |
| + | # EXAMPLE |
| + | |
| + | ~~~c |
| + | int main(void) |
| + | { |
| + | CURLSHcode sh; |
| + | CURLSH *share = curl_share_init(); |
| + | CURLcode rc; |
| + | CURL *curl; |
| + | |
| + | sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); |
| + | if(sh) |
| + | printf("Error: %s\n", curl_share_strerror(sh)); |
| + | |
| + | curl = curl_easy_init(); |
| + | if(curl) { |
| + | unsigned char *shmac, *sdata; |
| + | size_t hlen, slen; |
| + | |
| + | curl_easy_setopt(curl, CURLOPT_SHARE, share); |
| + | |
| + | /* read shmac and sdata from storage */ |
| + | rc = curl_easy_ssls_import(curl, NULL, shmac, hlen, sdata, slen); |
| + | |
| + | /* always cleanup */ |
| + | curl_easy_cleanup(curl); |
| + | } |
| + | curl_share_cleanup(share); |
| + | } |
| + | ~~~ |
| + | |
| + | # %AVAILABILITY% |
| + | |
| + | # RETURN VALUE |
| + | |
| + | This function returns a CURLcode indicating success or error. |
| + | |
| + | CURLE_OK (0) means everything was OK, non-zero means an error occurred, see |
| + | libcurl-errors(3). If CURLOPT_ERRORBUFFER(3) was set with curl_easy_setopt(3) |
| + | there can be an error message stored in the error buffer when non-zero is |
| + | returned. |
| @@ -105,6 +105,10 @@ Tracing of DNS-over-HTTP operations to resolve hostnames. | |
| Traces reading of upload data from the application in order to send it to the server. | |
| + | ## `ssls` |
| + | |
| + | Tracing of SSL Session handling, e.g. caching/import/export. |
| + | |
| ## `smtp` | |
| Tracing of SMTP operations when this protocol is enabled in your build. | |
| @@ -300,6 +300,13 @@ GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) | |
| supports SSL (HTTPS/FTPS) (Added in 7.10) | |
| + | ## SSLS-EXPORT |
| + | |
| + | *features* mask bit: non-existent |
| + | |
| + | libcurl was built with SSL session import/export support |
| + | (experimental, added in 8.12.0) |
| + | |
| ## SSPI | |
| *features* mask bit: CURL_VERSION_SSPI | |
| @@ -235,6 +235,7 @@ | |
| --ssl-no-revoke 7.44.0 | |
| --ssl-reqd 7.20.0 | |
| --ssl-revoke-best-effort 7.70.0 | |
| + | --ssl-sessions 8.12.0 |
| --sslv2 (-2) 5.9 | |
| --sslv3 (-3) 5.9 | |
| --stderr 6.2 | |
| @@ -3232,6 +3232,50 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); | |
| #define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) | |
| #define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) | |
| + | /* |
| + | * NAME curl_easy_ssls_import() |
| + | * |
| + | * DESCRIPTION |
| + | * |
| + | * The curl_easy_ssls_import function adds a previously exported SSL session |
| + | * to the SSL session cache of the easy handle (or the underlying share). |
| + | */ |
| + | CURL_EXTERN CURLcode curl_easy_ssls_import(CURL *handle, |
| + | const char *session_key, |
| + | const unsigned char *shmac, |
| + | size_t shmac_len, |
| + | const unsigned char *sdata, |
| + | size_t sdata_len); |
| + | |
| + | /* This is the curl_ssls_export_cb callback prototype. It |
| + | * is passed to curl_easy_ssls_export() to extract SSL sessions/tickets. */ |
| + | typedef CURLcode curl_ssls_export_cb(CURL *handle, |
| + | void *userptr, |
| + | const char *session_key, |
| + | const unsigned char *shmac, |
| + | size_t shmac_len, |
| + | const unsigned char *sdata, |
| + | size_t sdata_len, |
| + | curl_off_t valid_until, |
| + | int ietf_tls_id, |
| + | const char *alpn, |
| + | size_t earlydata_max); |
| + | |
| + | /* |
| + | * NAME curl_easy_ssls_export() |
| + | * |
| + | * DESCRIPTION |
| + | * |
| + | * The curl_easy_ssls_export function iterates over all SSL sessions stored |
| + | * in the easy handle (or underlying share) and invokes the passed |
| + | * callback. |
| + | * |
| + | */ |
| + | CURL_EXTERN CURLcode curl_easy_ssls_export(CURL *handle, |
| + | curl_ssls_export_cb *export_fn, |
| + | void *userptr); |
| + | |
| + | |
| #ifdef __cplusplus | |
| } /* end of extern "C" */ | |
| #endif | |
| @@ -57,6 +57,7 @@ LIB_VTLS_CFILES = \ | |
| vtls/sectransp.c \ | |
| vtls/vtls.c \ | |
| vtls/vtls_scache.c \ | |
| + | vtls/vtls_spack.c \ |
| vtls/wolfssl.c \ | |
| vtls/x509asn1.c | |
| @@ -76,6 +77,7 @@ LIB_VTLS_HFILES = \ | |
| vtls/vtls.h \ | |
| vtls/vtls_int.h \ | |
| vtls/vtls_scache.h \ | |
| + | vtls/vtls_spack.h \ |
| vtls/wolfssl.h \ | |
| vtls/x509asn1.h | |
| @@ -28,7 +28,9 @@ | |
| !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC) | |
| #include "curl_get_line.h" | |
| + | #ifdef BUILDING_LIBCURL |
| #include "curl_memory.h" | |
| + | #endif |
| /* The last #include file should be: */ | |
| #include "memdebug.h" | |
| @@ -26,6 +26,12 @@ | |
| #include "dynbuf.h" | |
| + | #ifndef BUILDING_LIBCURL |
| + | /* this renames functions so that the tool code can use the same code |
| + | without getting symbol collisions */ |
| + | #define Curl_get_line(a,b) curlx_get_line(a,b) |
| + | #endif |
| + | |
| /* Curl_get_line() returns complete lines that end with a newline. */ | |
| int Curl_get_line(struct dynbuf *buf, FILE *input); | |
| @@ -239,6 +239,24 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...) | |
| } | |
| #endif /* !CURL_DISABLE_SMTP */ | |
| + | #ifdef USE_SSL |
| + | struct curl_trc_feat Curl_trc_feat_ssls = { |
| + | "SSLS", |
| + | CURL_LOG_LVL_NONE, |
| + | }; |
| + | |
| + | void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...) |
| + | { |
| + | DEBUGASSERT(!strchr(fmt, '\n')); |
| + | if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) { |
| + | va_list ap; |
| + | va_start(ap, fmt); |
| + | trc_infof(data, &Curl_trc_feat_ssls, fmt, ap); |
| + | va_end(ap); |
| + | } |
| + | } |
| + | #endif /* USE_SSL */ |
| + | |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| struct curl_trc_feat Curl_trc_feat_ws = { | |
| "WS", | |
| @@ -279,6 +297,9 @@ static struct trc_feat_def trc_feats[] = { | |
| #ifndef CURL_DISABLE_SMTP | |
| { &Curl_trc_feat_smtp, TRC_CT_PROTOCOL }, | |
| #endif | |
| + | #ifdef USE_SSL |
| + | { &Curl_trc_feat_ssls, TRC_CT_NETWORK }, |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| { &Curl_trc_feat_ws, TRC_CT_PROTOCOL }, | |
| #endif | |
| @@ -94,6 +94,11 @@ void Curl_failf(struct Curl_easy *data, | |
| do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \ | |
| Curl_trc_smtp(data, __VA_ARGS__); } while(0) | |
| #endif /* !CURL_DISABLE_SMTP */ | |
| + | #ifdef USE_SSL |
| + | #define CURL_TRC_SSLS(data, ...) \ |
| + | do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) \ |
| + | Curl_trc_ssls(data, __VA_ARGS__); } while(0) |
| + | #endif /* USE_SSL */ |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| #define CURL_TRC_WS(data, ...) \ | |
| do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \ | |
| @@ -113,6 +118,9 @@ void Curl_failf(struct Curl_easy *data, | |
| #ifndef CURL_DISABLE_SMTP | |
| #define CURL_TRC_SMTP Curl_trc_smtp | |
| #endif | |
| + | #ifdef USE_SSL |
| + | #define CURL_TRC_SSLS Curl_trc_ssls |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| #define CURL_TRC_WS Curl_trc_ws | |
| #endif | |
| @@ -167,6 +175,11 @@ extern struct curl_trc_feat Curl_trc_feat_smtp; | |
| void Curl_trc_smtp(struct Curl_easy *data, | |
| const char *fmt, ...) CURL_PRINTF(2, 3); | |
| #endif | |
| + | #ifdef USE_SSL |
| + | extern struct curl_trc_feat Curl_trc_feat_ssls; |
| + | void Curl_trc_ssls(struct Curl_easy *data, |
| + | const char *fmt, ...) CURL_PRINTF(2, 3); |
| + | #endif |
| #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) | |
| extern struct curl_trc_feat Curl_trc_feat_ws; | |
| void Curl_trc_ws(struct Curl_easy *data, | |
| @@ -48,6 +48,7 @@ | |
| #include <curl/curl.h> | |
| #include "transfer.h" | |
| #include "vtls/vtls.h" | |
| + | #include "vtls/vtls_scache.h" |
| #include "url.h" | |
| #include "getinfo.h" | |
| #include "hostip.h" | |
| @@ -1336,3 +1337,41 @@ CURLcode curl_easy_upkeep(CURL *d) | |
| /* Use the common function to keep connections alive. */ | |
| return Curl_cpool_upkeep(data); | |
| } | |
| + | |
| + | CURLcode curl_easy_ssls_import(CURL *d, const char *session_key, |
| + | const unsigned char *shmac, size_t shmac_len, |
| + | const unsigned char *sdata, size_t sdata_len) |
| + | { |
| + | #ifdef USE_SSLS_EXPORT |
| + | struct Curl_easy *data = d; |
| + | if(!GOOD_EASY_HANDLE(data)) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | return Curl_ssl_session_import(data, session_key, |
| + | shmac, shmac_len, sdata, sdata_len); |
| + | #else |
| + | (void)d; |
| + | (void)session_key; |
| + | (void)shmac; |
| + | (void)shmac_len; |
| + | (void)sdata; |
| + | (void)sdata_len; |
| + | return CURLE_NOT_BUILT_IN; |
| + | #endif |
| + | } |
| + | |
| + | CURLcode curl_easy_ssls_export(CURL *d, |
| + | curl_ssls_export_cb *export_fn, |
| + | void *userptr) |
| + | { |
| + | #ifdef USE_SSLS_EXPORT |
| + | struct Curl_easy *data = d; |
| + | if(!GOOD_EASY_HANDLE(data)) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | return Curl_ssl_session_export(data, export_fn, userptr); |
| + | #else |
| + | (void)d; |
| + | (void)export_fn; |
| + | (void)userptr; |
| + | return CURLE_NOT_BUILT_IN; |
| + | #endif |
| + | } |
| @@ -15,6 +15,8 @@ curl_easy_recv | |
| curl_easy_reset | |
| curl_easy_send | |
| curl_easy_setopt | |
| + | curl_easy_ssls_export |
| + | curl_easy_ssls_import |
| curl_easy_strerror | |
| curl_easy_unescape | |
| curl_easy_upkeep | |
| @@ -523,6 +523,9 @@ static const struct feat features_table[] = { | |
| #ifdef USE_SSL | |
| FEATURE("SSL", NULL, CURL_VERSION_SSL), | |
| #endif | |
| + | #if defined(USE_SSLS_EXPORT) |
| + | FEATURE("SSLS-EXPORT", NULL, 0), |
| + | #endif |
| #ifdef USE_WINDOWS_SSPI | |
| FEATURE("SSPI", NULL, CURL_VERSION_SSPI), | |
| #endif | |
| @@ -476,6 +476,10 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) | |
| data, &ctx->peer); | |
| CURL_TRC_CF(data, cf, "handshake complete after %dms", | |
| (int)Curl_timediff(ctx->handshake_at, ctx->started_at)); | |
| + | /* In case of earlydata, where we simulate being connected, update |
| + | * the handshake time when we really did connect */ |
| + | if(ctx->use_earlydata) |
| + | Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); |
| #ifdef USE_GNUTLS | |
| if(ctx->use_earlydata) { | |
| int flags = gnutls_session_get_flags(ctx->tls.gtls.session); | |
| @@ -751,10 +751,11 @@ CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, | |
| /* extract session ID to the allocated buffer */ | |
| gnutls_session_get_data(session, sdata, &sdata_len); | |
| - | |
| - | CURL_TRC_CF(data, cf, "get session id (len=%zu, alpn=%s) and store in cache", |
| - | sdata_len, alpn ? alpn : "-"); |
| earlydata_max = gnutls_record_get_max_early_data_size(session); | |
| + | |
| + | CURL_TRC_CF(data, cf, "get session id (len=%zu, alpn=%s, earlymax=%zu) " |
| + | "and store in cache", sdata_len, alpn ? alpn : "-", |
| + | earlydata_max); |
| if(quic_tp && quic_tp_len) { | |
| qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len); | |
| if(!qtp_clone) { | |
| @@ -667,7 +667,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, | |
| return result; | |
| } | |
| - | /* get 32 bits of random */ |
| + | /* get length bytes of randomness */ |
| CURLcode Curl_ssl_random(struct Curl_easy *data, | |
| unsigned char *entropy, | |
| size_t length) | |
| @@ -22,22 +22,6 @@ | |
| * | |
| ***************************************************************************/ | |
| - | /* 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 | |
| @@ -58,6 +42,7 @@ | |
| #include "vtls.h" /* generic SSL protos etc */ | |
| #include "vtls_int.h" | |
| #include "vtls_scache.h" | |
| + | #include "vtls_spack.h" |
| #include "strcase.h" | |
| #include "url.h" | |
| @@ -65,6 +50,7 @@ | |
| #include "share.h" | |
| #include "curl_trc.h" | |
| #include "curl_sha256.h" | |
| + | #include "rand.h" |
| #include "warnless.h" | |
| #include "curl_printf.h" | |
| #include "strdup.h" | |
| @@ -215,18 +201,33 @@ static void cf_ssl_scache_peer_set_obj(struct Curl_ssl_scache_peer *peer, | |
| 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) |
| + | 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, |
| + | const unsigned char *salt, |
| + | const unsigned char *hmac) |
| { | |
| CURLcode result = CURLE_OUT_OF_MEMORY; | |
| DEBUGASSERT(!peer->ssl_peer_key); | |
| - | peer->ssl_peer_key = strdup(ssl_peer_key); |
| - | if(!peer->ssl_peer_key) |
| + | if(ssl_peer_key) { |
| + | peer->ssl_peer_key = strdup(ssl_peer_key); |
| + | if(!peer->ssl_peer_key) |
| + | goto out; |
| + | peer->hmac_set = FALSE; |
| + | } |
| + | else if(salt && hmac) { |
| + | memcpy(peer->key_salt, salt, sizeof(peer->key_salt)); |
| + | memcpy(peer->key_hmac, hmac, sizeof(peer->key_hmac)); |
| + | peer->hmac_set = TRUE; |
| + | } |
| + | else { |
| + | result = CURLE_BAD_FUNCTION_ARGUMENT; |
| goto out; | |
| + | } |
| if(clientcert) { | |
| peer->clientcert = strdup(clientcert); | |
| if(!peer->clientcert) | |
| @@ -557,7 +558,16 @@ out: | |
| 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)) |
| + | if(!conn_config) { |
| + | if(peer->clientcert) |
| + | return FALSE; |
| + | #ifdef USE_TLS_SRP |
| + | if(peer->srp_username || peer->srp_password) |
| + | return FALSE; |
| + | #endif |
| + | return TRUE; |
| + | } |
| + | else if(!Curl_safecmp(peer->clientcert, conn_config->clientcert)) |
| return FALSE; | |
| #ifdef USE_TLS_SRP | |
| if(Curl_timestrcmp(peer->srp_username, conn_config->username) || | |
| @@ -567,21 +577,17 @@ static bool cf_ssl_scache_match_auth(struct Curl_ssl_scache_peer *peer, | |
| 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) |
| + | static CURLcode |
| + | cf_ssl_find_peer_by_key(struct Curl_easy *data, |
| + | struct Curl_ssl_scache *scache, |
| + | const char *ssl_peer_key, |
| + | struct ssl_primary_config *conn_config, |
| + | 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 && | |
| @@ -611,6 +617,8 @@ static CURLcode cf_ssl_find_peer(struct Curl_cfilter *cf, | |
| goto out; | |
| if(!memcmp(scache->peers[i].key_hmac, my_hmac, sizeof(my_hmac))) { | |
| /* remember peer_key for future lookups */ | |
| + | CURL_TRC_SSLS(data, "peer entry %zu key recovered: %s", |
| + | i, ssl_peer_key); |
| scache->peers[i].ssl_peer_key = strdup(ssl_peer_key); | |
| if(!scache->peers[i].ssl_peer_key) { | |
| result = CURLE_OUT_OF_MEMORY; | |
| @@ -621,34 +629,18 @@ static CURLcode cf_ssl_find_peer(struct Curl_cfilter *cf, | |
| } | |
| } | |
| } | |
| + | CURL_TRC_SSLS(data, "peer not found for %s", ssl_peer_key); |
| 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) |
| + | static struct Curl_ssl_scache_peer * |
| + | cf_ssl_get_free_peer(struct Curl_ssl_scache *scache) |
| { | |
| - | 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 */ |
| + | /* 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) { | |
| @@ -667,39 +659,86 @@ static CURLcode cf_ssl_add_peer(struct Curl_cfilter *cf, | |
| } | |
| } | |
| DEBUGASSERT(peer); | |
| - | if(!peer) |
| + | if(peer) |
| + | cf_ssl_scache_clear_peer(peer); |
| + | return peer; |
| + | } |
| + | |
| + | static CURLcode |
| + | cf_ssl_add_peer(struct Curl_easy *data, |
| + | struct Curl_ssl_scache *scache, |
| + | const char *ssl_peer_key, |
| + | struct ssl_primary_config *conn_config, |
| + | struct Curl_ssl_scache_peer **ppeer) |
| + | { |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | CURLcode result = CURLE_OK; |
| + | |
| + | *ppeer = NULL; |
| + | if(ssl_peer_key) { |
| + | result = cf_ssl_find_peer_by_key(data, scache, ssl_peer_key, conn_config, |
| + | &peer); |
| + | if(result || !scache->peer_count) |
| + | return result; |
| + | } |
| + | |
| + | if(peer) { |
| + | *ppeer = 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, |
| + | } |
| + | |
| + | peer = cf_ssl_get_free_peer(scache); |
| + | if(peer) { |
| + | const char *ccert = conn_config ? conn_config->clientcert : NULL; |
| + | const char *username = NULL, *password = NULL; |
| #ifdef USE_TLS_SRP | |
| - | conn_config->username, |
| - | conn_config->password); |
| - | #else |
| - | NULL, NULL); |
| + | username = conn_config ? conn_config->username : NULL; |
| + | password = conn_config ? conn_config->password : NULL; |
| #endif | |
| - | if(result) |
| - | goto out; |
| - | /* all ready */ |
| - | *ppeer = peer; |
| - | result = CURLE_OK; |
| + | result = cf_ssl_scache_peer_init(peer, ssl_peer_key, ccert, |
| + | username, password, NULL, NULL); |
| + | 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) |
| + | static void cf_scache_peer_add_session(struct Curl_ssl_scache_peer *peer, |
| + | struct Curl_ssl_session *s, |
| + | curl_off_t now) |
| + | { |
| + | /* 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)); |
| + | } |
| + | } |
| + | } |
| + | |
| + | static CURLcode cf_scache_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; | |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| CURLcode result = CURLE_OUT_OF_MEMORY; | |
| curl_off_t now = (curl_off_t)time(NULL); | |
| curl_off_t max_lifetime; | |
| @@ -719,32 +758,19 @@ static CURLcode cf_scache_peer_add_session(struct Curl_cfilter *cf, | |
| s->valid_until = now + max_lifetime; | |
| if(cf_scache_session_expired(s, now)) { | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] add, session already expired"); |
| + | CURL_TRC_SSLS(data, "add, session already expired"); |
| Curl_ssl_session_destroy(s); | |
| return CURLE_OK; | |
| } | |
| - | result = cf_ssl_add_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | result = cf_ssl_add_peer(data, scache, ssl_peer_key, conn_config, &peer); |
| if(result || !peer) { | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result); |
| + | CURL_TRC_SSLS(data, "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)); |
| - | } |
| - | } |
| + | cf_scache_peer_add_session(peer, s, now); |
| out: | |
| if(result) { | |
| @@ -752,12 +778,12 @@ out: | |
| ssl_peer_key, result); | |
| } | |
| else | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] added session for %s [proto=0x%x, " |
| - | "valid_secs=%" FMT_OFF_T ", alpn=%s, earlydata=%zu, " |
| - | "quic_tp=%s], peer has %zu sessions now", |
| - | ssl_peer_key, s->ietf_tls_id, s->valid_until - now, s->alpn, |
| - | s->earlydata_max, s->quic_tp ? "yes" : "no", |
| - | Curl_llist_count(&peer->sessions)); |
| + | CURL_TRC_SSLS(data, "added session for %s [proto=0x%x, " |
| + | "valid_secs=%" FMT_OFF_T ", alpn=%s, earlydata=%zu, " |
| + | "quic_tp=%s], peer has %zu sessions now", |
| + | ssl_peer_key, s->ietf_tls_id, s->valid_until - now, |
| + | s->alpn, s->earlydata_max, s->quic_tp ? "yes" : "no", |
| + | Curl_llist_count(&peer->sessions)); |
| return result; | |
| } | |
| @@ -767,10 +793,16 @@ CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf, | |
| struct Curl_ssl_session *s) | |
| { | |
| struct Curl_ssl_scache *scache = data->state.ssl_scache; | |
| + | struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
| CURLcode result; | |
| + | if(!ssl_config || !scache || !ssl_config->primary.cache_session) { |
| + | Curl_ssl_session_destroy(s); |
| + | return CURLE_OK; |
| + | } |
| + | |
| Curl_ssl_scache_lock(data); | |
| - | result = cf_scache_peer_add_session(cf, data, scache, ssl_peer_key, s); |
| + | result = cf_scache_add_session(cf, data, scache, ssl_peer_key, s); |
| Curl_ssl_scache_unlock(data); | |
| return result; | |
| } | |
| @@ -794,6 +826,7 @@ CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, | |
| struct Curl_ssl_session **ps) | |
| { | |
| struct Curl_ssl_scache *scache = data->state.ssl_scache; | |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| struct Curl_ssl_scache_peer *peer = NULL; | |
| struct Curl_llist_node *n; | |
| struct Curl_ssl_session *s = NULL; | |
| @@ -804,7 +837,8 @@ CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, | |
| return CURLE_OK; | |
| Curl_ssl_scache_lock(data); | |
| - | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | result = cf_ssl_find_peer_by_key(data, scache, ssl_peer_key, conn_config, |
| + | &peer); |
| if(!result && peer) { | |
| cf_scache_peer_remove_expired(peer, (curl_off_t)time(NULL)); | |
| n = Curl_llist_head(&peer->sessions); | |
| @@ -817,14 +851,14 @@ CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, | |
| Curl_ssl_scache_unlock(data); | |
| if(s) { | |
| *ps = s; | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] took session for %s [proto=0x%x, " |
| - | "alpn=%s, earlydata=%zu, quic_tp=%s], %zu sessions remain", |
| - | ssl_peer_key, s->ietf_tls_id, s->alpn, |
| - | s->earlydata_max, s->quic_tp ? "yes" : "no", |
| - | Curl_llist_count(&peer->sessions)); |
| + | CURL_TRC_SSLS(data, "took session for %s [proto=0x%x, " |
| + | "alpn=%s, earlydata=%zu, quic_tp=%s], %zu sessions remain", |
| + | ssl_peer_key, s->ietf_tls_id, s->alpn, |
| + | s->earlydata_max, s->quic_tp ? "yes" : "no", |
| + | Curl_llist_count(&peer->sessions)); |
| } | |
| else { | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] no cached session for %s", ssl_peer_key); |
| + | CURL_TRC_SSLS(data, "no cached session for %s", ssl_peer_key); |
| } | |
| return result; | |
| } | |
| @@ -836,15 +870,16 @@ CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf, | |
| Curl_ssl_scache_obj_dtor *sobj_free) | |
| { | |
| struct Curl_ssl_scache *scache = data->state.ssl_scache; | |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| 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); |
| + | result = cf_ssl_add_peer(data, scache, ssl_peer_key, conn_config, &peer); |
| if(result || !peer) { | |
| - | CURL_TRC_CF(data, cf, "[SCACHE] unable to add scache peer: %d", result); |
| + | CURL_TRC_SSLS(data, "unable to add scache peer: %d", result); |
| goto out; | |
| } | |
| @@ -863,6 +898,7 @@ bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf, | |
| void **sobj) | |
| { | |
| struct Curl_ssl_scache *scache = data->state.ssl_scache; | |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| struct Curl_ssl_scache_peer *peer = NULL; | |
| CURLcode result; | |
| @@ -870,15 +906,16 @@ bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf, | |
| if(!scache) | |
| return FALSE; | |
| - | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | result = cf_ssl_find_peer_by_key(data, scache, ssl_peer_key, conn_config, |
| + | &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); |
| + | CURL_TRC_SSLS(data, "%s cached session for '%s'", |
| + | *sobj ? "Found" : "No", ssl_peer_key); |
| return !!*sobj; | |
| } | |
| @@ -887,6 +924,7 @@ void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf, | |
| const char *ssl_peer_key) | |
| { | |
| struct Curl_ssl_scache *scache = data->state.ssl_scache; | |
| + | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
| struct Curl_ssl_scache_peer *peer = NULL; | |
| CURLcode result; | |
| @@ -895,10 +933,237 @@ void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf, | |
| return; | |
| Curl_ssl_scache_lock(data); | |
| - | result = cf_ssl_find_peer(cf, data, scache, ssl_peer_key, &peer); |
| + | result = cf_ssl_find_peer_by_key(data, scache, ssl_peer_key, conn_config, |
| + | &peer); |
| if(!result && peer) | |
| cf_ssl_scache_clear_peer(peer); | |
| Curl_ssl_scache_unlock(data); | |
| } | |
| + | #ifdef USE_SSLS_EXPORT |
| + | |
| + | #define CURL_SSL_TICKET_MAX (16*1024) |
| + | |
| + | static CURLcode cf_ssl_scache_peer_set_hmac(struct Curl_ssl_scache_peer *peer) |
| + | { |
| + | CURLcode result; |
| + | |
| + | DEBUGASSERT(peer); |
| + | if(!peer->ssl_peer_key) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | |
| + | result = Curl_rand(NULL, peer->key_salt, sizeof(peer->key_salt)); |
| + | if(result) |
| + | return result; |
| + | |
| + | result = Curl_hmacit(&Curl_HMAC_SHA256, |
| + | peer->key_salt, sizeof(peer->key_salt), |
| + | (const unsigned char *)peer->ssl_peer_key, |
| + | strlen(peer->ssl_peer_key), |
| + | peer->key_hmac); |
| + | if(!result) |
| + | peer->hmac_set = TRUE; |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode |
| + | cf_ssl_find_peer_by_hmac(struct Curl_ssl_scache *scache, |
| + | const unsigned char *salt, |
| + | const unsigned char *hmac, |
| + | struct Curl_ssl_scache_peer **ppeer) |
| + | { |
| + | size_t i; |
| + | CURLcode result = CURLE_OK; |
| + | |
| + | *ppeer = NULL; |
| + | /* look for an entry that matches salt+hmac exactly or has a known |
| + | * ssl_peer_key which salt+hmac's to the same. */ |
| + | for(i = 0; scache && i < scache->peer_count; i++) { |
| + | struct Curl_ssl_scache_peer *peer = &scache->peers[i]; |
| + | if(!cf_ssl_scache_match_auth(peer, NULL)) |
| + | continue; |
| + | if(scache->peers[i].hmac_set && |
| + | !memcmp(peer->key_salt, salt, sizeof(peer->key_salt)) && |
| + | !memcmp(peer->key_hmac, hmac, sizeof(peer->key_hmac))) { |
| + | /* found exact match, return */ |
| + | *ppeer = peer; |
| + | goto out; |
| + | } |
| + | else if(peer->ssl_peer_key) { |
| + | unsigned char my_hmac[CURL_SHA256_DIGEST_LENGTH]; |
| + | /* compute hmac for the passed salt */ |
| + | result = Curl_hmacit(&Curl_HMAC_SHA256, |
| + | salt, sizeof(peer->key_salt), |
| + | (const unsigned char *)peer->ssl_peer_key, |
| + | strlen(peer->ssl_peer_key), |
| + | my_hmac); |
| + | if(result) |
| + | goto out; |
| + | if(!memcmp(my_hmac, hmac, sizeof(my_hmac))) { |
| + | /* cryptohash match, take over salt+hmac if no set and return */ |
| + | if(!peer->hmac_set) { |
| + | memcpy(peer->key_salt, salt, sizeof(peer->key_salt)); |
| + | memcpy(peer->key_hmac, hmac, sizeof(peer->key_hmac)); |
| + | peer->hmac_set = TRUE; |
| + | } |
| + | *ppeer = peer; |
| + | goto out; |
| + | } |
| + | } |
| + | } |
| + | out: |
| + | return result; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_session_import(struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | const unsigned char *shmac, size_t shmac_len, |
| + | const unsigned char *sdata, size_t sdata_len) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer = NULL; |
| + | struct Curl_ssl_session *s = NULL; |
| + | bool locked = FALSE; |
| + | CURLcode r; |
| + | |
| + | if(!scache) { |
| + | r = CURLE_BAD_FUNCTION_ARGUMENT; |
| + | goto out; |
| + | } |
| + | if(!ssl_peer_key && (!shmac || !shmac_len)) { |
| + | r = CURLE_BAD_FUNCTION_ARGUMENT; |
| + | goto out; |
| + | } |
| + | |
| + | r = Curl_ssl_session_unpack(data, sdata, sdata_len, &s); |
| + | if(r) |
| + | goto out; |
| + | |
| + | Curl_ssl_scache_lock(data); |
| + | locked = TRUE; |
| + | |
| + | if(ssl_peer_key) { |
| + | r = cf_ssl_add_peer(data, scache, ssl_peer_key, NULL, &peer); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | else if(shmac_len != (sizeof(peer->key_salt) + sizeof(peer->key_hmac))) { |
| + | /* Either salt+hmac was garbled by caller or is from a curl version |
| + | * that does things differently */ |
| + | r = CURLE_BAD_FUNCTION_ARGUMENT; |
| + | goto out; |
| + | } |
| + | else { |
| + | const unsigned char *salt = shmac; |
| + | const unsigned char *hmac = shmac + sizeof(peer->key_salt); |
| + | |
| + | r = cf_ssl_find_peer_by_hmac(scache, salt, hmac, &peer); |
| + | if(r) |
| + | goto out; |
| + | if(!peer) { |
| + | peer = cf_ssl_get_free_peer(scache); |
| + | if(peer) { |
| + | r = cf_ssl_scache_peer_init(peer, ssl_peer_key, NULL, |
| + | NULL, NULL, salt, hmac); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | } |
| + | } |
| + | |
| + | if(peer) { |
| + | cf_scache_peer_add_session(peer, s, time(NULL)); |
| + | s = NULL; /* peer is now owner */ |
| + | CURL_TRC_SSLS(data, "successfully imported ticket for peer %s, now " |
| + | "with %zu tickets", |
| + | peer->ssl_peer_key ? peer->ssl_peer_key : "without key", |
| + | Curl_llist_count(&peer->sessions)); |
| + | } |
| + | |
| + | out: |
| + | if(locked) |
| + | Curl_ssl_scache_unlock(data); |
| + | Curl_ssl_session_destroy(s); |
| + | return r; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_session_export(struct Curl_easy *data, |
| + | curl_ssls_export_cb *export_fn, |
| + | void *userptr) |
| + | { |
| + | struct Curl_ssl_scache *scache = data->state.ssl_scache; |
| + | struct Curl_ssl_scache_peer *peer; |
| + | struct dynbuf sbuf, hbuf; |
| + | struct Curl_llist_node *n; |
| + | size_t i, npeers = 0, ntickets = 0; |
| + | curl_off_t now = time(NULL); |
| + | CURLcode r = CURLE_OK; |
| + | |
| + | if(!export_fn) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | if(!scache) |
| + | return CURLE_OK; |
| + | |
| + | Curl_ssl_scache_lock(data); |
| + | |
| + | Curl_dyn_init(&hbuf, (CURL_SHA256_DIGEST_LENGTH * 2) + 1); |
| + | Curl_dyn_init(&sbuf, CURL_SSL_TICKET_MAX); |
| + | |
| + | for(i = 0; scache && i < scache->peer_count; i++) { |
| + | peer = &scache->peers[i]; |
| + | if(!peer->ssl_peer_key && !peer->hmac_set) |
| + | continue; /* skip free entry */ |
| + | if(peer->clientcert || peer->srp_username || peer->srp_password) |
| + | continue; /* not exporting those */ |
| + | |
| + | Curl_dyn_reset(&hbuf); |
| + | cf_scache_peer_remove_expired(peer, now); |
| + | n = Curl_llist_head(&peer->sessions); |
| + | if(n) |
| + | ++npeers; |
| + | while(n) { |
| + | struct Curl_ssl_session *s = Curl_node_elem(n); |
| + | if(!peer->hmac_set) { |
| + | r = cf_ssl_scache_peer_set_hmac(peer); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | if(!Curl_dyn_len(&hbuf)) { |
| + | r = Curl_dyn_addn(&hbuf, peer->key_salt, sizeof(peer->key_salt)); |
| + | if(r) |
| + | goto out; |
| + | r = Curl_dyn_addn(&hbuf, peer->key_hmac, sizeof(peer->key_hmac)); |
| + | if(r) |
| + | goto out; |
| + | } |
| + | Curl_dyn_reset(&sbuf); |
| + | r = Curl_ssl_session_pack(data, s, &sbuf); |
| + | if(r) |
| + | goto out; |
| + | |
| + | r = export_fn(data, userptr, peer->ssl_peer_key, |
| + | Curl_dyn_uptr(&hbuf), Curl_dyn_len(&hbuf), |
| + | Curl_dyn_uptr(&sbuf), Curl_dyn_len(&sbuf), |
| + | s->valid_until, s->ietf_tls_id, |
| + | s->alpn, s->earlydata_max); |
| + | if(r) |
| + | goto out; |
| + | ++ntickets; |
| + | n = Curl_node_next(n); |
| + | } |
| + | |
| + | } |
| + | r = CURLE_OK; |
| + | CURL_TRC_SSLS(data, "exported %zu session tickets for %zu peers", |
| + | ntickets, npeers); |
| + | |
| + | out: |
| + | Curl_ssl_scache_unlock(data); |
| + | Curl_dyn_free(&hbuf); |
| + | Curl_dyn_free(&sbuf); |
| + | return r; |
| + | } |
| + | |
| + | #endif /* USE_SSLS_EXPORT */ |
| + | |
| #endif /* USE_SSL */ | |
| @@ -195,6 +195,18 @@ void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf, | |
| struct Curl_easy *data, | |
| const char *ssl_peer_key); | |
| + | #ifdef USE_SSLS_EXPORT |
| + | |
| + | CURLcode Curl_ssl_session_import(struct Curl_easy *data, |
| + | const char *ssl_peer_key, |
| + | const unsigned char *shmac, size_t shmac_len, |
| + | const unsigned char *sdata, size_t sdata_len); |
| + | |
| + | CURLcode Curl_ssl_session_export(struct Curl_easy *data, |
| + | curl_ssls_export_cb *export_fn, |
| + | void *userptr); |
| + | |
| + | #endif /* USE_SSLS_EXPORT */ |
| #else /* USE_SSL */ | |
| @@ -0,0 +1,345 @@ | |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * 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" |
| + | |
| + | #ifdef USE_SSLS_EXPORT |
| + | |
| + | #include "urldata.h" |
| + | #include "curl_trc.h" |
| + | #include "vtls_scache.h" |
| + | #include "vtls_spack.h" |
| + | #include "strdup.h" |
| + | |
| + | /* The last #include files should be: */ |
| + | #include "curl_memory.h" |
| + | #include "memdebug.h" |
| + | |
| + | #ifdef _MSC_VER |
| + | #if _MSC_VER >= 1600 |
| + | #include <stdint.h> |
| + | #else |
| + | typedef unsigned char uint8_t; |
| + | typedef unsigned __int16 uint16_t; |
| + | typedef unsigned __int32 uint32_t; |
| + | typedef unsigned __int64 uint64_t; |
| + | #endif |
| + | #endif /* _MSC_VER */ |
| + | |
| + | #ifndef UINT16_MAX |
| + | #define UINT16_MAX 0xffff |
| + | #endif |
| + | #ifndef UINT32_MAX |
| + | #define UINT32_MAX 0xffffffff |
| + | #endif |
| + | |
| + | #define CURL_SPACK_VERSION 0x01 |
| + | #define CURL_SPACK_IETF_ID 0x02 |
| + | #define CURL_SPACK_VALID_UNTIL 0x03 |
| + | #define CURL_SPACK_TICKET 0x04 |
| + | #define CURL_SPACK_ALPN 0x05 |
| + | #define CURL_SPACK_EARLYDATA 0x06 |
| + | #define CURL_SPACK_QUICTP 0x07 |
| + | |
| + | static CURLcode spack_enc8(struct dynbuf *buf, uint8_t b) |
| + | { |
| + | return Curl_dyn_addn(buf, &b, 1); |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_dec8(uint8_t *val, const uint8_t **src, const uint8_t *end) |
| + | { |
| + | if(end - *src < 1) |
| + | return CURLE_READ_ERROR; |
| + | *val = **src; |
| + | *src += 1; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode spack_enc16(struct dynbuf *buf, uint16_t val) |
| + | { |
| + | uint8_t nval[2]; |
| + | nval[0] = (uint8_t)(val >> 8); |
| + | nval[1] = (uint8_t)val; |
| + | return Curl_dyn_addn(buf, nval, sizeof(nval)); |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_dec16(uint16_t *val, const uint8_t **src, const uint8_t *end) |
| + | { |
| + | if(end - *src < 2) |
| + | return CURLE_READ_ERROR; |
| + | *val = (uint16_t)((*src)[0] << 8 | (*src)[1]); |
| + | *src += 2; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode spack_enc32(struct dynbuf *buf, uint32_t val) |
| + | { |
| + | uint8_t nval[4]; |
| + | nval[0] = (uint8_t)(val >> 24); |
| + | nval[1] = (uint8_t)(val >> 16); |
| + | nval[2] = (uint8_t)(val >> 8); |
| + | nval[3] = (uint8_t)val; |
| + | return Curl_dyn_addn(buf, nval, sizeof(nval)); |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_dec32(uint32_t *val, const uint8_t **src, const uint8_t *end) |
| + | { |
| + | if(end - *src < 4) |
| + | return CURLE_READ_ERROR; |
| + | *val = (uint32_t)(*src)[0] << 24 | (uint32_t)(*src)[1] << 16 | |
| + | (uint32_t)(*src)[2] << 8 | (*src)[3]; |
| + | *src += 4; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode spack_enc64(struct dynbuf *buf, uint64_t val) |
| + | { |
| + | uint8_t nval[8]; |
| + | nval[0] = (uint8_t)(val >> 56); |
| + | nval[1] = (uint8_t)(val >> 48); |
| + | nval[2] = (uint8_t)(val >> 40); |
| + | nval[3] = (uint8_t)(val >> 32); \ |
| + | nval[4] = (uint8_t)(val >> 24); |
| + | nval[5] = (uint8_t)(val >> 16); |
| + | nval[6] = (uint8_t)(val >> 8); |
| + | nval[7] = (uint8_t)val; |
| + | return Curl_dyn_addn(buf, nval, sizeof(nval)); |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_dec64(uint64_t *val, const uint8_t **src, const uint8_t *end) |
| + | { |
| + | if(end - *src < 8) |
| + | return CURLE_READ_ERROR; |
| + | *val = (uint64_t)(*src)[0] << 56 | (uint64_t)(*src)[1] << 48 | |
| + | (uint64_t)(*src)[2] << 40 | (uint64_t)(*src)[3] << 32 | |
| + | (uint64_t)(*src)[4] << 24 | (uint64_t)(*src)[5] << 16 | |
| + | (uint64_t)(*src)[6] << 8 | (*src)[7]; |
| + | *src += 8; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode spack_encstr16(struct dynbuf *buf, const char *s) |
| + | { |
| + | size_t slen = strlen(s); |
| + | CURLcode r; |
| + | if(slen > UINT16_MAX) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | r = spack_enc16(buf, (uint16_t)slen); |
| + | if(!r) { |
| + | r = Curl_dyn_addn(buf, s, slen); |
| + | } |
| + | return r; |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_decstr16(char **val, const uint8_t **src, const uint8_t *end) |
| + | { |
| + | uint16_t slen; |
| + | CURLcode r; |
| + | |
| + | *val = NULL; |
| + | r = spack_dec16(&slen, src, end); |
| + | if(r) |
| + | return r; |
| + | if(end - *src < slen) |
| + | return CURLE_READ_ERROR; |
| + | *val = Curl_memdup0((const char *)(*src), slen); |
| + | *src += slen; |
| + | return *val ? CURLE_OK : CURLE_OUT_OF_MEMORY; |
| + | } |
| + | |
| + | static CURLcode spack_encdata16(struct dynbuf *buf, |
| + | const uint8_t *data, size_t data_len) |
| + | { |
| + | CURLcode r; |
| + | if(data_len > UINT16_MAX) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | r = spack_enc16(buf, (uint16_t)data_len); |
| + | if(!r) { |
| + | r = Curl_dyn_addn(buf, data, data_len); |
| + | } |
| + | return r; |
| + | } |
| + | |
| + | static CURLcode |
| + | spack_decdata16(uint8_t **val, size_t *val_len, |
| + | const uint8_t **src, const uint8_t *end) |
| + | { |
| + | uint16_t data_len; |
| + | CURLcode r; |
| + | |
| + | *val = NULL; |
| + | r = spack_dec16(&data_len, src, end); |
| + | if(r) |
| + | return r; |
| + | if(end - *src < data_len) |
| + | return CURLE_READ_ERROR; |
| + | *val = Curl_memdup0((const char *)(*src), data_len); |
| + | *val_len = data_len; |
| + | *src += data_len; |
| + | return *val ? CURLE_OK : CURLE_OUT_OF_MEMORY; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_session_pack(struct Curl_easy *data, |
| + | struct Curl_ssl_session *s, |
| + | struct dynbuf *buf) |
| + | { |
| + | CURLcode r; |
| + | DEBUGASSERT(s->sdata); |
| + | DEBUGASSERT(s->sdata_len); |
| + | |
| + | if(s->valid_until < 0) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | |
| + | r = spack_enc8(buf, CURL_SPACK_VERSION); |
| + | if(!r) |
| + | r = spack_enc8(buf, CURL_SPACK_TICKET); |
| + | if(!r) |
| + | r = spack_encdata16(buf, s->sdata, s->sdata_len); |
| + | if(!r) |
| + | r = spack_enc8(buf, CURL_SPACK_IETF_ID); |
| + | if(!r) |
| + | r = spack_enc16(buf, (uint16_t)s->ietf_tls_id); |
| + | if(!r) |
| + | r = spack_enc8(buf, CURL_SPACK_VALID_UNTIL); |
| + | if(!r) |
| + | r = spack_enc64(buf, (uint64_t)s->valid_until); |
| + | if(!r && s->alpn) { |
| + | r = spack_enc8(buf, CURL_SPACK_ALPN); |
| + | if(!r) |
| + | r = spack_encstr16(buf, s->alpn); |
| + | } |
| + | if(!r && s->earlydata_max) { |
| + | if(s->earlydata_max > UINT32_MAX) |
| + | r = CURLE_BAD_FUNCTION_ARGUMENT; |
| + | if(!r) |
| + | r = spack_enc8(buf, CURL_SPACK_EARLYDATA); |
| + | if(!r) |
| + | r = spack_enc32(buf, (uint32_t)s->earlydata_max); |
| + | } |
| + | if(!r && s->quic_tp && s->quic_tp_len) { |
| + | r = spack_enc8(buf, CURL_SPACK_QUICTP); |
| + | if(!r) |
| + | r = spack_encdata16(buf, s->quic_tp, s->quic_tp_len); |
| + | } |
| + | |
| + | if(r) |
| + | CURL_TRC_SSLS(data, "error packing data: %d", r); |
| + | return r; |
| + | } |
| + | |
| + | CURLcode Curl_ssl_session_unpack(struct Curl_easy *data, |
| + | const unsigned char *buf, size_t buflen, |
| + | struct Curl_ssl_session **ps) |
| + | { |
| + | struct Curl_ssl_session *s = NULL; |
| + | const unsigned char *end = buf + buflen; |
| + | uint8_t val8, *pval8; |
| + | uint16_t val16; |
| + | uint32_t val32; |
| + | uint64_t val64; |
| + | CURLcode r; |
| + | |
| + | DEBUGASSERT(buf); |
| + | DEBUGASSERT(buflen); |
| + | *ps = NULL; |
| + | |
| + | r = spack_dec8(&val8, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | if(val8 != CURL_SPACK_VERSION) { |
| + | r = CURLE_READ_ERROR; |
| + | goto out; |
| + | } |
| + | |
| + | s = calloc(1, sizeof(*s)); |
| + | if(!s) { |
| + | r = CURLE_OUT_OF_MEMORY; |
| + | goto out; |
| + | } |
| + | |
| + | while(buf < end) { |
| + | r = spack_dec8(&val8, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | |
| + | switch(val8) { |
| + | case CURL_SPACK_ALPN: |
| + | r = spack_decstr16(&s->alpn, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | break; |
| + | case CURL_SPACK_EARLYDATA: |
| + | r = spack_dec32(&val32, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | s->earlydata_max = val32; |
| + | break; |
| + | case CURL_SPACK_IETF_ID: |
| + | r = spack_dec16(&val16, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | s->ietf_tls_id = val16; |
| + | break; |
| + | case CURL_SPACK_QUICTP: { |
| + | r = spack_decdata16(&pval8, &s->quic_tp_len, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | s->quic_tp = pval8; |
| + | break; |
| + | } |
| + | case CURL_SPACK_TICKET: { |
| + | r = spack_decdata16(&pval8, &s->sdata_len, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | s->sdata = pval8; |
| + | break; |
| + | } |
| + | case CURL_SPACK_VALID_UNTIL: |
| + | r = spack_dec64(&val64, &buf, end); |
| + | if(r) |
| + | goto out; |
| + | s->valid_until = (curl_off_t)val64; |
| + | break; |
| + | default: /* unknown tag */ |
| + | r = CURLE_READ_ERROR; |
| + | goto out; |
| + | } |
| + | } |
| + | |
| + | out: |
| + | if(r) { |
| + | CURL_TRC_SSLS(data, "error unpacking data: %d", r); |
| + | Curl_ssl_session_destroy(s); |
| + | } |
| + | else |
| + | *ps = s; |
| + | return r; |
| + | } |
| + | |
| + | #endif /* USE_SSLS_EXPORT */ |
| @@ -0,0 +1,43 @@ | |
| + | #ifndef HEADER_CURL_VTLS_SPACK_H |
| + | #define HEADER_CURL_VTLS_SPACK_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" |
| + | |
| + | #ifdef USE_SSLS_EXPORT |
| + | |
| + | struct dynbuf; |
| + | struct Curl_ssl_session; |
| + | |
| + | CURLcode Curl_ssl_session_pack(struct Curl_easy *data, |
| + | struct Curl_ssl_session *s, |
| + | struct dynbuf *buf); |
| + | |
| + | CURLcode Curl_ssl_session_unpack(struct Curl_easy *data, |
| + | const unsigned char *buf, size_t buflen, |
| + | struct Curl_ssl_session **ps); |
| + | |
| + | #endif /* USE_SSLS_EXPORT */ |
| + | |
| + | #endif /* HEADER_CURL_VTLS_SPACK_H */ |
| @@ -653,3 +653,41 @@ AS_HELP_STRING([--disable-ech],[Disable ECH support]), | |
| esac | |
| ]) | |
| ]) | |
| + | |
| + | dnl CURL_CHECK_OPTION_SSLS_EXPORT |
| + | dnl ----------------------------------------------------- |
| + | dnl Verify whether configure has been invoked with option |
| + | dnl --enable-ssl-session-export or --disable-ssl-session-export, and set |
| + | dnl shell variable want_ech as appropriate. |
| + | |
| + | AC_DEFUN([CURL_CHECK_OPTION_SSLS_EXPORT], [ |
| + | AC_MSG_CHECKING([whether to enable SSL session export support]) |
| + | OPT_SSLS_EXPORT="default" |
| + | AC_ARG_ENABLE(ssls-export, |
| + | AS_HELP_STRING([--enable-ssls-export], |
| + | [Enable SSL session export support]) |
| + | AS_HELP_STRING([--disable-ssls-export], |
| + | [Disable SSL session export support]), |
| + | OPT_SSLS_EXPORT=$enableval) |
| + | case "$OPT_SSLS_EXPORT" in |
| + | no) |
| + | dnl --disable-ssls-export option used |
| + | want_ssls_export="no" |
| + | curl_ssls_export_msg="no (--enable-ssls-export)" |
| + | AC_MSG_RESULT([no]) |
| + | ;; |
| + | default) |
| + | dnl configure option not specified |
| + | want_ssls_export="no" |
| + | curl_ssls_export_msg="no (--enable-ssls-export)" |
| + | AC_MSG_RESULT([no]) |
| + | ;; |
| + | *) |
| + | dnl --enable-ssls-export option used |
| + | want_ssls_export="yes" |
| + | curl_ssls_export_msg="enabled (--disable-ssls-export)" |
| + | AC_MSG_RESULT([yes]) |
| + | ;; |
| + | esac |
| + | ]) |
| + | ]) |
| @@ -164,6 +164,7 @@ rem | |
| call :element %1 lib "timediff.c" %3 | |
| call :element %1 lib "nonblock.c" %3 | |
| call :element %1 lib "warnless.c" %3 | |
| + | call :element %1 lib "curl_get_line.c" %3 |
| call :element %1 lib "curl_multibyte.c" %3 | |
| call :element %1 lib "version_win32.c" %3 | |
| call :element %1 lib "dynbuf.c" %3 | |
| @@ -176,6 +177,7 @@ rem | |
| call :element %1 lib "nonblock.h" %3 | |
| call :element %1 lib "warnless.h" %3 | |
| call :element %1 lib "curl_ctype.h" %3 | |
| + | call :element %1 lib "curl_get_line.h" %3 |
| call :element %1 lib "curl_multibyte.h" %3 | |
| call :element %1 lib "version_win32.h" %3 | |
| call :element %1 lib "dynbuf.h" %3 | |
| @@ -61,6 +61,8 @@ my %api = ( | |
| 'curl_easy_reset' => 'API', | |
| 'curl_easy_send' => 'API', | |
| 'curl_easy_setopt' => 'API', | |
| + | 'curl_easy_ssls_export' => 'API', |
| + | 'curl_easy_ssls_import' => 'API', |
| 'curl_easy_strerror' => 'API', | |
| 'curl_easy_unescape' => 'API', | |
| 'curl_easy_upkeep' => 'API', | |
| @@ -32,12 +32,14 @@ | |
| # libcurl sources to include in curltool lib we use for test binaries | |
| CURLTOOL_LIBCURL_CFILES = \ | |
| ../lib/base64.c \ | |
| - | ../lib/dynbuf.c |
| + | ../lib/dynbuf.c \ |
| + | ../lib/curl_get_line.c |
| # libcurl has sources that provide functions named curlx_* that are not part of | |
| # the official API, but we reuse the code here to avoid duplication. | |
| CURLX_CFILES = \ | |
| ../lib/base64.c \ | |
| + | ../lib/curl_get_line.c \ |
| ../lib/curl_multibyte.c \ | |
| ../lib/dynbuf.c \ | |
| ../lib/nonblock.c \ | |
| @@ -48,6 +50,7 @@ CURLX_CFILES = \ | |
| CURLX_HFILES = \ | |
| ../lib/curl_ctype.h \ | |
| + | ../lib/curl_get_line.h \ |
| ../lib/curl_multibyte.h \ | |
| ../lib/curl_setup.h \ | |
| ../lib/dynbuf.h \ | |
| @@ -92,6 +95,7 @@ CURL_CFILES = \ | |
| tool_progress.c \ | |
| tool_setopt.c \ | |
| tool_sleep.c \ | |
| + | tool_ssls.c \ |
| tool_stderr.c \ | |
| tool_strdup.c \ | |
| tool_urlglob.c \ | |
| @@ -139,6 +143,7 @@ CURL_HFILES = \ | |
| tool_setopt.h \ | |
| tool_setup.h \ | |
| tool_sleep.h \ | |
| + | tool_ssls.h \ |
| tool_stderr.h \ | |
| tool_strdup.h \ | |
| tool_urlglob.h \ | |
| @@ -330,6 +330,7 @@ struct GlobalConfig { | |
| bool styled_output; /* enable fancy output style detection */ | |
| long ms_per_transfer; /* start next transfer after (at least) this | |
| many milliseconds */ | |
| + | char *ssl_sessions; /* file to load/save SSL session tickets */ |
| #ifdef DEBUGBUILD | |
| bool test_duphandle; | |
| bool test_event_based; | |
| @@ -300,6 +300,7 @@ static const struct LongShort aliases[]= { | |
| {"ssl-no-revoke", ARG_BOOL, ' ', C_SSL_NO_REVOKE}, | |
| {"ssl-reqd", ARG_BOOL, ' ', C_SSL_REQD}, | |
| {"ssl-revoke-best-effort", ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT}, | |
| + | {"ssl-sessions", ARG_FILE, ' ', C_SSL_SESSIONS}, |
| {"sslv2", ARG_NONE, '2', C_SSLV2}, | |
| {"sslv3", ARG_NONE, '3', C_SSLV3}, | |
| {"stderr", ARG_FILE, ' ', C_STDERR}, | |
| @@ -2470,6 +2471,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ | |
| if(feature_ssl) | |
| config->ssl_revoke_best_effort = TRUE; | |
| break; | |
| + | case C_SSL_SESSIONS: /* --ssl-sessions */ |
| + | if(feature_ssls_export) |
| + | err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); |
| + | else |
| + | err = PARAM_LIBCURL_DOESNT_SUPPORT; |
| + | break; |
| case C_TCP_FASTOPEN: /* --tcp-fastopen */ | |
| config->tcp_fastopen = TRUE; | |
| break; | |
| @@ -259,6 +259,7 @@ typedef enum { | |
| C_SSL_NO_REVOKE, | |
| C_SSL_REQD, | |
| C_SSL_REVOKE_BEST_EFFORT, | |
| + | C_SSL_SESSIONS, |
| C_SSLV2, | |
| C_SSLV3, | |
| C_STDERR, | |
| @@ -84,6 +84,7 @@ bool feature_ssl = FALSE; | |
| bool feature_tls_srp = FALSE; | |
| bool feature_zstd = FALSE; | |
| bool feature_ech = FALSE; | |
| + | bool feature_ssls_export = FALSE; |
| static struct feature_name_presentp { | |
| const char *feature_name; | |
| @@ -115,6 +116,7 @@ static struct feature_name_presentp { | |
| {"SPNEGO", &feature_spnego, CURL_VERSION_SPNEGO}, | |
| {"SSL", &feature_ssl, CURL_VERSION_SSL}, | |
| {"SSPI", NULL, CURL_VERSION_SSPI}, | |
| + | {"SSLS-EXPORT", &feature_ssls_export, 0}, |
| {"threadsafe", NULL, CURL_VERSION_THREADSAFE}, | |
| {"TLS-SRP", &feature_tls_srp, CURL_VERSION_TLSAUTH_SRP}, | |
| {"TrackMemory", NULL, CURL_VERSION_CURLDEBUG}, | |
| @@ -62,6 +62,7 @@ extern bool feature_ssl; | |
| extern bool feature_tls_srp; | |
| extern bool feature_zstd; | |
| extern bool feature_ech; | |
| + | extern bool feature_ssls_export; |
| CURLcode get_libcurl_info(void); | |
| const char *proto_token(const char *proto); | |
| @@ -715,6 +715,9 @@ const struct helptxt helptext[] = { | |
| {" --ssl-revoke-best-effort", | |
| "Ignore missing cert CRL dist points", | |
| CURLHELP_TLS}, | |
| + | {" --ssl-sessions <filename>", |
| + | "Load/save SSL session tickets from/to this file", |
| + | CURLHELP_TLS}, |
| {"-2, --sslv2", | |
| "SSLv2", | |
| CURLHELP_DEPRECATED}, | |
| @@ -87,6 +87,7 @@ | |
| #include "tool_parsecfg.h" | |
| #include "tool_setopt.h" | |
| #include "tool_sleep.h" | |
| + | #include "tool_ssls.h" |
| #include "tool_urlglob.h" | |
| #include "tool_util.h" | |
| #include "tool_writeout.h" | |
| @@ -3232,18 +3233,31 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) | |
| curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL); | |
| curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS); | |
| - | /* Get the required arguments for each operation */ |
| - | do { |
| - | result = get_args(operation, count++); |
| + | if(global->ssl_sessions && feature_ssls_export) |
| + | result = tool_ssls_load(global, global->first, share, |
| + | global->ssl_sessions); |
| - | operation = operation->next; |
| - | } while(!result && operation); |
| + | if(!result) { |
| + | /* Get the required arguments for each operation */ |
| + | do { |
| + | result = get_args(operation, count++); |
| - | /* Set the current operation pointer */ |
| - | global->current = global->first; |
| + | operation = operation->next; |
| + | } while(!result && operation); |
| - | /* now run! */ |
| - | result = run_all_transfers(global, share, result); |
| + | /* Set the current operation pointer */ |
| + | global->current = global->first; |
| + | |
| + | /* now run! */ |
| + | result = run_all_transfers(global, share, result); |
| + | |
| + | if(global->ssl_sessions && feature_ssls_export) { |
| + | CURLcode r2 = tool_ssls_save(global, global->first, share, |
| + | global->ssl_sessions); |
| + | if(r2 && !result) |
| + | result = r2; |
| + | } |
| + | } |
| curl_share_cleanup(share); | |
| if(global->libcurl) { | |
| @@ -0,0 +1,222 @@ | |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * 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 "tool_setup.h" |
| + | |
| + | #include "curlx.h" |
| + | #include "tool_cfgable.h" |
| + | #include "tool_cb_dbg.h" |
| + | #include "tool_msgs.h" |
| + | #include "tool_setopt.h" |
| + | #include "tool_ssls.h" |
| + | #include "dynbuf.h" |
| + | #include "curl_base64.h" |
| + | #include "curl_get_line.h" |
| + | |
| + | /* The maximum line length for an ecoded session ticket */ |
| + | #define MAX_SSLS_LINE (64 * 1024) |
| + | |
| + | |
| + | static CURLcode tool_ssls_easy(struct GlobalConfig *global, |
| + | struct OperationConfig *config, |
| + | CURLSH *share, CURL **peasy) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | |
| + | *peasy = curl_easy_init(); |
| + | if(!*peasy) |
| + | return CURLE_OUT_OF_MEMORY; |
| + | |
| + | result = curl_easy_setopt(*peasy, CURLOPT_SHARE, share); |
| + | if(global->tracetype != TRACE_NONE) { |
| + | my_setopt(*peasy, CURLOPT_DEBUGFUNCTION, tool_debug_cb); |
| + | my_setopt(*peasy, CURLOPT_DEBUGDATA, config); |
| + | my_setopt(*peasy, CURLOPT_VERBOSE, 1L); |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | CURLcode tool_ssls_load(struct GlobalConfig *global, |
| + | struct OperationConfig *config, |
| + | CURLSH *share, const char *filename) |
| + | { |
| + | FILE *fp; |
| + | CURL *easy = NULL; |
| + | struct dynbuf buf; |
| + | unsigned char *shmac = NULL, *sdata = NULL; |
| + | char *c, *line, *end; |
| + | size_t shmac_len, sdata_len; |
| + | CURLcode r = CURLE_OK; |
| + | int i, imported; |
| + | |
| + | curlx_dyn_init(&buf, MAX_SSLS_LINE); |
| + | fp = fopen(filename, FOPEN_READTEXT); |
| + | if(!fp) { /* ok if it does not exist */ |
| + | notef(global, "SSL session file does not exist (yet?): %s", filename); |
| + | goto out; |
| + | } |
| + | |
| + | r = tool_ssls_easy(global, config, share, &easy); |
| + | if(r) |
| + | goto out; |
| + | |
| + | i = imported = 0; |
| + | while(Curl_get_line(&buf, fp)) { |
| + | ++i; |
| + | curl_free(shmac); |
| + | curl_free(sdata); |
| + | line = Curl_dyn_ptr(&buf); |
| + | while(*line && ISBLANK(*line)) |
| + | line++; |
| + | if(*line == '#') |
| + | /* skip commented lines */ |
| + | continue; |
| + | |
| + | c = memchr(line, ':', strlen(line)); |
| + | if(!c) { |
| + | warnf(global, "unrecognized line %d in ssl session file %s", |
| + | i, filename); |
| + | continue; |
| + | } |
| + | *c = '\0'; |
| + | r = curlx_base64_decode(line, &shmac, &shmac_len); |
| + | if(r) { |
| + | warnf(global, "invalid shmax base64 encoding in line %d", i); |
| + | continue; |
| + | } |
| + | line = c + 1; |
| + | end = line + strlen(line) - 1; |
| + | while((end > line) && (*end == '\n' || *end == '\r' || ISBLANK(*line))) { |
| + | *end = '\0'; |
| + | --end; |
| + | } |
| + | r = curlx_base64_decode(line, &sdata, &sdata_len); |
| + | if(r) { |
| + | warnf(global, "invalid sdata base64 encoding in line %d: %s", i, line); |
| + | continue; |
| + | } |
| + | |
| + | r = curl_easy_ssls_import(easy, NULL, shmac, shmac_len, sdata, sdata_len); |
| + | if(r) { |
| + | warnf(global, "import of session from line %d rejected(%d)", i, r); |
| + | continue; |
| + | } |
| + | ++imported; |
| + | } |
| + | r = CURLE_OK; |
| + | |
| + | out: |
| + | if(easy) |
| + | curl_easy_cleanup(easy); |
| + | if(fp) |
| + | fclose(fp); |
| + | curlx_dyn_free(&buf); |
| + | curl_free(shmac); |
| + | curl_free(sdata); |
| + | return r; |
| + | } |
| + | |
| + | struct tool_ssls_ctx { |
| + | struct GlobalConfig *global; |
| + | FILE *fp; |
| + | int exported; |
| + | }; |
| + | |
| + | static CURLcode tool_ssls_exp(CURL *easy, void *userptr, |
| + | const char *session_key, |
| + | const unsigned char *shmac, size_t shmac_len, |
| + | const unsigned char *sdata, size_t sdata_len, |
| + | curl_off_t valid_until, int ietf_tls_id, |
| + | const char *alpn, size_t earlydata_max) |
| + | { |
| + | struct tool_ssls_ctx *ctx = userptr; |
| + | char *enc = NULL; |
| + | size_t enc_len; |
| + | CURLcode r; |
| + | |
| + | (void)easy; |
| + | (void)valid_until; |
| + | (void)ietf_tls_id; |
| + | (void)alpn; |
| + | (void)earlydata_max; |
| + | if(!ctx->exported) |
| + | fputs("# Your SSL session cache. https://curl.se/docs/ssl-sessions.html\n" |
| + | "# This file was generated by libcurl! Edit at your own risk.\n", |
| + | ctx->fp); |
| + | |
| + | r = curlx_base64_encode((const char *)shmac, shmac_len, &enc, &enc_len); |
| + | if(r) |
| + | goto out; |
| + | r = CURLE_WRITE_ERROR; |
| + | if(enc_len != fwrite(enc, 1, enc_len, ctx->fp)) |
| + | goto out; |
| + | if(EOF == fputc(':', ctx->fp)) |
| + | goto out; |
| + | curl_free(enc); |
| + | r = curlx_base64_encode((const char *)sdata, sdata_len, &enc, &enc_len); |
| + | if(r) |
| + | goto out; |
| + | r = CURLE_WRITE_ERROR; |
| + | if(enc_len != fwrite(enc, 1, enc_len, ctx->fp)) |
| + | goto out; |
| + | if(EOF == fputc('\n', ctx->fp)) |
| + | goto out; |
| + | r = CURLE_OK; |
| + | ctx->exported++; |
| + | out: |
| + | if(r) |
| + | warnf(ctx->global, "Warning: error saving SSL session for '%s': %d", |
| + | session_key, r); |
| + | curl_free(enc); |
| + | return r; |
| + | } |
| + | |
| + | CURLcode tool_ssls_save(struct GlobalConfig *global, |
| + | struct OperationConfig *config, |
| + | CURLSH *share, const char *filename) |
| + | { |
| + | struct tool_ssls_ctx ctx; |
| + | CURL *easy = NULL; |
| + | CURLcode r = CURLE_OK; |
| + | |
| + | ctx.global = global; |
| + | ctx.exported = 0; |
| + | ctx.fp = fopen(filename, FOPEN_WRITETEXT); |
| + | if(!ctx.fp) { |
| + | warnf(global, "Warning: Failed to create SSL session file %s", filename); |
| + | goto out; |
| + | } |
| + | |
| + | r = tool_ssls_easy(global, config, share, &easy); |
| + | if(r) |
| + | goto out; |
| + | |
| + | r = curl_easy_ssls_export(easy, tool_ssls_exp, &ctx); |
| + | |
| + | out: |
| + | if(easy) |
| + | curl_easy_cleanup(easy); |
| + | if(ctx.fp) |
| + | fclose(ctx.fp); |
| + | return r; |
| + | } |
| @@ -0,0 +1,37 @@ | |
| + | #ifndef HEADER_CURL_TOOL_SSLS_H |
| + | #define HEADER_CURL_TOOL_SSLS_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 "tool_setup.h" |
| + | #include "tool_operate.h" |
| + | |
| + | |
| + | CURLcode tool_ssls_load(struct GlobalConfig *global, |
| + | struct OperationConfig *config, |
| + | CURLSH *share, const char *filename); |
| + | CURLcode tool_ssls_save(struct GlobalConfig *global, |
| + | struct OperationConfig *config, |
| + | CURLSH *share, const char *filename); |
| + | |
| + | #endif /* HEADER_CURL_TOOL_SSLS_H */ |
| @@ -67,6 +67,8 @@ curl_version_info | |
| curl_easy_strerror | |
| curl_share_strerror | |
| curl_easy_pause | |
| + | curl_easy_ssls_import |
| + | curl_easy_ssls_export |
| curl_easy_init | |
| curl_easy_setopt | |
| curl_easy_perform | |
| @@ -390,3 +390,37 @@ class TestSSLUse: | |
| match_trace = line | |
| break | |
| assert match_trace, f'Did not find "{exp_trace}" in trace\n{r.dump_logs()}' | |
| + | |
| + | @pytest.mark.skipif(condition=not Env.curl_has_feature('SSLS-EXPORT'), |
| + | reason='curl lacks SSL session export support') |
| + | def test_17_15_session_export(self, env: Env, httpd): |
| + | proto = 'http/1.1' |
| + | if env.curl_uses_lib('libressl'): |
| + | pytest.skip('Libressl resumption does not work inTLSv1.3') |
| + | if env.curl_uses_lib('rustls-ffi'): |
| + | pytest.skip('rustsls does not expose sessions') |
| + | if env.curl_uses_lib('bearssl'): |
| + | pytest.skip('BearSSL does not support TLSv1.3') |
| + | if env.curl_uses_lib('mbedtls') and \ |
| + | not env.curl_lib_version_at_least('mbedtls', '3.6.0'): |
| + | pytest.skip('mbedtls TLSv1.3 session resume not working before 3.6.0') |
| + | run_env = os.environ.copy() |
| + | run_env['CURL_DEBUG'] = 'ssl,scache' |
| + | # clean session file first, then reuse |
| + | session_file = os.path.join(env.gen_dir, 'test_17_15.sessions') |
| + | if os.path.exists(session_file): |
| + | return os.remove(session_file) |
| + | xargs = ['--tls-max', '1.3', '--tlsv1.3', '--ssl-sessions', session_file] |
| + | curl = CurlClient(env=env, run_env=run_env) |
| + | # tell the server to close the connection after each request |
| + | url = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo' |
| + | r = curl.http_get(url=url, alpn_proto=proto, extra_args=xargs) |
| + | assert r.exit_code == 0, f'{r}' |
| + | assert r.json['HTTPS'] == 'on', f'{r.json}' |
| + | assert r.json['SSL_SESSION_RESUMED'] == 'Initial', f'{r.json}\n{r.dump_logs()}' |
| + | # ok, run again, sessions should be imported |
| + | run_dir2 = os.path.join(env.gen_dir, 'curl2') |
| + | curl = CurlClient(env=env, run_env=run_env, run_dir=run_dir2) |
| + | r = curl.http_get(url=url, alpn_proto=proto, extra_args=xargs) |
| + | assert r.exit_code == 0, f'{r}' |
| + | assert r.json['SSL_SESSION_RESUMED'] == 'Resumed', f'{r.json}\n{r.dump_logs()}' |
| @@ -34,6 +34,7 @@ CURLX_SRCS = \ | |
| ../../lib/dynbuf.c \ | |
| ../../lib/strdup.c \ | |
| ../../lib/strcase.c \ | |
| + | ../../lib/curl_get_line.c \ |
| ../../lib/curl_multibyte.c | |
| CURLX_HDRS = \ | |
| @@ -45,6 +46,7 @@ CURLX_HDRS = \ | |
| ../../lib/curl_ctype.h \ | |
| ../../lib/dynbuf.h \ | |
| ../../lib/strdup.h \ | |
| + | ../../lib/curl_get_line.h \ |
| ../../lib/curl_multibyte.h | |
| USEFUL = \ | |
| @@ -22,6 +22,8 @@ | |
| * | |
| ***************************************************************************/ | |
| #include "curlcheck.h" | |
| + | /* disable the curlx_get_line redefinitions for this unit test */ |
| + | #define BUILDING_LIBCURL |
| #include "curl_get_line.h" | |
| #include "memdebug.h" | |
| @@ -688,6 +688,7 @@ CURL_FROM_LIBCURL=$(CURL_DIROBJ)\tool_hugehelp.obj \ | |
| $(CURL_DIROBJ)\nonblock.obj \ | |
| $(CURL_DIROBJ)\strtoofft.obj \ | |
| $(CURL_DIROBJ)\warnless.obj \ | |
| + | $(CURL_DIROBJ)\curl_get_line.obj \ |
| $(CURL_DIROBJ)\curl_multibyte.obj \ | |
| $(CURL_DIROBJ)\version_win32.obj \ | |
| $(CURL_DIROBJ)\dynbuf.obj \ | |
| @@ -708,6 +709,8 @@ $(CURL_DIROBJ)\strtoofft.obj: ../lib/strtoofft.c | |
| $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strtoofft.c | |
| $(CURL_DIROBJ)\warnless.obj: ../lib/warnless.c | |
| $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/warnless.c | |
| + | $(CURL_DIROBJ)\curl_get_line.obj: ../lib/curl_get_line.c |
| + | $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curl_get_line.c |
| $(CURL_DIROBJ)\curl_multibyte.obj: ../lib/curl_multibyte.c | |
| $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curl_multibyte.c | |
| $(CURL_DIROBJ)\version_win32.obj: ../lib/version_win32.c | |