From: Daniel Stenberg Date: Fri, 30 Dec 2022 16:37:11 +0000 (+0100) Subject: vtls: use ALPN HTTP/1.0 when HTTP/1.0 is used X-Git-Tag: curl-7_88_0~200 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=df856cb5c94665c9083dc8be5bb02392d841cc1e;p=thirdparty%2Fcurl.git vtls: use ALPN HTTP/1.0 when HTTP/1.0 is used Previously libcurl would use the HTTP/1.1 ALPN id even when the application specified HTTP/1.0. Reported-by: William Tang Ref: #10183 --- diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c index d9c0ce0eed..86b2b39897 100644 --- a/lib/vtls/bearssl.c +++ b/lib/vtls/bearssl.c @@ -698,19 +698,25 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, * protocols array in `struct ssl_backend_data`. */ + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + backend->protocols[cur++] = ALPN_HTTP_1_0; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_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); - } + ) { + backend->protocols[cur++] = ALPN_H2; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + } #endif - backend->protocols[cur++] = ALPN_HTTP_1_1; - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + 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); diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 104dce6093..3857cc303a 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -704,23 +704,28 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) int cur = 0; gnutls_datum_t protocols[2]; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + protocols[cur].data = (unsigned char *)ALPN_HTTP_1_0; + protocols[cur++].size = ALPN_HTTP_1_0_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_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); - } + ) { + protocols[cur].data = (unsigned char *)ALPN_H2; + protocols[cur++].size = ALPN_H2_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + } #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); + protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; + protocols[cur++].size = ALPN_HTTP_1_1_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + } if(gnutls_alpn_set_protocols(backend->gtls.session, protocols, cur, 0)) { failf(data, "failed setting ALPN"); diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 0b81662b93..5fef12fc7f 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -650,11 +650,16 @@ 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]; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + *p++ = ALPN_HTTP_1_0; + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2) - *p++ = ALPN_H2; + if(data->state.httpwant >= CURL_HTTP_VERSION_2) + *p++ = ALPN_H2; #endif - *p++ = ALPN_HTTP_1_1; + *p++ = ALPN_HTTP_1_1; + } *p = NULL; /* this function doesn't clone the protocols array, which is why we need to keep it around */ diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 03694d22ba..790f4464ec 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -896,6 +896,10 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { cf->conn->alpn = CURL_HTTP_VERSION_1_1; } + else if(buflen == ALPN_HTTP_1_0_LENGTH && + !memcmp(ALPN_HTTP_1_0, buf, ALPN_HTTP_1_0_LENGTH)) { + cf->conn->alpn = CURL_HTTP_VERSION_1_0; + } /* This callback might get called when PR_Recv() is used within * close_one() during a connection shutdown. At that point there might not @@ -2167,20 +2171,27 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf, int cur = 0; unsigned char protocols[128]; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + protocols[cur++] = ALPN_HTTP_1_0_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_0, ALPN_HTTP_1_0_LENGTH); + cur += ALPN_HTTP_1_0_LENGTH; + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_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; - } + ) { + 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; + 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(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) goto error; diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 2c2ebfff4f..f5dd14d53f 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3642,25 +3642,32 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, int cur = 0; unsigned char protocols[128]; + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + protocols[cur++] = ALPN_HTTP_1_0_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_0, ALPN_HTTP_1_0_LENGTH); + cur += ALPN_HTTP_1_0_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) + && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) #endif - ) { - protocols[cur++] = ALPN_H2_LENGTH; + ) { + 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); - } + 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); - + 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); + } /* expects length prefixed preference ordered list of protocols in wire * format */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 27f4ec8d8c..6cb0731a98 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -349,22 +349,40 @@ 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(); + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + rustls_slice_bytes alpn[] = { + { (const uint8_t *)ALPN_HTTP_1_0, ALPN_HTTP_1_0_LENGTH } + }; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1); + } + else { + 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 }, + }; #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); + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy) #endif - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + ) { + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 2); + } + else +#endif + { + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1); + } + } if(!verifypeer) { rustls_client_config_builder_dangerous_set_certificate_verifier( config_builder, cr_verify_none); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 7eab9542af..7a279839f0 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1215,19 +1215,27 @@ 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); + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + alpn_buffer[cur++] = ALPN_HTTP_1_0_LENGTH; + memcpy(&alpn_buffer[cur], ALPN_HTTP_1_0, ALPN_HTTP_1_0_LENGTH); + cur += ALPN_HTTP_1_0_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); } + else { +#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); + } #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); + 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); + } *list_len = curlx_uitous(cur - list_start_index); *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index ab7965465f..aa25d1b15c 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -1790,20 +1790,25 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_0)); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); + } + else { #ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!isproxy || !cf->conn->bits.tunnel_proxy) + && (!isproxy || !cf->conn->bits.tunnel_proxy) #endif - ) { - CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2)); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); - } + ) { + CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2)); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + } #endif - CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1)); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); - + 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 */ diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 1c121ee0e4..0dad7eebb5 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -69,6 +69,8 @@ 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" diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 7cc4774e83..9aa1e74865 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -640,16 +640,21 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* 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); + if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + strcpy(protocols, ALPN_HTTP_1_0); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_0); } + else { +#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); - + strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + } if(wolfSSL_UseALPN(backend->handle, protocols, (unsigned)strlen(protocols), WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {