mirror of
https://github.com/curl/curl.git
synced 2025-03-01 15:15:34 +08:00
vtls: new io_need flags for poll handling
- decouple need to recv/send from negotiation state, we need this later in shutdown handling as well - move ssl enums from urldata.h to vtls_int.h - implement use of `connssl->io_need` in vtls.c. and all backends Closes #13879
This commit is contained in:
parent
f75aa2857f
commit
937ba94ed5
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user