Skip to content

Commit

Permalink
schannel: ban server ALPN selection during recv renegotiation
Browse files Browse the repository at this point in the history
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.

Ref: curl#9451

Closes #xxxx
  • Loading branch information
jay committed Sep 14, 2022
1 parent 6e62818 commit e6d6bef
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 4 deletions.
20 changes: 16 additions & 4 deletions lib/vtls/schannel.c
Expand Up @@ -1334,6 +1334,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 */
Expand Down Expand Up @@ -1731,8 +1732,14 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}

if(alpn_result.ProtoNegoStatus ==
SecApplicationProtocolNegotiationStatus_Success) {
if(backend->recv_renegotiating &&
(alpn_result.ProtoNegoStatus !=
SecApplicationProtocolNegotiationStatus_None)) {
failf(data, "schannel: the server selected an ALPN protocol too late");
return CURLE_SSL_CONNECT_ERROR;
}
else if(alpn_result.ProtoNegoStatus ==
SecApplicationProtocolNegotiationStatus_Success) {

infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR,
alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
Expand All @@ -1752,8 +1759,11 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
else
infof(data, VTLS_INFOF_NO_ALPN);
Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);

if(!backend->recv_renegotiating) {
Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
#endif

Expand Down Expand Up @@ -2313,7 +2323,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;
Expand Down
1 change: 1 addition & 0 deletions lib/vtls/schannel.h
Expand Up @@ -180,6 +180,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 */
Expand Down

0 comments on commit e6d6bef

Please sign in to comment.