diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vtls')
32 files changed, 1021 insertions, 1052 deletions
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c index d9c0ce0eed..7e3eb79ce8 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.c +++ b/Utilities/cmcurl/lib/vtls/bearssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2022, Michael Forney, <mforney@mforney.org> + * Copyright (C) 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 @@ -58,7 +58,7 @@ struct ssl_backend_data { unsigned char buf[BR_SSL_BUFSIZE_BIDI]; br_x509_trust_anchor *anchors; size_t anchors_len; - const char *protocols[2]; + const char *protocols[ALPN_ENTRIES_MAX]; /* SSL client context is active */ bool active; /* size of pending write, yet to be flushed */ @@ -691,29 +691,17 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, Curl_ssl_sessionid_unlock(data); } - if(cf->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`. - */ + if(connssl->alpn) { + struct alpn_proto_buf proto; + size_t i; -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 -#ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) -#endif - ) { - backend->protocols[cur++] = ALPN_H2; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + for(i = 0; i < connssl->alpn->count; ++i) { + backend->protocols[i] = connssl->alpn->entries[i]; } -#endif - - backend->protocols[cur++] = ALPN_HTTP_1_1; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); - - br_ssl_engine_set_protocol_names(&backend->ctx.eng, - backend->protocols, cur); + br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols, + connssl->alpn->count); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) @@ -862,26 +850,11 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, DEBUGASSERT(backend); if(cf->conn->bits.tls_enable_alpn) { - const char *protocol; - - protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); - if(protocol) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, protocol); + const char *proto; -#ifdef USE_HTTP2 - if(!strcmp(protocol, ALPN_H2)) - cf->conn->alpn = CURL_HTTP_VERSION_2; - else -#endif - if(!strcmp(protocol, ALPN_HTTP_1_1)) - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - else - infof(data, "ALPN, unrecognized protocol %s", protocol); - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); - } - else - infof(data, VTLS_INFOF_NO_ALPN); + proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto, + proto? strlen(proto) : 0); } if(ssl_config->primary.sessionid) { @@ -977,7 +950,7 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, { CURLcode ret; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); timediff_t timeout_ms; int what; diff --git a/Utilities/cmcurl/lib/vtls/bearssl.h b/Utilities/cmcurl/lib/vtls/bearssl.h index 5125359961..b3651b092c 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.h +++ b/Utilities/cmcurl/lib/vtls/bearssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2022, Michael Forney, <mforney@mforney.org> + * Copyright (C) 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 diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 2074dcaa48..59fd27ce4e 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.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 @@ -499,7 +499,7 @@ static void cancel_async_handshake(struct Curl_cfilter *cf, (void)data; DEBUGASSERT(BACKEND); - if(QsoCancelOperation(cf->conn->sock[cf->sockindex], 0) > 0) + if(QsoCancelOperation(Curl_conn_cf_get_socket(cf, data), 0) > 0) QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL); } @@ -532,7 +532,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, int directions) DEBUGASSERT(connssl_next->backend); n = 1; fds[0].fd = BACKEND->remotefd; - fds[1].fd = cf->conn->sock[cf->sockindex]; + fds[1].fd = Curl_conn_cf_get_socket(cf, data); if(directions & SOS_READ) { fds[0].events |= POLLOUT; @@ -847,7 +847,7 @@ static CURLcode gskit_connect_step1(struct Curl_cfilter *cf, result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1); if(!result) result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0? - BACKEND->localfd: cf->conn->sock[cf->sockindex]); + BACKEND->localfd: Curl_conn_cf_get_socket(cf, data)); if(!result) result = set_ciphers(cf, data, BACKEND->handle, &protoflags); if(!protoflags) { @@ -1208,7 +1208,7 @@ static int gskit_shutdown(struct Curl_cfilter *cf, close_one(cf, data); rc = 0; - what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), SSL_SHUTDOWN_TIMEOUT); while(loop--) { @@ -1230,7 +1230,7 @@ static int gskit_shutdown(struct Curl_cfilter *cf, notify alert from the server. No way to gsk_secure_soc_read() now, so use read(). */ - nread = read(cf->conn->sock[cf->sockindex], buf, sizeof(buf)); + nread = read(Curl_conn_cf_get_socket(cf, data), buf, sizeof(buf)); if(nread < 0) { char buffer[STRERROR_LEN]; @@ -1241,7 +1241,7 @@ static int gskit_shutdown(struct Curl_cfilter *cf, if(nread <= 0) break; - what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0); + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0); } return rc; diff --git a/Utilities/cmcurl/lib/vtls/gskit.h b/Utilities/cmcurl/lib/vtls/gskit.h index cf923f6b85..c71e6a0117 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.h +++ b/Utilities/cmcurl/lib/vtls/gskit.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index 104dce6093..07dfaa437c 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.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 @@ -84,7 +84,7 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen) { struct Curl_cfilter *cf = s; struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result; @@ -102,7 +102,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen) { struct Curl_cfilter *cf = s; struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result; @@ -214,7 +214,7 @@ static CURLcode handshake(struct Curl_cfilter *cf, struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; gnutls_session_t session; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); DEBUGASSERT(backend); session = backend->gtls.session; @@ -434,12 +434,10 @@ CURLcode gtls_client_init(struct Curl_easy *data, } #ifdef USE_GNUTLS_SRP - if((config->authtype == CURL_TLSAUTH_SRP) && - Curl_auth_allowed_to_host(data)) { + if(config->username && Curl_auth_allowed_to_host(data)) { infof(data, "Using TLS-SRP username: %s", config->username); - rc = gnutls_srp_allocate_client_credentials( - >ls->srp_client_cred); + rc = gnutls_srp_allocate_client_credentials(>ls->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); @@ -581,7 +579,7 @@ CURLcode gtls_client_init(struct Curl_easy *data, #ifdef USE_GNUTLS_SRP /* Only add SRP to the cipher list if SRP is requested. Otherwise * GnuTLS will disable TLS 1.3 support. */ - if(config->authtype == CURL_TLSAUTH_SRP) { + if(config->username) { size_t len = strlen(prioritylist); char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); @@ -646,7 +644,7 @@ CURLcode gtls_client_init(struct Curl_easy *data, #ifdef USE_GNUTLS_SRP /* put the credentials to the current session */ - if(config->authtype == CURL_TLSAUTH_SRP) { + if(config->username) { rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP, gtls->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { @@ -700,32 +698,22 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(result) return result; - if(cf->conn->bits.tls_enable_alpn) { - int cur = 0; - gnutls_datum_t protocols[2]; + if(connssl->alpn) { + struct alpn_proto_buf proto; + gnutls_datum_t alpn[ALPN_ENTRIES_MAX]; + size_t i; -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 -#ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) -#endif - ) { - protocols[cur].data = (unsigned char *)ALPN_H2; - protocols[cur].size = ALPN_H2_LENGTH; - cur++; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + for(i = 0; i < connssl->alpn->count; ++i) { + alpn[i].data = (unsigned char *)connssl->alpn->entries[i]; + alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]); } -#endif - - protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; - protocols[cur].size = ALPN_HTTP_1_1_LENGTH; - cur++; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); - - if(gnutls_alpn_set_protocols(backend->gtls.session, protocols, cur, 0)) { + if(gnutls_alpn_set_protocols(backend->gtls.session, alpn, + (unsigned)connssl->alpn->count, 0)) { failf(data, "failed setting ALPN"); return CURLE_SSL_CONNECT_ERROR; } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } /* This might be a reconnect, so we check for a session ID in the cache @@ -860,10 +848,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, config->verifyhost || config->issuercert) { #ifdef USE_GNUTLS_SRP - if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP - && ssl_config->primary.username - && !config->verifypeer - && gnutls_cipher_get(session)) { + if(ssl_config->primary.username && !config->verifypeer && + gnutls_cipher_get(session)) { /* no peer cert, but auth is ok if we have SRP user and cipher and no peer verify */ } @@ -1271,28 +1257,10 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, int rc; rc = gnutls_alpn_get_selected_protocol(session, &proto); - if(rc == 0) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, proto.size, - proto.data); - -#ifdef USE_HTTP2 - if(proto.size == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, proto.data, - ALPN_H2_LENGTH)) { - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(proto.size == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - } + if(rc == 0) + Curl_alpn_set_negotiated(cf, data, proto.data, proto.size); else - infof(data, VTLS_INFOF_NO_ALPN); - - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + Curl_alpn_set_negotiated(cf, data, NULL, 0); } if(ssl_config->primary.sessionid) { @@ -1516,7 +1484,7 @@ static int gtls_shutdown(struct Curl_cfilter *cf, char buf[120]; while(!done) { - int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], + int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close @@ -1556,8 +1524,7 @@ static int gtls_shutdown(struct Curl_cfilter *cf, gnutls_certificate_free_credentials(backend->gtls.cred); #ifdef USE_GNUTLS_SRP - if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP - && ssl_config->primary.username != NULL) + if(ssl_config->primary.username) gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred); #endif diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h index 49c1c47637..ac141e1c61 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.h +++ b/Utilities/cmcurl/lib/vtls/gtls.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/hostcheck.c b/Utilities/cmcurl/lib/vtls/hostcheck.c index 2a648f20a9..e827dc58f3 100644 --- a/Utilities/cmcurl/lib/vtls/hostcheck.c +++ b/Utilities/cmcurl/lib/vtls/hostcheck.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 diff --git a/Utilities/cmcurl/lib/vtls/hostcheck.h b/Utilities/cmcurl/lib/vtls/hostcheck.h index d3c4eab56d..22a1ac2e56 100644 --- a/Utilities/cmcurl/lib/vtls/hostcheck.h +++ b/Utilities/cmcurl/lib/vtls/hostcheck.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c index 1952a690ca..d37bb183e7 100644 --- a/Utilities/cmcurl/lib/vtls/keylog.c +++ b/Utilities/cmcurl/lib/vtls/keylog.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 diff --git a/Utilities/cmcurl/lib/vtls/keylog.h b/Utilities/cmcurl/lib/vtls/keylog.h index 5d3c675b3e..eff5bf38f3 100644 --- a/Utilities/cmcurl/lib/vtls/keylog.h +++ b/Utilities/cmcurl/lib/vtls/keylog.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index 0b81662b93..7f0f4e3668 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -159,15 +159,14 @@ static void mbed_debug(void *context, int level, const char *f_name, static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen) { struct Curl_cfilter *cf = bio; - struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result; DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result); - /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"), - blen, (int)nwritten, result)); */ + DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%zu) -> %zd, err=%d", + blen, nwritten, result)); if(nwritten < 0 && CURLE_AGAIN == result) { nwritten = MBEDTLS_ERR_SSL_WANT_WRITE; } @@ -177,8 +176,7 @@ static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen) static int bio_cf_read(void *bio, unsigned char *buf, size_t blen) { struct Curl_cfilter *cf = bio; - struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result; @@ -188,8 +186,8 @@ static int bio_cf_read(void *bio, unsigned char *buf, size_t blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result); - /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"), - blen, (int)nread, result)); */ + DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%zu) -> %zd, err=%d", + blen, nread, result)); if(nread < 0 && CURLE_AGAIN == result) { nread = MBEDTLS_ERR_SSL_WANT_READ; } @@ -648,14 +646,13 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } #ifdef HAS_ALPN - if(cf->conn->bits.tls_enable_alpn) { - const char **p = &backend->protocols[0]; -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2) - *p++ = ALPN_H2; -#endif - *p++ = ALPN_HTTP_1_1; - *p = NULL; + if(connssl->alpn) { + struct alpn_proto_buf proto; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + backend->protocols[i] = connssl->alpn->entries[i]; + } /* this function doesn't clone the protocols array, which is why we need to keep it around */ if(mbedtls_ssl_conf_alpn_protocols(&backend->config, @@ -663,8 +660,8 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) failf(data, "Failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } - for(p = &backend->protocols[0]; *p; ++p) - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, *p); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } #endif @@ -844,28 +841,11 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) } #ifdef HAS_ALPN - if(cf->conn->bits.tls_enable_alpn) { - const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl); + if(connssl->alpn) { + const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl); - if(next_protocol) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, next_protocol); -#ifdef USE_HTTP2 - if(!strncmp(next_protocol, ALPN_H2, ALPN_H2_LENGTH) && - !next_protocol[ALPN_H2_LENGTH]) { - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && - !next_protocol[ALPN_HTTP_1_1_LENGTH]) { - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - } - else { - infof(data, VTLS_INFOF_NO_ALPN); - } - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto, + proto? strlen(proto) : 0); } #endif @@ -1081,7 +1061,7 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, { CURLcode retcode; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); timediff_t timeout_ms; int what; diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.h b/Utilities/cmcurl/lib/vtls/mbedtls.h index ec3b43bf9c..d8a0a06eb6 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com> + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c index 7d019ede53..bcb7106a63 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h index 22e8725ab0..2b0bd41c8b 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com> + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index 03694d22ba..774cbdd7ba 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.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 @@ -873,11 +873,11 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) #endif case SSL_NEXT_PROTO_NO_SUPPORT: case SSL_NEXT_PROTO_NO_OVERLAP: - infof(data, VTLS_INFOF_NO_ALPN); + Curl_alpn_set_negotiated(cf, data, NULL, 0); return; #ifdef SSL_ENABLE_ALPN case SSL_NEXT_PROTO_SELECTED: - infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, buflen, buf); + Curl_alpn_set_negotiated(cf, data, buf, buflen); break; #endif default: @@ -885,25 +885,6 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) break; } -#ifdef USE_HTTP2 - if(buflen == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) { - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(buflen == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - - /* This callback might get called when PR_Recv() is used within - * close_one() during a connection shutdown. At that point there might not - * be any "bundle" associated with the connection anymore. - */ - if(conn->bundle) - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } } @@ -1897,7 +1878,7 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, PRFileDesc *nspr_io_stub = NULL; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); @@ -2163,27 +2144,17 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, #endif #if defined(SSL_ENABLE_ALPN) - if(cf->conn->bits.tls_enable_alpn) { - int cur = 0; - unsigned char protocols[128]; - -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 -#ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) -#endif - ) { - protocols[cur++] = ALPN_H2_LENGTH; - memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); - cur += ALPN_H2_LENGTH; - } -#endif - protocols[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; + if(connssl->alpn) { + struct alpn_proto_buf proto; - if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) + result = Curl_alpn_to_proto_buf(&proto, connssl->alpn); + if(result || SSL_SetNextProtoNego(backend->handle, proto.data, proto.len) + != SECSuccess) { + failf(data, "Error setting ALPN"); goto error; + } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } #endif @@ -2393,6 +2364,19 @@ static ssize_t nss_send(struct Curl_cfilter *cf, return rc; /* number of bytes */ } +static bool +nss_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) +{ + struct ssl_connect_data *connssl = cf->ctx; + PRFileDesc *fd = connssl->backend->handle->lower; + char buf; + + (void) data; + + /* Returns true in case of error to force reading. */ + return PR_Recv(fd, (void *) &buf, 1, PR_MSG_PEEK, PR_INTERVAL_NO_WAIT) != 0; +} + static ssize_t nss_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* transfer */ char *buf, /* store read data here */ @@ -2543,7 +2527,7 @@ const struct Curl_ssl Curl_ssl_nss = { nss_check_cxn, /* check_cxn */ /* NSS has no shutdown function provided and thus always fail */ Curl_none_shutdown, /* shutdown */ - Curl_none_data_pending, /* data_pending */ + nss_data_pending, /* data_pending */ nss_random, /* random */ nss_cert_status_request, /* cert_status_request */ nss_connect, /* connect */ diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h index 454a38f1fb..ad7eef5801 100644 --- a/Utilities/cmcurl/lib/vtls/nssg.h +++ b/Utilities/cmcurl/lib/vtls/nssg.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index c5085be3c3..e3a50bd6ef 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.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 @@ -96,6 +96,7 @@ #include "curl_memory.h" #include "memdebug.h" + /* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS renegotiations when built with BoringSSL. Renegotiating is non-compliant with HTTP/2 and "an extremely dangerous protocol feature". Beware. @@ -262,6 +263,12 @@ #define HAVE_OPENSSL_VERSION #endif +#ifdef OPENSSL_IS_BORINGSSL +typedef uint32_t sslerr_t; +#else +typedef unsigned long sslerr_t; +#endif + /* * Whether the OpenSSL version has the API needed to support sharing an * X509_STORE between connections. The API is: @@ -285,17 +292,17 @@ #endif /* !LIBRESSL_VERSION_NUMBER */ struct ssl_backend_data { - struct Curl_easy *logger; /* transfer handle to pass trace logs to, only - using sockindex 0 */ /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; + BIO_METHOD *bio_method; CURLcode io_result; /* result of last BIO cfilter operation */ #ifndef HAVE_KEYLOG_CALLBACK /* Set to true once a valid keylog entry has been created to avoid dupes. */ bool keylog_done; #endif + bool x509_store_setup; /* x509 store has been set up */ }; #if defined(HAVE_SSL_X509_STORE_SHARE) @@ -710,14 +717,14 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result = CURLE_SEND_ERROR; DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); - /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"), - blen, (int)nwritten, result)); */ + DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d", + blen, (int)nwritten, result)); BIO_clear_retry_flags(bio); connssl->backend->io_result = result; if(nwritten < 0) { @@ -731,7 +738,7 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result = CURLE_RECV_ERROR; @@ -741,64 +748,75 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); - /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"), - blen, (int)nread, result)); */ + DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d", + blen, (int)nread, result)); BIO_clear_retry_flags(bio); connssl->backend->io_result = result; if(nread < 0) { if(CURLE_AGAIN == result) BIO_set_retry_read(bio); } + + /* Before returning server replies to the SSL instance, we need + * to have setup the x509 store or verification will fail. */ + if(!connssl->backend->x509_store_setup) { + result = Curl_ssl_setup_x509_store(cf, data, connssl->backend->ctx); + if(result) { + connssl->backend->io_result = result; + return -1; + } + connssl->backend->x509_store_setup = TRUE; + } + return (int)nread; } -static BIO_METHOD *bio_cf_method = NULL; - #if USE_PRE_1_1_API static BIO_METHOD bio_cf_meth_1_0 = { - BIO_TYPE_MEM, - "OpenSSL CF BIO", - bio_cf_out_write, - bio_cf_in_read, - NULL, /* puts is never called */ - NULL, /* gets is never called */ - bio_cf_ctrl, - bio_cf_create, - bio_cf_destroy, - NULL + BIO_TYPE_MEM, + "OpenSSL CF BIO", + bio_cf_out_write, + bio_cf_in_read, + NULL, /* puts is never called */ + NULL, /* gets is never called */ + bio_cf_ctrl, + bio_cf_create, + bio_cf_destroy, + NULL }; -static void bio_cf_init_methods(void) +static BIO_METHOD *bio_cf_method_create(void) { - bio_cf_method = &bio_cf_meth_1_0; + return &bio_cf_meth_1_0; } -#define bio_cf_free_methods() Curl_nop_stmt +#define bio_cf_method_free(m) Curl_nop_stmt #else -static void bio_cf_init_methods(void) +static BIO_METHOD *bio_cf_method_create(void) { - bio_cf_method = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO"); - BIO_meth_set_write(bio_cf_method, &bio_cf_out_write); - BIO_meth_set_read(bio_cf_method, &bio_cf_in_read); - BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl); - BIO_meth_set_create(bio_cf_method, &bio_cf_create); - BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy); + BIO_METHOD *m = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO"); + if(m) { + BIO_meth_set_write(m, &bio_cf_out_write); + BIO_meth_set_read(m, &bio_cf_in_read); + BIO_meth_set_ctrl(m, &bio_cf_ctrl); + BIO_meth_set_create(m, &bio_cf_create); + BIO_meth_set_destroy(m, &bio_cf_destroy); + } + return m; } -static void bio_cf_free_methods(void) +static void bio_cf_method_free(BIO_METHOD *m) { - BIO_meth_free(bio_cf_method); + if(m) + BIO_meth_free(m); } #endif -static bool ossl_attach_data(struct Curl_cfilter *cf, - struct Curl_easy *data); - /* * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have @@ -930,54 +948,6 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) return buf; } -/* Return an extra data index for the transfer data. - * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). - */ -static int ossl_get_ssl_data_index(void) -{ - static int ssl_ex_data_data_index = -1; - if(ssl_ex_data_data_index < 0) { - ssl_ex_data_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - } - return ssl_ex_data_data_index; -} - -/* Return an extra data index for the associated Curl_cfilter instance. - * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). - */ -static int ossl_get_ssl_cf_index(void) -{ - static int ssl_ex_data_cf_index = -1; - if(ssl_ex_data_cf_index < 0) { - ssl_ex_data_cf_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - } - return ssl_ex_data_cf_index; -} - -/* Return an extra data index for the sockindex. - * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). - */ -static int ossl_get_ssl_sockindex_index(void) -{ - static int sockindex_index = -1; - if(sockindex_index < 0) { - sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - } - return sockindex_index; -} - -/* Return an extra data index for proxy boolean. - * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). - */ -static int ossl_get_proxy_index(void) -{ - static int proxy_index = -1; - if(proxy_index < 0) { - proxy_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - } - return proxy_index; -} - static int passwd_callback(char *buf, int num, int encrypting, void *global_passwd) { @@ -1254,7 +1224,7 @@ SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob, if(ret) { X509 *ca; - unsigned long err; + sslerr_t err; if(!SSL_CTX_clear_chain_certs(ctx)) { ret = 0; @@ -1776,14 +1746,8 @@ static int ossl_init(void) OpenSSL_add_all_algorithms(); #endif - bio_cf_init_methods(); Curl_tls_keylog_open(); - /* Initialize the extra data indexes */ - if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_cf_index() < 0 || - ossl_get_ssl_sockindex_index() < 0 || ossl_get_proxy_index() < 0) - return 0; - return 1; } @@ -1822,7 +1786,6 @@ static void ossl_cleanup(void) #endif Curl_tls_keylog_close(); - bio_cf_free_methods(); } /* @@ -1840,7 +1803,10 @@ static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data) #ifdef MSG_PEEK char buf; ssize_t nread; - nread = recv((RECV_TYPE_ARG1)cf->conn->sock[cf->sockindex], + curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); + if(sock == CURL_SOCKET_BAD) + return 0; /* no socket, consider closed */ + nread = recv((RECV_TYPE_ARG1)sock, (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); if(nread == 0) @@ -1968,19 +1934,15 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data) return list; } -#define set_logger(connssl, data) \ - connssl->backend->logger = data - static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; + (void)data; DEBUGASSERT(backend); if(backend->handle) { - set_logger(connssl, data); - if(cf->next && cf->next->connected) { char buf[32]; /* Maybe the server has already sent a close notify alert. @@ -1997,6 +1959,11 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) if(backend->ctx) { SSL_CTX_free(backend->ctx); backend->ctx = NULL; + backend->x509_store_setup = FALSE; + } + if(backend->bio_method) { + bio_cf_method_free(backend->bio_method); + backend->bio_method = NULL; } } @@ -2034,7 +2001,7 @@ static int ossl_shutdown(struct Curl_cfilter *cf, if(backend->handle) { buffsize = (int)sizeof(buf); while(!done && loop--) { - int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], + int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); @@ -2163,6 +2130,22 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, return FALSE; } +static CURLcode +ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert, const char *hostname, + const char *dispname); + +CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert) +{ + const char *hostname, *dispname; + int port; + + (void)conn; + Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port); + return ossl_verifyhost(data, conn, server_cert, hostname, dispname); +} + /* Quote from RFC2818 section 3.1 "Server Identity" If a subjectAltName extension of type dNSName is present, that MUST @@ -2185,8 +2168,10 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, This function is now used from ngtcp2 (QUIC) as well. */ -CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, - X509 *server_cert) +static CURLcode +ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, + X509 *server_cert, const char *hostname, + const char *dispname) { bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ @@ -2200,12 +2185,9 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ - const char *hostname, *dispname; - int port; size_t hostlen; (void)conn; - Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port); hostlen = strlen(hostname); #ifndef ENABLE_IPV6 @@ -2668,24 +2650,15 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, const void *buf, size_t len, SSL *ssl, void *userp) { - char unknown[32]; - const char *verstr = NULL; - struct connectdata *conn = userp; - int cf_idx = ossl_get_ssl_cf_index(); - struct ssl_connect_data *connssl; + const char *verstr = "???"; + struct Curl_cfilter *cf = userp; struct Curl_easy *data = NULL; - struct Curl_cfilter *cf; - - DEBUGASSERT(cf_idx >= 0); - cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx); - DEBUGASSERT(cf); - connssl = cf->ctx; - DEBUGASSERT(connssl); - DEBUGASSERT(connssl->backend); - data = connssl->backend->logger; + char unknown[32]; - if(!conn || !data || !data->set.fdebug || - (direction != 0 && direction != 1)) + if(!cf) + return; + data = CF_DATA_CURRENT(cf); + if(!data || !data->set.fdebug || (direction && direction != 1)) return; switch(ssl_ver) { @@ -2730,6 +2703,9 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, * For TLS 1.3, skip notification of the decrypted inner Content-Type. */ if(ssl_ver +#ifdef SSL3_RT_HEADER + && content_type != SSL3_RT_HEADER +#endif #ifdef SSL3_RT_INNER_CONTENT_TYPE && content_type != SSL3_RT_INNER_CONTENT_TYPE #endif @@ -2765,7 +2741,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, } txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), - CFMSG(cf, "%s (%s), %s, %s (%d):\n"), + "%s (%s), %s, %s (%d):\n", verstr, direction?"OUT":"IN", tls_rt_name, msg_name, msg_type); if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) { @@ -2983,21 +2959,14 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) struct Curl_easy *data; struct Curl_cfilter *cf; const struct ssl_config_data *config; - curl_socket_t *sockindex_ptr; - int data_idx = ossl_get_ssl_data_index(); - int cf_idx = ossl_get_ssl_cf_index(); - int sockindex_idx = ossl_get_ssl_sockindex_index(); - int proxy_idx = ossl_get_proxy_index(); + struct ssl_connect_data *connssl; bool isproxy; - if(data_idx < 0 || cf_idx < 0 || sockindex_idx < 0 || proxy_idx < 0) - return 0; - - cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx); - data = (struct Curl_easy *) SSL_get_ex_data(ssl, data_idx); + cf = (struct Curl_cfilter*) SSL_get_app_data(ssl); + connssl = cf? cf->ctx : NULL; + data = connssl? CF_DATA_CURRENT(cf) : NULL; /* The sockindex has been stored as a pointer to an array element */ - sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx); - if(!cf || !data || !sockindex_ptr) + if(!cf || !data) return 0; isproxy = Curl_ssl_cf_is_proxy(cf); @@ -3091,7 +3060,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store, BIO_free(cbio); /* if we didn't end up importing anything, treat that as an error */ - return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE); + return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE; } static CURLcode populate_x509_store(struct Curl_cfilter *cf, @@ -3110,206 +3079,219 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, const char * const ssl_crlfile = ssl_config->primary.CRLfile; const bool verifypeer = conn_config->verifypeer; bool imported_native_ca = false; + bool imported_ca_info_blob = false; if(!store) return CURLE_OUT_OF_MEMORY; + if(verifypeer) { #if defined(USE_WIN32_CRYPTO) - /* Import certificates from the Windows root certificate store if requested. - https://stackoverflow.com/questions/9507184/ - https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 - https://datatracker.ietf.org/doc/html/rfc5280 */ - if((conn_config->verifypeer || conn_config->verifyhost) && - (ssl_config->native_ca_store)) { - HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); - - if(hStore) { - PCCERT_CONTEXT pContext = NULL; - /* The array of enhanced key usage OIDs will vary per certificate and is - declared outside of the loop so that rather than malloc/free each - iteration we can grow it with realloc, when necessary. */ - CERT_ENHKEY_USAGE *enhkey_usage = NULL; - DWORD enhkey_usage_size = 0; - - /* This loop makes a best effort to import all valid certificates from - the MS root store. If a certificate cannot be imported it is skipped. - 'result' is used to store only hard-fail conditions (such as out of - memory) that cause an early break. */ - result = CURLE_OK; - for(;;) { - X509 *x509; - FILETIME now; - BYTE key_usage[2]; - DWORD req_size; - const unsigned char *encoded_cert; + /* Import certificates from the Windows root certificate store if + requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://datatracker.ietf.org/doc/html/rfc5280 */ + if(ssl_config->native_ca_store) { + HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and + is declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is + skipped. 'result' is used to store only hard-fail conditions (such + as out of memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - char cert_name[256]; + char cert_name[256]; #endif - pContext = CertEnumCertificatesInStore(hStore, pContext); - if(!pContext) - break; + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, - NULL, cert_name, sizeof(cert_name))) { - strcpy(cert_name, "Unknown"); - } - infof(data, "SSL: Checking cert \"%s\"", cert_name); + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"", cert_name); #endif + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; - encoded_cert = (const unsigned char *)pContext->pbCertEncoded; - if(!encoded_cert) - continue; - - GetSystemTimeAsFileTime(&now); - if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || - CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) - continue; - - /* If key usage exists check for signing attribute */ - if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, - pContext->pCertInfo, - key_usage, sizeof(key_usage))) { - if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) continue; - } - else if(GetLastError()) - continue; - - /* If enhanced key usage exists check for server auth attribute. - * - * Note "In a Microsoft environment, a certificate might also have EKU - * extended properties that specify valid uses for the certificate." - * The call below checks both, and behavior varies depending on what is - * found. For more details see CertGetEnhancedKeyUsage doc. - */ - if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { - if(req_size && req_size > enhkey_usage_size) { - void *tmp = realloc(enhkey_usage, req_size); - - if(!tmp) { - failf(data, "SSL: Out of memory allocating for OID list"); - result = CURLE_OUT_OF_MEMORY; - break; - } - enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; - enhkey_usage_size = req_size; + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; } + else if(GetLastError()) + continue; - if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { - if(!enhkey_usage->cUsageIdentifier) { - /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is - good for all uses. If it returns zero, the certificate has no - valid uses." */ - if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) - continue; + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have + * EKU extended properties that specify valid uses for the + * certificate." The call below checks both, and behavior varies + * depending on what is found. For more details see + * CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; } - else { - DWORD i; - bool found = false; - - for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { - if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, - enhkey_usage->rgpszUsageIdentifier[i])) { - found = true; - break; - } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate + is good for all uses. If it returns zero, the certificate + has no valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } - if(!found) - continue; + if(!found) + continue; + } } + else + continue; } else continue; - } - else - continue; - x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); - if(!x509) - continue; + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; - /* Try to import the certificate. This may fail for legitimate reasons - such as duplicate certificate, which is allowed by MS but not - OpenSSL. */ - if(X509_STORE_add_cert(store, x509) == 1) { + /* Try to import the certificate. This may fail for legitimate + reasons such as duplicate certificate, which is allowed by MS but + not OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - infof(data, "SSL: Imported cert \"%s\"", cert_name); + infof(data, "SSL: Imported cert \"%s\"", cert_name); #endif - imported_native_ca = true; + imported_native_ca = true; + } + X509_free(x509); } - X509_free(x509); - } - free(enhkey_usage); - CertFreeCertificateContext(pContext); - CertCloseStore(hStore, 0); + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); - if(result) - return result; + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported Windows CA store"); + else + infof(data, "error importing Windows CA store, continuing anyway"); } - if(imported_native_ca) - infof(data, "successfully imported Windows CA store"); - else - infof(data, "error importing Windows CA store, continuing anyway"); - } #endif - - if(ca_info_blob) { - result = load_cacert_from_memory(store, ca_info_blob); - if(result) { - if(result == CURLE_OUT_OF_MEMORY || - (verifypeer && !imported_native_ca)) { + if(ca_info_blob) { + result = load_cacert_from_memory(store, ca_info_blob); + if(result) { failf(data, "error importing CA certificate blob"); return result; } - /* Only warn if no certificate verification is required. */ - infof(data, "error importing CA certificate blob, continuing anyway"); + else { + imported_ca_info_blob = true; + infof(data, "successfully imported CA certificate blob"); + } } - } - if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) { + if(ssl_cafile || ssl_capath) { #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ - if(ssl_cafile && - !X509_STORE_load_file(store, ssl_cafile)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate file: %s", ssl_cafile); - return CURLE_SSL_CACERT_BADFILE; - } - if(ssl_capath && - !X509_STORE_load_path(store, ssl_capath)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate path: %s", ssl_capath); - return CURLE_SSL_CACERT_BADFILE; - } + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "error setting certificate file, continuing anyway"); + } + if(ssl_capath && !X509_STORE_load_path(store, ssl_capath)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "error setting certificate path, continuing anyway"); + } #else - /* tell OpenSSL where to find CA certificates that are used to verify the - server's certificate. */ - if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ + if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) { + if(!imported_native_ca && !imported_ca_info_blob) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + infof(data, "error setting certificate verify locations," + " continuing anyway"); + } + } #endif - infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); - } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } #ifdef CURL_CA_FALLBACK - if(verifypeer && - !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { - /* verifying the peer without any CA certificates won't - work so use openssl's built-in default as fallback */ - X509_STORE_set_default_paths(store); - } + if(!ssl_cafile && !ssl_capath && + !imported_native_ca && !imported_ca_info_blob) { + /* verifying the peer without any CA certificates won't + work so use openssl's built-in default as fallback */ + X509_STORE_set_default_paths(store); + } #endif + } if(ssl_crlfile) { /* tell OpenSSL where to find CRL file that is used to check certificate @@ -3440,9 +3422,9 @@ static void set_cached_x509_store(struct Curl_cfilter *cf, } } -static CURLcode set_up_x509_store(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ssl_backend_data *backend) +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); @@ -3462,10 +3444,10 @@ static CURLcode set_up_x509_store(struct Curl_cfilter *cf, cached_store = get_cached_x509_store(cf, data); if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) { - SSL_CTX_set_cert_store(backend->ctx, cached_store); + SSL_CTX_set_cert_store(ssl_ctx, cached_store); } else { - X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); result = populate_x509_store(cf, data, store); if(result == CURLE_OK && cache_criteria_met) { @@ -3476,11 +3458,11 @@ static CURLcode set_up_x509_store(struct Curl_cfilter *cf, return result; } #else /* HAVE_SSL_X509_STORE_SHARE */ -static CURLcode set_up_x509_store(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ssl_backend_data *backend) +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx) { - X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); return populate_x509_store(cf, data, store); } @@ -3510,9 +3492,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, #endif #endif const long int ssl_version = conn_config->version; -#ifdef USE_OPENSSL_SRP - const enum CURL_TLSAUTH ssl_authtype = ssl_config->primary.authtype; -#endif char * const ssl_cert = ssl_config->primary.clientcert; const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; const char * const ssl_cert_type = ssl_config->cert_type; @@ -3580,8 +3559,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, if(data->set.fdebug && data->set.verbose) { /* the SSL trace callback is only used for verbose logging */ SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); - SSL_CTX_set_msg_callback_arg(backend->ctx, cf->conn); - set_logger(connssl, data); + SSL_CTX_set_msg_callback_arg(backend->ctx, cf); } #endif @@ -3677,36 +3655,17 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, SSL_CTX_set_options(backend->ctx, ctx_options); #ifdef HAS_ALPN - if(cf->conn->bits.tls_enable_alpn) { - int cur = 0; - unsigned char protocols[128]; - -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 -#ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) -#endif - ) { - protocols[cur++] = ALPN_H2_LENGTH; - - memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); - cur += ALPN_H2_LENGTH; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); - } -#endif - - protocols[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + if(connssl->alpn) { + struct alpn_proto_buf proto; - /* expects length prefixed preference ordered list of protocols in wire - * format - */ - if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) { + result = Curl_alpn_to_proto_buf(&proto, connssl->alpn); + if(result || + SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) { failf(data, "Error setting ALPN"); return CURLE_SSL_CONNECT_ERROR; } + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } #endif @@ -3764,8 +3723,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, #endif #ifdef USE_OPENSSL_SRP - if((ssl_authtype == CURL_TLSAUTH_SRP) && - Curl_auth_allowed_to_host(data)) { + if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { char * const ssl_username = ssl_config->primary.username; char * const ssl_password = ssl_config->primary.password; infof(data, "Using TLS-SRP username: %s", ssl_username); @@ -3789,10 +3747,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif - result = set_up_x509_store(cf, data, backend); - if(result) - return result; - /* OpenSSL always tries to verify the peer, this only says whether it should * 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 @@ -3836,6 +3790,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, return CURLE_OUT_OF_MEMORY; } + SSL_set_app_data(backend->handle, cf); + #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(conn_config->verifystatus) @@ -3863,13 +3819,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif - if(!ossl_attach_data(cf, data)) { - /* Maybe the internal errors of SSL_get_ex_new_index or SSL_set_ex_data */ - failf(data, "SSL: ossl_attach_data failed: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return CURLE_SSL_CONNECT_ERROR; - } + SSL_set_app_data(backend->handle, cf); if(ssl_config->primary.sessionid) { Curl_ssl_sessionid_lock(data); @@ -3888,13 +3838,26 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, Curl_ssl_sessionid_unlock(data); } - bio = BIO_new(bio_cf_method); + backend->bio_method = bio_cf_method_create(); + if(!backend->bio_method) + return CURLE_OUT_OF_MEMORY; + bio = BIO_new(backend->bio_method); if(!bio) return CURLE_OUT_OF_MEMORY; BIO_set_data(bio, cf); +#ifdef HAVE_SSL_SET0_WBIO + /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works + * without backward compat quirks. Every call takes one reference, so we + * up it and pass. SSL* then owns it and will free. + * We check on the function in configure, since libressl and friends + * each have their own versions to add support for this. */ + BIO_up_ref(bio); + SSL_set0_rbio(backend->handle, bio); + SSL_set0_wbio(backend->handle, bio); +#else SSL_set_bio(backend->handle, bio, bio); - +#endif connssl->connecting_state = ssl_connect_2; return CURLE_OK; @@ -3915,6 +3878,16 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, ERR_clear_error(); err = SSL_connect(backend->handle); + + if(!backend->x509_store_setup) { + /* After having send off the ClientHello, we prepare the x509 + * store to verify the coming certificate from the server */ + CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx); + if(result) + return result; + backend->x509_store_setup = TRUE; + } + #ifndef HAVE_KEYLOG_CALLBACK if(Curl_tls_keylog_enabled()) { /* If key logging is enabled, wait for the handshake to complete and then @@ -3949,7 +3922,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, } else { /* untreated error */ - unsigned long errdetail; + sslerr_t errdetail; char error_buffer[256]=""; CURLcode result; long lerr; @@ -4043,26 +4016,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, const unsigned char *neg_protocol; unsigned int len; SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len); - if(len) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, len, neg_protocol); - -#ifdef USE_HTTP2 - if(len == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, neg_protocol, len)) { - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(len == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - } - else - infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + return Curl_alpn_set_negotiated(cf, data, neg_protocol, len); } #endif @@ -4205,7 +4160,8 @@ static CURLcode servercert(struct Curl_cfilter *cf, BIO_free(mem); if(conn_config->verifyhost) { - result = Curl_ossl_verifyhost(data, conn, backend->server_cert); + result = ossl_verifyhost(data, conn, backend->server_cert, + connssl->hostname, connssl->dispname); if(result) { X509_free(backend->server_cert); backend->server_cert = NULL; @@ -4379,7 +4335,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, { CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); int what; /* check if the connection has already been established */ @@ -4418,8 +4374,9 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, } /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing) { + if(!nonblocking && + (connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing)) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; @@ -4427,7 +4384,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking?0:timeout_ms); + timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -4435,11 +4392,6 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, goto out; } if(0 == what) { - if(nonblocking) { - *done = FALSE; - result = CURLE_OK; - goto out; - } /* timeout */ failf(data, "SSL connection timeout"); result = CURLE_OPERATION_TIMEDOUT; @@ -4527,7 +4479,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, 'size_t' */ int err; char error_buffer[256]; - unsigned long sslerror; + sslerr_t sslerror; int memlen; int rc; struct ssl_connect_data *connssl = cf->ctx; @@ -4539,7 +4491,6 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, ERR_clear_error(); memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - set_logger(connssl, data); rc = SSL_write(backend->handle, mem, memlen); if(rc <= 0) { @@ -4636,7 +4587,6 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf, ERR_clear_error(); buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - set_logger(connssl, data); nread = (ssize_t)SSL_read(backend->handle, buf, buffsize); if(nread <= 0) { @@ -4854,89 +4804,6 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl, (void *)backend->ctx : (void *)backend->handle; } -static bool ossl_attach_data(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; - const struct ssl_config_data *config; - - DEBUGASSERT(backend); - - /* If we don't have SSL context, do nothing. */ - if(!backend->handle) - return FALSE; - - config = Curl_ssl_cf_get_config(cf, data); - if(config->primary.sessionid) { - int data_idx = ossl_get_ssl_data_index(); - int cf_idx = ossl_get_ssl_cf_index(); - int sockindex_idx = ossl_get_ssl_sockindex_index(); - int proxy_idx = ossl_get_proxy_index(); - - if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 && - proxy_idx >= 0) { - int data_status, cf_status, sockindex_status, proxy_status; - - /* Store the data needed for the "new session" callback. - * The sockindex is stored as a pointer to an array element. */ - data_status = SSL_set_ex_data(backend->handle, data_idx, data); - cf_status = SSL_set_ex_data(backend->handle, cf_idx, cf); - sockindex_status = SSL_set_ex_data(backend->handle, sockindex_idx, - cf->conn->sock + cf->sockindex); -#ifndef CURL_DISABLE_PROXY - proxy_status = SSL_set_ex_data(backend->handle, proxy_idx, - Curl_ssl_cf_is_proxy(cf)? - (void *) 1 : NULL); -#else - proxy_status = SSL_set_ex_data(backend->handle, proxy_idx, NULL); -#endif - if(data_status && cf_status && sockindex_status && proxy_status) - return TRUE; - } - return FALSE; - } - return TRUE; -} - -/* - * Starting with TLS 1.3, the ossl_new_session_cb callback gets called after - * the handshake. If the transfer that sets up the callback gets killed before - * this callback arrives, we must make sure to properly clear the data to - * avoid UAF problems. A future optimization could be to instead store another - * transfer that might still be using the same connection. - */ - -static void ossl_detach_data(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; - DEBUGASSERT(backend); - - /* If we don't have SSL context, do nothing. */ - if(!backend->handle) - return; - - if(ssl_config->primary.sessionid) { - int data_idx = ossl_get_ssl_data_index(); - int cf_idx = ossl_get_ssl_cf_index(); - int sockindex_idx = ossl_get_ssl_sockindex_index(); - int proxy_idx = ossl_get_proxy_index(); - - if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 && - proxy_idx >= 0) { - /* Disable references to data in "new session" callback to avoid - * accessing a stale pointer. */ - SSL_set_ex_data(backend->handle, data_idx, NULL); - SSL_set_ex_data(backend->handle, cf_idx, NULL); - SSL_set_ex_data(backend->handle, sockindex_idx, NULL); - SSL_set_ex_data(backend->handle, proxy_idx, NULL); - } - } -} - static void ossl_free_multi_ssl_backend_data( struct multi_ssl_backend_data *mbackend) { @@ -4990,8 +4857,8 @@ const struct Curl_ssl Curl_ssl_openssl = { #else NULL, /* sha256sum */ #endif - ossl_attach_data, /* use of data in this connection */ - ossl_detach_data, /* remote of data from this connection */ + NULL, /* use of data in this connection */ + NULL, /* remote of data from this connection */ ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */ ossl_recv, /* recv decrypted data */ ossl_send, /* send data to encrypt */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h index 9df4ecddba..950faab889 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.h +++ b/Utilities/cmcurl/lib/vtls/openssl.h @@ -7,7 +7,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 @@ -56,5 +56,14 @@ CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl); +/** + * Setup the OpenSSL X509_STORE in `ssl_ctx` for the cfilter `cf` and + * easy handle `data`. Will allow reuse of a shared cache if suitable + * and configured. + */ +CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + SSL_CTX *ssl_ctx); + #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c index 27f4ec8d8c..003533dbb9 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.c +++ b/Utilities/cmcurl/lib/vtls/rustls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020 - 2022, Jacob Hoffman-Andrews, + * Copyright (C) Jacob Hoffman-Andrews, * <github@hoffman-andrews.com> * * This software is licensed as described in the file COPYING, which @@ -150,6 +150,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, size_t plain_bytes_copied = 0; rustls_result rresult = 0; char errorbuf[255]; + size_t errorlen; rustls_io_result io_error; DEBUGASSERT(backend); @@ -161,7 +162,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, io_error = rustls_connection_read_tls(rconn, read_cb, &io_ctx, &tls_bytes_read); if(io_error == EAGAIN || io_error == EWOULDBLOCK) { - infof(data, CFMSG(cf, "cr_recv: EAGAIN or EWOULDBLOCK")); + DEBUGF(LOG_CF(data, cf, "cr_recv: EAGAIN or EWOULDBLOCK")); } else if(io_error) { char buffer[STRERROR_LEN]; @@ -171,12 +172,13 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, return -1; } - infof(data, CFMSG(cf, "cr_recv: read %ld TLS bytes"), tls_bytes_read); + DEBUGF(LOG_CF(data, cf, "cr_recv: read %ld TLS bytes", tls_bytes_read)); rresult = rustls_connection_process_new_packets(rconn); if(rresult != RUSTLS_RESULT_OK) { - rustls_error(rresult, errorbuf, sizeof(errorbuf), &n); - failf(data, "%.*s", n, errorbuf); + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_process_new_packets: %.*s", + errorlen, errorbuf); *err = map_error(rresult); return -1; } @@ -189,14 +191,21 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, plainlen - plain_bytes_copied, &n); if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { - infof(data, CFMSG(cf, "cr_recv: got PLAINTEXT_EMPTY. " - "will try again later.")); + DEBUGF(LOG_CF(data, cf, "cr_recv: got PLAINTEXT_EMPTY. " + "will try again later.")); backend->data_pending = FALSE; break; } + else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) { + failf(data, "rustls: peer closed TCP connection " + "without first closing TLS connection"); + *err = CURLE_READ_ERROR; + return -1; + } else if(rresult != RUSTLS_RESULT_OK) { /* n always equals 0 in this case, don't need to check it */ - failf(data, "error in rustls_connection_read: %d", rresult); + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_read: %.*s", errorlen, errorbuf); *err = CURLE_READ_ERROR; return -1; } @@ -207,7 +216,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, break; } else { - infof(data, CFMSG(cf, "cr_recv: got %ld plain bytes"), n); + DEBUGF(LOG_CF(data, cf, "cr_recv: got %ld plain bytes", n)); plain_bytes_copied += n; } } @@ -254,22 +263,25 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, size_t tlswritten_total = 0; rustls_result rresult; rustls_io_result io_error; + char errorbuf[256]; + size_t errorlen; DEBUGASSERT(backend); rconn = backend->conn; - infof(data, CFMSG(cf, "cr_send: %ld plain bytes"), plainlen); + DEBUGF(LOG_CF(data, cf, "cr_send: %ld plain bytes", plainlen)); if(plainlen > 0) { rresult = rustls_connection_write(rconn, plainbuf, plainlen, &plainwritten); if(rresult != RUSTLS_RESULT_OK) { - failf(data, "error in rustls_connection_write"); + rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); + failf(data, "rustls_connection_write: %.*s", errorlen, errorbuf); *err = CURLE_WRITE_ERROR; return -1; } else if(plainwritten == 0) { - failf(data, "EOF in rustls_connection_write"); + failf(data, "rustls_connection_write: EOF"); *err = CURLE_WRITE_ERROR; return -1; } @@ -282,8 +294,8 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx, &tlswritten); if(io_error == EAGAIN || io_error == EWOULDBLOCK) { - infof(data, CFMSG(cf, "cr_send: EAGAIN after %ld bytes"), - tlswritten_total); + DEBUGF(LOG_CF(data, cf, "cr_send: EAGAIN after %zu bytes", + tlswritten_total)); *err = CURLE_AGAIN; return -1; } @@ -299,7 +311,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, *err = CURLE_WRITE_ERROR; return -1; } - infof(data, CFMSG(cf, "cr_send: wrote %ld TLS bytes"), tlswritten); + DEBUGF(LOG_CF(data, cf, "cr_send: wrote %zu TLS bytes", tlswritten)); tlswritten_total += tlswritten; } @@ -349,22 +361,25 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, char errorbuf[256]; size_t errorlen; int result; - rustls_slice_bytes alpn[2] = { - { (const uint8_t *)ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH }, - { (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH }, - }; DEBUGASSERT(backend); rconn = backend->conn; config_builder = rustls_client_config_builder_new(); -#ifdef USE_HTTP2 - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); - rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 2); -#else - rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1); -#endif - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + if(connssl->alpn) { + struct alpn_proto_buf proto; + rustls_slice_bytes alpn[ALPN_ENTRIES_MAX]; + size_t i; + + for(i = 0; i < connssl->alpn->count; ++i) { + alpn[i].data = (const uint8_t *)connssl->alpn->entries[i]; + alpn[i].len = strlen(connssl->alpn->entries[i]); + } + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, + connssl->alpn->count); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); + } if(!verifypeer) { rustls_client_config_builder_dangerous_set_certificate_verifier( config_builder, cr_verify_none); @@ -384,7 +399,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, result = rustls_root_cert_store_add_pem(roots, ca_info_blob->data, ca_info_blob->len, verifypeer); if(result != RUSTLS_RESULT_OK) { - failf(data, "failed to parse trusted certificates from blob"); + failf(data, "rustls: failed to parse trusted certificates from blob"); rustls_root_cert_store_free(roots); rustls_client_config_free( rustls_client_config_builder_build(config_builder)); @@ -394,7 +409,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, result = rustls_client_config_builder_use_roots(config_builder, roots); rustls_root_cert_store_free(roots); if(result != RUSTLS_RESULT_OK) { - failf(data, "failed to load trusted certificates"); + failf(data, "rustls: failed to load trusted certificates"); rustls_client_config_free( rustls_client_config_builder_build(config_builder)); return CURLE_SSL_CACERT_BADFILE; @@ -404,7 +419,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, result = rustls_client_config_builder_load_roots_from_file( config_builder, ssl_cafile); if(result != RUSTLS_RESULT_OK) { - failf(data, "failed to load trusted certificates"); + failf(data, "rustls: failed to load trusted certificates"); rustls_client_config_free( rustls_client_config_builder_build(config_builder)); return CURLE_SSL_CACERT_BADFILE; @@ -416,7 +431,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, { char *snihost = Curl_ssl_snihost(data, hostname, NULL); if(!snihost) { - failf(data, "Failed to set SNI"); + failf(data, "rustls: failed to get SNI"); return CURLE_SSL_CONNECT_ERROR; } result = rustls_client_connection_new(backend->config, snihost, &rconn); @@ -439,29 +454,7 @@ cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data, size_t len = 0; rustls_connection_get_alpn_protocol(rconn, &protocol, &len); - if(!protocol) { - infof(data, VTLS_INFOF_NO_ALPN); - return; - } - -#ifdef USE_HTTP2 - if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_H2); - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(len == ALPN_HTTP_1_1_LENGTH && - 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) { - infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_HTTP_1_1); - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - else { - infof(data, "ALPN, negotiated an unrecognized protocol"); - } - - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + Curl_alpn_set_negotiated(cf, data, protocol, len); } static CURLcode @@ -469,7 +462,7 @@ cr_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done) { struct ssl_connect_data *const connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); struct ssl_backend_data *const backend = connssl->backend; struct rustls_connection *rconn = NULL; CURLcode tmperr = CURLE_OK; @@ -573,7 +566,7 @@ cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *socks) { struct ssl_connect_data *const connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); struct ssl_backend_data *const backend = connssl->backend; struct rustls_connection *rconn = NULL; @@ -616,7 +609,7 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data) rustls_connection_send_close_notify(backend->conn); n = cr_send(cf, data, NULL, 0, &tmperr); if(n < 0) { - failf(data, "error sending close notify: %d", tmperr); + failf(data, "rustls: error sending close_notify: %d", tmperr); } rustls_connection_free(backend->conn); diff --git a/Utilities/cmcurl/lib/vtls/rustls.h b/Utilities/cmcurl/lib/vtls/rustls.h index 6b393dd639..bfbe23de3e 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.h +++ b/Utilities/cmcurl/lib/vtls/rustls.h @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020 - 2022, Jacob Hoffman-Andrews, + * Copyright (C) Jacob Hoffman-Andrews, * <github@hoffman-andrews.com> * * This software is licensed as described in the file COPYING, which diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index 7eab9542af..452fa409a5 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -5,9 +5,9 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de> - * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com> + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Marc Hoersken, <info@marc-hoersken.de> + * Copyright (C) Mark Salisbury, <mark.salisbury@hp.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -1105,7 +1105,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ - backend->use_alpn = cf->conn->bits.tls_enable_alpn && + backend->use_alpn = connssl->alpn && !GetProcAddress(GetModuleHandle(TEXT("ntdll")), "wine_get_version") && curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, @@ -1196,6 +1196,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) int list_start_index = 0; unsigned int *extension_len = NULL; unsigned short* list_len = NULL; + struct alpn_proto_buf proto; /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the buffer. */ @@ -1215,25 +1216,22 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) list_start_index = cur; -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2) { - alpn_buffer[cur++] = ALPN_H2_LENGTH; - memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH); - cur += ALPN_H2_LENGTH; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + result = Curl_alpn_to_proto_buf(&proto, connssl->alpn); + if(result) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; } -#endif - - alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; - memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - cur += ALPN_HTTP_1_1_LENGTH; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + memcpy(&alpn_buffer[cur], proto.data, proto.len); + cur += proto.len; *list_len = curlx_uitous(cur - list_start_index); *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } else { InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); @@ -1727,40 +1725,23 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - unsigned char alpn = 0; - - infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, - alpn_result.ProtocolIdSize, alpn_result.ProtocolId); + unsigned char prev_alpn = cf->conn->alpn; -#ifdef USE_HTTP2 - if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) { - alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, - ALPN_HTTP_1_1_LENGTH)) { - alpn = CURL_HTTP_VERSION_1_1; - } + Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId, + alpn_result.ProtocolIdSize); if(backend->recv_renegotiating) { - if(alpn != cf->conn->alpn) { + if(prev_alpn != cf->conn->alpn && + prev_alpn != CURL_HTTP_VERSION_NONE) { + /* Renegotiation selected a different protocol now, we cannot + * deal with this */ failf(data, "schannel: server selected an ALPN protocol too late"); return CURLE_SSL_CONNECT_ERROR; } } - else - cf->conn->alpn = alpn; } else { if(!backend->recv_renegotiating) - infof(data, VTLS_INFOF_NO_ALPN); - } - - if(!backend->recv_renegotiating) { - Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + Curl_alpn_set_negotiated(cf, data, NULL, 0); } } #endif @@ -1841,7 +1822,7 @@ schannel_connect_common(struct Curl_cfilter *cf, { CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); timediff_t timeout_ms; int what; @@ -2056,7 +2037,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, } else if(!timeout_ms) timeout_ms = TIMEDIFF_T_MAX; - what = SOCKET_WRITABLE(cf->conn->sock[cf->sockindex], timeout_ms); + what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h index 6d4235a96c..7fae39fa0a 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.h +++ b/Utilities/cmcurl/lib/vtls/schannel.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al. - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>, 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 @@ -179,8 +179,8 @@ struct ssl_backend_data { size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; /* encdata_is_incomplete: if encdata contains only a partial record that - can't be decrypted without another Curl_read_plain (that is, status is - SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes + can't be decrypted without another recv() (that is, status is + SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds more bytes into encdata then set this back to false. */ bool encdata_is_incomplete; unsigned long req_flags, ret_flags; diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c index e4992162e6..d75ee8dfe7 100644 --- a/Utilities/cmcurl/lib/vtls/schannel_verify.c +++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c @@ -5,9 +5,9 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de> - * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com> - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Marc Hoersken, <info@marc-hoersken.de> + * Copyright (C) Mark Salisbury, <mark.salisbury@hp.com> + * 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 diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index d903c53d10..2e98169e26 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>. + * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -137,14 +137,6 @@ #include "memdebug.h" -#define DEBUG_CF 0 - -#if DEBUG_CF -#define CF_DEBUGF(x) x -#else -#define CF_DEBUGF(x) do { } while(0) -#endif - /* From MacTypes.h (which we can't include because it isn't present in iOS: */ #define ioErr -36 #define paramErr -50 @@ -840,15 +832,15 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection, struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result; OSStatus rtn = noErr; DEBUGASSERT(data); nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result); - CF_DEBUGF(infof(data, CFMSG(cf, "bio_read(len=%zu) -> %zd, result=%d"), - *dataLength, nread, result)); + DEBUGF(LOG_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d", + *dataLength, nread, result)); if(nread < 0) { switch(result) { case CURLE_OK: @@ -876,15 +868,15 @@ static OSStatus bio_cf_out_write(SSLConnectionRef connection, struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; - struct Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result; OSStatus rtn = noErr; DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result); - CF_DEBUGF(infof(data, CFMSG(cf, "bio_send(len=%zu) -> %zd, result=%d"), - *dataLength, nwritten, result)); + DEBUGF(LOG_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d", + *dataLength, nwritten, result)); if(nwritten <= 0) { if(result == CURLE_AGAIN) { rtn = errSSLWouldBlock; @@ -1644,7 +1636,6 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, const bool verifypeer = conn_config->verifypeer; char * const ssl_cert = ssl_config->primary.clientcert; const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; - bool isproxy = Curl_ssl_cf_is_proxy(cf); #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1657,7 +1648,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, DEBUGASSERT(backend); - CF_DEBUGF(infof(data, CFMSG(cf, "connect_step1"))); + DEBUGF(LOG_CF(data, cf, "connect_step1")); GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); #endif /* CURL_BUILD_MAC */ @@ -1805,33 +1796,28 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 - if(cf->conn->bits.tls_enable_alpn) { + if(connssl->alpn) { if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { + struct alpn_proto_buf proto; + size_t i; + CFStringRef cstr; CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 -#ifndef CURL_DISABLE_PROXY - && (!isproxy || !cf->conn->bits.tunnel_proxy) -#endif - ) { - CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2)); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + for(i = 0; i < connssl->alpn->count; ++i) { + cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i], + kCFStringEncodingUTF8); + if(!cstr) + return CURLE_OUT_OF_MEMORY; + CFArrayAppendValue(alpnArr, cstr); + CFRelease(cstr); } -#endif - - CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1)); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); - - /* expects length prefixed preference ordered list of protocols in wire - * format - */ err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); if(err != noErr) infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d", err); CFRelease(alpnArr); + Curl_alpn_to_proto_str(&proto, connssl->alpn); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } } #endif @@ -2302,7 +2288,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf, /* This is not a PEM file, probably a certificate in DER format. */ rc = append_cert_to_array(data, certbuf, buflen, array); if(rc != CURLE_OK) { - CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed"))); + DEBUGF(LOG_CF(data, cf, "append_cert for CA failed")); result = rc; goto out; } @@ -2316,7 +2302,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf, rc = append_cert_to_array(data, der, derlen, array); free(der); if(rc != CURLE_OK) { - CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed"))); + DEBUGF(LOG_CF(data, cf, "append_cert for CA failed")); result = rc; goto out; } @@ -2332,7 +2318,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf, goto out; } - CF_DEBUGF(infof(data, CFMSG(cf, "setting %d trust anchors"), n)); + DEBUGF(LOG_CF(data, cf, "setting %d trust anchors", n)); ret = SecTrustSetAnchorCertificates(trust, array); if(ret != noErr) { failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret); @@ -2354,11 +2340,11 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf, switch(trust_eval) { case kSecTrustResultUnspecified: /* what does this really mean? */ - CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Unspecified"))); + DEBUGF(LOG_CF(data, cf, "trust result: Unspecified")); result = CURLE_OK; goto out; case kSecTrustResultProceed: - CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Proceed"))); + DEBUGF(LOG_CF(data, cf, "trust result: Proceed")); result = CURLE_OK; goto out; @@ -2391,7 +2377,7 @@ static CURLcode verify_cert(struct Curl_cfilter *cf, size_t buflen; if(ca_info_blob) { - CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from config blob"))); + DEBUGF(LOG_CF(data, cf, "verify_peer, CA from config blob")); certbuf = (unsigned char *)malloc(ca_info_blob->len + 1); if(!certbuf) { return CURLE_OUT_OF_MEMORY; @@ -2401,8 +2387,7 @@ static CURLcode verify_cert(struct Curl_cfilter *cf, certbuf[ca_info_blob->len]='\0'; } else if(cafile) { - CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from file '%s'"), - cafile)); + DEBUGF(LOG_CF(data, cf, "verify_peer, CA from file '%s'", cafile)); if(read_cert(cafile, &certbuf, &buflen) < 0) { failf(data, "SSL: failed to read or invalid CA certificate"); return CURLE_SSL_CACERT_BADFILE; @@ -2538,7 +2523,7 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf, || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); DEBUGASSERT(backend); - CF_DEBUGF(infof(data, CFMSG(cf, "connect_step2"))); + DEBUGF(LOG_CF(data, cf, "connect_step2")); /* Here goes nothing: */ check_handshake: @@ -3003,7 +2988,7 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf, { struct ssl_connect_data *connssl = cf->ctx; - CF_DEBUGF(infof(data, CFMSG(cf, "connect_step3"))); + DEBUGF(LOG_CF(data, cf, "connect_step3")); /* There is no step 3! * Well, okay, let's collect server certificates, and if verbose mode is on, * let's print the details of the server certificates. */ @@ -3022,7 +3007,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, { CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); int what; /* check if the connection has already been established */ @@ -3112,7 +3097,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, } if(ssl_connect_done == connssl->connecting_state) { - CF_DEBUGF(infof(data, CFMSG(cf, "connected"))); + DEBUGF(LOG_CF(data, cf, "connected")); connssl->state = ssl_connection_complete; *done = TRUE; } @@ -3158,7 +3143,7 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data) DEBUGASSERT(backend); if(backend->ssl_ctx) { - CF_DEBUGF(infof(data, CFMSG(cf, "close"))); + DEBUGF(LOG_CF(data, cf, "close")); (void)SSLClose(backend->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext) @@ -3200,9 +3185,10 @@ static int sectransp_shutdown(struct Curl_cfilter *cf, rc = 0; - what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), + SSL_SHUTDOWN_TIMEOUT); - CF_DEBUGF(infof(data, CFMSG(cf, "shutdown"))); + DEBUGF(LOG_CF(data, cf, "shutdown")); while(loop--) { if(what < 0) { /* anything that gets here is fatally bad */ @@ -3229,7 +3215,7 @@ static int sectransp_shutdown(struct Curl_cfilter *cf, if(nread <= 0) break; - what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0); + what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0); } return rc; @@ -3271,7 +3257,7 @@ static int sectransp_check_cxn(struct Curl_cfilter *cf, DEBUGASSERT(backend); if(backend->ssl_ctx) { - CF_DEBUGF(infof(data, CFMSG(cf, "check connection"))); + DEBUGF(LOG_CF(data, cf, "check connection")); err = SSLGetSessionState(backend->ssl_ctx, &state); if(err == noErr) return state == kSSLConnected || state == kSSLHandshake; @@ -3292,7 +3278,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf, DEBUGASSERT(backend); if(backend->ssl_ctx) { /* SSL is in use */ - CF_DEBUGF(infof(data, CFMSG(cf, "data_pending"))); + DEBUGF(LOG_CF((struct Curl_easy *)data, cf, "data_pending")); err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer); if(err == noErr) return buffer > 0UL; diff --git a/Utilities/cmcurl/lib/vtls/sectransp.h b/Utilities/cmcurl/lib/vtls/sectransp.h index 2d53b7c480..0f1085ad91 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.h +++ b/Utilities/cmcurl/lib/vtls/sectransp.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>. + * 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 diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 873ee6bac7..15f6844c7b 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.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 @@ -73,6 +73,7 @@ #include "curl_memory.h" #include "memdebug.h" + /* convenience macro to check if this handle is using a shared SSL session */ #define SSLSESSION_SHARED(data) (data->share && \ (data->share->specifier & \ @@ -150,7 +151,6 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, #ifdef USE_TLS_SRP !Curl_timestrcmp(data->username, needle->username) && !Curl_timestrcmp(data->password, needle->password) && - (data->authtype == needle->authtype) && #endif strcasecompare(data->cipher_list, needle->cipher_list) && strcasecompare(data->cipher_list13, needle->cipher_list13) && @@ -173,9 +173,6 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, dest->verifystatus = source->verifystatus; dest->sessionid = source->sessionid; dest->ssl_options = source->ssl_options; -#ifdef USE_TLS_SRP - dest->authtype = source->authtype; -#endif CLONE_BLOB(cert_blob); CLONE_BLOB(ca_info_blob); @@ -272,8 +269,8 @@ void Curl_ssl_cleanup(void) static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ - const long sslver = data->set.ssl.primary.version; - if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) { + const unsigned char sslver = data->set.ssl.primary.version; + if(sslver >= CURL_SSLVERSION_LAST) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } @@ -293,7 +290,8 @@ static bool ssl_prefs_check(struct Curl_easy *data) return TRUE; } -static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data) +static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, + const struct alpn_spec *alpn) { struct ssl_connect_data *ctx; @@ -302,6 +300,7 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data) if(!ctx) return NULL; + ctx->alpn = alpn; ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); if(!ctx->backend) { free(ctx); @@ -318,13 +317,6 @@ static void cf_ctx_free(struct ssl_connect_data *ctx) } } -static void cf_ctx_set_data(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - if(cf->ctx) - ((struct ssl_connect_data *)cf->ctx)->call_data = data; -} - static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; @@ -339,7 +331,6 @@ static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data) result = Curl_ssl->connect_blocking(cf, data); if(!result) { - Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */ DEBUGASSERT(connssl->state == ssl_connection_complete); } @@ -615,19 +606,20 @@ int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *socks) { struct ssl_connect_data *connssl = cf->ctx; + curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); - (void)data; - if(connssl->connecting_state == ssl_connect_2_writing) { - /* write mode */ - socks[0] = cf->conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); - } - if(connssl->connecting_state == ssl_connect_2_reading) { - /* read mode */ - socks[0] = cf->conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); + if(sock != CURL_SOCKET_BAD) { + if(connssl->connecting_state == ssl_connect_2_writing) { + /* write mode */ + socks[0] = sock; + return GETSOCK_WRITESOCK(0); + } + if(connssl->connecting_state == ssl_connect_2_reading) { + /* read mode */ + socks[0] = sock; + return GETSOCK_READSOCK(0); + } } - return GETSOCK_BLANK; } @@ -685,20 +677,6 @@ void Curl_ssl_version(char *buffer, size_t size) #endif } -/* - * This function tries to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn) -{ - struct Curl_cfilter *cf = Curl_ssl_cf_get_ssl(conn->cfilter[FIRSTSOCKET]); - return cf? Curl_ssl->check_cxn(cf, data) : -1; -} - void Curl_ssl_free_certinfo(struct Curl_easy *data) { struct curl_certinfo *ci = &data->info.certs; @@ -1430,53 +1408,80 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, #ifdef USE_SSL +static void free_hostname(struct ssl_connect_data *connssl) +{ + if(connssl->dispname != connssl->hostname) + free(connssl->dispname); + free(connssl->hostname); + connssl->hostname = connssl->dispname = NULL; +} + static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - /* TODO: close_one closes BOTH conn->ssl AND conn->proxy_ssl for this - * sockindex (if in use). Gladly, it is safe to call more than once. */ if(connssl) { Curl_ssl->close(cf, data); connssl->state = ssl_connection_none; + free_hostname(connssl); } cf->connected = FALSE; } -static void reinit_hostname(struct Curl_cfilter *cf) +static CURLcode reinit_hostname(struct Curl_cfilter *cf) { struct ssl_connect_data *connssl = cf->ctx; + const char *ehostname, *edispname; + int eport; + /* We need the hostname for SNI negotiation. Once handshaked, this + * remains the SNI hostname for the TLS connection. But when the + * connection is reused, the settings in cf->conn might change. + * So we keep a copy of the hostname we use for SNI. + */ #ifndef CURL_DISABLE_PROXY if(Curl_ssl_cf_is_proxy(cf)) { - /* TODO: there is not definition for a proxy setup on a secondary conn */ - connssl->hostname = cf->conn->http_proxy.host.name; - connssl->dispname = cf->conn->http_proxy.host.dispname; - connssl->port = cf->conn->http_proxy.port; + ehostname = cf->conn->http_proxy.host.name; + edispname = cf->conn->http_proxy.host.dispname; + eport = cf->conn->http_proxy.port; } else #endif { - /* TODO: secondaryhostname is set to the IP address we connect to - * in the FTP handler, it is assumed that host verification uses the - * hostname from FIRSTSOCKET */ - if(cf->sockindex == SECONDARYSOCKET && 0) { - connssl->hostname = cf->conn->secondaryhostname; - connssl->dispname = connssl->hostname; - connssl->port = cf->conn->secondary_port; + ehostname = cf->conn->host.name; + edispname = cf->conn->host.dispname; + eport = cf->conn->remote_port; + } + + /* change if ehostname changed */ + if(ehostname && (!connssl->hostname + || strcmp(ehostname, connssl->hostname))) { + free_hostname(connssl); + connssl->hostname = strdup(ehostname); + if(!connssl->hostname) { + free_hostname(connssl); + return CURLE_OUT_OF_MEMORY; } + if(!edispname || !strcmp(ehostname, edispname)) + connssl->dispname = connssl->hostname; else { - connssl->hostname = cf->conn->host.name; - connssl->dispname = cf->conn->host.dispname; - connssl->port = cf->conn->remote_port; + connssl->dispname = strdup(edispname); + if(!connssl->dispname) { + free_hostname(connssl); + return CURLE_OUT_OF_MEMORY; + } } } - DEBUGASSERT(connssl->hostname); + connssl->port = eport; + return CURLE_OK; } static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) { - cf_ctx_set_data(cf, data); + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); cf_close(cf, data); + CF_DATA_RESTORE(cf, save); cf_ctx_free(cf->ctx); cf->ctx = NULL; } @@ -1484,10 +1489,12 @@ static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) static void ssl_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) { - cf_ctx_set_data(cf, data); + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); cf_close(cf, data); cf->next->cft->close(cf->next, data); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); } static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, @@ -1495,6 +1502,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, bool blocking, bool *done) { struct ssl_connect_data *connssl = cf->ctx; + struct cf_call_data save; CURLcode result; if(cf->connected) { @@ -1502,7 +1510,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, return CURLE_OK; } - cf_ctx_set_data(cf, data); + CF_DATA_SAVE(save, cf, data); (void)connssl; DEBUGASSERT(data->conn); DEBUGASSERT(data->conn == cf->conn); @@ -1513,10 +1521,10 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, if(result || !*done) goto out; - /* TODO: right now we do not fully control when hostname is set, - * assign it on each connect call. */ - reinit_hostname(cf); *done = FALSE; + result = reinit_hostname(cf); + if(result) + goto out; if(blocking) { result = ssl_connect(cf, data); @@ -1528,26 +1536,26 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, if(!result && *done) { cf->connected = TRUE; - if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf)) - Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */ + connssl->handshake_done = Curl_now(); DEBUGASSERT(connssl->state == ssl_connection_complete); } out: - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); return result; } static bool ssl_cf_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { + struct cf_call_data save; bool result; - cf_ctx_set_data(cf, (struct Curl_easy *)data); - if(cf->ctx && Curl_ssl->data_pending(cf, data)) + CF_DATA_SAVE(save, cf, data); + if(Curl_ssl->data_pending(cf, data)) result = TRUE; else result = cf->next->cft->has_data_pending(cf->next, data); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); return result; } @@ -1555,12 +1563,13 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, CURLcode *err) { + struct cf_call_data save; ssize_t nwritten; + CF_DATA_SAVE(save, cf, data); *err = CURLE_OK; - cf_ctx_set_data(cf, data); nwritten = Curl_ssl->send_plain(cf, data, buf, len, err); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); return nwritten; } @@ -1568,12 +1577,13 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char *buf, size_t len, CURLcode *err) { + struct cf_call_data save; ssize_t nread; + CF_DATA_SAVE(save, cf, data); *err = CURLE_OK; - cf_ctx_set_data(cf, data); nread = Curl_ssl->recv_plain(cf, data, buf, len, err); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); return nread; } @@ -1581,39 +1591,72 @@ static int ssl_cf_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *socks) { + struct cf_call_data save; int result; - cf_ctx_set_data(cf, data); + CF_DATA_SAVE(save, cf, data); result = Curl_ssl->get_select_socks(cf, data, socks); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); return result; } -static void ssl_cf_attach_data(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { - if(Curl_ssl->attach_data) { - cf_ctx_set_data(cf, data); - Curl_ssl->attach_data(cf, data); - cf_ctx_set_data(cf, NULL); + struct ssl_connect_data *connssl = cf->ctx; + struct cf_call_data save; + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_CONN_REPORT_STATS: + if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf)) + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done); + break; + case CF_CTRL_DATA_ATTACH: + if(Curl_ssl->attach_data) { + CF_DATA_SAVE(save, cf, data); + Curl_ssl->attach_data(cf, data); + CF_DATA_RESTORE(cf, save); + } + break; + case CF_CTRL_DATA_DETACH: + if(Curl_ssl->detach_data) { + CF_DATA_SAVE(save, cf, data); + Curl_ssl->detach_data(cf, data); + CF_DATA_RESTORE(cf, save); + } + break; + default: + break; } + return CURLE_OK; } -static void ssl_cf_detach_data(struct Curl_cfilter *cf, - struct Curl_easy *data) +static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data) { - if(Curl_ssl->detach_data) { - cf_ctx_set_data(cf, data); - Curl_ssl->detach_data(cf, data); - cf_ctx_set_data(cf, NULL); - } + struct cf_call_data save; + bool result; + /* + * This function tries to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ + CF_DATA_SAVE(save, cf, data); + result = Curl_ssl->check_cxn(cf, data) != 0; + CF_DATA_RESTORE(cf, save); + return result; } -static const struct Curl_cftype cft_ssl = { +struct Curl_cftype Curl_cft_ssl = { "SSL", CF_TYPE_SSL, + CURL_LOG_DEFAULT, ssl_cf_destroy, - Curl_cf_def_setup, ssl_cf_connect, ssl_cf_close, Curl_cf_def_get_host, @@ -1621,15 +1664,17 @@ static const struct Curl_cftype cft_ssl = { ssl_cf_data_pending, ssl_cf_send, ssl_cf_recv, - ssl_cf_attach_data, - ssl_cf_detach_data, + ssl_cf_cntrl, + cf_ssl_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, }; -static const struct Curl_cftype cft_ssl_proxy = { +struct Curl_cftype Curl_cft_ssl_proxy = { "SSL-PROXY", CF_TYPE_SSL, + CURL_LOG_DEFAULT, ssl_cf_destroy, - Curl_cf_def_setup, ssl_cf_connect, ssl_cf_close, Curl_cf_def_get_host, @@ -1637,65 +1682,107 @@ static const struct Curl_cftype cft_ssl_proxy = { ssl_cf_data_pending, ssl_cf_send, ssl_cf_recv, - ssl_cf_attach_data, - ssl_cf_detach_data, + ssl_cf_cntrl, + cf_ssl_is_alive, + Curl_cf_def_conn_keep_alive, + Curl_cf_def_query, }; -CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn) { - struct Curl_cfilter *cf; + struct Curl_cfilter *cf = NULL; struct ssl_connect_data *ctx; CURLcode result; DEBUGASSERT(data->conn); - ctx = cf_ctx_new(data); + + ctx = cf_ctx_new(data, Curl_alpn_get_spec(data, conn)); if(!ctx) { result = CURLE_OUT_OF_MEMORY; goto out; } - result = Curl_cf_create(&cf, &cft_ssl, ctx); - if(result) - goto out; - - Curl_conn_cf_add(data, conn, sockindex, cf); - - result = CURLE_OK; + result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx); out: if(result) cf_ctx_free(ctx); + *pcf = result? NULL : cf; return result; } -#ifndef CURL_DISABLE_PROXY -CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) { struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_create(&cf, data, conn); + if(!result) + Curl_conn_cf_add(data, conn, sockindex, cf); + return result; +} + +CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_create(&cf, data, cf_at->conn); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); + return result; +} + +#ifndef CURL_DISABLE_PROXY +static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = NULL; struct ssl_connect_data *ctx; CURLcode result; - ctx = cf_ctx_new(data); + ctx = cf_ctx_new(data, Curl_alpn_get_proxy_spec(data, conn)); if(!ctx) { result = CURLE_OUT_OF_MEMORY; goto out; } + result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx); - result = Curl_cf_create(&cf, &cft_ssl_proxy, ctx); +out: if(result) - goto out; + cf_ctx_free(ctx); + *pcf = result? NULL : cf; + return result; +} - Curl_conn_cf_add(data, conn, sockindex, cf); +CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf; + CURLcode result; - result = CURLE_OK; + result = cf_ssl_proxy_create(&cf, data, conn); + if(!result) + Curl_conn_cf_add(data, conn, sockindex, cf); + return result; +} -out: - if(result) - cf_ctx_free(ctx); +CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf; + CURLcode result; + + result = cf_ssl_proxy_create(&cf, data, cf_at->conn); + if(!result) + Curl_conn_cf_insert_after(cf_at, cf); return result; } @@ -1717,9 +1804,10 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, /* get first filter in chain, if any is present */ cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]); if(cf) { - cf_ctx_set_data(cf, data); + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); result = Curl_ssl->get_internals(cf->ctx, info); - cf_ctx_set_data(cf, NULL); + CF_DATA_RESTORE(cf, save); } } return result; @@ -1733,7 +1821,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, (void)data; for(; cf; cf = cf->next) { - if(cf->cft == &cft_ssl) { + if(cf->cft == &Curl_cft_ssl) { if(Curl_ssl->shut_down(cf, data)) result = CURLE_SSL_SHUTDOWN_FAILED; Curl_conn_cf_discard(cf, data); @@ -1749,7 +1837,7 @@ static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn, struct Curl_cfilter *cf, *lowest_ssl_cf = NULL; for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) { - if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy) { + if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) { lowest_ssl_cf = cf; if(cf->connected || (cf->next && cf->next->connected)) { /* connected or about to start */ @@ -1762,7 +1850,7 @@ static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn, bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf) { - return (cf->cft == &cft_ssl_proxy); + return (cf->cft == &Curl_cft_ssl_proxy); } struct ssl_config_data * @@ -1814,10 +1902,142 @@ Curl_ssl_get_primary_config(struct Curl_easy *data, struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf) { for(; cf; cf = cf->next) { - if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy) + if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) return cf; } return NULL; } +static const struct alpn_spec ALPN_SPEC_H10 = { + { ALPN_HTTP_1_0 }, 1 +}; +static const struct alpn_spec ALPN_SPEC_H11 = { + { ALPN_HTTP_1_1 }, 1 +}; +#ifdef USE_HTTP2 +static const struct alpn_spec ALPN_SPEC_H2_H11 = { + { ALPN_H2, ALPN_HTTP_1_1 }, 2 +}; +#endif + +const struct alpn_spec * +Curl_alpn_get_spec(struct Curl_easy *data, struct connectdata *conn) +{ + if(!conn->bits.tls_enable_alpn) + return NULL; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) + return &ALPN_SPEC_H10; +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2) + return &ALPN_SPEC_H2_H11; +#endif + return &ALPN_SPEC_H11; +} + +const struct alpn_spec * +Curl_alpn_get_proxy_spec(struct Curl_easy *data, struct connectdata *conn) +{ + if(!conn->bits.tls_enable_alpn) + return NULL; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) + return &ALPN_SPEC_H10; + return &ALPN_SPEC_H11; +} + +CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, + const struct alpn_spec *spec) +{ + size_t i, len; + int off = 0; + unsigned char blen; + + memset(buf, 0, sizeof(*buf)); + for(i = 0; spec && i < spec->count; ++i) { + len = strlen(spec->entries[i]); + if(len >= ALPN_NAME_MAX) + return CURLE_FAILED_INIT; + blen = (unsigned char)len; + if(off + blen + 1 >= (int)sizeof(buf->data)) + return CURLE_FAILED_INIT; + buf->data[off++] = blen; + memcpy(buf->data + off, spec->entries[i], blen); + off += blen; + } + buf->len = off; + return CURLE_OK; +} + +CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, + const struct alpn_spec *spec) +{ + size_t i, len; + size_t off = 0; + + memset(buf, 0, sizeof(*buf)); + for(i = 0; spec && i < spec->count; ++i) { + len = strlen(spec->entries[i]); + if(len >= ALPN_NAME_MAX) + return CURLE_FAILED_INIT; + if(off + len + 2 >= (int)sizeof(buf->data)) + return CURLE_FAILED_INIT; + if(off) + buf->data[off++] = ','; + memcpy(buf->data + off, spec->entries[i], len); + off += len; + } + buf->data[off] = '\0'; + buf->len = (int)off; + return CURLE_OK; +} + +CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data, + const unsigned char *proto, + size_t proto_len) +{ + int can_multi = 0; + + if(proto && proto_len) { + if(proto_len == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) { + cf->conn->alpn = CURL_HTTP_VERSION_1_1; + } + else if(proto_len == ALPN_HTTP_1_0_LENGTH && + !memcmp(ALPN_HTTP_1_0, proto, ALPN_HTTP_1_0_LENGTH)) { + cf->conn->alpn = CURL_HTTP_VERSION_1_0; + } +#ifdef USE_HTTP2 + else if(proto_len == ALPN_H2_LENGTH && + !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) { + cf->conn->alpn = CURL_HTTP_VERSION_2; + can_multi = 1; + } +#endif +#ifdef USE_HTTP3 + else if(proto_len == ALPN_H3_LENGTH && + !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) { + cf->conn->alpn = CURL_HTTP_VERSION_3; + can_multi = 1; + } +#endif + else { + cf->conn->alpn = CURL_HTTP_VERSION_NONE; + failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto); + /* TODO: do we want to fail this? Previous code just ignored it and + * some vtls backends even ignore the return code of this function. */ + /* return CURLE_NOT_BUILT_IN; */ + goto out; + } + infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto); + } + else { + cf->conn->alpn = CURL_HTTP_VERSION_NONE; + infof(data, VTLS_INFOF_NO_ALPN); + } + +out: + Curl_multiuse_state(data, can_multi? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); + return CURLE_OK; +} + #endif /* USE_SSL */ diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h index 5ad64fcf60..0d9e74a699 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.h +++ b/Utilities/cmcurl/lib/vtls/vtls.h @@ -7,7 +7,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 @@ -27,7 +27,6 @@ struct connectdata; struct ssl_config_data; -struct ssl_connect_data; struct ssl_primary_config; struct Curl_ssl_session; @@ -53,6 +52,7 @@ struct Curl_ssl_session; /* Curl_multi SSL backend-specific data; declared differently by each SSL backend */ struct multi_ssl_backend_data; +struct Curl_cfilter; CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail); @@ -68,8 +68,53 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, /* see https://www.iana.org/assignments/tls-extensiontype-values/ */ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" +#define ALPN_HTTP_1_0_LENGTH 8 +#define ALPN_HTTP_1_0 "http/1.0" #define ALPN_H2_LENGTH 2 #define ALPN_H2 "h2" +#define ALPN_H3_LENGTH 2 +#define ALPN_H3 "h3" + +/* conservative sizes on the ALPN entries and count we are handling, + * we can increase these if we ever feel the need or have to accommodate + * ALPN strings from the "outside". */ +#define ALPN_NAME_MAX 10 +#define ALPN_ENTRIES_MAX 3 +#define ALPN_PROTO_BUF_MAX (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1)) + +struct alpn_spec { + const char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX]; + size_t count; /* number of entries */ +}; + +struct alpn_proto_buf { + unsigned char data[ALPN_PROTO_BUF_MAX]; + int len; +}; + +CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, + const struct alpn_spec *spec); +CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, + const struct alpn_spec *spec); + +CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data, + const unsigned char *proto, + size_t proto_len); + +/** + * Get the ALPN specification to use for talking to remote host. + * May return NULL if ALPN is disabled on the connection. + */ +const struct alpn_spec * +Curl_alpn_get_spec(struct Curl_easy *data, struct connectdata *conn); + +/** + * Get the ALPN specification to use for talking to the proxy. + * May return NULL if ALPN is disabled on the connection. + */ +const struct alpn_spec * +Curl_alpn_get_proxy_spec(struct Curl_easy *data, struct connectdata *conn); char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen); @@ -95,7 +140,6 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); /* init the SSL session ID cache */ CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); void Curl_ssl_version(char *buffer, size_t size); -int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn); /* Certificate information list handling. */ @@ -156,6 +200,9 @@ CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, struct connectdata *conn, int sockindex); +CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); + CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, int sockindex); @@ -163,6 +210,8 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data, struct connectdata *conn, int sockindex); +CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data); #endif /* !CURL_DISABLE_PROXY */ /** @@ -208,6 +257,9 @@ bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option); void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, CURLINFO info, int n); +extern struct Curl_cftype Curl_cft_ssl; +extern struct Curl_cftype Curl_cft_ssl_proxy; + #else /* if not USE_SSL */ /* When SSL support is not present, just define away these function calls */ @@ -218,7 +270,6 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN #define Curl_ssl_engines_list(x) NULL #define Curl_ssl_initsessions(x,y) CURLE_OK -#define Curl_ssl_check_cxn(d,x) 0 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_kill_session(x) Curl_nop_stmt #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h index 6710a2b559..a20ca7db7f 100644 --- a/Utilities/cmcurl/lib/vtls/vtls_int.h +++ b/Utilities/cmcurl/lib/vtls/vtls_int.h @@ -7,7 +7,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 @@ -33,18 +33,20 @@ struct ssl_connect_data { ssl_connection_state state; ssl_connect_state connecting_state; - const char *hostname; /* hostnaem for verification */ - const char *dispname; /* display version of hostname */ + char *hostname; /* hostname for verification */ + char *dispname; /* display version of hostname */ int port; /* remote port at origin */ + const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ struct ssl_backend_data *backend; /* vtls backend specific props */ - struct Curl_easy *call_data; /* data handle used in current call, - * same as parameter passed, but available - * here for backend internal callbacks - * that need it. NULLed after at the - * end of each vtls filter invcocation. */ + struct cf_call_data call_data; /* data handle used in current call */ + struct curltime handshake_done; /* time when handshake finished */ }; +#define CF_CTX_CALL_DATA(cf) \ + ((struct ssl_connect_data *)(cf)->ctx)->call_data + + /* Definitions for SSL Implementations */ struct Curl_ssl { diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index 7cc4774e83..2e57899324 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/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 @@ -218,29 +218,9 @@ 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 @@ -299,8 +279,7 @@ static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) static int 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 Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result = CURLE_OK; @@ -315,8 +294,7 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) static int 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 Curl_easy *data = connssl->call_data; + struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result = CURLE_OK; @@ -633,29 +611,18 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #endif #ifdef HAVE_ALPN - if(cf->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 */ @@ -707,7 +674,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } #else /* USE_BIO_CHAIN */ /* pass the raw socket into the SSL layer */ - if(!SSL_set_fd(backend->handle, (int)cf->conn->sock[cf->sockindex])) { + if(!SSL_set_fd(backend->handle, (int)Curl_conn_cf_get_socket(cf, data))) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } @@ -883,25 +850,11 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) 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)) - cf->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)) - cf->conn->alpn = CURL_HTTP_VERSION_2; -#endif - else - infof(data, "ALPN, unrecognized protocol %.*s", protocol_len, - protocol); - Curl_multiuse_state(data, cf->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; @@ -1166,7 +1119,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf, { CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = cf->conn->sock[cf->sockindex]; + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); int what; /* check if the connection has already been established */ diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.h b/Utilities/cmcurl/lib/vtls/wolfssl.h index b2e7c3fde2..a5ed848099 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.h +++ b/Utilities/cmcurl/lib/vtls/wolfssl.h @@ -7,7 +7,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 diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c index 4c1c9a8b79..39e4fb33bc 100644 --- a/Utilities/cmcurl/lib/vtls/x509asn1.c +++ b/Utilities/cmcurl/lib/vtls/x509asn1.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 @@ -48,6 +48,7 @@ #include "curl_ctype.h" #include "hostcheck.h" #include "vtls/vtls.h" +#include "vtls/vtls_int.h" #include "sendf.h" #include "inet_pton.h" #include "curl_base64.h" @@ -1313,7 +1314,8 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, /* Get the server IP address. */ #ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, connssl->hostname, &addr)) + if(cf->conn->bits.ipv6_ip && + Curl_inet_pton(AF_INET6, connssl->hostname, &addr)) addrlen = sizeof(struct in6_addr); else #endif @@ -1348,19 +1350,18 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, break; switch(name.tag) { case 2: /* DNS name. */ - matched = 0; len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); - if(len > 0) { - if(size_t)len == strlen(dnsname) - matched = Curl_cert_hostcheck(dnsname, (size_t)len, - connssl->hostname, hostlen); - free(dnsname); - } + if(len > 0 && (size_t)len == strlen(dnsname)) + matched = Curl_cert_hostcheck(dnsname, (size_t)len, + connssl->hostname, hostlen); + else + matched = 0; + free(dnsname); break; case 7: /* IP address. */ - matched = (name.end - name.beg) == addrlen && + matched = (size_t)(name.end - name.beg) == addrlen && !memcmp(&addr, name.beg, addrlen); break; } @@ -1406,8 +1407,10 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, failf(data, "SSL: unable to obtain common name from peer certificate"); else { len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); - if(len < 0) + if(len < 0) { + free(dnsname); return CURLE_OUT_OF_MEMORY; + } if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ failf(data, "SSL: illegal cert name field"); else if(Curl_cert_hostcheck((const char *) dnsname, diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.h b/Utilities/cmcurl/lib/vtls/x509asn1.h index eb8e9597cb..5496de40e4 100644 --- a/Utilities/cmcurl/lib/vtls/x509asn1.h +++ b/Utilities/cmcurl/lib/vtls/x509asn1.h @@ -8,7 +8,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 |