From: Jay Satiro Date: Fri, 9 Sep 2022 19:33:47 +0000 (-0400) Subject: schannel: ban server ALPN change during recv renegotiation X-Git-Tag: curl-7_86_0~162 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5c0d02b7a7e31ca49c71a7512381686a94ae1cd7;p=thirdparty%2Fcurl.git schannel: ban server ALPN change during recv renegotiation By the time schannel_recv is renegotiating the connection, libcurl has already decided on a protocol and it is too late for the server to select a protocol via ALPN except for the originally selected protocol. Ref: https://github.com/curl/curl/issues/9451 Closes https://github.com/curl/curl/pull/9463 --- diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 25b46b23c0..50928aee61 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1314,6 +1314,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, backend->recv_unrecoverable_err = CURLE_OK; backend->recv_sspi_close_notify = false; backend->recv_connection_closed = false; + backend->recv_renegotiating = false; backend->encdata_is_incomplete = false; /* continue to second handshake step */ @@ -1713,6 +1714,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { + unsigned char alpn = 0; infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, alpn_result.ProtocolIdSize, alpn_result.ProtocolId); @@ -1720,20 +1722,33 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH && !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) { - conn->alpn = CURL_HTTP_VERSION_2; + 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)) { - conn->alpn = CURL_HTTP_VERSION_1_1; + alpn = CURL_HTTP_VERSION_1_1; } + if(backend->recv_renegotiating) { + if(alpn != conn->alpn) { + failf(data, "schannel: server selected an ALPN protocol too late"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else + conn->alpn = alpn; + } + else { + if(!backend->recv_renegotiating) + infof(data, VTLS_INFOF_NO_ALPN); + } + + if(!backend->recv_renegotiating) { + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? + BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } - else - infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif @@ -2293,7 +2308,9 @@ schannel_recv(struct Curl_easy *data, int sockindex, infof(data, "schannel: renegotiating SSL/TLS connection"); connssl->state = ssl_connection_negotiating; connssl->connecting_state = ssl_connect_2_writing; + backend->recv_renegotiating = true; *err = schannel_connect_common(data, conn, sockindex, FALSE, &done); + backend->recv_renegotiating = false; if(*err) { infof(data, "schannel: renegotiation failed"); goto cleanup; diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index b2d222ac24..000d1e7b30 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -179,6 +179,7 @@ struct ssl_backend_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool recv_renegotiating; /* true if recv is doing renegotiation */ bool use_alpn; /* true if ALPN is used for this connection */ #ifdef HAS_MANUAL_VERIFY_API bool use_manual_cred_validation; /* true if manual cred validation is used */