diff options
author | AlexSm <alex@ydb.tech> | 2024-01-18 11:28:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-18 11:28:56 +0100 |
commit | 9d0a3761b3201e0d9db879a7adf91876ebdb0564 (patch) | |
tree | 541d11ac878c18efd7ebca81e35112aa0fef995b /contrib/libs/curl/lib/vtls/wolfssl.c | |
parent | 404ef8886ecc9736bc58ade6da2fbd83b486a408 (diff) | |
download | ydb-9d0a3761b3201e0d9db879a7adf91876ebdb0564.tar.gz |
Library import 8 (#1074)
* Library import 8
* Add contrib/libs/cxxsupp/libcxx/include/__verbose_abort
Diffstat (limited to 'contrib/libs/curl/lib/vtls/wolfssl.c')
-rw-r--r-- | contrib/libs/curl/lib/vtls/wolfssl.c | 644 |
1 files changed, 402 insertions, 242 deletions
diff --git a/contrib/libs/curl/lib/vtls/wolfssl.c b/contrib/libs/curl/lib/vtls/wolfssl.c index b068639c80..fa5f51eb26 100644 --- a/contrib/libs/curl/lib/vtls/wolfssl.c +++ b/contrib/libs/curl/lib/vtls/wolfssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,6 +55,7 @@ #include "sendf.h" #include "inet_pton.h" #include "vtls.h" +#include "vtls_int.h" #include "keylog.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ @@ -84,13 +85,17 @@ #endif #endif -struct ssl_backend_data { - SSL_CTX* ctx; - SSL* handle; -}; +#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO +#define USE_BIO_CHAIN +#else +#undef USE_BIO_CHAIN +#endif -static Curl_recv wolfssl_recv; -static Curl_send wolfssl_send; +struct wolfssl_ssl_backend_data { + WOLFSSL_CTX *ctx; + WOLFSSL *handle; + CURLcode io_result; /* result of last BIO cfilter operation */ +}; #ifdef OPENSSL_EXTRA /* @@ -175,7 +180,8 @@ wolfssl_log_tls12_secret(SSL *ssl) } #endif - if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) { + if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != + SSL_SUCCESS) { return; } @@ -214,46 +220,153 @@ static const struct group_name_map gnm[] = { { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, - { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" }, - { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" }, - { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" }, - { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" }, - { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" }, - { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" }, - { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" }, - { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" }, - { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" }, - { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" }, - { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" }, - { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" }, - { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" }, - { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" }, - { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" }, - { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" }, - { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" }, { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, - { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" }, - { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" }, - { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" }, { 0, NULL } }; #endif +#ifdef USE_BIO_CHAIN + +static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio) +{ + wolfSSL_BIO_set_shutdown(bio, 1); + wolfSSL_BIO_set_init(bio, 1); + wolfSSL_BIO_set_data(bio, NULL); + return 1; +} + +static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio) +{ + if(!bio) + return 0; + return 1; +} + +static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) +{ + struct Curl_cfilter *cf = BIO_get_data(bio); + long ret = 1; + + (void)cf; + (void)ptr; + switch(cmd) { + case BIO_CTRL_GET_CLOSE: + ret = (long)wolfSSL_BIO_get_shutdown(bio); + break; + case BIO_CTRL_SET_CLOSE: + wolfSSL_BIO_set_shutdown(bio, (int)num); + break; + case BIO_CTRL_FLUSH: + /* we do no delayed writes, but if we ever would, this + * needs to trigger it. */ + ret = 1; + break; + case BIO_CTRL_DUP: + ret = 1; + break; +#ifdef BIO_CTRL_EOF + case BIO_CTRL_EOF: + /* EOF has been reached on input? */ + return (!cf->next || !cf->next->connected); +#endif + default: + ret = 0; + break; + } + return ret; +} + +static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio, + const char *buf, int blen) +{ + struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nwritten; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); + backend->io_result = result; + CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d", + blen, nwritten, result); + wolfSSL_BIO_clear_retry_flags(bio); + if(nwritten < 0 && CURLE_AGAIN == result) + BIO_set_retry_write(bio); + return (int)nwritten; +} + +static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) +{ + struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct Curl_easy *data = CF_DATA_CURRENT(cf); + ssize_t nread; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + /* OpenSSL catches this case, so should we. */ + if(!buf) + return 0; + + nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + backend->io_result = result; + CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result); + wolfSSL_BIO_clear_retry_flags(bio); + if(nread < 0 && CURLE_AGAIN == result) + BIO_set_retry_read(bio); + return (int)nread; +} + +static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL; + +static void wolfssl_bio_cf_init_methods(void) +{ + wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO"); + wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write); + wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read); + wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl); + wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create); + wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy); +} + +static void wolfssl_bio_cf_free_methods(void) +{ + wolfSSL_BIO_meth_free(wolfssl_bio_cf_method); +} + +#else /* USE_BIO_CHAIN */ + +#define wolfssl_bio_cf_init_methods() Curl_nop_stmt +#define wolfssl_bio_cf_free_methods() Curl_nop_stmt + +#endif /* !USE_BIO_CHAIN */ + /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ static CURLcode -wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, - int sockindex) +wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { char *ciphers, *curves; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; - SSL_METHOD* req_method = NULL; - curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; + const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const char * const ssl_capath = conn_config->CApath; + WOLFSSL_METHOD* req_method = NULL; #ifdef HAVE_LIBOQS word16 oqsAlg = 0; size_t idx = 0; @@ -264,19 +377,21 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, #else #define use_sni(x) Curl_nop_stmt #endif + bool imported_native_ca = false; + bool imported_ca_info_blob = false; DEBUGASSERT(backend); if(connssl->state == ssl_connection_complete) return CURLE_OK; - if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { + if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) { failf(data, "wolfSSL does not support to set maximum SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(SSL_CONN_CONFIG(version)) { + switch(conn_config->version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ @@ -308,8 +423,13 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, #endif break; case CURL_SSLVERSION_TLSv1_2: +#ifndef WOLFSSL_NO_TLS12 req_method = TLSv1_2_client_method(); use_sni(TRUE); +#else + failf(data, "wolfSSL does not support TLS 1.2"); + return CURLE_NOT_BUILT_IN; +#endif break; case CURL_SSLVERSION_TLSv1_3: #ifdef WOLFSSL_TLS13 @@ -331,15 +451,15 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, } if(backend->ctx) - SSL_CTX_free(backend->ctx); - backend->ctx = SSL_CTX_new(req_method); + wolfSSL_CTX_free(backend->ctx); + backend->ctx = wolfSSL_CTX_new(req_method); if(!backend->ctx) { failf(data, "SSL: couldn't create a context"); return CURLE_OUT_OF_MEMORY; } - switch(SSL_CONN_CONFIG(version)) { + switch(conn_config->version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ @@ -360,10 +480,11 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } #endif + default: break; } - ciphers = SSL_CONN_CONFIG(cipher_list); + ciphers = conn_config->cipher_list; if(ciphers) { if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); @@ -372,7 +493,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, infof(data, "Cipher selection: %s", ciphers); } - curves = SSL_CONN_CONFIG(curves); + curves = conn_config->curves; if(curves) { #ifdef HAVE_LIBOQS @@ -392,20 +513,55 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } } + +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS) + /* load native CA certificates */ + if(ssl_config->native_ca_store) { + if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) { + infof(data, "error importing native CA store, continuing anyway"); + } + else { + imported_native_ca = true; + infof(data, "successfully imported native CA store"); + } + } +#endif /* !NO_FILESYSTEM */ + + /* load certificate blob */ + if(ca_info_blob) { + if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data, + ca_info_blob->len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + if(imported_native_ca) { + infof(data, "error importing CA certificate blob, continuing anyway"); + } + else { + failf(data, "error importing CA certificate blob"); + return CURLE_SSL_CACERT_BADFILE; + } + } + else { + imported_ca_info_blob = true; + infof(data, "successfully imported CA certificate blob"); + } + } + #ifndef NO_FILESYSTEM - /* load trusted cacert */ - if(SSL_CONN_CONFIG(CAfile)) { - if(1 != SSL_CTX_load_verify_locations(backend->ctx, - SSL_CONN_CONFIG(CAfile), - SSL_CONN_CONFIG(CApath))) { - if(SSL_CONN_CONFIG(verifypeer)) { + /* load trusted cacert from file if not blob */ + if(ssl_cafile || ssl_capath) { + int rc = + wolfSSL_CTX_load_verify_locations_ex(backend->ctx, + ssl_cafile, + ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { + if(conn_config->verifypeer && !imported_ca_info_blob && + !imported_native_ca) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:" " CAfile: %s CApath: %s", - SSL_CONN_CONFIG(CAfile)? - SSL_CONN_CONFIG(CAfile): "none", - SSL_CONN_CONFIG(CApath)? - SSL_CONN_CONFIG(CApath) : "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -419,27 +575,25 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Everything is fine. */ infof(data, "successfully set certificate verify locations:"); } - infof(data, " CAfile: %s", - SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none"); - infof(data, " CApath: %s", - SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none"); + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } /* Load the client certificate, and private key */ - if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) { - int file_type = do_file_type(SSL_SET_OPTION(cert_type)); + if(ssl_config->primary.clientcert && ssl_config->key) { + int file_type = do_file_type(ssl_config->cert_type); - if(SSL_CTX_use_certificate_file(backend->ctx, - SSL_SET_OPTION(primary.clientcert), - file_type) != 1) { + if(wolfSSL_CTX_use_certificate_file(backend->ctx, + ssl_config->primary.clientcert, + file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } - file_type = do_file_type(SSL_SET_OPTION(key_type)); - if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key), - file_type) != 1) { + file_type = do_file_type(ssl_config->key_type); + if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key, + file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } @@ -450,30 +604,17 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(backend->ctx, - SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: - SSL_VERIFY_NONE, - NULL); + wolfSSL_CTX_set_verify(backend->ctx, + conn_config->verifypeer?SSL_VERIFY_PEER: + SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI - if(sni) { - struct in_addr addr4; -#ifdef ENABLE_IPV6 - struct in6_addr addr6; -#endif - const char * const hostname = SSL_HOST_NAME(); - size_t hostname_len = strlen(hostname); - if((hostname_len < USHRT_MAX) && - !Curl_inet_pton(AF_INET, hostname, &addr4) -#ifdef ENABLE_IPV6 - && !Curl_inet_pton(AF_INET6, hostname, &addr6) -#endif - ) { - size_t snilen; - char *snihost = Curl_ssl_snihost(data, hostname, &snilen); - if(!snihost || - wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost, - (unsigned short)snilen) != 1) { + if(sni && connssl->peer.sni) { + size_t sni_len = strlen(connssl->peer.sni); + if((sni_len < USHRT_MAX)) { + if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, + connssl->peer.sni, + (unsigned short)sni_len) != 1) { failf(data, "Failed to set SNI"); return CURLE_SSL_CONNECT_ERROR; } @@ -491,7 +632,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } #ifdef NO_FILESYSTEM - else if(SSL_CONN_CONFIG(verifypeer)) { + else if(conn_config->verifypeer) { failf(data, "SSL: Certificates can't be loaded because wolfSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" @@ -502,8 +643,8 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Let's make an SSL structure */ if(backend->handle) - SSL_free(backend->handle); - backend->handle = SSL_new(backend->ctx); + wolfSSL_free(backend->handle); + backend->handle = wolfSSL_new(backend->ctx); if(!backend->handle) { failf(data, "SSL: couldn't create a handle"); return CURLE_OUT_OF_MEMORY; @@ -518,29 +659,18 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, #endif #ifdef HAVE_ALPN - if(conn->bits.tls_enable_alpn) { - char protocols[128]; - *protocols = '\0'; - - /* wolfSSL's ALPN protocol name list format is a comma separated string of - protocols in descending order of preference, eg: "h2,http/1.1" */ - -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2) { - strcpy(protocols + strlen(protocols), ALPN_H2 ","); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); - } -#endif - - strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + if(connssl->alpn) { + struct alpn_proto_buf proto; + CURLcode result; - if(wolfSSL_UseALPN(backend->handle, protocols, - (unsigned)strlen(protocols), + result = Curl_alpn_to_proto_str(&proto, connssl->alpn); + if(result || + wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len, WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { failf(data, "SSL: failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } #endif /* HAVE_ALPN */ @@ -563,29 +693,41 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, #endif /* HAVE_SECURE_RENEGOTIATION */ /* Check if there's a cached ID we can/should use here! */ - if(SSL_SET_OPTION(primary.sessionid)) { + if(ssl_config->primary.sessionid) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(data); - if(!Curl_ssl_getsessionid(data, conn, - SSL_IS_PROXY() ? TRUE : FALSE, - &ssl_sessionid, NULL, sockindex)) { + if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) { /* we got a session id, use it! */ if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_delsessionid(data, ssl_sessionid); infof(data, "Can't use session ID, going on without"); } else - infof(data, "SSL re-using session ID"); + infof(data, "SSL reusing session ID"); } Curl_ssl_sessionid_unlock(data); } +#ifdef USE_BIO_CHAIN + { + WOLFSSL_BIO *bio; + + bio = BIO_new(wolfssl_bio_cf_method); + if(!bio) + return CURLE_OUT_OF_MEMORY; + + wolfSSL_BIO_set_data(bio, cf); + wolfSSL_set_bio(backend->handle, bio, bio); + } +#else /* USE_BIO_CHAIN */ /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(backend->handle, (int)sockfd)) { + if(!wolfSSL_set_fd(backend->handle, + (int)Curl_conn_cf_get_socket(cf, data))) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } +#endif /* !USE_BIO_CHAIN */ connssl->connecting_state = ssl_connect_2; return CURLE_OK; @@ -593,31 +735,30 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, static CURLcode -wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, - int sockindex) +wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { int ret = -1; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; - const char * const dispname = SSL_HOST_DISPNAME(); - const char * const pinnedpubkey = SSL_PINNED_PUB_KEY(); + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; DEBUGASSERT(backend); - ERR_clear_error(); - - conn->recv[sockindex] = wolfssl_recv; - conn->send[sockindex] = wolfssl_send; + wolfSSL_ERR_clear_error(); /* Enable RFC2818 checks */ - if(SSL_CONN_CONFIG(verifyhost)) { - char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL); - if(!snihost || - (wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)) + if(conn_config->verifyhost) { + char *snihost = connssl->peer.sni? + connssl->peer.sni : connssl->peer.hostname; + if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE) return CURLE_SSL_CONNECT_ERROR; } - ret = SSL_connect(backend->handle); + ret = wolfSSL_connect(backend->handle); #ifdef OPENSSL_EXTRA if(Curl_tls_keylog_enabled()) { @@ -645,7 +786,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(ret != 1) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int detail = SSL_get_error(backend->handle, ret); + int detail = wolfSSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; @@ -661,32 +802,32 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 failf(data, " subject alt name(s) or common name do not match \"%s\"", - dispname); + connssl->peer.dispname); return CURLE_PEER_FAILED_VERIFICATION; #else /* When the wolfssl_check_domain_name() is used and you desire to - * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost + * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA * error. The only way to do this is currently to switch the * Wolfssl_check_domain_name() in and out based on the - * 'conn->ssl_config.verifyhost' value. */ - if(SSL_CONN_CONFIG(verifyhost)) { + * 'ssl_config.verifyhost' value. */ + if(conn_config->verifyhost) { failf(data, " subject alt name(s) or common name do not match \"%s\"\n", - dispname); + connssl->dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, " subject alt name(s) and/or common name do not match \"%s\"", - dispname); + connssl->dispname); return CURLE_OK; } #endif } #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { - if(SSL_CONN_CONFIG(verifypeer)) { + if(conn_config->verifypeer) { failf(data, " CA signer not available for verification"); return CURLE_SSL_CACERT_BADFILE; } @@ -698,9 +839,12 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } #endif + else if(backend->io_result == CURLE_AGAIN) { + return CURLE_OK; + } else { failf(data, "SSL_connect failed with error %d: %s", detail, - ERR_error_string(detail, error_buffer)); + wolfSSL_ERR_error_string(detail, error_buffer)); return CURLE_SSL_CONNECT_ERROR; } } @@ -714,7 +858,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, struct Curl_asn1Element *pubkey; CURLcode result; - x509 = SSL_get_peer_certificate(backend->handle); + x509 = wolfSSL_get_peer_certificate(backend->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; @@ -751,7 +895,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, } #ifdef HAVE_ALPN - if(conn->bits.tls_enable_alpn) { + if(connssl->alpn) { int rc; char *protocol = NULL; unsigned short protocol_len = 0; @@ -759,25 +903,11 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); if(rc == SSL_SUCCESS) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, protocol_len, protocol); - - if(protocol_len == ALPN_HTTP_1_1_LENGTH && - !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) - conn->alpn = CURL_HTTP_VERSION_1_1; -#ifdef USE_HTTP2 - else if(data->state.httpwant >= CURL_HTTP_VERSION_2 && - protocol_len == ALPN_H2_LENGTH && - !memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH)) - conn->alpn = CURL_HTTP_VERSION_2; -#endif - else - infof(data, "ALPN, unrecognized protocol %.*s", protocol_len, - protocol); - Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol, + protocol_len); } else if(rc == SSL_ALPN_NOT_FOUND) - infof(data, VTLS_INFOF_NO_ALPN); + Curl_alpn_set_negotiated(cf, data, NULL, 0); else { failf(data, "ALPN, failure getting protocol, error %d", rc); return CURLE_SSL_CONNECT_ERROR; @@ -799,28 +929,27 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, static CURLcode -wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, - int sockindex) +wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { CURLcode result = CURLE_OK; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; + const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); DEBUGASSERT(backend); - if(SSL_SET_OPTION(primary.sessionid)) { + if(ssl_config->primary.sessionid) { bool incache; bool added = FALSE; void *old_ssl_sessionid = NULL; - /* SSL_get1_session allocates memory that has to be freed. */ - SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle); - bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + /* wolfSSL_get1_session allocates memory that has to be freed. */ + WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle); if(our_ssl_sessionid) { Curl_ssl_sessionid_lock(data); - incache = !(Curl_ssl_getsessionid(data, conn, isproxy, - &old_ssl_sessionid, NULL, sockindex)); + incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing"); @@ -830,11 +959,10 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, } if(!incache) { - result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, - 0, sockindex, NULL); + result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL); if(result) { Curl_ssl_sessionid_unlock(data); - SSL_SESSION_free(our_ssl_sessionid); + wolfSSL_SESSION_free(our_ssl_sessionid); failf(data, "failed to store ssl session"); return result; } @@ -846,7 +974,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(!added) { /* If the session info wasn't added to the cache, free our copy. */ - SSL_SESSION_free(our_ssl_sessionid); + wolfSSL_SESSION_free(our_ssl_sessionid); } } } @@ -857,50 +985,57 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, } -static ssize_t wolfssl_send(struct Curl_easy *data, - int sockindex, +static ssize_t wolfssl_send(struct Curl_cfilter *cf, + struct Curl_easy *data, const void *mem, size_t len, CURLcode *curlcode) { - struct connectdata *conn = data->conn; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; int rc; DEBUGASSERT(backend); - ERR_clear_error(); - - rc = SSL_write(backend->handle, mem, memlen); + wolfSSL_ERR_clear_error(); + rc = wolfSSL_write(backend->handle, mem, memlen); if(rc <= 0) { - int err = SSL_get_error(backend->handle, rc); + int err = wolfSSL_get_error(backend->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_write() */ + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len); *curlcode = CURLE_AGAIN; return -1; default: + if(backend->io_result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len); + *curlcode = CURLE_AGAIN; + return -1; + } + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err); failf(data, "SSL write: %s, errno %d", - ERR_error_string(err, error_buffer), + wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO); *curlcode = CURLE_SEND_ERROR; return -1; } } + CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc); return rc; } -static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn, - int sockindex) +static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; (void) data; @@ -910,64 +1045,73 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn, char buf[32]; /* Maybe the server has already sent a close notify alert. Read it to avoid an RST on the TCP connection. */ - (void)SSL_read(backend->handle, buf, (int)sizeof(buf)); - (void)SSL_shutdown(backend->handle); - SSL_free(backend->handle); + (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf)); + (void)wolfSSL_shutdown(backend->handle); + wolfSSL_free(backend->handle); backend->handle = NULL; } if(backend->ctx) { - SSL_CTX_free(backend->ctx); + wolfSSL_CTX_free(backend->ctx); backend->ctx = NULL; } } -static ssize_t wolfssl_recv(struct Curl_easy *data, - int num, - char *buf, - size_t buffersize, +static ssize_t wolfssl_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t blen, CURLcode *curlcode) { - struct connectdata *conn = data->conn; - struct ssl_connect_data *connssl = &conn->ssl[num]; - struct ssl_backend_data *backend = connssl->backend; + struct ssl_connect_data *connssl = cf->ctx; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; int nread; DEBUGASSERT(backend); - ERR_clear_error(); + wolfSSL_ERR_clear_error(); + *curlcode = CURLE_OK; - nread = SSL_read(backend->handle, buf, buffsize); + nread = wolfSSL_read(backend->handle, buf, buffsize); if(nread <= 0) { - int err = SSL_get_error(backend->handle, nread); + int err = wolfSSL_get_error(backend->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen); + *curlcode = CURLE_OK; + return 0; case SSL_ERROR_NONE: /* FALLTHROUGH */ case SSL_ERROR_WANT_READ: /* FALLTHROUGH */ case SSL_ERROR_WANT_WRITE: - /* there's data pending, re-invoke SSL_read() */ + /* there's data pending, re-invoke wolfSSL_read() */ + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen); *curlcode = CURLE_AGAIN; return -1; default: + if(backend->io_result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen); + *curlcode = CURLE_AGAIN; + return -1; + } failf(data, "SSL read: %s, errno %d", - ERR_error_string(err, error_buffer), SOCKERRNO); + wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; } } + CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread); return nread; } static void wolfssl_session_free(void *ptr) { - SSL_SESSION_free(ptr); + wolfSSL_SESSION_free(ptr); } @@ -983,15 +1127,20 @@ static size_t wolfssl_version(char *buffer, size_t size) static int wolfssl_init(void) { + int ret; + #ifdef OPENSSL_EXTRA Curl_tls_keylog_open(); #endif - return (wolfSSL_Init() == SSL_SUCCESS); + ret = (wolfSSL_Init() == SSL_SUCCESS); + wolfssl_bio_cf_init_methods(); + return ret; } static void wolfssl_cleanup(void) { + wolfssl_bio_cf_free_methods(); wolfSSL_Cleanup(); #ifdef OPENSSL_EXTRA Curl_tls_keylog_close(); @@ -999,14 +1148,18 @@ static void wolfssl_cleanup(void) } -static bool wolfssl_data_pending(const struct connectdata *conn, - int connindex) +static bool wolfssl_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) { - const struct ssl_connect_data *connssl = &conn->ssl[connindex]; - struct ssl_backend_data *backend = connssl->backend; - DEBUGASSERT(backend); + struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; + + (void)data; + DEBUGASSERT(ctx && ctx->backend); + + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; if(backend->handle) /* SSL is in use */ - return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE; + return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE; else return FALSE; } @@ -1016,20 +1169,20 @@ static bool wolfssl_data_pending(const struct connectdata *conn, * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ -static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn, - int sockindex) +static int wolfssl_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data) { + struct ssl_connect_data *ctx = cf->ctx; + struct wolfssl_ssl_backend_data *backend; int retval = 0; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct ssl_backend_data *backend = connssl->backend; - (void) data; - - DEBUGASSERT(backend); + (void)data; + DEBUGASSERT(ctx && ctx->backend); + backend = (struct wolfssl_ssl_backend_data *)ctx->backend; if(backend->handle) { - ERR_clear_error(); - SSL_free(backend->handle); + wolfSSL_ERR_clear_error(); + wolfSSL_free(backend->handle); backend->handle = NULL; } return retval; @@ -1037,15 +1190,14 @@ static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn, static CURLcode -wolfssl_connect_common(struct Curl_easy *data, - struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) +wolfssl_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool nonblocking, + bool *done) { CURLcode result; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); int what; /* check if the connection has already been established */ @@ -1064,7 +1216,7 @@ wolfssl_connect_common(struct Curl_easy *data, return CURLE_OPERATION_TIMEDOUT; } - result = wolfssl_connect_step1(data, conn, sockindex); + result = wolfssl_connect_step1(cf, data); if(result) return result; } @@ -1119,7 +1271,7 @@ wolfssl_connect_common(struct Curl_easy *data, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ - result = wolfssl_connect_step2(data, conn, sockindex); + result = wolfssl_connect_step2(cf, data); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || @@ -1128,15 +1280,13 @@ wolfssl_connect_common(struct Curl_easy *data, } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { - result = wolfssl_connect_step3(data, conn, sockindex); + result = wolfssl_connect_step3(cf, data); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; - conn->recv[sockindex] = wolfssl_recv; - conn->send[sockindex] = wolfssl_send; *done = TRUE; } else @@ -1149,21 +1299,21 @@ wolfssl_connect_common(struct Curl_easy *data, } -static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data, - struct connectdata *conn, - int sockindex, bool *done) +static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { - return wolfssl_connect_common(data, conn, sockindex, TRUE, done); + return wolfssl_connect_common(cf, data, TRUE, done); } -static CURLcode wolfssl_connect(struct Curl_easy *data, - struct connectdata *conn, int sockindex) +static CURLcode wolfssl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) { CURLcode result; bool done = FALSE; - result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done); + result = wolfssl_connect_common(cf, data, FALSE, &done); if(result) return result; @@ -1195,7 +1345,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ { wc_Sha256 SHA256pw; (void)unused; - wc_InitSha256(&SHA256pw); + if(wc_InitSha256(&SHA256pw)) + return CURLE_FAILED_INIT; wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen); wc_Sha256Final(&SHA256pw, sha256sum); return CURLE_OK; @@ -1204,7 +1355,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ static void *wolfssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { - struct ssl_backend_data *backend = connssl->backend; + struct wolfssl_ssl_backend_data *backend = + (struct wolfssl_ssl_backend_data *)connssl->backend; (void)info; DEBUGASSERT(backend); return backend->handle; @@ -1216,9 +1368,14 @@ const struct Curl_ssl Curl_ssl_wolfssl = { #ifdef KEEP_PEER_CERT SSLSUPP_PINNEDPUBKEY | #endif +#ifdef USE_BIO_CHAIN + SSLSUPP_HTTPS_PROXY | +#endif + SSLSUPP_CA_PATH | + SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX, - sizeof(struct ssl_backend_data), + sizeof(struct wolfssl_ssl_backend_data), wolfssl_init, /* init */ wolfssl_cleanup, /* cleanup */ @@ -1230,7 +1387,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = { Curl_none_cert_status_request, /* cert_status_request */ wolfssl_connect, /* connect */ wolfssl_connect_nonblocking, /* connect_nonblocking */ - Curl_ssl_getsock, /* getsock */ + Curl_ssl_adjust_pollset, /* adjust_pollset */ wolfssl_get_internals, /* get_internals */ wolfssl_close, /* close_one */ Curl_none_close_all, /* close_all */ @@ -1241,7 +1398,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = { Curl_none_false_start, /* false_start */ wolfssl_sha256sum, /* sha256sum */ NULL, /* associate_connection */ - NULL /* disassociate_connection */ + NULL, /* disassociate_connection */ + NULL, /* free_multi_ssl_backend_data */ + wolfssl_recv, /* recv decrypted data */ + wolfssl_send, /* send data to encrypt */ }; #endif |