diff --git a/lib/urldata.h b/lib/urldata.h index 15eb1f8364..df2de388d9 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -257,22 +257,6 @@ enum protection_level { }; #endif -/* enum for the nonblocking SSL connection state machine */ -typedef enum { - ssl_connect_1, - ssl_connect_2, - ssl_connect_2_reading, - ssl_connect_2_writing, - ssl_connect_3, - ssl_connect_done -} ssl_connect_state; - -typedef enum { - ssl_connection_none, - ssl_connection_negotiating, - ssl_connection_complete -} ssl_connection_state; - /* SSL backend-specific data; declared differently by each SSL backend */ struct ssl_backend_data; diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c index dd59780c86..b62be48e8b 100644 --- a/lib/vtls/bearssl.c +++ b/lib/vtls/bearssl.c @@ -722,6 +722,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf, ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result); CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result); if(ret <= 0) { + if(result == CURLE_AGAIN) + connssl->io_need |= CURL_SSL_IO_NEED_SEND; return result; } br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); @@ -735,6 +737,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf, return CURLE_RECV_ERROR; } if(ret <= 0) { + if(result == CURLE_AGAIN) + connssl->io_need |= CURL_SSL_IO_NEED_RECV; return result; } br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); @@ -925,9 +929,7 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, return ret; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -938,13 +940,12 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, } /* if ssl is expecting something, check if it's available. */ - if(ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + if(connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; CURL_TRC_CF(data, cf, "connect_common, check socket"); what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, @@ -975,11 +976,9 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ + connssl->io_need = CURL_SSL_IO_NEED_NONE; ret = bearssl_connect_step2(cf, data); - if(ret || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) return ret; } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 9038739d4e..a828ce22ee 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -251,6 +251,7 @@ static CURLcode handshake(struct Curl_cfilter *cf, DEBUGASSERT(backend); session = backend->gtls.session; + connssl->connecting_state = ssl_connect_2; for(;;) { timediff_t timeout_ms; @@ -266,13 +267,12 @@ static CURLcode handshake(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(connssl->io_need) { int what; - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: @@ -294,6 +294,7 @@ static CURLcode handshake(struct Curl_cfilter *cf, /* socket is readable or writable */ } + connssl->io_need = CURL_SSL_IO_NEED_NONE; backend->gtls.io_result = CURLE_OK; rc = gnutls_handshake(session); @@ -306,9 +307,9 @@ static CURLcode handshake(struct Curl_cfilter *cf, } if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - connssl->connecting_state = + connssl->io_need = gnutls_record_get_direction(session)? - ssl_connect_2_writing:ssl_connect_2_reading; + CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV; continue; } else if((rc < 0) && !gnutls_error_is_fatal(rc)) { @@ -1684,8 +1685,8 @@ out: */ /* We use connssl->connecting_state to keep track of the connection status; there are three states: 'ssl_connect_1' (not started yet or complete), - 'ssl_connect_2_reading' (waiting for data from server), and - 'ssl_connect_2_writing' (waiting to be able to write). + 'ssl_connect_2' (doing handshake with the server), and + 'ssl_connect_3' (verifying and getting stats). */ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 8393b02d2f..b71af28055 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -943,11 +943,11 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) ret = mbedtls_ssl_handshake(&backend->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; return CURLE_OK; } else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { - connssl->connecting_state = ssl_connect_2_writing; + connssl->io_need = CURL_SSL_IO_NEED_SEND; return CURLE_OK; } else if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { @@ -1358,9 +1358,7 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, return retcode; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -1372,13 +1370,12 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, } /* 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(connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : timeout_ms); @@ -1408,11 +1405,10 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ + connssl->io_need = CURL_SSL_IO_NEED_NONE; retcode = mbed_connect_step2(cf, data); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(retcode || + (nonblocking && (ssl_connect_2 == connssl->connecting_state))) return retcode; } /* repeat step2 until all transactions are done. */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index bc6a10f96c..f6346bbf03 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -4165,11 +4165,10 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, struct ssl_connect_data *connssl = cf->ctx; struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state); DEBUGASSERT(octx); + connssl->io_need = CURL_SSL_IO_NEED_NONE; ERR_clear_error(); err = SSL_connect(octx->ssl); @@ -4198,11 +4197,11 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, int detail = SSL_get_error(octx->ssl, err); if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; return CURLE_OK; } if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; + connssl->io_need = CURL_SSL_IO_NEED_SEND; return CURLE_OK; } #ifdef SSL_ERROR_WANT_ASYNC @@ -4828,9 +4827,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, goto out; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check allowed time left */ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -4843,14 +4840,12 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, } /* if ssl is expecting something, check if it's available. */ - if(!nonblocking && - (connssl->connecting_state == ssl_connect_2_reading || - connssl->connecting_state == ssl_connect_2_writing)) { + if(!nonblocking && connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, timeout_ms); @@ -4876,10 +4871,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, * or epoll() will always have a valid fdset to wait on. */ result = ossl_connect_step2(cf, data); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) goto out; } /* repeat step2 until all transactions are done. */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index d666f1b60a..722797c2b9 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -604,6 +604,7 @@ cr_connect_common(struct Curl_cfilter *cf, * Connection has been established according to rustls. Set send/recv * handlers, and update the state machine. */ + connssl->io_need = CURL_SSL_IO_NEED_NONE; if(!rustls_connection_is_handshaking(rconn)) { infof(data, "Done handshaking"); /* rustls claims it is no longer handshaking *before* it has @@ -613,7 +614,7 @@ cr_connect_common(struct Curl_cfilter *cf, cr_set_negotiated_alpn(cf, data, rconn); cr_send(cf, data, NULL, 0, &tmperr); if(tmperr == CURLE_AGAIN) { - connssl->connecting_state = ssl_connect_2_writing; + connssl->io_need = CURL_SSL_IO_NEED_SEND; return CURLE_OK; } else if(tmperr != CURLE_OK) { @@ -625,6 +626,7 @@ cr_connect_common(struct Curl_cfilter *cf, return CURLE_OK; } + connssl->connecting_state = ssl_connect_2; wants_read = rustls_connection_wants_read(rconn); wants_write = rustls_connection_wants_write(rconn) || backend->plain_out_buffered; @@ -632,8 +634,6 @@ cr_connect_common(struct Curl_cfilter *cf, writefd = wants_write?sockfd:CURL_SOCKET_BAD; readfd = wants_read?sockfd:CURL_SOCKET_BAD; - connssl->connecting_state = wants_write? - ssl_connect_2_writing : ssl_connect_2_reading; /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -661,6 +661,10 @@ cr_connect_common(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block", wants_read&&wants_write ? "writing and reading" : wants_write ? "writing" : "reading"); + if(wants_write) + connssl->io_need |= CURL_SSL_IO_NEED_SEND; + if(wants_read) + connssl->io_need |= CURL_SSL_IO_NEED_RECV; return CURLE_OK; } /* socket is readable or writable */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 57d0c33d64..02e59d8469 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1332,7 +1332,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) DEBUGASSERT(backend); - doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; + doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %d (step 2/3)", @@ -1393,8 +1394,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) backend->encdata_offset, &result); if(result == CURLE_AGAIN) { - if(connssl->connecting_state != ssl_connect_2_writing) - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; DEBUGF(infof(data, "schannel: failed to receive handshake, " "need more data")); return CURLE_OK; @@ -1448,7 +1448,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { backend->encdata_is_incomplete = true; - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; DEBUGF(infof(data, "schannel: received incomplete message, need more data")); return CURLE_OK; @@ -1460,7 +1460,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; - connssl->connecting_state = ssl_connect_2_writing; + connssl->io_need = CURL_SSL_IO_NEED_SEND; DEBUGF(infof(data, "schannel: a client certificate has been requested")); return CURLE_OK; @@ -1560,7 +1560,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* check if the handshake needs to be continued */ if(sspi_status == SEC_I_CONTINUE_NEEDED) { - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; return CURLE_OK; } @@ -1867,9 +1867,7 @@ schannel_connect_common(struct Curl_cfilter *cf, return result; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -1881,13 +1879,12 @@ schannel_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(connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd : CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd : CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : timeout_ms); @@ -1918,10 +1915,7 @@ schannel_connect_common(struct Curl_cfilter *cf, * have a valid fdset to wait on. */ result = schannel_connect_step2(cf, data); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ @@ -2320,7 +2314,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* begin renegotiation */ infof(data, "schannel: renegotiating SSL/TLS connection"); connssl->state = ssl_connection_negotiating; - connssl->connecting_state = ssl_connect_2_writing; + connssl->connecting_state = ssl_connect_2; + connssl->io_need = CURL_SSL_IO_NEED_SEND; backend->recv_renegotiating = true; *err = schannel_connect_common(cf, data, FALSE, &done); backend->recv_renegotiating = false; diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index 52fdce7cc4..a77345a738 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -1948,21 +1948,20 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf, SSLCipherSuite cipher; SSLProtocol protocol = 0; - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state); DEBUGASSERT(backend); CURL_TRC_CF(data, cf, "connect_step2"); /* Here goes nothing: */ check_handshake: + connssl->io_need = CURL_SSL_IO_NEED_NONE; err = SSLHandshake(backend->ssl_ctx); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = backend->ssl_direction ? - ssl_connect_2_writing : ssl_connect_2_reading; + connssl->io_need = backend->ssl_direction ? + CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV; return CURLE_OK; /* The below is errSSLServerAuthCompleted; it's not defined in @@ -2460,9 +2459,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, return result; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check allowed time left */ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -2474,13 +2471,12 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, } /* 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(connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : timeout_ms); @@ -2510,10 +2506,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, * or epoll() will always have a valid fdset to wait on. */ result = sectransp_connect_step2(cf, data); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 1a6aa54aa4..373c155787 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -772,11 +772,12 @@ void Curl_ssl_close_all(struct Curl_easy *data) void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, struct easy_pollset *ps) { - if(!cf->connected) { - struct ssl_connect_data *connssl = cf->ctx; + struct ssl_connect_data *connssl = cf->ctx; + + if(connssl->io_need) { curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); if(sock != CURL_SOCKET_BAD) { - if(connssl->connecting_state == ssl_connect_2_writing) { + if(connssl->io_need & CURL_SSL_IO_NEED_SEND) { Curl_pollset_set_out_only(data, ps, sock); CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%" CURL_FORMAT_SOCKET_T, sock); diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index 9ac964d114..46bc82bbaf 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -64,15 +64,34 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, const unsigned char *proto, size_t proto_len); +/* enum for the nonblocking SSL connection state machine */ +typedef enum { + ssl_connect_1, + ssl_connect_2, + ssl_connect_3, + ssl_connect_done +} ssl_connect_state; + +typedef enum { + ssl_connection_none, + ssl_connection_negotiating, + ssl_connection_complete +} ssl_connection_state; + +#define CURL_SSL_IO_NEED_NONE (0) +#define CURL_SSL_IO_NEED_RECV (1<<0) +#define CURL_SSL_IO_NEED_SEND (1<<1) + /* Information in each SSL cfilter context: cf->ctx */ struct ssl_connect_data { - ssl_connection_state state; - ssl_connect_state connecting_state; struct ssl_peer peer; const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ void *backend; /* vtls backend specific props */ struct cf_call_data call_data; /* data handle used in current call */ struct curltime handshake_done; /* time when handshake finished */ + ssl_connection_state state; + ssl_connect_state connecting_state; + int io_need; /* TLS signals special SEND/RECV needs */ BIT(use_alpn); /* if ALPN shall be used in handshake */ BIT(peer_closed); /* peer has closed connection */ }; diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 7de3c1a107..cbb0fd5785 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -659,11 +659,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #ifndef NO_OLD_TLS req_method = TLSv1_1_client_method(); use_sni(TRUE); + break; #else failf(data, "wolfSSL does not support TLS 1.1"); return CURLE_NOT_BUILT_IN; #endif - break; case CURL_SSLVERSION_TLSv1_2: #ifndef WOLFSSL_NO_TLS12 req_method = TLSv1_2_client_method(); @@ -1047,6 +1047,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) backend->x509_store_setup = wssl.x509_store_setup; } + connssl->io_need = CURL_SSL_IO_NEED_NONE; ret = wolfSSL_connect(backend->handle); #ifdef OPENSSL_EXTRA @@ -1078,11 +1079,11 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) int detail = wolfSSL_get_error(backend->handle, ret); if(SSL_ERROR_WANT_READ == detail) { - connssl->connecting_state = ssl_connect_2_reading; + connssl->io_need = CURL_SSL_IO_NEED_RECV; return CURLE_OK; } else if(SSL_ERROR_WANT_WRITE == detail) { - connssl->connecting_state = ssl_connect_2_writing; + connssl->io_need = CURL_SSL_IO_NEED_SEND; return CURLE_OK; } /* There is no easy way to override only the CN matching. @@ -1524,9 +1525,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf, return result; } - while(ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state) { + while(ssl_connect_2 == connssl->connecting_state) { /* check allowed time left */ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -1538,13 +1537,12 @@ wolfssl_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(connssl->io_need) { - curl_socket_t writefd = ssl_connect_2_writing == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading == - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? + sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)? + sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0:timeout_ms); @@ -1575,10 +1573,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf, * have a valid fdset to wait on. */ result = wolfssl_connect_step2(cf, data); - if(result || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) + if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */