logo

oasis

Own branch of Oasis Linux (upstream: <https://git.sr.ht/~mcf/oasis/>) git clone https://anongit.hacktivis.me/git/oasis.git
commit: d60cc6499f645384ba1000c9b074becfb20f13db
parent ed5d7b1e7bbe2dc4be9840c1b17fb3cbd3951e4c
Author: Michael Forney <mforney@mforney.org>
Date:   Tue, 26 Nov 2019 22:37:33 -0800

curl: Update BearSSL patch to the one applied upstream

Diffstat:

Dpkg/curl/patch/0001-Add-BearSSL-vtls-implementation.patch1311-------------------------------------------------------------------------------
Apkg/curl/patch/0001-TLS-add-BearSSL-vtls-implementation.patch1316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg/curl/ver2+-
3 files changed, 1317 insertions(+), 1312 deletions(-)

diff --git a/pkg/curl/patch/0001-Add-BearSSL-vtls-implementation.patch b/pkg/curl/patch/0001-Add-BearSSL-vtls-implementation.patch @@ -1,1311 +0,0 @@ -From 70ce89a54fca01be671f5210630ab289fdb648a6 Mon Sep 17 00:00:00 2001 -From: Michael Forney <mforney@mforney.org> -Date: Thu, 7 Nov 2019 20:17:18 -0800 -Subject: [PATCH] Add BearSSL vtls implementation -Upstream: https://github.com/curl/curl/pull/4597 - ---- - CMake/FindBearSSL.cmake | 9 + - CMakeLists.txt | 11 + - Makefile.am | 4 +- - configure.ac | 98 +++- - docs/FAQ | 6 +- - docs/INSTALL.md | 1 + - docs/LICENSE-MIXING.md | 5 + - docs/libcurl/curl_global_sslset.3 | 3 +- - docs/libcurl/symbols-in-versions | 1 + - include/curl/curl.h | 3 +- - lib/Makefile.inc | 5 +- - lib/curl_config.h.cmake | 3 + - lib/curl_setup.h | 3 +- - lib/vtls/bearssl.c | 870 ++++++++++++++++++++++++++++++ - lib/vtls/bearssl.h | 32 ++ - lib/vtls/vtls.c | 4 +- - lib/vtls/vtls.h | 1 + - 17 files changed, 1045 insertions(+), 14 deletions(-) - create mode 100644 CMake/FindBearSSL.cmake - create mode 100644 lib/vtls/bearssl.c - create mode 100644 lib/vtls/bearssl.h - -diff --git a/CMake/FindBearSSL.cmake b/CMake/FindBearSSL.cmake -new file mode 100644 -index 000000000..20d239a4f ---- /dev/null -+++ b/CMake/FindBearSSL.cmake -@@ -0,0 +1,9 @@ -+find_path(BEARSSL_INCLUDE_DIRS bearssl.h) -+ -+find_library(BEARSSL_LIBRARY bearssl) -+ -+include(FindPackageHandleStandardArgs) -+find_package_handle_standard_args(BEARSSL DEFAULT_MSG -+ BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) -+ -+mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 20b9bd011..a2ad6933b 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -295,6 +295,7 @@ if(WIN32) - CMAKE_USE_WINSSL OFF) - endif() - option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF) -+option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF) - - set(openssl_default ON) - if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS) -@@ -307,6 +308,7 @@ count_true(enabled_ssl_options_count - CMAKE_USE_SECTRANSP - CMAKE_USE_OPENSSL - CMAKE_USE_MBEDTLS -+ CMAKE_USE_BEARSSL - ) - if(enabled_ssl_options_count GREATER "1") - set(CURL_WITH_MULTI_SSL ON) -@@ -379,6 +381,14 @@ if(CMAKE_USE_MBEDTLS) - include_directories(${MBEDTLS_INCLUDE_DIRS}) - endif() - -+if(CMAKE_USE_BEARSSL) -+ find_package(BearSSL REQUIRED) -+ set(SSL_ENABLED ON) -+ set(USE_BEARSSL ON) -+ list(APPEND CURL_LIBS ${BEARSSL_LIBRARY}) -+ include_directories(${BEARSSL_INCLUDE_DIRS}) -+endif() -+ - option(USE_NGHTTP2 "Use Nghttp2 library" OFF) - if(USE_NGHTTP2) - find_package(NGHTTP2 REQUIRED) -@@ -1251,6 +1261,7 @@ _add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) - _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) - _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP) - _add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) -+_add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL) - if(_items) - list(SORT _items) - endif() -diff --git a/Makefile.am b/Makefile.am -index 3116e1053..b98d5ee71 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -30,8 +30,8 @@ CMAKE_DIST = CMakeLists.txt CMake/CMakeConfigurableFile.in \ - CMake/Macros.cmake \ - CMake/CurlSymbolHiding.cmake CMake/FindCARES.cmake \ - CMake/FindLibSSH2.cmake CMake/FindNGHTTP2.cmake \ -- CMake/FindMbedTLS.cmake CMake/cmake_uninstall.cmake.in \ -- CMake/curl-config.cmake.in -+ CMake/FindMbedTLS.cmake CMake/FindBearSSL.cmake \ -+ CMake/cmake_uninstall.cmake.in CMake/curl-config.cmake.in - - VC6_LIBTMPL = projects/Windows/VC6/lib/libcurl.tmpl - VC6_LIBDSP = projects/Windows/VC6/lib/libcurl.dsp.dist -diff --git a/configure.ac b/configure.ac -index cb8f4943e..11fa05803 100755 ---- a/configure.ac -+++ b/configure.ac -@@ -156,7 +156,7 @@ AC_SUBST(PKGADD_VENDOR) - - dnl - dnl initialize all the info variables -- curl_ssl_msg="no (--with-{ssl,gnutls,nss,mbedtls,wolfssl,schannel,secure-transport,mesalink,amissl} )" -+ curl_ssl_msg="no (--with-{ssl,gnutls,nss,mbedtls,wolfssl,schannel,secure-transport,mesalink,amissl,bearssl} )" - curl_ssh_msg="no (--with-libssh2)" - curl_zlib_msg="no (--with-zlib)" - curl_brotli_msg="no (--with-brotli)" -@@ -2399,6 +2399,98 @@ if test -z "$ssl_backends" -o "x$OPT_MESALINK" != xno; then - test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" - fi - -+dnl ---------------------------------------------------- -+dnl check for BearSSL -+dnl ---------------------------------------------------- -+ -+OPT_BEARSSL=no -+ -+_cppflags=$CPPFLAGS -+_ldflags=$LDFLAGS -+AC_ARG_WITH(bearssl,dnl -+AC_HELP_STRING([--with-bearssl=PATH],[where to look for BearSSL, PATH points to the installation root]) -+AC_HELP_STRING([--without-bearssl], [disable BearSSL detection]), -+ OPT_BEARSSL=$withval) -+ -+if test -z "$ssl_backends" -o "x$OPT_BEARSSL" != xno; then -+ ssl_msg= -+ -+ if test X"$OPT_BEARSSL" != Xno; then -+ -+ if test "$OPT_BEARSSL" = "yes"; then -+ OPT_BEARSSL="" -+ fi -+ -+ if test -z "$OPT_BEARSSL" ; then -+ dnl check for lib first without setting any new path -+ -+ AC_CHECK_LIB(bearssl, br_ssl_client_init_full, -+ dnl libbearssl found, set the variable -+ [ -+ AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) -+ AC_SUBST(USE_BEARSSL, [1]) -+ BEARSSL_ENABLED=1 -+ USE_BEARSSL="yes" -+ ssl_msg="BearSSL" -+ test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes -+ ], [], -lbearssl) -+ fi -+ -+ addld="" -+ addlib="" -+ addcflags="" -+ bearssllib="" -+ -+ if test "x$USE_BEARSSL" != "xyes"; then -+ dnl add the path and test again -+ addld=-L$OPT_BEARSSL/lib$libsuff -+ addcflags=-I$OPT_BEARSSL/include -+ bearssllib=$OPT_BEARSSL/lib$libsuff -+ -+ LDFLAGS="$LDFLAGS $addld" -+ if test "$addcflags" != "-I/usr/include"; then -+ CPPFLAGS="$CPPFLAGS $addcflags" -+ fi -+ -+ AC_CHECK_LIB(bearssl, br_ssl_client_init_full, -+ [ -+ AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) -+ AC_SUBST(USE_BEARSSL, [1]) -+ BEARSSL_ENABLED=1 -+ USE_BEARSSL="yes" -+ ssl_msg="BearSSL" -+ test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes -+ ], -+ [ -+ CPPFLAGS=$_cppflags -+ LDFLAGS=$_ldflags -+ ], -lbearssl) -+ fi -+ -+ if test "x$USE_BEARSSL" = "xyes"; then -+ AC_MSG_NOTICE([detected BearSSL]) -+ check_for_ca_bundle=1 -+ -+ LIBS="-lbearssl $LIBS" -+ -+ if test -n "$bearssllib"; then -+ dnl when shared libs were found in a path that the run-time -+ dnl linker doesn't search through, we need to add it to -+ dnl CURL_LIBRARY_PATH to prevent further configure tests to fail -+ dnl due to this -+ if test "x$cross_compiling" != "xyes"; then -+ CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$bearssllib" -+ export CURL_LIBRARY_PATH -+ AC_MSG_NOTICE([Added $bearssllib to CURL_LIBRARY_PATH]) -+ fi -+ fi -+ fi -+ -+ fi dnl BearSSL not disabled -+ -+ test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" -+fi -+ - dnl ---------------------------------------------------- - dnl NSS. Only check if GnuTLS and OpenSSL are not enabled - dnl ---------------------------------------------------- -@@ -2529,10 +2621,10 @@ if test -z "$ssl_backends" -o "x$OPT_NSS" != xno; then - test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" - fi - --case "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$WINSSL_ENABLED$SECURETRANSPORT_ENABLED$MESALINK_ENABLED$AMISSL_ENABLED" in -+case "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$WINSSL_ENABLED$SECURETRANSPORT_ENABLED$MESALINK_ENABLED$BEARSSL_ENABLED$AMISSL_ENABLED" in - x) - AC_MSG_WARN([SSL disabled, you will not be able to use HTTPS, FTPS, NTLM and more.]) -- AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-nss, --with-schannel, --with-secure-transport, --with-mesalink or --with-amissl to address this.]) -+ AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-nss, --with-schannel, --with-secure-transport, --with-mesalink, --with-amissl or --with-bearssl to address this.]) - ;; - x1) - # one SSL backend is enabled -diff --git a/docs/FAQ b/docs/FAQ -index 4136b9170..53f1c9e7a 100644 ---- a/docs/FAQ -+++ b/docs/FAQ -@@ -447,9 +447,9 @@ FAQ - - curl can be built to use one of the following SSL alternatives: OpenSSL, - libressl, BoringSSL, GnuTLS, wolfSSL, NSS, mbedTLS, MesaLink, Secure -- Transport (native iOS/OS X), Schannel (native Windows) or GSKit (native IBM -- i). They all have their pros and cons, and we try to maintain a comparison -- of them here: https://curl.haxx.se/docs/ssl-compared.html -+ Transport (native iOS/OS X), Schannel (native Windows), GSKit (native IBM -+ i), or BearSSL. They all have their pros and cons, and we try to maintain a -+ comparison of them here: https://curl.haxx.se/docs/ssl-compared.html - - 2.3 Where can I find a copy of LIBEAY32.DLL? - -diff --git a/docs/INSTALL.md b/docs/INSTALL.md -index 78d632c70..de1e3b7c8 100644 ---- a/docs/INSTALL.md -+++ b/docs/INSTALL.md -@@ -120,6 +120,7 @@ libressl. - - schannel: `--without-ssl --with-schannel` - - secure transport: `--without-ssl --with-secure-transport` - - MesaLink: `--without-ssl --with-mesalink` -+ - BearSSL: `--without-ssl --with-bearssl` - - # Windows - -diff --git a/docs/LICENSE-MIXING.md b/docs/LICENSE-MIXING.md -index e4f6759e4..1083a2dcd 100644 ---- a/docs/LICENSE-MIXING.md -+++ b/docs/LICENSE-MIXING.md -@@ -75,6 +75,11 @@ not have the announcement clause that collides with GPL. - (May be used for SSL/TLS support) As an OpenSSL fork, it has the same - license as that. - -+## BearSSL -+ -+ (May be used for SSL/TLS support) Uses an MIT license that is very liberal -+ and imposes no restrictions on any other library or part you may link with. -+ - ## c-ares - - (Used for asynchronous name resolves) Uses an MIT license that is very -diff --git a/docs/libcurl/curl_global_sslset.3 b/docs/libcurl/curl_global_sslset.3 -index 22d95065d..b3a6967c6 100644 ---- a/docs/libcurl/curl_global_sslset.3 -+++ b/docs/libcurl/curl_global_sslset.3 -@@ -43,7 +43,8 @@ typedef enum { - CURLSSLBACKEND_DARWINSSL = 9, - CURLSSLBACKEND_AXTLS = 10, /* deprecated */ - CURLSSLBACKEND_MBEDTLS = 11, -- CURLSSLBACKEND_MESALINK = 12 -+ CURLSSLBACKEND_MESALINK = 12, -+ CURLSSLBACKEND_BEARSSL = 13 - } curl_sslbackend; - - .B "CURLsslset curl_global_sslset(curl_sslbackend " id, -diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions -index bf23b4488..b68d30556 100644 ---- a/docs/libcurl/symbols-in-versions -+++ b/docs/libcurl/symbols-in-versions -@@ -718,6 +718,7 @@ CURLSSH_AUTH_NONE 7.16.1 - CURLSSH_AUTH_PASSWORD 7.16.1 - CURLSSH_AUTH_PUBLICKEY 7.16.1 - CURLSSLBACKEND_AXTLS 7.38.0 7.61.0 -+CURLSSLBACKEND_BEARSSL 7.68.0 - CURLSSLBACKEND_BORINGSSL 7.49.0 - CURLSSLBACKEND_CYASSL 7.34.0 - CURLSSLBACKEND_DARWINSSL 7.34.0 7.64.1 -diff --git a/include/curl/curl.h b/include/curl/curl.h -index dcbe8995c..d4ba6441b 100644 ---- a/include/curl/curl.h -+++ b/include/curl/curl.h -@@ -154,7 +154,8 @@ typedef enum { - CURLSSLBACKEND_SECURETRANSPORT = 9, - CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ - CURLSSLBACKEND_MBEDTLS = 11, -- CURLSSLBACKEND_MESALINK = 12 -+ CURLSSLBACKEND_MESALINK = 12, -+ CURLSSLBACKEND_BEARSSL = 13 - } curl_sslbackend; - - /* aliases for library clones and renames */ -diff --git a/lib/Makefile.inc b/lib/Makefile.inc -index 72ef428ee..c58d72e87 100644 ---- a/lib/Makefile.inc -+++ b/lib/Makefile.inc -@@ -30,12 +30,13 @@ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h - LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/polarssl.c vtls/polarssl_threadlock.c \ - vtls/wolfssl.c vtls/schannel.c vtls/schannel_verify.c \ -- vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c -+ vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c \ -+ vtls/bearssl.c - - LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ - vtls/wolfssl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \ -- vtls/mbedtls.h vtls/mesalink.h -+ vtls/mbedtls.h vtls/mesalink.h vtls/bearssl.h - - LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c - -diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake -index e0793a7ee..60837d4f4 100644 ---- a/lib/curl_config.h.cmake -+++ b/lib/curl_config.h.cmake -@@ -948,6 +948,9 @@ ${SIZEOF_TIME_T_CODE} - /* if mbedTLS is enabled */ - #cmakedefine USE_MBEDTLS 1 - -+/* if BearSSL is enabled */ -+#cmakedefine USE_BEARSSL 1 -+ - /* if libSSH2 is in use */ - #cmakedefine USE_LIBSSH2 1 - -diff --git a/lib/curl_setup.h b/lib/curl_setup.h -index 13af8cdec..b4ba92931 100644 ---- a/lib/curl_setup.h -+++ b/lib/curl_setup.h -@@ -644,7 +644,8 @@ int netware_init(void); - #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ - defined(USE_MBEDTLS) || \ - defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ -- defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) -+ defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \ -+ defined(USE_BEARSSL) - #define USE_SSL /* SSL support has been enabled */ - #endif - -diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c -new file mode 100644 -index 000000000..14ba2fa44 ---- /dev/null -+++ b/lib/vtls/bearssl.c -@@ -0,0 +1,870 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> -+ * -+ * This software is licensed as described in the file COPYING, which -+ * you should have received as part of this distribution. The terms -+ * are also available at https://curl.haxx.se/docs/copyright.html. -+ * -+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell -+ * copies of the Software, and permit persons to whom the Software is -+ * furnished to do so, under the terms of the COPYING file. -+ * -+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -+ * KIND, either express or implied. -+ * -+ ***************************************************************************/ -+#include "curl_setup.h" -+ -+#ifdef USE_BEARSSL -+ -+#include <bearssl.h> -+ -+#include "bearssl.h" -+#include "urldata.h" -+#include "sendf.h" -+#include "inet_pton.h" -+#include "vtls.h" -+#include "connect.h" -+#include "select.h" -+#include "multiif.h" -+#include "curl_printf.h" -+#include "curl_memory.h" -+ -+struct x509_context { -+ const br_x509_class *vtable; -+ br_x509_minimal_context minimal; -+ bool verifyhost; -+ bool verifypeer; -+}; -+ -+struct ssl_backend_data { -+ br_ssl_client_context ctx; -+ struct x509_context x509; -+ unsigned char buf[BR_SSL_BUFSIZE_BIDI]; -+ br_x509_trust_anchor *anchors; -+ size_t anchors_len; -+ const char *protocols[2]; -+}; -+ -+#define BACKEND connssl->backend -+ -+struct cafile_parser { -+ CURLcode err; -+ bool in_cert; -+ br_x509_decoder_context xc; -+ /* array of trust anchors loaded from CAfile */ -+ br_x509_trust_anchor *anchors; -+ size_t anchors_len; -+ /* buffer for DN data */ -+ unsigned char dn[1024]; -+ size_t dn_len; -+}; -+ -+static void append_dn(void *ctx, const void *buf, size_t len) -+{ -+ struct cafile_parser *ca = ctx; -+ -+ if(ca->err != CURLE_OK || !ca->in_cert) -+ return; -+ if(sizeof(ca->dn) - ca->dn_len < len) { -+ ca->err = CURLE_FAILED_INIT; -+ return; -+ } -+ memcpy(ca->dn + ca->dn_len, buf, len); -+ ca->dn_len += len; -+} -+ -+static void x509_push(void *ctx, const void *buf, size_t len) -+{ -+ struct cafile_parser *ca = ctx; -+ -+ if(ca->in_cert) -+ br_x509_decoder_push(&ca->xc, buf, len); -+} -+ -+static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, -+ size_t *anchors_len) -+{ -+ struct cafile_parser ca; -+ br_pem_decoder_context pc; -+ br_x509_trust_anchor *ta; -+ size_t ta_size; -+ br_x509_trust_anchor *new_anchors; -+ size_t new_anchors_len; -+ br_x509_pkey *pkey; -+ FILE *fp; -+ unsigned char buf[BUFSIZ], *p; -+ const char *name; -+ size_t n, i, pushed; -+ -+ fp = fopen(path, "rb"); -+ if(!fp) -+ return CURLE_SSL_CACERT_BADFILE; -+ -+ ca.err = CURLE_OK; -+ ca.in_cert = FALSE; -+ ca.anchors = NULL; -+ ca.anchors_len = 0; -+ br_pem_decoder_init(&pc); -+ br_pem_decoder_setdest(&pc, x509_push, &ca); -+ for(;;) { -+ n = fread(buf, 1, sizeof(buf), fp); -+ if(n == 0) -+ break; -+ p = buf; -+ while(n) { -+ pushed = br_pem_decoder_push(&pc, p, n); -+ if(ca.err) -+ goto fail; -+ p += pushed; -+ n -= pushed; -+ -+ switch(br_pem_decoder_event(&pc)) { -+ case 0: -+ break; -+ case BR_PEM_BEGIN_OBJ: -+ name = br_pem_decoder_name(&pc); -+ if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE")) -+ break; -+ br_x509_decoder_init(&ca.xc, append_dn, &ca); -+ if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) { -+ ca.err = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ new_anchors_len = ca.anchors_len + 1; -+ new_anchors = realloc(ca.anchors, -+ new_anchors_len * sizeof(ca.anchors[0])); -+ if(!new_anchors) { -+ ca.err = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ ca.anchors = new_anchors; -+ ca.anchors_len = new_anchors_len; -+ ca.in_cert = TRUE; -+ ca.dn_len = 0; -+ ta = &ca.anchors[ca.anchors_len - 1]; -+ ta->dn.data = NULL; -+ break; -+ case BR_PEM_END_OBJ: -+ if(!ca.in_cert) -+ break; -+ ca.in_cert = FALSE; -+ if(br_x509_decoder_last_error(&ca.xc)) { -+ ca.err = CURLE_SSL_CACERT_BADFILE; -+ goto fail; -+ } -+ ta->flags = 0; -+ if(br_x509_decoder_isCA(&ca.xc)) -+ ta->flags |= BR_X509_TA_CA; -+ pkey = br_x509_decoder_get_pkey(&ca.xc); -+ if(!pkey) { -+ ca.err = CURLE_SSL_CACERT_BADFILE; -+ goto fail; -+ } -+ ta->pkey = *pkey; -+ -+ /* calculate space needed for trust anchor data */ -+ ta_size = ca.dn_len; -+ switch(pkey->key_type) { -+ case BR_KEYTYPE_RSA: -+ ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen; -+ break; -+ case BR_KEYTYPE_EC: -+ ta_size += pkey->key.ec.qlen; -+ break; -+ default: -+ ca.err = CURLE_FAILED_INIT; -+ goto fail; -+ } -+ -+ /* fill in trust anchor DN and public key data */ -+ ta->dn.data = malloc(ta_size); -+ if(!ta->dn.data) { -+ ca.err = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ memcpy(ta->dn.data, ca.dn, ca.dn_len); -+ ta->dn.len = ca.dn_len; -+ switch(pkey->key_type) { -+ case BR_KEYTYPE_RSA: -+ ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len; -+ memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen); -+ ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen; -+ memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen); -+ break; -+ case BR_KEYTYPE_EC: -+ ta->pkey.key.ec.q = ta->dn.data + ta->dn.len; -+ memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen); -+ break; -+ } -+ break; -+ default: -+ ca.err = CURLE_SSL_CACERT_BADFILE; -+ goto fail; -+ } -+ } -+ } -+ if(ferror(fp)) -+ ca.err = CURLE_READ_ERROR; -+ -+fail: -+ fclose(fp); -+ if(ca.err == CURLE_OK) { -+ *anchors = ca.anchors; -+ *anchors_len = ca.anchors_len; -+ } -+ else { -+ for(i = 0; i < ca.anchors_len; ++i) -+ free(ca.anchors[i].dn.data); -+ free(ca.anchors); -+ } -+ -+ return ca.err; -+} -+ -+static void x509_start_chain(const br_x509_class **ctx, -+ const char *server_name) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ -+ if(!x509->verifyhost) -+ server_name = NULL; -+ x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name); -+} -+ -+static void x509_start_cert(const br_x509_class **ctx, uint32_t length) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ -+ x509->minimal.vtable->start_cert(&x509->minimal.vtable, length); -+} -+ -+static void x509_append(const br_x509_class **ctx, const unsigned char *buf, -+ size_t len) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ -+ x509->minimal.vtable->append(&x509->minimal.vtable, buf, len); -+} -+ -+static void x509_end_cert(const br_x509_class **ctx) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ -+ x509->minimal.vtable->end_cert(&x509->minimal.vtable); -+} -+ -+static unsigned x509_end_chain(const br_x509_class **ctx) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ unsigned err; -+ -+ err = x509->minimal.vtable->end_chain(&x509->minimal.vtable); -+ if(err && !x509->verifypeer) { -+ /* ignore any X.509 errors */ -+ err = BR_ERR_OK; -+ } -+ -+ return err; -+} -+ -+static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx, -+ unsigned *usages) -+{ -+ struct x509_context *x509 = (struct x509_context *)ctx; -+ -+ return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages); -+} -+ -+static const br_x509_class x509_vtable = { -+ sizeof(struct x509_context), -+ x509_start_chain, -+ x509_start_cert, -+ x509_append, -+ x509_end_cert, -+ x509_end_chain, -+ x509_get_pkey -+}; -+ -+static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) -+{ -+ struct Curl_easy *data = conn->data; -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); -+ const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : -+ conn->host.name; -+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer); -+ const bool verifyhost = SSL_CONN_CONFIG(verifyhost); -+ CURLcode ret; -+ unsigned version_min, version_max; -+#ifdef ENABLE_IPV6 -+ struct in6_addr addr; -+#else -+ struct in_addr addr; -+#endif -+ -+ switch(SSL_CONN_CONFIG(version)) { -+ case CURL_SSLVERSION_SSLv2: -+ failf(data, "BearSSL does not support SSLv2"); -+ return CURLE_SSL_CONNECT_ERROR; -+ case CURL_SSLVERSION_SSLv3: -+ failf(data, "BearSSL does not support SSLv3"); -+ return CURLE_SSL_CONNECT_ERROR; -+ case CURL_SSLVERSION_TLSv1_0: -+ version_min = BR_TLS10; -+ version_max = BR_TLS10; -+ break; -+ case CURL_SSLVERSION_TLSv1_1: -+ version_min = BR_TLS11; -+ version_max = BR_TLS11; -+ break; -+ case CURL_SSLVERSION_TLSv1_2: -+ version_min = BR_TLS12; -+ version_max = BR_TLS12; -+ break; -+ case CURL_SSLVERSION_DEFAULT: -+ case CURL_SSLVERSION_TLSv1: -+ version_min = BR_TLS10; -+ version_max = BR_TLS12; -+ break; -+ default: -+ failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); -+ return CURLE_SSL_CONNECT_ERROR; -+ } -+ -+ if(ssl_cafile) { -+ ret = load_cafile(ssl_cafile, &BACKEND->anchors, &BACKEND->anchors_len); -+ if(ret != CURLE_OK) { -+ if(verifypeer) { -+ failf(data, "error setting certificate verify locations:\n" -+ " CAfile: %s\n", ssl_cafile); -+ return ret; -+ } -+ infof(data, "error setting certificate verify locations," -+ " continuing anyway:\n"); -+ } -+ } -+ -+ /* initialize SSL context */ -+ br_ssl_client_init_full(&BACKEND->ctx, &BACKEND->x509.minimal, -+ BACKEND->anchors, BACKEND->anchors_len); -+ br_ssl_engine_set_versions(&BACKEND->ctx.eng, version_min, version_max); -+ br_ssl_engine_set_buffer(&BACKEND->ctx.eng, BACKEND->buf, -+ sizeof(BACKEND->buf), 1); -+ -+ /* initialize X.509 context */ -+ BACKEND->x509.vtable = &x509_vtable; -+ BACKEND->x509.verifypeer = verifypeer; -+ BACKEND->x509.verifyhost = verifyhost; -+ br_ssl_engine_set_x509(&BACKEND->ctx.eng, &BACKEND->x509.vtable); -+ -+ if(SSL_SET_OPTION(primary.sessionid)) { -+ void *session; -+ -+ Curl_ssl_sessionid_lock(conn); -+ if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { -+ br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); -+ infof(data, "BearSSL: re-using session ID\n"); -+ } -+ Curl_ssl_sessionid_unlock(conn); -+ } -+ -+ if(conn->bits.tls_enable_alpn) { -+ int cur = 0; -+ -+ /* NOTE: when adding more protocols here, increase the size of the -+ * protocols array in `struct ssl_backend_data`. -+ */ -+ -+#ifdef USE_NGHTTP2 -+ if(data->set.httpversion >= CURL_HTTP_VERSION_2 && -+ (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { -+ BACKEND->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; -+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); -+ } -+#endif -+ -+ BACKEND->protocols[cur++] = ALPN_HTTP_1_1; -+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); -+ -+ br_ssl_engine_set_protocol_names(&BACKEND->ctx.eng, -+ BACKEND->protocols, cur); -+ } -+ -+ if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) -+#ifdef ENABLE_IPV6 -+ || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) -+#endif -+ ) { -+ if(verifyhost) { -+ failf(data, "BearSSL: " -+ "host verification of IP address is not supported"); -+ return CURLE_PEER_FAILED_VERIFICATION; -+ } -+ hostname = NULL; -+ } -+ -+ br_ssl_client_reset(&BACKEND->ctx, hostname, 0); -+ -+ connssl->connecting_state = ssl_connect_2; -+ -+ return CURLE_OK; -+} -+ -+static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) -+{ -+ struct Curl_easy *data = conn->data; -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ curl_socket_t sockfd = conn->sock[sockindex]; -+ unsigned state; -+ unsigned char *buf; -+ size_t len; -+ ssize_t ret; -+ int err; -+ -+ for(;;) { -+ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); -+ if(state & BR_SSL_CLOSED) { -+ err = br_ssl_engine_last_error(&BACKEND->ctx.eng); -+ switch(err) { -+ case BR_ERR_X509_EXPIRED: -+ failf(data, "SSL: X.509 verification: " -+ "certificate is expired or not yet valid"); -+ return CURLE_PEER_FAILED_VERIFICATION; -+ case BR_ERR_X509_BAD_SERVER_NAME: -+ failf(data, "SSL: X.509 verification: " -+ "expected server name was not found in the chain"); -+ return CURLE_PEER_FAILED_VERIFICATION; -+ case BR_ERR_X509_NOT_TRUSTED: -+ failf(data, "SSL: X.509 verification: " -+ "chain could not be linked to a trust anchor"); -+ return CURLE_PEER_FAILED_VERIFICATION; -+ } -+ /* X.509 errors are documented to have the range 32..63 */ -+ if(err >= 32 && err < 64) -+ return CURLE_PEER_FAILED_VERIFICATION; -+ return CURLE_SSL_CONNECT_ERROR; -+ } -+ if(state & (BR_SSL_SENDAPP | BR_SSL_RECVAPP)) { -+ connssl->connecting_state = ssl_connect_3; -+ return CURLE_OK; -+ } -+ if(state & BR_SSL_SENDREC) { -+ buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); -+ ret = swrite(sockfd, buf, len); -+ if(ret == -1) { -+ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { -+ connssl->connecting_state = ssl_connect_2_writing; -+ return CURLE_OK; -+ } -+ return CURLE_SEND_ERROR; -+ } -+ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); -+ } -+ else if(state & BR_SSL_RECVREC) { -+ buf = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &len); -+ ret = sread(sockfd, buf, len); -+ if(ret == -1) { -+ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { -+ connssl->connecting_state = ssl_connect_2_reading; -+ return CURLE_OK; -+ } -+ return CURLE_READ_ERROR; -+ } -+ if(ret == 0) -+ return CURLE_SSL_CONNECT_ERROR; -+ br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); -+ } -+ } -+} -+ -+static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) -+{ -+ struct Curl_easy *data = conn->data; -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ CURLcode ret; -+ -+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); -+ -+ if(conn->bits.tls_enable_alpn) { -+ const char *protocol; -+ -+ protocol = br_ssl_engine_get_selected_protocol(&BACKEND->ctx.eng); -+ if(protocol) { -+ infof(data, "ALPN, server accepted to use %s\n", protocol); -+ -+#ifdef USE_NGHTTP2 -+ if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID)) -+ conn->negnpn = CURL_HTTP_VERSION_2; -+ else -+#endif -+ if(!strcmp(protocol, ALPN_HTTP_1_1)) -+ conn->negnpn = CURL_HTTP_VERSION_1_1; -+ else -+ infof(data, "ALPN, unrecognized protocol %s\n", protocol); -+ Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? -+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); -+ } -+ else -+ infof(data, "ALPN, server did not agree to a protocol\n"); -+ } -+ -+ if(SSL_SET_OPTION(primary.sessionid)) { -+ bool incache; -+ void *oldsession; -+ br_ssl_session_parameters *session; -+ -+ session = malloc(sizeof(*session)); -+ if(!session) -+ return CURLE_OUT_OF_MEMORY; -+ br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); -+ Curl_ssl_sessionid_lock(conn); -+ incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); -+ if(incache) -+ Curl_ssl_delsessionid(conn, oldsession); -+ ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); -+ Curl_ssl_sessionid_unlock(conn); -+ if(ret) { -+ free(session); -+ return CURLE_OUT_OF_MEMORY; -+ } -+ } -+ -+ connssl->connecting_state = ssl_connect_done; -+ -+ return CURLE_OK; -+} -+ -+static ssize_t bearssl_send(struct connectdata *conn, int sockindex, -+ const void *buf, size_t len, CURLcode *err) -+{ -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ unsigned state; -+ unsigned char *rec, *app; -+ size_t reclen, applen; -+ ssize_t ret; -+ -+ applen = 0; -+ for(;;) { -+ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); -+ if(state & BR_SSL_SENDREC) { -+ rec = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &reclen); -+ ret = swrite(conn->sock[sockindex], rec, reclen); -+ if(ret == -1) { -+ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) -+ *err = CURLE_AGAIN; -+ else -+ *err = CURLE_SEND_ERROR; -+ return -1; -+ } -+ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); -+ } -+ else if(state & BR_SSL_SENDAPP && applen == 0) { -+ app = br_ssl_engine_sendapp_buf(&BACKEND->ctx.eng, &applen); -+ if(applen > len) -+ applen = len; -+ memcpy(app, buf, applen); -+ br_ssl_engine_sendapp_ack(&BACKEND->ctx.eng, applen); -+ br_ssl_engine_flush(&BACKEND->ctx.eng, 0); -+ } -+ else if(state & BR_SSL_CLOSED || applen == 0) { -+ *err = CURLE_SEND_ERROR; -+ return -1; -+ } -+ else -+ break; -+ } -+ -+ return applen; -+} -+ -+static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, -+ char *buf, size_t len, CURLcode *err) -+{ -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ unsigned state; -+ unsigned char *rec, *app; -+ size_t reclen, applen; -+ ssize_t ret; -+ -+ for(;;) { -+ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); -+ if(state & BR_SSL_RECVREC) { -+ rec = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &reclen); -+ ret = sread(conn->sock[sockindex], rec, reclen); -+ if(ret == -1 && (SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)) { -+ *err = CURLE_AGAIN; -+ return -1; -+ } -+ if(ret <= 0) { -+ *err = CURLE_RECV_ERROR; -+ return -1; -+ } -+ br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); -+ } -+ else if(state & BR_SSL_RECVAPP) { -+ app = br_ssl_engine_recvapp_buf(&BACKEND->ctx.eng, &applen); -+ if(applen > len) -+ applen = len; -+ memcpy(buf, app, applen); -+ br_ssl_engine_recvapp_ack(&BACKEND->ctx.eng, applen); -+ break; -+ } -+ else { -+ *err = CURLE_RECV_ERROR; -+ return -1; -+ } -+ } -+ -+ return applen; -+} -+ -+static CURLcode bearssl_connect_common(struct connectdata *conn, -+ int sockindex, -+ bool nonblocking, -+ bool *done) -+{ -+ CURLcode ret; -+ struct Curl_easy *data = conn->data; -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ curl_socket_t sockfd = conn->sock[sockindex]; -+ time_t timeout_ms; -+ int what; -+ -+ /* check if the connection has already been established */ -+ if(ssl_connection_complete == connssl->state) { -+ *done = TRUE; -+ return CURLE_OK; -+ } -+ -+ if(ssl_connect_1 == connssl->connecting_state) { -+ ret = bearssl_connect_step1(conn, sockindex); -+ if(ret) -+ return ret; -+ } -+ -+ while(ssl_connect_2 == connssl->connecting_state || -+ ssl_connect_2_reading == connssl->connecting_state || -+ ssl_connect_2_writing == connssl->connecting_state) { -+ /* check allowed time left */ -+ timeout_ms = Curl_timeleft(data, NULL, TRUE); -+ -+ if(timeout_ms < 0) { -+ /* no need to continue if time already is up */ -+ failf(data, "SSL connection timeout"); -+ return CURLE_OPERATION_TIMEDOUT; -+ } -+ -+ /* if ssl is expecting something, check if it's available. */ -+ if(ssl_connect_2_reading == connssl->connecting_state || -+ ssl_connect_2_writing == connssl->connecting_state) { -+ -+ curl_socket_t writefd = ssl_connect_2_writing == -+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD; -+ curl_socket_t readfd = ssl_connect_2_reading == -+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD; -+ -+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, -+ nonblocking?0:timeout_ms); -+ if(what < 0) { -+ /* fatal error */ -+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); -+ return CURLE_SSL_CONNECT_ERROR; -+ } -+ else if(0 == what) { -+ if(nonblocking) { -+ *done = FALSE; -+ return CURLE_OK; -+ } -+ else { -+ /* timeout */ -+ failf(data, "SSL connection timeout"); -+ return CURLE_OPERATION_TIMEDOUT; -+ } -+ } -+ /* socket is readable or writable */ -+ } -+ -+ /* Run transaction, and return to the caller if it failed or if this -+ * connection is done nonblocking and this loop would execute again. This -+ * permits the owner of a multi handle to abort a connection attempt -+ * before step2 has completed while ensuring that a client using select() -+ * or epoll() will always have a valid fdset to wait on. -+ */ -+ ret = bearssl_connect_step2(conn, sockindex); -+ if(ret || (nonblocking && -+ (ssl_connect_2 == connssl->connecting_state || -+ ssl_connect_2_reading == connssl->connecting_state || -+ ssl_connect_2_writing == connssl->connecting_state))) -+ return ret; -+ } -+ -+ if(ssl_connect_3 == connssl->connecting_state) { -+ ret = bearssl_connect_step3(conn, sockindex); -+ if(ret) -+ return ret; -+ } -+ -+ if(ssl_connect_done == connssl->connecting_state) { -+ connssl->state = ssl_connection_complete; -+ conn->recv[sockindex] = bearssl_recv; -+ conn->send[sockindex] = bearssl_send; -+ *done = TRUE; -+ } -+ else -+ *done = FALSE; -+ -+ /* Reset our connect state machine */ -+ connssl->connecting_state = ssl_connect_1; -+ -+ return CURLE_OK; -+} -+ -+static size_t Curl_bearssl_version(char *buffer, size_t size) -+{ -+ return msnprintf(buffer, size, "BearSSL"); -+} -+ -+static bool Curl_bearssl_data_pending(const struct connectdata *conn, -+ int connindex) -+{ -+ const struct ssl_connect_data *connssl = &conn->ssl[connindex]; -+ -+ return br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_RECVAPP; -+} -+ -+static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, -+ unsigned char *entropy, size_t length) -+{ -+ static br_hmac_drbg_context ctx; -+ static bool seeded = FALSE; -+ -+ if(!seeded) { -+ br_prng_seeder seeder; -+ -+ br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); -+ seeder = br_prng_seeder_system(NULL); -+ if(!seeder || !seeder(&ctx.vtable)) -+ return CURLE_FAILED_INIT; -+ seeded = TRUE; -+ } -+ br_hmac_drbg_generate(&ctx, entropy, length); -+ -+ return CURLE_OK; -+} -+ -+static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex) -+{ -+ CURLcode ret; -+ bool done = FALSE; -+ -+ ret = bearssl_connect_common(conn, sockindex, FALSE, &done); -+ if(ret) -+ return ret; -+ -+ DEBUGASSERT(done); -+ -+ return CURLE_OK; -+} -+ -+static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, -+ int sockindex, bool *done) -+{ -+ return bearssl_connect_common(conn, sockindex, TRUE, done); -+} -+ -+static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, -+ CURLINFO info UNUSED_PARAM) -+{ -+ return &BACKEND->ctx; -+} -+ -+static void Curl_bearssl_close(struct connectdata *conn, int sockindex) -+{ -+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; -+ unsigned char *buf; -+ size_t len, i; -+ ssize_t ret; -+ -+ if(connssl->connecting_state == ssl_connect_done) { -+ br_ssl_engine_close(&BACKEND->ctx.eng); -+ while(br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_SENDREC) { -+ buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); -+ ret = swrite(conn->sock[sockindex], buf, len); -+ if(ret < 0) -+ break; -+ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); -+ } -+ for(i = 0; i < BACKEND->anchors_len; ++i) -+ free(BACKEND->anchors[i].dn.data); -+ free(BACKEND->anchors); -+ } -+} -+ -+static void Curl_bearssl_session_free(void *ptr) -+{ -+ free(ptr); -+} -+ -+static CURLcode Curl_bearssl_md5sum(unsigned char *input, -+ size_t inputlen, -+ unsigned char *md5sum, -+ size_t md5len UNUSED_PARAM) -+{ -+ br_md5_context ctx; -+ -+ br_md5_init(&ctx); -+ br_md5_update(&ctx, input, inputlen); -+ br_md5_out(&ctx, md5sum); -+ return CURLE_OK; -+} -+ -+static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, -+ size_t inputlen, -+ unsigned char *sha256sum, -+ size_t sha256len UNUSED_PARAM) -+{ -+ br_sha256_context ctx; -+ -+ br_sha256_init(&ctx); -+ br_sha256_update(&ctx, input, inputlen); -+ br_sha256_out(&ctx, sha256sum); -+ return CURLE_OK; -+} -+ -+const struct Curl_ssl Curl_ssl_bearssl = { -+ { CURLSSLBACKEND_BEARSSL, "bearssl" }, -+ -+ 0, -+ -+ sizeof(struct ssl_backend_data), -+ -+ Curl_none_init, -+ Curl_none_cleanup, -+ Curl_bearssl_version, -+ Curl_none_check_cxn, -+ Curl_none_shutdown, -+ Curl_bearssl_data_pending, -+ Curl_bearssl_random, -+ Curl_none_cert_status_request, -+ Curl_bearssl_connect, -+ Curl_bearssl_connect_nonblocking, -+ Curl_bearssl_get_internals, -+ Curl_bearssl_close, -+ Curl_none_close_all, -+ Curl_bearssl_session_free, -+ Curl_none_set_engine, -+ Curl_none_set_engine_default, -+ Curl_none_engines_list, -+ Curl_none_false_start, -+ Curl_bearssl_md5sum, -+ Curl_bearssl_sha256sum -+}; -+ -+#endif /* USE_BEARSSL */ -diff --git a/lib/vtls/bearssl.h b/lib/vtls/bearssl.h -new file mode 100644 -index 000000000..5f94922b9 ---- /dev/null -+++ b/lib/vtls/bearssl.h -@@ -0,0 +1,32 @@ -+#ifndef HEADER_CURL_BEARSSL_H -+#define HEADER_CURL_BEARSSL_H -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> -+ * -+ * This software is licensed as described in the file COPYING, which -+ * you should have received as part of this distribution. The terms -+ * are also available at https://curl.haxx.se/docs/copyright.html. -+ * -+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell -+ * copies of the Software, and permit persons to whom the Software is -+ * furnished to do so, under the terms of the COPYING file. -+ * -+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -+ * KIND, either express or implied. -+ * -+ ***************************************************************************/ -+ -+#include "curl_setup.h" -+ -+#ifdef USE_BEARSSL -+ -+extern const struct Curl_ssl Curl_ssl_bearssl; -+ -+#endif /* USE_BEARSSL */ -+#endif /* HEADER_CURL_BEARSSL_H */ -diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c -index e6d756225..894fd8a43 100644 ---- a/lib/vtls/vtls.c -+++ b/lib/vtls/vtls.c -@@ -517,7 +517,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) - - #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_SECTRANSP) || defined(USE_POLARSSL) || defined(USE_NSS) || \ -- defined(USE_MBEDTLS) || defined(USE_WOLFSSL) -+ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL) - int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks) - { - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; -@@ -1189,6 +1189,8 @@ const struct Curl_ssl *Curl_ssl = - &Curl_ssl_schannel; - #elif defined(USE_MESALINK) - &Curl_ssl_mesalink; -+#elif defined(USE_BEARSSL) -+ &Curl_ssl_bearssl; - #else - #error "Missing struct Curl_ssl for selected SSL backend" - #endif -diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h -index 61d8416c2..976cc4360 100644 ---- a/lib/vtls/vtls.h -+++ b/lib/vtls/vtls.h -@@ -108,6 +108,7 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, - #include "sectransp.h" /* SecureTransport (Darwin) version */ - #include "mbedtls.h" /* mbedTLS versions */ - #include "mesalink.h" /* MesaLink versions */ -+#include "bearssl.h" /* BearSSL versions */ - - #ifndef MAX_PINNED_PUBKEY_SIZE - #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ --- -2.24.0 - diff --git a/pkg/curl/patch/0001-TLS-add-BearSSL-vtls-implementation.patch b/pkg/curl/patch/0001-TLS-add-BearSSL-vtls-implementation.patch @@ -0,0 +1,1316 @@ +From cb6d971e3a913c93edcdebbfdf7840c200175c31 Mon Sep 17 00:00:00 2001 +From: Michael Forney <mforney@mforney.org> +Date: Thu, 7 Nov 2019 20:17:18 -0800 +Subject: [PATCH] TLS: add BearSSL vtls implementation +Upstream: 9b879160df01e7ddbb4770904391d3b74114302b + +Closes #4597 +--- + CMake/FindBearSSL.cmake | 9 + + CMakeLists.txt | 11 + + Makefile.am | 4 +- + configure.ac | 98 +++- + docs/FAQ | 6 +- + docs/INSTALL.md | 1 + + docs/LICENSE-MIXING.md | 5 + + docs/libcurl/curl_global_sslset.3 | 3 +- + docs/libcurl/symbols-in-versions | 1 + + include/curl/curl.h | 3 +- + lib/Makefile.inc | 5 +- + lib/curl_config.h.cmake | 3 + + lib/curl_setup.h | 3 +- + lib/vtls/bearssl.c | 874 ++++++++++++++++++++++++++++++ + lib/vtls/bearssl.h | 32 ++ + lib/vtls/vtls.c | 4 +- + lib/vtls/vtls.h | 1 + + 17 files changed, 1049 insertions(+), 14 deletions(-) + create mode 100644 CMake/FindBearSSL.cmake + create mode 100644 lib/vtls/bearssl.c + create mode 100644 lib/vtls/bearssl.h + +diff --git a/CMake/FindBearSSL.cmake b/CMake/FindBearSSL.cmake +new file mode 100644 +index 000000000..20d239a4f +--- /dev/null ++++ b/CMake/FindBearSSL.cmake +@@ -0,0 +1,9 @@ ++find_path(BEARSSL_INCLUDE_DIRS bearssl.h) ++ ++find_library(BEARSSL_LIBRARY bearssl) ++ ++include(FindPackageHandleStandardArgs) ++find_package_handle_standard_args(BEARSSL DEFAULT_MSG ++ BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) ++ ++mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 20b9bd011..a2ad6933b 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -295,6 +295,7 @@ if(WIN32) + CMAKE_USE_WINSSL OFF) + endif() + option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF) ++option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF) + + set(openssl_default ON) + if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS) +@@ -307,6 +308,7 @@ count_true(enabled_ssl_options_count + CMAKE_USE_SECTRANSP + CMAKE_USE_OPENSSL + CMAKE_USE_MBEDTLS ++ CMAKE_USE_BEARSSL + ) + if(enabled_ssl_options_count GREATER "1") + set(CURL_WITH_MULTI_SSL ON) +@@ -379,6 +381,14 @@ if(CMAKE_USE_MBEDTLS) + include_directories(${MBEDTLS_INCLUDE_DIRS}) + endif() + ++if(CMAKE_USE_BEARSSL) ++ find_package(BearSSL REQUIRED) ++ set(SSL_ENABLED ON) ++ set(USE_BEARSSL ON) ++ list(APPEND CURL_LIBS ${BEARSSL_LIBRARY}) ++ include_directories(${BEARSSL_INCLUDE_DIRS}) ++endif() ++ + option(USE_NGHTTP2 "Use Nghttp2 library" OFF) + if(USE_NGHTTP2) + find_package(NGHTTP2 REQUIRED) +@@ -1251,6 +1261,7 @@ _add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) + _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) + _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP) + _add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) ++_add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL) + if(_items) + list(SORT _items) + endif() +diff --git a/Makefile.am b/Makefile.am +index 3116e1053..b98d5ee71 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -30,8 +30,8 @@ CMAKE_DIST = CMakeLists.txt CMake/CMakeConfigurableFile.in \ + CMake/Macros.cmake \ + CMake/CurlSymbolHiding.cmake CMake/FindCARES.cmake \ + CMake/FindLibSSH2.cmake CMake/FindNGHTTP2.cmake \ +- CMake/FindMbedTLS.cmake CMake/cmake_uninstall.cmake.in \ +- CMake/curl-config.cmake.in ++ CMake/FindMbedTLS.cmake CMake/FindBearSSL.cmake \ ++ CMake/cmake_uninstall.cmake.in CMake/curl-config.cmake.in + + VC6_LIBTMPL = projects/Windows/VC6/lib/libcurl.tmpl + VC6_LIBDSP = projects/Windows/VC6/lib/libcurl.dsp.dist +diff --git a/configure.ac b/configure.ac +index cb8f4943e..11fa05803 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -156,7 +156,7 @@ AC_SUBST(PKGADD_VENDOR) + + dnl + dnl initialize all the info variables +- curl_ssl_msg="no (--with-{ssl,gnutls,nss,mbedtls,wolfssl,schannel,secure-transport,mesalink,amissl} )" ++ curl_ssl_msg="no (--with-{ssl,gnutls,nss,mbedtls,wolfssl,schannel,secure-transport,mesalink,amissl,bearssl} )" + curl_ssh_msg="no (--with-libssh2)" + curl_zlib_msg="no (--with-zlib)" + curl_brotli_msg="no (--with-brotli)" +@@ -2399,6 +2399,98 @@ if test -z "$ssl_backends" -o "x$OPT_MESALINK" != xno; then + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" + fi + ++dnl ---------------------------------------------------- ++dnl check for BearSSL ++dnl ---------------------------------------------------- ++ ++OPT_BEARSSL=no ++ ++_cppflags=$CPPFLAGS ++_ldflags=$LDFLAGS ++AC_ARG_WITH(bearssl,dnl ++AC_HELP_STRING([--with-bearssl=PATH],[where to look for BearSSL, PATH points to the installation root]) ++AC_HELP_STRING([--without-bearssl], [disable BearSSL detection]), ++ OPT_BEARSSL=$withval) ++ ++if test -z "$ssl_backends" -o "x$OPT_BEARSSL" != xno; then ++ ssl_msg= ++ ++ if test X"$OPT_BEARSSL" != Xno; then ++ ++ if test "$OPT_BEARSSL" = "yes"; then ++ OPT_BEARSSL="" ++ fi ++ ++ if test -z "$OPT_BEARSSL" ; then ++ dnl check for lib first without setting any new path ++ ++ AC_CHECK_LIB(bearssl, br_ssl_client_init_full, ++ dnl libbearssl found, set the variable ++ [ ++ AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) ++ AC_SUBST(USE_BEARSSL, [1]) ++ BEARSSL_ENABLED=1 ++ USE_BEARSSL="yes" ++ ssl_msg="BearSSL" ++ test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes ++ ], [], -lbearssl) ++ fi ++ ++ addld="" ++ addlib="" ++ addcflags="" ++ bearssllib="" ++ ++ if test "x$USE_BEARSSL" != "xyes"; then ++ dnl add the path and test again ++ addld=-L$OPT_BEARSSL/lib$libsuff ++ addcflags=-I$OPT_BEARSSL/include ++ bearssllib=$OPT_BEARSSL/lib$libsuff ++ ++ LDFLAGS="$LDFLAGS $addld" ++ if test "$addcflags" != "-I/usr/include"; then ++ CPPFLAGS="$CPPFLAGS $addcflags" ++ fi ++ ++ AC_CHECK_LIB(bearssl, br_ssl_client_init_full, ++ [ ++ AC_DEFINE(USE_BEARSSL, 1, [if BearSSL is enabled]) ++ AC_SUBST(USE_BEARSSL, [1]) ++ BEARSSL_ENABLED=1 ++ USE_BEARSSL="yes" ++ ssl_msg="BearSSL" ++ test bearssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes ++ ], ++ [ ++ CPPFLAGS=$_cppflags ++ LDFLAGS=$_ldflags ++ ], -lbearssl) ++ fi ++ ++ if test "x$USE_BEARSSL" = "xyes"; then ++ AC_MSG_NOTICE([detected BearSSL]) ++ check_for_ca_bundle=1 ++ ++ LIBS="-lbearssl $LIBS" ++ ++ if test -n "$bearssllib"; then ++ dnl when shared libs were found in a path that the run-time ++ dnl linker doesn't search through, we need to add it to ++ dnl CURL_LIBRARY_PATH to prevent further configure tests to fail ++ dnl due to this ++ if test "x$cross_compiling" != "xyes"; then ++ CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$bearssllib" ++ export CURL_LIBRARY_PATH ++ AC_MSG_NOTICE([Added $bearssllib to CURL_LIBRARY_PATH]) ++ fi ++ fi ++ fi ++ ++ fi dnl BearSSL not disabled ++ ++ test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" ++fi ++ + dnl ---------------------------------------------------- + dnl NSS. Only check if GnuTLS and OpenSSL are not enabled + dnl ---------------------------------------------------- +@@ -2529,10 +2621,10 @@ if test -z "$ssl_backends" -o "x$OPT_NSS" != xno; then + test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg" + fi + +-case "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$WINSSL_ENABLED$SECURETRANSPORT_ENABLED$MESALINK_ENABLED$AMISSL_ENABLED" in ++case "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$WINSSL_ENABLED$SECURETRANSPORT_ENABLED$MESALINK_ENABLED$BEARSSL_ENABLED$AMISSL_ENABLED" in + x) + AC_MSG_WARN([SSL disabled, you will not be able to use HTTPS, FTPS, NTLM and more.]) +- AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-nss, --with-schannel, --with-secure-transport, --with-mesalink or --with-amissl to address this.]) ++ AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-wolfssl, --with-mbedtls, --with-nss, --with-schannel, --with-secure-transport, --with-mesalink, --with-amissl or --with-bearssl to address this.]) + ;; + x1) + # one SSL backend is enabled +diff --git a/docs/FAQ b/docs/FAQ +index 4136b9170..53f1c9e7a 100644 +--- a/docs/FAQ ++++ b/docs/FAQ +@@ -447,9 +447,9 @@ FAQ + + curl can be built to use one of the following SSL alternatives: OpenSSL, + libressl, BoringSSL, GnuTLS, wolfSSL, NSS, mbedTLS, MesaLink, Secure +- Transport (native iOS/OS X), Schannel (native Windows) or GSKit (native IBM +- i). They all have their pros and cons, and we try to maintain a comparison +- of them here: https://curl.haxx.se/docs/ssl-compared.html ++ Transport (native iOS/OS X), Schannel (native Windows), GSKit (native IBM ++ i), or BearSSL. They all have their pros and cons, and we try to maintain a ++ comparison of them here: https://curl.haxx.se/docs/ssl-compared.html + + 2.3 Where can I find a copy of LIBEAY32.DLL? + +diff --git a/docs/INSTALL.md b/docs/INSTALL.md +index 78d632c70..de1e3b7c8 100644 +--- a/docs/INSTALL.md ++++ b/docs/INSTALL.md +@@ -120,6 +120,7 @@ libressl. + - schannel: `--without-ssl --with-schannel` + - secure transport: `--without-ssl --with-secure-transport` + - MesaLink: `--without-ssl --with-mesalink` ++ - BearSSL: `--without-ssl --with-bearssl` + + # Windows + +diff --git a/docs/LICENSE-MIXING.md b/docs/LICENSE-MIXING.md +index e4f6759e4..1083a2dcd 100644 +--- a/docs/LICENSE-MIXING.md ++++ b/docs/LICENSE-MIXING.md +@@ -75,6 +75,11 @@ not have the announcement clause that collides with GPL. + (May be used for SSL/TLS support) As an OpenSSL fork, it has the same + license as that. + ++## BearSSL ++ ++ (May be used for SSL/TLS support) Uses an MIT license that is very liberal ++ and imposes no restrictions on any other library or part you may link with. ++ + ## c-ares + + (Used for asynchronous name resolves) Uses an MIT license that is very +diff --git a/docs/libcurl/curl_global_sslset.3 b/docs/libcurl/curl_global_sslset.3 +index 22d95065d..b3a6967c6 100644 +--- a/docs/libcurl/curl_global_sslset.3 ++++ b/docs/libcurl/curl_global_sslset.3 +@@ -43,7 +43,8 @@ typedef enum { + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, /* deprecated */ + CURLSSLBACKEND_MBEDTLS = 11, +- CURLSSLBACKEND_MESALINK = 12 ++ CURLSSLBACKEND_MESALINK = 12, ++ CURLSSLBACKEND_BEARSSL = 13 + } curl_sslbackend; + + .B "CURLsslset curl_global_sslset(curl_sslbackend " id, +diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions +index bf23b4488..b68d30556 100644 +--- a/docs/libcurl/symbols-in-versions ++++ b/docs/libcurl/symbols-in-versions +@@ -718,6 +718,7 @@ CURLSSH_AUTH_NONE 7.16.1 + CURLSSH_AUTH_PASSWORD 7.16.1 + CURLSSH_AUTH_PUBLICKEY 7.16.1 + CURLSSLBACKEND_AXTLS 7.38.0 7.61.0 ++CURLSSLBACKEND_BEARSSL 7.68.0 + CURLSSLBACKEND_BORINGSSL 7.49.0 + CURLSSLBACKEND_CYASSL 7.34.0 + CURLSSLBACKEND_DARWINSSL 7.34.0 7.64.1 +diff --git a/include/curl/curl.h b/include/curl/curl.h +index dcbe8995c..d4ba6441b 100644 +--- a/include/curl/curl.h ++++ b/include/curl/curl.h +@@ -154,7 +154,8 @@ typedef enum { + CURLSSLBACKEND_SECURETRANSPORT = 9, + CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ + CURLSSLBACKEND_MBEDTLS = 11, +- CURLSSLBACKEND_MESALINK = 12 ++ CURLSSLBACKEND_MESALINK = 12, ++ CURLSSLBACKEND_BEARSSL = 13 + } curl_sslbackend; + + /* aliases for library clones and renames */ +diff --git a/lib/Makefile.inc b/lib/Makefile.inc +index 72ef428ee..c58d72e87 100644 +--- a/lib/Makefile.inc ++++ b/lib/Makefile.inc +@@ -30,12 +30,13 @@ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h + LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ + vtls/polarssl.c vtls/polarssl_threadlock.c \ + vtls/wolfssl.c vtls/schannel.c vtls/schannel_verify.c \ +- vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c ++ vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c \ ++ vtls/bearssl.c + + LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ + vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \ + vtls/wolfssl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \ +- vtls/mbedtls.h vtls/mesalink.h ++ vtls/mbedtls.h vtls/mesalink.h vtls/bearssl.h + + LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c + +diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake +index e0793a7ee..60837d4f4 100644 +--- a/lib/curl_config.h.cmake ++++ b/lib/curl_config.h.cmake +@@ -948,6 +948,9 @@ ${SIZEOF_TIME_T_CODE} + /* if mbedTLS is enabled */ + #cmakedefine USE_MBEDTLS 1 + ++/* if BearSSL is enabled */ ++#cmakedefine USE_BEARSSL 1 ++ + /* if libSSH2 is in use */ + #cmakedefine USE_LIBSSH2 1 + +diff --git a/lib/curl_setup.h b/lib/curl_setup.h +index 13af8cdec..b4ba92931 100644 +--- a/lib/curl_setup.h ++++ b/lib/curl_setup.h +@@ -644,7 +644,8 @@ int netware_init(void); + #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ + defined(USE_MBEDTLS) || \ + defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ +- defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) ++ defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \ ++ defined(USE_BEARSSL) + #define USE_SSL /* SSL support has been enabled */ + #endif + +diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c +new file mode 100644 +index 000000000..51694c48d +--- /dev/null ++++ b/lib/vtls/bearssl.c +@@ -0,0 +1,874 @@ ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.haxx.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ ***************************************************************************/ ++#include "curl_setup.h" ++ ++#ifdef USE_BEARSSL ++ ++#include <bearssl.h> ++ ++#include "bearssl.h" ++#include "urldata.h" ++#include "sendf.h" ++#include "inet_pton.h" ++#include "vtls.h" ++#include "connect.h" ++#include "select.h" ++#include "multiif.h" ++#include "curl_printf.h" ++#include "curl_memory.h" ++ ++struct x509_context { ++ const br_x509_class *vtable; ++ br_x509_minimal_context minimal; ++ bool verifyhost; ++ bool verifypeer; ++}; ++ ++struct ssl_backend_data { ++ br_ssl_client_context ctx; ++ struct x509_context x509; ++ unsigned char buf[BR_SSL_BUFSIZE_BIDI]; ++ br_x509_trust_anchor *anchors; ++ size_t anchors_len; ++ const char *protocols[2]; ++ /* SSL client context is active */ ++ bool active; ++}; ++ ++#define BACKEND connssl->backend ++ ++struct cafile_parser { ++ CURLcode err; ++ bool in_cert; ++ br_x509_decoder_context xc; ++ /* array of trust anchors loaded from CAfile */ ++ br_x509_trust_anchor *anchors; ++ size_t anchors_len; ++ /* buffer for DN data */ ++ unsigned char dn[1024]; ++ size_t dn_len; ++}; ++ ++static void append_dn(void *ctx, const void *buf, size_t len) ++{ ++ struct cafile_parser *ca = ctx; ++ ++ if(ca->err != CURLE_OK || !ca->in_cert) ++ return; ++ if(sizeof(ca->dn) - ca->dn_len < len) { ++ ca->err = CURLE_FAILED_INIT; ++ return; ++ } ++ memcpy(ca->dn + ca->dn_len, buf, len); ++ ca->dn_len += len; ++} ++ ++static void x509_push(void *ctx, const void *buf, size_t len) ++{ ++ struct cafile_parser *ca = ctx; ++ ++ if(ca->in_cert) ++ br_x509_decoder_push(&ca->xc, buf, len); ++} ++ ++static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, ++ size_t *anchors_len) ++{ ++ struct cafile_parser ca; ++ br_pem_decoder_context pc; ++ br_x509_trust_anchor *ta; ++ size_t ta_size; ++ br_x509_trust_anchor *new_anchors; ++ size_t new_anchors_len; ++ br_x509_pkey *pkey; ++ FILE *fp; ++ unsigned char buf[BUFSIZ], *p; ++ const char *name; ++ size_t n, i, pushed; ++ ++ fp = fopen(path, "rb"); ++ if(!fp) ++ return CURLE_SSL_CACERT_BADFILE; ++ ++ ca.err = CURLE_OK; ++ ca.in_cert = FALSE; ++ ca.anchors = NULL; ++ ca.anchors_len = 0; ++ br_pem_decoder_init(&pc); ++ br_pem_decoder_setdest(&pc, x509_push, &ca); ++ for(;;) { ++ n = fread(buf, 1, sizeof(buf), fp); ++ if(n == 0) ++ break; ++ p = buf; ++ while(n) { ++ pushed = br_pem_decoder_push(&pc, p, n); ++ if(ca.err) ++ goto fail; ++ p += pushed; ++ n -= pushed; ++ ++ switch(br_pem_decoder_event(&pc)) { ++ case 0: ++ break; ++ case BR_PEM_BEGIN_OBJ: ++ name = br_pem_decoder_name(&pc); ++ if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE")) ++ break; ++ br_x509_decoder_init(&ca.xc, append_dn, &ca); ++ if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) { ++ ca.err = CURLE_OUT_OF_MEMORY; ++ goto fail; ++ } ++ new_anchors_len = ca.anchors_len + 1; ++ new_anchors = realloc(ca.anchors, ++ new_anchors_len * sizeof(ca.anchors[0])); ++ if(!new_anchors) { ++ ca.err = CURLE_OUT_OF_MEMORY; ++ goto fail; ++ } ++ ca.anchors = new_anchors; ++ ca.anchors_len = new_anchors_len; ++ ca.in_cert = TRUE; ++ ca.dn_len = 0; ++ ta = &ca.anchors[ca.anchors_len - 1]; ++ ta->dn.data = NULL; ++ break; ++ case BR_PEM_END_OBJ: ++ if(!ca.in_cert) ++ break; ++ ca.in_cert = FALSE; ++ if(br_x509_decoder_last_error(&ca.xc)) { ++ ca.err = CURLE_SSL_CACERT_BADFILE; ++ goto fail; ++ } ++ ta->flags = 0; ++ if(br_x509_decoder_isCA(&ca.xc)) ++ ta->flags |= BR_X509_TA_CA; ++ pkey = br_x509_decoder_get_pkey(&ca.xc); ++ if(!pkey) { ++ ca.err = CURLE_SSL_CACERT_BADFILE; ++ goto fail; ++ } ++ ta->pkey = *pkey; ++ ++ /* calculate space needed for trust anchor data */ ++ ta_size = ca.dn_len; ++ switch(pkey->key_type) { ++ case BR_KEYTYPE_RSA: ++ ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen; ++ break; ++ case BR_KEYTYPE_EC: ++ ta_size += pkey->key.ec.qlen; ++ break; ++ default: ++ ca.err = CURLE_FAILED_INIT; ++ goto fail; ++ } ++ ++ /* fill in trust anchor DN and public key data */ ++ ta->dn.data = malloc(ta_size); ++ if(!ta->dn.data) { ++ ca.err = CURLE_OUT_OF_MEMORY; ++ goto fail; ++ } ++ memcpy(ta->dn.data, ca.dn, ca.dn_len); ++ ta->dn.len = ca.dn_len; ++ switch(pkey->key_type) { ++ case BR_KEYTYPE_RSA: ++ ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len; ++ memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen); ++ ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen; ++ memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen); ++ break; ++ case BR_KEYTYPE_EC: ++ ta->pkey.key.ec.q = ta->dn.data + ta->dn.len; ++ memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen); ++ break; ++ } ++ break; ++ default: ++ ca.err = CURLE_SSL_CACERT_BADFILE; ++ goto fail; ++ } ++ } ++ } ++ if(ferror(fp)) ++ ca.err = CURLE_READ_ERROR; ++ ++fail: ++ fclose(fp); ++ if(ca.err == CURLE_OK) { ++ *anchors = ca.anchors; ++ *anchors_len = ca.anchors_len; ++ } ++ else { ++ for(i = 0; i < ca.anchors_len; ++i) ++ free(ca.anchors[i].dn.data); ++ free(ca.anchors); ++ } ++ ++ return ca.err; ++} ++ ++static void x509_start_chain(const br_x509_class **ctx, ++ const char *server_name) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ ++ if(!x509->verifyhost) ++ server_name = NULL; ++ x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name); ++} ++ ++static void x509_start_cert(const br_x509_class **ctx, uint32_t length) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ ++ x509->minimal.vtable->start_cert(&x509->minimal.vtable, length); ++} ++ ++static void x509_append(const br_x509_class **ctx, const unsigned char *buf, ++ size_t len) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ ++ x509->minimal.vtable->append(&x509->minimal.vtable, buf, len); ++} ++ ++static void x509_end_cert(const br_x509_class **ctx) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ ++ x509->minimal.vtable->end_cert(&x509->minimal.vtable); ++} ++ ++static unsigned x509_end_chain(const br_x509_class **ctx) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ unsigned err; ++ ++ err = x509->minimal.vtable->end_chain(&x509->minimal.vtable); ++ if(err && !x509->verifypeer) { ++ /* ignore any X.509 errors */ ++ err = BR_ERR_OK; ++ } ++ ++ return err; ++} ++ ++static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx, ++ unsigned *usages) ++{ ++ struct x509_context *x509 = (struct x509_context *)ctx; ++ ++ return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages); ++} ++ ++static const br_x509_class x509_vtable = { ++ sizeof(struct x509_context), ++ x509_start_chain, ++ x509_start_cert, ++ x509_append, ++ x509_end_cert, ++ x509_end_chain, ++ x509_get_pkey ++}; ++ ++static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) ++{ ++ struct Curl_easy *data = conn->data; ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); ++ const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ++ conn->host.name; ++ const bool verifypeer = SSL_CONN_CONFIG(verifypeer); ++ const bool verifyhost = SSL_CONN_CONFIG(verifyhost); ++ CURLcode ret; ++ unsigned version_min, version_max; ++#ifdef ENABLE_IPV6 ++ struct in6_addr addr; ++#else ++ struct in_addr addr; ++#endif ++ ++ switch(SSL_CONN_CONFIG(version)) { ++ case CURL_SSLVERSION_SSLv2: ++ failf(data, "BearSSL does not support SSLv2"); ++ return CURLE_SSL_CONNECT_ERROR; ++ case CURL_SSLVERSION_SSLv3: ++ failf(data, "BearSSL does not support SSLv3"); ++ return CURLE_SSL_CONNECT_ERROR; ++ case CURL_SSLVERSION_TLSv1_0: ++ version_min = BR_TLS10; ++ version_max = BR_TLS10; ++ break; ++ case CURL_SSLVERSION_TLSv1_1: ++ version_min = BR_TLS11; ++ version_max = BR_TLS11; ++ break; ++ case CURL_SSLVERSION_TLSv1_2: ++ version_min = BR_TLS12; ++ version_max = BR_TLS12; ++ break; ++ case CURL_SSLVERSION_DEFAULT: ++ case CURL_SSLVERSION_TLSv1: ++ version_min = BR_TLS10; ++ version_max = BR_TLS12; ++ break; ++ default: ++ failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); ++ return CURLE_SSL_CONNECT_ERROR; ++ } ++ ++ if(ssl_cafile) { ++ ret = load_cafile(ssl_cafile, &BACKEND->anchors, &BACKEND->anchors_len); ++ if(ret != CURLE_OK) { ++ if(verifypeer) { ++ failf(data, "error setting certificate verify locations:\n" ++ " CAfile: %s\n", ssl_cafile); ++ return ret; ++ } ++ infof(data, "error setting certificate verify locations," ++ " continuing anyway:\n"); ++ } ++ } ++ ++ /* initialize SSL context */ ++ br_ssl_client_init_full(&BACKEND->ctx, &BACKEND->x509.minimal, ++ BACKEND->anchors, BACKEND->anchors_len); ++ br_ssl_engine_set_versions(&BACKEND->ctx.eng, version_min, version_max); ++ br_ssl_engine_set_buffer(&BACKEND->ctx.eng, BACKEND->buf, ++ sizeof(BACKEND->buf), 1); ++ ++ /* initialize X.509 context */ ++ BACKEND->x509.vtable = &x509_vtable; ++ BACKEND->x509.verifypeer = verifypeer; ++ BACKEND->x509.verifyhost = verifyhost; ++ br_ssl_engine_set_x509(&BACKEND->ctx.eng, &BACKEND->x509.vtable); ++ ++ if(SSL_SET_OPTION(primary.sessionid)) { ++ void *session; ++ ++ Curl_ssl_sessionid_lock(conn); ++ if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { ++ br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); ++ infof(data, "BearSSL: re-using session ID\n"); ++ } ++ Curl_ssl_sessionid_unlock(conn); ++ } ++ ++ if(conn->bits.tls_enable_alpn) { ++ int cur = 0; ++ ++ /* NOTE: when adding more protocols here, increase the size of the ++ * protocols array in `struct ssl_backend_data`. ++ */ ++ ++#ifdef USE_NGHTTP2 ++ if(data->set.httpversion >= CURL_HTTP_VERSION_2 && ++ (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { ++ BACKEND->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; ++ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); ++ } ++#endif ++ ++ BACKEND->protocols[cur++] = ALPN_HTTP_1_1; ++ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); ++ ++ br_ssl_engine_set_protocol_names(&BACKEND->ctx.eng, ++ BACKEND->protocols, cur); ++ } ++ ++ if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) ++#ifdef ENABLE_IPV6 ++ || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) ++#endif ++ ) { ++ if(verifyhost) { ++ failf(data, "BearSSL: " ++ "host verification of IP address is not supported"); ++ return CURLE_PEER_FAILED_VERIFICATION; ++ } ++ hostname = NULL; ++ } ++ ++ if(!br_ssl_client_reset(&BACKEND->ctx, hostname, 0)) ++ return CURLE_FAILED_INIT; ++ BACKEND->active = TRUE; ++ ++ connssl->connecting_state = ssl_connect_2; ++ ++ return CURLE_OK; ++} ++ ++static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) ++{ ++ struct Curl_easy *data = conn->data; ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ curl_socket_t sockfd = conn->sock[sockindex]; ++ unsigned state; ++ unsigned char *buf; ++ size_t len; ++ ssize_t ret; ++ int err; ++ ++ for(;;) { ++ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); ++ if(state & BR_SSL_CLOSED) { ++ err = br_ssl_engine_last_error(&BACKEND->ctx.eng); ++ switch(err) { ++ case BR_ERR_X509_EXPIRED: ++ failf(data, "SSL: X.509 verification: " ++ "certificate is expired or not yet valid"); ++ return CURLE_PEER_FAILED_VERIFICATION; ++ case BR_ERR_X509_BAD_SERVER_NAME: ++ failf(data, "SSL: X.509 verification: " ++ "expected server name was not found in the chain"); ++ return CURLE_PEER_FAILED_VERIFICATION; ++ case BR_ERR_X509_NOT_TRUSTED: ++ failf(data, "SSL: X.509 verification: " ++ "chain could not be linked to a trust anchor"); ++ return CURLE_PEER_FAILED_VERIFICATION; ++ } ++ /* X.509 errors are documented to have the range 32..63 */ ++ if(err >= 32 && err < 64) ++ return CURLE_PEER_FAILED_VERIFICATION; ++ return CURLE_SSL_CONNECT_ERROR; ++ } ++ if(state & (BR_SSL_SENDAPP | BR_SSL_RECVAPP)) { ++ connssl->connecting_state = ssl_connect_3; ++ return CURLE_OK; ++ } ++ if(state & BR_SSL_SENDREC) { ++ buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); ++ ret = swrite(sockfd, buf, len); ++ if(ret == -1) { ++ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { ++ connssl->connecting_state = ssl_connect_2_writing; ++ return CURLE_OK; ++ } ++ return CURLE_SEND_ERROR; ++ } ++ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); ++ } ++ else if(state & BR_SSL_RECVREC) { ++ buf = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &len); ++ ret = sread(sockfd, buf, len); ++ if(ret == -1) { ++ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { ++ connssl->connecting_state = ssl_connect_2_reading; ++ return CURLE_OK; ++ } ++ return CURLE_READ_ERROR; ++ } ++ if(ret == 0) ++ return CURLE_SSL_CONNECT_ERROR; ++ br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); ++ } ++ } ++} ++ ++static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) ++{ ++ struct Curl_easy *data = conn->data; ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ CURLcode ret; ++ ++ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); ++ ++ if(conn->bits.tls_enable_alpn) { ++ const char *protocol; ++ ++ protocol = br_ssl_engine_get_selected_protocol(&BACKEND->ctx.eng); ++ if(protocol) { ++ infof(data, "ALPN, server accepted to use %s\n", protocol); ++ ++#ifdef USE_NGHTTP2 ++ if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID)) ++ conn->negnpn = CURL_HTTP_VERSION_2; ++ else ++#endif ++ if(!strcmp(protocol, ALPN_HTTP_1_1)) ++ conn->negnpn = CURL_HTTP_VERSION_1_1; ++ else ++ infof(data, "ALPN, unrecognized protocol %s\n", protocol); ++ Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? ++ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); ++ } ++ else ++ infof(data, "ALPN, server did not agree to a protocol\n"); ++ } ++ ++ if(SSL_SET_OPTION(primary.sessionid)) { ++ bool incache; ++ void *oldsession; ++ br_ssl_session_parameters *session; ++ ++ session = malloc(sizeof(*session)); ++ if(!session) ++ return CURLE_OUT_OF_MEMORY; ++ br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); ++ Curl_ssl_sessionid_lock(conn); ++ incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); ++ if(incache) ++ Curl_ssl_delsessionid(conn, oldsession); ++ ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); ++ Curl_ssl_sessionid_unlock(conn); ++ if(ret) { ++ free(session); ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ ++ connssl->connecting_state = ssl_connect_done; ++ ++ return CURLE_OK; ++} ++ ++static ssize_t bearssl_send(struct connectdata *conn, int sockindex, ++ const void *buf, size_t len, CURLcode *err) ++{ ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ unsigned state; ++ unsigned char *rec, *app; ++ size_t reclen, applen; ++ ssize_t ret; ++ ++ applen = 0; ++ for(;;) { ++ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); ++ if(state & BR_SSL_SENDREC) { ++ rec = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &reclen); ++ ret = swrite(conn->sock[sockindex], rec, reclen); ++ if(ret == -1) { ++ if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) ++ *err = CURLE_AGAIN; ++ else ++ *err = CURLE_SEND_ERROR; ++ return -1; ++ } ++ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); ++ } ++ else if(state & BR_SSL_SENDAPP && applen == 0) { ++ app = br_ssl_engine_sendapp_buf(&BACKEND->ctx.eng, &applen); ++ if(applen > len) ++ applen = len; ++ memcpy(app, buf, applen); ++ br_ssl_engine_sendapp_ack(&BACKEND->ctx.eng, applen); ++ br_ssl_engine_flush(&BACKEND->ctx.eng, 0); ++ } ++ else if(state & BR_SSL_CLOSED || applen == 0) { ++ *err = CURLE_SEND_ERROR; ++ return -1; ++ } ++ else ++ break; ++ } ++ ++ return applen; ++} ++ ++static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, ++ char *buf, size_t len, CURLcode *err) ++{ ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ unsigned state; ++ unsigned char *rec, *app; ++ size_t reclen, applen; ++ ssize_t ret; ++ ++ for(;;) { ++ state = br_ssl_engine_current_state(&BACKEND->ctx.eng); ++ if(state & BR_SSL_RECVREC) { ++ rec = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &reclen); ++ ret = sread(conn->sock[sockindex], rec, reclen); ++ if(ret == -1 && (SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)) { ++ *err = CURLE_AGAIN; ++ return -1; ++ } ++ if(ret <= 0) { ++ *err = CURLE_RECV_ERROR; ++ return -1; ++ } ++ br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); ++ } ++ else if(state & BR_SSL_RECVAPP) { ++ app = br_ssl_engine_recvapp_buf(&BACKEND->ctx.eng, &applen); ++ if(applen > len) ++ applen = len; ++ memcpy(buf, app, applen); ++ br_ssl_engine_recvapp_ack(&BACKEND->ctx.eng, applen); ++ break; ++ } ++ else { ++ *err = CURLE_RECV_ERROR; ++ return -1; ++ } ++ } ++ ++ return applen; ++} ++ ++static CURLcode bearssl_connect_common(struct connectdata *conn, ++ int sockindex, ++ bool nonblocking, ++ bool *done) ++{ ++ CURLcode ret; ++ struct Curl_easy *data = conn->data; ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ curl_socket_t sockfd = conn->sock[sockindex]; ++ time_t timeout_ms; ++ int what; ++ ++ /* check if the connection has already been established */ ++ if(ssl_connection_complete == connssl->state) { ++ *done = TRUE; ++ return CURLE_OK; ++ } ++ ++ if(ssl_connect_1 == connssl->connecting_state) { ++ ret = bearssl_connect_step1(conn, sockindex); ++ if(ret) ++ return ret; ++ } ++ ++ while(ssl_connect_2 == connssl->connecting_state || ++ ssl_connect_2_reading == connssl->connecting_state || ++ ssl_connect_2_writing == connssl->connecting_state) { ++ /* check allowed time left */ ++ timeout_ms = Curl_timeleft(data, NULL, TRUE); ++ ++ if(timeout_ms < 0) { ++ /* no need to continue if time already is up */ ++ failf(data, "SSL connection timeout"); ++ return CURLE_OPERATION_TIMEDOUT; ++ } ++ ++ /* if ssl is expecting something, check if it's available. */ ++ if(ssl_connect_2_reading == connssl->connecting_state || ++ ssl_connect_2_writing == connssl->connecting_state) { ++ ++ curl_socket_t writefd = ssl_connect_2_writing == ++ connssl->connecting_state?sockfd:CURL_SOCKET_BAD; ++ curl_socket_t readfd = ssl_connect_2_reading == ++ connssl->connecting_state?sockfd:CURL_SOCKET_BAD; ++ ++ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, ++ nonblocking?0:timeout_ms); ++ if(what < 0) { ++ /* fatal error */ ++ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); ++ return CURLE_SSL_CONNECT_ERROR; ++ } ++ else if(0 == what) { ++ if(nonblocking) { ++ *done = FALSE; ++ return CURLE_OK; ++ } ++ else { ++ /* timeout */ ++ failf(data, "SSL connection timeout"); ++ return CURLE_OPERATION_TIMEDOUT; ++ } ++ } ++ /* socket is readable or writable */ ++ } ++ ++ /* Run transaction, and return to the caller if it failed or if this ++ * connection is done nonblocking and this loop would execute again. This ++ * permits the owner of a multi handle to abort a connection attempt ++ * before step2 has completed while ensuring that a client using select() ++ * or epoll() will always have a valid fdset to wait on. ++ */ ++ ret = bearssl_connect_step2(conn, sockindex); ++ if(ret || (nonblocking && ++ (ssl_connect_2 == connssl->connecting_state || ++ ssl_connect_2_reading == connssl->connecting_state || ++ ssl_connect_2_writing == connssl->connecting_state))) ++ return ret; ++ } ++ ++ if(ssl_connect_3 == connssl->connecting_state) { ++ ret = bearssl_connect_step3(conn, sockindex); ++ if(ret) ++ return ret; ++ } ++ ++ if(ssl_connect_done == connssl->connecting_state) { ++ connssl->state = ssl_connection_complete; ++ conn->recv[sockindex] = bearssl_recv; ++ conn->send[sockindex] = bearssl_send; ++ *done = TRUE; ++ } ++ else ++ *done = FALSE; ++ ++ /* Reset our connect state machine */ ++ connssl->connecting_state = ssl_connect_1; ++ ++ return CURLE_OK; ++} ++ ++static size_t Curl_bearssl_version(char *buffer, size_t size) ++{ ++ return msnprintf(buffer, size, "BearSSL"); ++} ++ ++static bool Curl_bearssl_data_pending(const struct connectdata *conn, ++ int connindex) ++{ ++ const struct ssl_connect_data *connssl = &conn->ssl[connindex]; ++ ++ return br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_RECVAPP; ++} ++ ++static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, ++ unsigned char *entropy, size_t length) ++{ ++ static br_hmac_drbg_context ctx; ++ static bool seeded = FALSE; ++ ++ if(!seeded) { ++ br_prng_seeder seeder; ++ ++ br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); ++ seeder = br_prng_seeder_system(NULL); ++ if(!seeder || !seeder(&ctx.vtable)) ++ return CURLE_FAILED_INIT; ++ seeded = TRUE; ++ } ++ br_hmac_drbg_generate(&ctx, entropy, length); ++ ++ return CURLE_OK; ++} ++ ++static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex) ++{ ++ CURLcode ret; ++ bool done = FALSE; ++ ++ ret = bearssl_connect_common(conn, sockindex, FALSE, &done); ++ if(ret) ++ return ret; ++ ++ DEBUGASSERT(done); ++ ++ return CURLE_OK; ++} ++ ++static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, ++ int sockindex, bool *done) ++{ ++ return bearssl_connect_common(conn, sockindex, TRUE, done); ++} ++ ++static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, ++ CURLINFO info UNUSED_PARAM) ++{ ++ return &BACKEND->ctx; ++} ++ ++static void Curl_bearssl_close(struct connectdata *conn, int sockindex) ++{ ++ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ++ unsigned char *buf; ++ size_t len, i; ++ ssize_t ret; ++ ++ if(BACKEND->active) { ++ br_ssl_engine_close(&BACKEND->ctx.eng); ++ while(br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_SENDREC) { ++ buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); ++ ret = swrite(conn->sock[sockindex], buf, len); ++ if(ret < 0) ++ break; ++ br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); ++ } ++ } ++ for(i = 0; i < BACKEND->anchors_len; ++i) ++ free(BACKEND->anchors[i].dn.data); ++ free(BACKEND->anchors); ++} ++ ++static void Curl_bearssl_session_free(void *ptr) ++{ ++ free(ptr); ++} ++ ++static CURLcode Curl_bearssl_md5sum(unsigned char *input, ++ size_t inputlen, ++ unsigned char *md5sum, ++ size_t md5len UNUSED_PARAM) ++{ ++ br_md5_context ctx; ++ ++ br_md5_init(&ctx); ++ br_md5_update(&ctx, input, inputlen); ++ br_md5_out(&ctx, md5sum); ++ return CURLE_OK; ++} ++ ++static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, ++ size_t inputlen, ++ unsigned char *sha256sum, ++ size_t sha256len UNUSED_PARAM) ++{ ++ br_sha256_context ctx; ++ ++ br_sha256_init(&ctx); ++ br_sha256_update(&ctx, input, inputlen); ++ br_sha256_out(&ctx, sha256sum); ++ return CURLE_OK; ++} ++ ++const struct Curl_ssl Curl_ssl_bearssl = { ++ { CURLSSLBACKEND_BEARSSL, "bearssl" }, ++ ++ 0, ++ ++ sizeof(struct ssl_backend_data), ++ ++ Curl_none_init, ++ Curl_none_cleanup, ++ Curl_bearssl_version, ++ Curl_none_check_cxn, ++ Curl_none_shutdown, ++ Curl_bearssl_data_pending, ++ Curl_bearssl_random, ++ Curl_none_cert_status_request, ++ Curl_bearssl_connect, ++ Curl_bearssl_connect_nonblocking, ++ Curl_bearssl_get_internals, ++ Curl_bearssl_close, ++ Curl_none_close_all, ++ Curl_bearssl_session_free, ++ Curl_none_set_engine, ++ Curl_none_set_engine_default, ++ Curl_none_engines_list, ++ Curl_none_false_start, ++ Curl_bearssl_md5sum, ++ Curl_bearssl_sha256sum ++}; ++ ++#endif /* USE_BEARSSL */ +diff --git a/lib/vtls/bearssl.h b/lib/vtls/bearssl.h +new file mode 100644 +index 000000000..5f94922b9 +--- /dev/null ++++ b/lib/vtls/bearssl.h +@@ -0,0 +1,32 @@ ++#ifndef HEADER_CURL_BEARSSL_H ++#define HEADER_CURL_BEARSSL_H ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) 2019, Michael Forney, <mforney@mforney.org> ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.haxx.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ ***************************************************************************/ ++ ++#include "curl_setup.h" ++ ++#ifdef USE_BEARSSL ++ ++extern const struct Curl_ssl Curl_ssl_bearssl; ++ ++#endif /* USE_BEARSSL */ ++#endif /* HEADER_CURL_BEARSSL_H */ +diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c +index e6d756225..894fd8a43 100644 +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -517,7 +517,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) + + #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_SECTRANSP) || defined(USE_POLARSSL) || defined(USE_NSS) || \ +- defined(USE_MBEDTLS) || defined(USE_WOLFSSL) ++ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL) + int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks) + { + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; +@@ -1189,6 +1189,8 @@ const struct Curl_ssl *Curl_ssl = + &Curl_ssl_schannel; + #elif defined(USE_MESALINK) + &Curl_ssl_mesalink; ++#elif defined(USE_BEARSSL) ++ &Curl_ssl_bearssl; + #else + #error "Missing struct Curl_ssl for selected SSL backend" + #endif +diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h +index 61d8416c2..976cc4360 100644 +--- a/lib/vtls/vtls.h ++++ b/lib/vtls/vtls.h +@@ -108,6 +108,7 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, + #include "sectransp.h" /* SecureTransport (Darwin) version */ + #include "mbedtls.h" /* mbedTLS versions */ + #include "mesalink.h" /* MesaLink versions */ ++#include "bearssl.h" /* BearSSL versions */ + + #ifndef MAX_PINNED_PUBKEY_SIZE + #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ +-- +2.24.0 + diff --git a/pkg/curl/ver b/pkg/curl/ver @@ -1 +1 @@ -7.67.0 r2 +7.67.0 r3