diff --git a/SOURCES/0036-curl-7.61.1-CVE-2022-22576.patch b/SOURCES/0036-curl-7.61.1-CVE-2022-22576.patch new file mode 100644 index 0000000..4f72dde --- /dev/null +++ b/SOURCES/0036-curl-7.61.1-CVE-2022-22576.patch @@ -0,0 +1,338 @@ +From 295124c256ed25f097192cfa9a67e460f7bb587f Mon Sep 17 00:00:00 2001 +From: nao +Date: Tue, 21 Jan 2020 10:30:37 +0100 +Subject: [PATCH 1/2] http: move "oauth_bearer" from connectdata to Curl_easy + +Fixes the bug where oauth_bearer gets deallocated when we re-use a +connection. + +Closes #4824 + +Upstream-commit: dea17b519dc1d83265ca6aa9a484a2cf242db3b9 +Signed-off-by: Kamil Dudka +--- + lib/curl_sasl.c | 14 ++++++++------ + lib/http.c | 12 +++++------- + lib/url.c | 9 --------- + lib/urldata.h | 2 -- + 4 files changed, 13 insertions(+), 24 deletions(-) + +diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c +index 354bc54..c767bef 100644 +--- a/lib/curl_sasl.c ++++ b/lib/curl_sasl.c +@@ -269,6 +269,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; + #endif ++ const char *oauth_bearer = data->set.str[STRING_BEARER]; + + sasl->force_ir = force_ir; /* Latch for future use */ + sasl->authused = 0; /* No mechanism used yet */ +@@ -339,7 +340,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + } + else + #endif +- if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) { ++ if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { + mech = SASL_MECH_STRING_OAUTHBEARER; + state1 = SASL_OAUTH2; + state2 = SASL_OAUTH2_RESP; +@@ -349,10 +350,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + hostname, + port, +- conn->oauth_bearer, ++ oauth_bearer, + &resp, &len); + } +- else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { ++ else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { + mech = SASL_MECH_STRING_XOAUTH2; + state1 = SASL_OAUTH2; + sasl->authused = SASL_MECH_XOAUTH2; +@@ -360,7 +361,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + if(force_ir || data->set.sasl_ir) + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, +- conn->oauth_bearer, ++ oauth_bearer, + &resp, &len); + } + else if(enabledmechs & SASL_MECH_PLAIN) { +@@ -429,6 +430,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + char *serverdata; + #endif + size_t len = 0; ++ const char *oauth_bearer = data->set.str[STRING_BEARER]; + + *progress = SASL_INPROGRESS; + +@@ -556,7 +558,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + hostname, + port, +- conn->oauth_bearer, ++ oauth_bearer, + &resp, &len); + + /* Failures maybe sent by the server as continuations for OAUTHBEARER */ +@@ -565,7 +567,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + else + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, +- conn->oauth_bearer, ++ oauth_bearer, + &resp, &len); + break; + +diff --git a/lib/http.c b/lib/http.c +index 26eb52d..bf19077 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -326,7 +326,7 @@ static CURLcode http_output_bearer(struct connectdata *conn) + userp = &conn->allocptr.userpwd; + free(*userp); + *userp = aprintf("Authorization: Bearer %s\r\n", +- conn->oauth_bearer); ++ conn->data->set.str[STRING_BEARER]); + + if(!*userp) { + result = CURLE_OUT_OF_MEMORY; +@@ -510,7 +510,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) + CURLcode result = CURLE_OK; + unsigned long authmask = ~0ul; + +- if(!conn->oauth_bearer) ++ if(!data->set.str[STRING_BEARER]) + authmask &= (unsigned long)~CURLAUTH_BEARER; + + if(100 <= data->req.httpcode && 199 >= data->req.httpcode) +@@ -520,7 +520,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) + if(data->state.authproblem) + return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; + +- if((conn->bits.user_passwd || conn->oauth_bearer) && ++ if((conn->bits.user_passwd || data->set.str[STRING_BEARER]) && + ((data->req.httpcode == 401) || + (conn->bits.authneg && data->req.httpcode < 300))) { + pickhost = pickoneauth(&data->state.authhost, authmask); +@@ -590,9 +590,7 @@ output_auth_headers(struct connectdata *conn, + { + const char *auth = NULL; + CURLcode result = CURLE_OK; +-#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) + struct Curl_easy *data = conn->data; +-#endif + #ifdef USE_SPNEGO + struct negotiatedata *negdata = proxy ? + &data->state.proxyneg : &data->state.negotiate; +@@ -664,7 +662,7 @@ output_auth_headers(struct connectdata *conn, + } + if(authstatus->picked == CURLAUTH_BEARER) { + /* Bearer */ +- if((!proxy && conn->oauth_bearer && ++ if((!proxy && data->set.str[STRING_BEARER] && + !Curl_checkheaders(conn, "Authorization:"))) { + auth = "Bearer"; + result = http_output_bearer(conn); +@@ -722,7 +720,7 @@ Curl_http_output_auth(struct connectdata *conn, + authproxy = &data->state.authproxy; + + if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || +- conn->bits.user_passwd || conn->oauth_bearer) ++ conn->bits.user_passwd || data->set.str[STRING_BEARER]) + /* continue please */; + else { + authhost->done = TRUE; +diff --git a/lib/url.c b/lib/url.c +index 4803653..fca0855 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -686,7 +686,6 @@ static void conn_free(struct connectdata *conn) + + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); +- Curl_safefree(conn->oauth_bearer); + Curl_safefree(conn->options); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); +@@ -4161,14 +4160,6 @@ static CURLcode create_conn(struct Curl_easy *data, + } + } + +- if(data->set.str[STRING_BEARER]) { +- conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); +- if(!conn->oauth_bearer) { +- result = CURLE_OUT_OF_MEMORY; +- goto out; +- } +- } +- + #ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); +diff --git a/lib/urldata.h b/lib/urldata.h +index 72a36fb..73a185c 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -850,8 +850,6 @@ struct connectdata { + char *passwd; /* password string, allocated */ + char *options; /* options string, allocated */ + +- char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ +- + int httpversion; /* the HTTP version*10 reported by the server */ + int rtspversion; /* the RTSP version*10 reported by the server */ + +-- +2.34.1 + + +From 85d1103c2fc0c9b1bdfae470dbafd45758e1c2f0 Mon Sep 17 00:00:00 2001 +From: Patrick Monnerat +Date: Mon, 25 Apr 2022 11:44:05 +0200 +Subject: [PATCH 2/2] url: check sasl additional parameters for connection + reuse. + +Also move static function safecmp() as non-static Curl_safecmp() since +its purpose is needed at several places. + +Bug: https://curl.se/docs/CVE-2022-22576.html + +CVE-2022-22576 + +Closes #8746 + +Upstream-commit: 852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 +Signed-off-by: Kamil Dudka +--- + lib/strcase.c | 10 ++++++++++ + lib/strcase.h | 2 ++ + lib/url.c | 12 +++++++++++- + lib/urldata.h | 2 ++ + lib/vtls/vtls.c | 19 +++++-------------- + 5 files changed, 30 insertions(+), 15 deletions(-) + +diff --git a/lib/strcase.c b/lib/strcase.c +index dd46ca1..692a3f1 100644 +--- a/lib/strcase.c ++++ b/lib/strcase.c +@@ -165,6 +165,16 @@ void Curl_strntoupper(char *dest, const char *src, size_t n) + } while(*src++ && --n); + } + ++/* Compare case-sensitive NUL-terminated strings, taking care of possible ++ * null pointers. Return true if arguments match. ++ */ ++bool Curl_safecmp(char *a, char *b) ++{ ++ if(a && b) ++ return !strcmp(a, b); ++ return !a && !b; ++} ++ + /* --- public functions --- */ + + int curl_strequal(const char *first, const char *second) +diff --git a/lib/strcase.h b/lib/strcase.h +index b628656..382b80a 100644 +--- a/lib/strcase.h ++++ b/lib/strcase.h +@@ -47,4 +47,6 @@ char Curl_raw_toupper(char in); + + void Curl_strntoupper(char *dest, const char *src, size_t n); + ++bool Curl_safecmp(char *a, char *b); ++ + #endif /* HEADER_CURL_STRCASE_H */ +diff --git a/lib/url.c b/lib/url.c +index adef2cd..94e3406 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -701,6 +701,7 @@ static void conn_free(struct connectdata *conn) + Curl_safefree(conn->allocptr.host); + Curl_safefree(conn->allocptr.cookiehost); + Curl_safefree(conn->allocptr.rtsp_transport); ++ Curl_safefree(conn->oauth_bearer); + Curl_safefree(conn->trailer); + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ +@@ -1291,7 +1292,8 @@ ConnectionExists(struct Curl_easy *data, + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ + if(strcmp(needle->user, check->user) || +- strcmp(needle->passwd, check->passwd)) { ++ strcmp(needle->passwd, check->passwd) || ++ !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { + /* one of them was different */ + continue; + } +@@ -4160,6 +4162,14 @@ static CURLcode create_conn(struct Curl_easy *data, + } + } + ++ if(data->set.str[STRING_BEARER]) { ++ conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); ++ if(!conn->oauth_bearer) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } ++ } ++ + #ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); +diff --git a/lib/urldata.h b/lib/urldata.h +index cc8a600..03da59a 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -850,6 +850,8 @@ struct connectdata { + char *passwd; /* password string, allocated */ + char *options; /* options string, allocated */ + ++ char *oauth_bearer; /* OAUTH2 bearer, allocated */ ++ + int httpversion; /* the HTTP version*10 reported by the server */ + int rtspversion; /* the RTSP version*10 reported by the server */ + +diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c +index 03b85ba..a40ac06 100644 +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -82,15 +82,6 @@ + else \ + dest->var = NULL; + +-static bool safecmp(char *a, char *b) +-{ +- if(a && b) +- return !strcmp(a, b); +- else if(!a && !b) +- return TRUE; /* match */ +- return FALSE; /* no match */ +-} +- + bool + Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) +@@ -100,11 +91,11 @@ Curl_ssl_config_matches(struct ssl_primary_config* data, + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +- safecmp(data->CApath, needle->CApath) && +- safecmp(data->CAfile, needle->CAfile) && +- safecmp(data->clientcert, needle->clientcert) && +- safecmp(data->random_file, needle->random_file) && +- safecmp(data->egdsocket, needle->egdsocket) && ++ Curl_safecmp(data->CApath, needle->CApath) && ++ Curl_safecmp(data->CAfile, needle->CAfile) && ++ Curl_safecmp(data->clientcert, needle->clientcert) && ++ Curl_safecmp(data->random_file, needle->random_file) && ++ Curl_safecmp(data->egdsocket, needle->egdsocket) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13)) + return TRUE; +-- +2.34.1 + diff --git a/SOURCES/0037-curl-7.61.1-CVE-2022-27776.patch b/SOURCES/0037-curl-7.61.1-CVE-2022-27776.patch new file mode 100644 index 0000000..b82cd5d --- /dev/null +++ b/SOURCES/0037-curl-7.61.1-CVE-2022-27776.patch @@ -0,0 +1,710 @@ +From 24ff6b126726201cf778038c332b3b921c7f5b2f Mon Sep 17 00:00:00 2001 +From: Katsuhiko YOSHIDA +Date: Sun, 30 Dec 2018 09:44:30 +0900 +Subject: [PATCH 1/6] cookies: skip custom cookies when redirecting cross-site + +Closes #3417 + +Upstream-commit: 1f30dc886d1a4a6e81599a9f5f5e9f60d97801d4 +Signed-off-by: Kamil Dudka +--- + docs/libcurl/opts/CURLOPT_HTTPHEADER.3 | 4 ++ + lib/http.c | 3 +- + tests/data/Makefile.inc | 2 +- + tests/data/test330 | 90 ++++++++++++++++++++++++++ + 4 files changed, 97 insertions(+), 2 deletions(-) + create mode 100644 tests/data/test330 + +diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 b/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 +index f5826e1..4af69f4 100644 +--- a/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 ++++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 +@@ -88,6 +88,10 @@ those servers will get all the contents of your custom headers too. + Starting in 7.58.0, libcurl will specifically prevent "Authorization:" headers + from being sent to other hosts than the first used one, unless specifically + permitted with the \fICURLOPT_UNRESTRICTED_AUTH(3)\fP option. ++ ++Starting in 7.64.0, libcurl will specifically prevent "Cookie:" headers ++from being sent to other hosts than the first used one, unless specifically ++permitted with the \fICURLOPT_UNRESTRICTED_AUTH(3)\fP option. + .SH DEFAULT + NULL + .SH PROTOCOLS +diff --git a/lib/http.c b/lib/http.c +index bf19077..0b5e476 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -1774,7 +1774,8 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Transfer-Encoding:", headers->data)) + /* HTTP/2 doesn't support chunked requests */ + ; +- else if(checkprefix("Authorization:", headers->data) && ++ else if((checkprefix("Authorization:", headers->data) || ++ checkprefix("Cookie:", headers->data)) && + /* be careful of sending this potentially sensitive header to + other hosts */ + (data->state.this_is_a_follow && +diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc +index e0f1ef4..77e85fd 100644 +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -56,7 +56,7 @@ test289 test290 test291 test292 test293 test294 test295 test296 test297 \ + test298 test299 test300 test301 test302 test303 test304 test305 test306 \ + test307 test308 test309 test310 test311 test312 test313 test314 test315 \ + test316 test317 test318 test319 test320 test321 test322 test323 test324 \ +-test325 test326 \ ++test325 test326 test330 \ + \ + test340 \ + \ +diff --git a/tests/data/test330 b/tests/data/test330 +new file mode 100644 +index 0000000..74607d5 +--- /dev/null ++++ b/tests/data/test330 +@@ -0,0 +1,90 @@ ++ ++ ++ ++HTTP ++followlocation ++cookies ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 302 OK ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake swsclose ++Content-Type: text/html ++Funny-head: yesyes ++Location: http://goto.second.host.now/3170002 ++Content-Length: 8 ++Connection: close ++ ++contents ++ ++ ++HTTP/1.1 200 OK ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake swsclose ++Content-Type: text/html ++Funny-head: yesyes ++Content-Length: 9 ++ ++contents ++ ++ ++ ++HTTP/1.1 302 OK ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake swsclose ++Content-Type: text/html ++Funny-head: yesyes ++Location: http://goto.second.host.now/3170002 ++Content-Length: 8 ++Connection: close ++ ++HTTP/1.1 200 OK ++Date: Thu, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake swsclose ++Content-Type: text/html ++Funny-head: yesyes ++Content-Length: 9 ++ ++contents ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with custom Cookie: and redirect to new host ++ ++ ++http://first.host.it.is/we/want/that/page/317 -x %HOSTIP:%HTTPPORT -H "Cookie: test=yes" --location ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET http://first.host.it.is/we/want/that/page/317 HTTP/1.1 ++Host: first.host.it.is ++Accept: */* ++Proxy-Connection: Keep-Alive ++Cookie: test=yes ++ ++GET http://goto.second.host.now/3170002 HTTP/1.1 ++Host: goto.second.host.now ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +-- +2.34.1 + + +From a3f3855c8bf3a39ef0d86ef04087c200bca765f1 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 19 Dec 2019 16:45:53 +0100 +Subject: [PATCH 2/6] sws: search for "Testno:" header uncondtionally if no + testno + +Even if the initial request line wasn't found. With the fix to 1455, the +test number is now detected correctly. + +(Problem found when running tests in random order.) + +Closes #4744 + +Upstream-commit: 25b69c482f45c7acd817920bd8fdf68887be51a2 +Signed-off-by: Kamil Dudka +--- + tests/data/test1455 | 3 ++- + tests/server/sws.c | 40 +++++++++++++++++++++++----------------- + 2 files changed, 25 insertions(+), 18 deletions(-) + +diff --git a/tests/data/test1455 b/tests/data/test1455 +index 0b77dc4..25f742e 100644 +--- a/tests/data/test1455 ++++ b/tests/data/test1455 +@@ -35,7 +35,7 @@ http + HTTP GET when PROXY Protocol enabled + + +-http://%HOSTIP:%HTTPPORT/1455 --haproxy-protocol ++http://%HOSTIP:%HTTPPORT/1455 --haproxy-protocol -H "Testno: 1455" + + + +@@ -53,6 +53,7 @@ proxy-line + GET /1455 HTTP/1.1 + Host: %HOSTIP:%HTTPPORT + Accept: */* ++Testno: 1455 + + + +diff --git a/tests/server/sws.c b/tests/server/sws.c +index fbe7761..4ece830 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -367,6 +367,8 @@ static int parse_servercmd(struct httprequest *req) + + filename = test2file(req->testno); + req->close = FALSE; ++ req->connmon = FALSE; ++ + stream = fopen(filename, "rb"); + if(!stream) { + error = errno; +@@ -391,8 +393,6 @@ static int parse_servercmd(struct httprequest *req) + return 1; /* done */ + } + +- req->connmon = FALSE; +- + cmd = orgcmd; + while(cmd && cmdsize) { + char *check; +@@ -548,12 +548,11 @@ static int ProcessRequest(struct httprequest *req) + snprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld", + req->testno, req->partno); + logmsg("%s", logbuf); +- +- /* find and parse for this test */ +- parse_servercmd(req); + } +- else ++ else { ++ logmsg("No test number"); + req->testno = DOCNUMBER_NOTHING; ++ } + + } + +@@ -613,14 +612,6 @@ static int ProcessRequest(struct httprequest *req) + } + } + +- if(req->testno == DOCNUMBER_NOTHING) { +- /* check for a Testno: header with the test case number */ +- char *testno = strstr(line, "\nTestno: "); +- if(testno) { +- req->testno = strtol(&testno[9], NULL, 10); +- logmsg("Found test number %d in Testno: header!", req->testno); +- } +- } + if(req->testno == DOCNUMBER_NOTHING) { + /* Still no test case number. Try to get the the number off the last dot + instead, IE we consider the TLD to be the test number. Test 123 can +@@ -661,8 +652,8 @@ static int ProcessRequest(struct httprequest *req) + } + } + else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) { +- logmsg("** Unusual request. Starts with %02x %02x %02x", +- line[0], line[1], line[2]); ++ logmsg("** Unusual request. Starts with %02x %02x %02x (%c%c%c)", ++ line[0], line[1], line[2], line[0], line[1], line[2]); + } + + if(!end) { +@@ -670,7 +661,22 @@ static int ProcessRequest(struct httprequest *req) + logmsg("request not complete yet"); + return 0; /* not complete yet */ + } +- logmsg("- request found to be complete"); ++ logmsg("- request found to be complete (%d)", req->testno); ++ ++ if(req->testno == DOCNUMBER_NOTHING) { ++ /* check for a Testno: header with the test case number */ ++ char *testno = strstr(line, "\nTestno: "); ++ if(testno) { ++ req->testno = strtol(&testno[9], NULL, 10); ++ logmsg("Found test number %d in Testno: header!", req->testno); ++ } ++ else { ++ logmsg("No Testno: header"); ++ } ++ } ++ ++ /* find and parse for this test */ ++ parse_servercmd(req); + + if(use_gopher) { + /* when using gopher we cannot check the request until the entire +-- +2.34.1 + + +From 3772ea764c05a1cf37b96c091ae266138e8a2867 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 16 Apr 2020 14:16:22 +0200 +Subject: [PATCH 3/6] runtests: always put test number in servercmd file + +Upstream-commit: d1a2816b4128faa8ebc50ce93285c7364652856e +Signed-off-by: Kamil Dudka +--- + tests/runtests.pl | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/tests/runtests.pl b/tests/runtests.pl +index a0fd991..8d8ed81 100755 +--- a/tests/runtests.pl ++++ b/tests/runtests.pl +@@ -3878,10 +3878,9 @@ sub singletest { + unlink($SERVER2IN); + unlink($PROXYIN); + +- if(@ftpservercmd) { +- # write the instructions to file +- writearray($FTPDCMD, \@ftpservercmd); +- } ++ push @ftpservercmd, "Testnum $testnum\n"; ++ # write the instructions to file ++ writearray($FTPDCMD, \@ftpservercmd); + + # get the command line options to use + my @blaha; +@@ -4222,9 +4221,6 @@ sub singletest { + } + } + +- # remove the test server commands file after each test +- unlink($FTPDCMD) if(-f $FTPDCMD); +- + # run the postcheck command + my @postcheck= getpart("client", "postcheck"); + if(@postcheck) { +-- +2.34.1 + + +From ac04f6feaa19c636aa09a1b50643d70a77be4465 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 14 May 2020 17:45:40 +0200 +Subject: [PATCH 4/6] sws: as last resort, get test number from server cmd file + +If it can't be found in the request. Also support --cmdfile to set it to +a custom file name. + +runtests.pl always writes this file with the test number in it since a +while back. + +Upstream-commit: a3b0699d5c110270f09ac51b5b465ca8753b35a9 +Signed-off-by: Kamil Dudka +--- + tests/server/sws.c | 68 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 51 insertions(+), 17 deletions(-) + +diff --git a/tests/server/sws.c b/tests/server/sws.c +index 4ece830..2696872 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -155,6 +155,10 @@ const char *serverlogfile = DEFAULT_LOGFILE; + #define REQUEST_PROXY_DUMP "log/proxy.input" + #define RESPONSE_PROXY_DUMP "log/proxy.response" + ++/* file in which additional instructions may be found */ ++#define DEFAULT_CMDFILE "log/ftpserver.cmd" ++const char *cmdfile = DEFAULT_CMDFILE; ++ + /* very-big-path support */ + #define MAXDOCNAMELEN 140000 + #define MAXDOCNAMELEN_TXT "139999" +@@ -358,6 +362,24 @@ static bool socket_domain_is_ip(void) + } + } + ++/* parse the file on disk that might have a test number for us */ ++static int parse_cmdfile(struct httprequest *req) ++{ ++ int testnum = DOCNUMBER_NOTHING; ++ char buf[256]; ++ FILE *f = fopen(cmdfile, FOPEN_READTEXT); ++ if(f) { ++ while(fgets(buf, sizeof(buf), f)) { ++ if(1 == sscanf(buf, "Testnum %d", &testnum)) { ++ logmsg("[%s] cmdfile says testnum %d", cmdfile, testnum); ++ req->testno = testnum; ++ } ++ } ++ fclose(f); ++ } ++ return 0; ++} ++ + /* based on the testno, parse the correct server commands */ + static int parse_servercmd(struct httprequest *req) + { +@@ -622,34 +644,41 @@ static int ProcessRequest(struct httprequest *req) + + /* get the number after it */ + if(ptr) { ++ long num; + ptr++; /* skip the dot */ + +- req->testno = strtol(ptr, &ptr, 10); ++ num = strtol(ptr, &ptr, 10); + +- if(req->testno > 10000) { +- req->partno = req->testno % 10000; +- req->testno /= 10000; ++ if(num) { ++ req->testno = num; ++ if(req->testno > 10000) { ++ req->partno = req->testno % 10000; ++ req->testno /= 10000; + +- logmsg("found test %d in requested host name", req->testno); ++ logmsg("found test %d in requested host name", req->testno); + ++ } ++ else ++ req->partno = 0; + } +- else +- req->partno = 0; + +- snprintf(logbuf, sizeof(logbuf), +- "Requested test number %ld part %ld (from host name)", ++ if(req->testno != DOCNUMBER_NOTHING) { ++ logmsg("Requested test number %ld part %ld (from host name)", + req->testno, req->partno); +- logmsg("%s", logbuf); +- ++ } + } ++ } + +- if(!req->testno) { +- logmsg("Did not find test number in PATH"); +- req->testno = DOCNUMBER_404; +- } +- else +- parse_servercmd(req); ++ if(req->testno == DOCNUMBER_NOTHING) ++ /* might get the test number */ ++ parse_cmdfile(req); ++ ++ if(req->testno == DOCNUMBER_NOTHING) { ++ logmsg("Did not find test number in PATH"); ++ req->testno = DOCNUMBER_404; + } ++ else ++ parse_servercmd(req); + } + else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) { + logmsg("** Unusual request. Starts with %02x %02x %02x (%c%c%c)", +@@ -2038,6 +2067,11 @@ int main(int argc, char *argv[]) + if(argc>arg) + serverlogfile = argv[arg++]; + } ++ else if(!strcmp("--cmdfile", argv[arg])) { ++ arg++; ++ if(argc>arg) ++ cmdfile = argv[arg++]; ++ } + else if(!strcmp("--gopher", argv[arg])) { + arg++; + use_gopher = TRUE; +-- +2.34.1 + + +From 9fa56a1e3ae7feff14668d8abd892fa028a9f32e Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 13:05:40 +0200 +Subject: [PATCH 5/6] http: avoid auth/cookie on redirects same host diff port + +CVE-2022-27776 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27776.html +Closes #8749 + +Upstream-commit: 6e659993952aa5f90f48864be84a1bbb047fc258 +Signed-off-by: Kamil Dudka +--- + lib/http.c | 33 +++++++++++++++++++++------------ + lib/urldata.h | 16 +++++++++------- + 2 files changed, 30 insertions(+), 19 deletions(-) + +diff --git a/lib/http.c b/lib/http.c +index 0b5e476..39fc7aa 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -688,6 +688,21 @@ output_auth_headers(struct connectdata *conn, + return CURLE_OK; + } + ++/* ++ * allow_auth_to_host() tells if autentication, cookies or other "sensitive ++ * data" can (still) be sent to this host. ++ */ ++static bool allow_auth_to_host(struct connectdata *conn) ++{ ++ struct Curl_easy *data = conn->data; ++ return (!data->state.this_is_a_follow || ++ data->set.allow_auth_to_other_hosts || ++ (data->state.first_host && ++ strcasecompare(data->state.first_host, conn->host.name) && ++ (data->state.first_remote_port == conn->remote_port) && ++ (data->state.first_remote_protocol == conn->handler->protocol))); ++} ++ + /** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication +@@ -756,15 +771,11 @@ Curl_http_output_auth(struct connectdata *conn, + with it */ + authproxy->done = TRUE; + +- /* To prevent the user+password to get sent to other than the original +- host due to a location-follow, we do some weirdo checks here */ +- if(!data->state.this_is_a_follow || +- conn->bits.netrc || +- !data->state.first_host || +- data->set.allow_auth_to_other_hosts || +- strcasecompare(data->state.first_host, conn->host.name)) { ++ /* To prevent the user+password to get sent to other than the original host ++ due to a location-follow */ ++ if(allow_auth_to_host(conn) ++ || conn->bits.netrc) + result = output_auth_headers(conn, authhost, request, path, FALSE); +- } + else + authhost->done = TRUE; + +@@ -1778,10 +1789,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Cookie:", headers->data)) && + /* be careful of sending this potentially sensitive header to + other hosts */ +- (data->state.this_is_a_follow && +- data->state.first_host && +- !data->set.allow_auth_to_other_hosts && +- !strcasecompare(data->state.first_host, conn->host.name))) ++ !allow_auth_to_host(conn)) + ; + else { + result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); +@@ -1937,6 +1945,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) + return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; ++ data->state.first_remote_protocol = conn->handler->protocol; + } + http->writebytecount = http->readbytecount = 0; + +diff --git a/lib/urldata.h b/lib/urldata.h +index d3b971c..4bb0a84 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1231,13 +1231,15 @@ struct UrlState { + bytes / second */ + bool this_is_a_follow; /* this is a followed Location: request */ + bool refused_stream; /* this was refused, try again */ +- char *first_host; /* host name of the first (not followed) request. +- if set, this should be the host name that we will +- sent authorization to, no else. Used to make Location: +- following not keep sending user+password... This is +- strdup() data. +- */ +- int first_remote_port; /* remote port of the first (not followed) request */ ++ ++ /* host name, port number and protocol of the first (not followed) request. ++ if set, this should be the host name that we will sent authorization to, ++ no else. Used to make Location: following not keep sending user+password. ++ This is strdup()ed data. */ ++ char *first_host; ++ int first_remote_port; ++ unsigned int first_remote_protocol; ++ + struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ + long sessionage; /* number of the most recent session */ + unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ +-- +2.34.1 + + +From a8bb1e37e22788abaca37c59cf447d690fdcdfa4 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 13:05:47 +0200 +Subject: [PATCH 6/6] test898: verify the fix for CVE-2022-27776 + +Do not pass on Authorization headers on redirects to another port + +Upstream-commit: afe752e0504ab60bf63787ede0b992cbe1065f78 +Signed-off-by: Kamil Dudka +--- + tests/data/Makefile.inc | 2 +- + tests/data/test898 | 91 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 92 insertions(+), 1 deletion(-) + create mode 100644 tests/data/test898 + +diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc +index 77e85fd..58c9e31 100644 +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -99,7 +99,7 @@ test850 test851 test852 test853 test854 test855 test856 test857 test858 \ + test859 test860 test861 test862 test863 test864 test865 test866 test867 \ + test868 test869 test870 test871 test872 test873 test874 test875 test876 \ + test877 test878 test879 test880 test881 test882 test883 test884 test885 \ +-test886 test887 test888 test889 test890 test891 \ ++test886 test887 test888 test889 test890 test891 test898 \ + \ + test900 test901 test902 test903 test904 test905 test906 test907 test908 \ + test909 test910 test911 test912 test913 test914 test915 test916 test917 \ +diff --git a/tests/data/test898 b/tests/data/test898 +new file mode 100644 +index 0000000..e295c26 +--- /dev/null ++++ b/tests/data/test898 +@@ -0,0 +1,91 @@ ++ ++ ++ ++HTTP ++--location ++Authorization ++Cookie ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/8980002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/8980002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with custom auth and cookies redirected to HTTP on a diff port ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.com -L -H "Authorization: Basic am9lOnNlY3JldA==" -H "Cookie: userpwd=am9lOnNlY3JldA==" ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET http://firsthost.com/ HTTP/1.1 ++Host: firsthost.com ++Accept: */* ++Proxy-Connection: Keep-Alive ++Authorization: Basic am9lOnNlY3JldA== ++Cookie: userpwd=am9lOnNlY3JldA== ++ ++GET http://firsthost.com:9999/a/path/8980002 HTTP/1.1 ++Host: firsthost.com:9999 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +-- +2.34.1 + diff --git a/SOURCES/0038-curl-7.61.1-CVE-2022-27774.patch b/SOURCES/0038-curl-7.61.1-CVE-2022-27774.patch new file mode 100644 index 0000000..5ad6854 --- /dev/null +++ b/SOURCES/0038-curl-7.61.1-CVE-2022-27774.patch @@ -0,0 +1,714 @@ +From 48f126157d36962e458bf12f90b50cfcef26eee9 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 16:24:33 +0200 +Subject: [PATCH 1/4] connect: store "conn_remote_port" in the info struct + +To make it available after the connection ended. + +Upstream-commit: 08b8ef4e726ba10f45081ecda5b3cea788d3c839 +Signed-off-by: Kamil Dudka +--- + lib/connect.c | 1 + + lib/urldata.h | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/connect.c b/lib/connect.c +index f724646..12a8aae 100644 +--- a/lib/connect.c ++++ b/lib/connect.c +@@ -614,6 +614,7 @@ void Curl_persistconninfo(struct connectdata *conn) + conn->data->info.conn_scheme = conn->handler->scheme; + conn->data->info.conn_protocol = conn->handler->protocol; + conn->data->info.conn_primary_port = conn->primary_port; ++ conn->data->info.conn_remote_port = conn->remote_port; + conn->data->info.conn_local_port = conn->local_port; + } + +diff --git a/lib/urldata.h b/lib/urldata.h +index 4bb0a84..cadf0e5 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1050,7 +1050,11 @@ struct PureInfo { + reused, in the connection cache. */ + + char conn_primary_ip[MAX_IPADR_LEN]; +- long conn_primary_port; ++ long conn_primary_port;/* this is the destination port to the connection, ++ which might have been a proxy */ ++ int conn_remote_port; /* this is the "remote port", which is the port ++ number of the used URL, independent of proxy or ++ not */ + + char conn_local_ip[MAX_IPADR_LEN]; + long conn_local_port; +-- +2.34.1 + + +From 6307fa6f9784402ba58697f46ba04354225391b7 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 16:24:33 +0200 +Subject: [PATCH 2/4] transfer: redirects to other protocols or ports clear + auth + +... unless explicitly permitted. + +Bug: https://curl.se/docs/CVE-2022-27774.html +Reported-by: Harry Sintonen +Closes #8748 + +Upstream-commit: 620ea21410030a9977396b4661806bc187231b79 +Signed-off-by: Kamil Dudka +--- + lib/transfer.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ + lib/url.c | 27 ++++++++++++++-------- + lib/urldata.h | 1 + + 3 files changed, 81 insertions(+), 10 deletions(-) + +diff --git a/lib/transfer.c b/lib/transfer.c +index ad5a7ba..2022cba 100644 +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1370,6 +1370,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) + data->state.wildcardmatch = data->set.wildcard_enabled; + data->set.followlocation = 0; /* reset the location-follow counter */ + data->state.this_is_a_follow = FALSE; /* reset this */ ++ data->state.this_is_a_follow_without_auth = FALSE; + data->state.errorbuf = FALSE; /* no error has occurred */ + data->state.httpversion = 0; /* don't assume any particular server version */ + +@@ -1554,6 +1555,68 @@ CURLcode Curl_follow(struct Curl_easy *data, + + } + ++ /* Clear auth if this redirects to a different port number or protocol, ++ unless permitted */ ++ if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { ++ int port; ++ bool clear = FALSE; ++ ++ CURLU *u = curl_url(); ++ if(!u) ++ return CURLE_OUT_OF_MEMORY; ++ ++ uc = curl_url_set(u, CURLUPART_URL, newurl, ++ ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0)); ++ if(uc) { ++ infof(data, "Clear auth, curl_url_set() failed\n"); ++ clear = TRUE; ++ } ++ ++ if(!clear) { ++ if(data->set.use_port && data->state.allow_port) ++ /* a custom port is used */ ++ port = (int)data->set.use_port; ++ else { ++ char *portnum; ++ uc = curl_url_get(u, CURLUPART_PORT, &portnum, CURLU_DEFAULT_PORT); ++ if(uc) { ++ infof(data, "Clear auth, failed to parse port number\n"); ++ clear = TRUE; ++ } ++ else { ++ port = atoi(portnum); ++ free(portnum); ++ } ++ } ++ } ++ if(!clear && port != data->info.conn_remote_port) { ++ infof(data, "Clear auth, redirects to port from %u to %u\n", ++ data->info.conn_remote_port, port); ++ clear = TRUE; ++ } ++ if(!clear) { ++ char *scheme; ++ const struct Curl_handler *p; ++ uc = curl_url_get(u, CURLUPART_SCHEME, &scheme, 0); ++ if(uc) { ++ infof(data, "Clear auth, failed to parse scheme\n"); ++ clear = TRUE; ++ } ++ else { ++ p = Curl_builtin_scheme(scheme); ++ if(p && (p->protocol != data->info.conn_protocol)) { ++ infof(data, "Clear auth, redirects scheme from %s to %s\n", ++ data->info.conn_scheme, scheme); ++ clear = TRUE; ++ } ++ free(scheme); ++ } ++ } ++ if(clear) ++ data->state.this_is_a_follow_without_auth = TRUE; ++ curl_url_cleanup(u); ++ } ++ + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ +diff --git a/lib/url.c b/lib/url.c +index ed3c933..7dd5267 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -3483,18 +3483,25 @@ static CURLcode override_login(struct Curl_easy *data, + struct connectdata *conn, + char **userp, char **passwdp, char **optionsp) + { +- if(data->set.str[STRING_USERNAME]) { +- free(*userp); +- *userp = strdup(data->set.str[STRING_USERNAME]); +- if(!*userp) +- return CURLE_OUT_OF_MEMORY; ++ if(data->state.this_is_a_follow ++ && data->state.this_is_a_follow_without_auth) ++ { ++ conn->bits.user_passwd = FALSE; + } ++ else { ++ if(data->set.str[STRING_USERNAME]) { ++ free(*userp); ++ *userp = strdup(data->set.str[STRING_USERNAME]); ++ if(!*userp) ++ return CURLE_OUT_OF_MEMORY; ++ } + +- if(data->set.str[STRING_PASSWORD]) { +- free(*passwdp); +- *passwdp = strdup(data->set.str[STRING_PASSWORD]); +- if(!*passwdp) +- return CURLE_OUT_OF_MEMORY; ++ if(data->set.str[STRING_PASSWORD]) { ++ free(*passwdp); ++ *passwdp = strdup(data->set.str[STRING_PASSWORD]); ++ if(!*passwdp) ++ return CURLE_OUT_OF_MEMORY; ++ } + } + + if(data->set.str[STRING_OPTIONS]) { +diff --git a/lib/urldata.h b/lib/urldata.h +index cadf0e5..026684b 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1234,6 +1234,7 @@ struct UrlState { + curl_off_t current_speed; /* the ProgressShow() function sets this, + bytes / second */ + bool this_is_a_follow; /* this is a followed Location: request */ ++ bool this_is_a_follow_without_auth; + bool refused_stream; /* this was refused, try again */ + + /* host name, port number and protocol of the first (not followed) request. +-- +2.34.1 + + +From b142f97840dfb033a1776d5a2986385da7753224 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 16:24:33 +0200 +Subject: [PATCH 3/4] tests: verify the fix for CVE-2022-27774 + + - Test 973 redirects from HTTP to FTP, clear auth + - Test 974 redirects from HTTP to HTTP different port, clear auth + - Test 975 redirects from HTTP to FTP, permitted to keep auth + - Test 976 redirects from HTTP to HTTP different port, permitted to keep + auth + +Upstream-commit: 5295e8d64ac6949ecb3f9e564317a608f51b90d8 +Signed-off-by: Kamil Dudka +--- + tests/data/Makefile.inc | 1 + + tests/data/test973 | 90 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test974 | 88 ++++++++++++++++++++++++++++++++++++++++ + tests/data/test975 | 90 +++++++++++++++++++++++++++++++++++++++++ + tests/data/test976 | 89 ++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 358 insertions(+) + create mode 100644 tests/data/test973 + create mode 100644 tests/data/test974 + create mode 100644 tests/data/test975 + create mode 100644 tests/data/test976 + +diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc +index 58c9e31..6c920ff 100644 +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -108,6 +108,7 @@ test927 test928 test929 test930 test931 test932 test933 test934 test935 \ + test936 test937 test938 test939 test940 test941 test942 test943 test944 \ + test945 test946 test947 test948 test949 test950 test951 test952 \ + \ ++test973 test974 test975 test976 \ + test980 test981 test982 test983 test984 test985 test986 \ + \ + test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ +diff --git a/tests/data/test973 b/tests/data/test973 +new file mode 100644 +index 0000000..6fe6ce0 +--- /dev/null ++++ b/tests/data/test973 +@@ -0,0 +1,90 @@ ++ ++ ++ ++HTTP ++FTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9730002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP w/o auth ++ ++ ++http://%HOSTIP:%HTTPPORT/973 -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET /973 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++Accept: */* ++ ++USER anonymous ++PASS ftp@example.com ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9730002 ++RETR 9730002 ++QUIT ++ ++ ++ +diff --git a/tests/data/test974 b/tests/data/test974 +new file mode 100644 +index 0000000..de02d89 +--- /dev/null ++++ b/tests/data/test974 +@@ -0,0 +1,88 @@ ++ ++ ++ ++HTTP ++--location ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/9740002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/9740002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port w/o auth ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.com -L -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET http://firsthost.com/ HTTP/1.1 ++Host: firsthost.com ++Authorization: Basic am9lOnNlY3JldA== ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.com:9999/a/path/9740002 HTTP/1.1 ++Host: firsthost.com:9999 ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +diff --git a/tests/data/test975 b/tests/data/test975 +new file mode 100644 +index 0000000..3a4eccf +--- /dev/null ++++ b/tests/data/test975 +@@ -0,0 +1,90 @@ ++ ++ ++ ++HTTP ++FTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++ ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: ftp://127.0.0.1:8992/a/path/9750002 ++ ++data ++ to ++ see ++that FTP ++works ++ so does it? ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ftp ++ ++ ++HTTP with auth redirected to FTP allowing auth to continue ++ ++ ++http://%HOSTIP:%HTTPPORT/975 --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET /975 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic am9lOnNlY3JldA== ++Accept: */* ++ ++USER joe ++PASS secret ++PWD ++CWD a ++CWD path ++EPSV ++TYPE I ++SIZE 9750002 ++RETR 9750002 ++QUIT ++ ++ ++ +diff --git a/tests/data/test976 b/tests/data/test976 +new file mode 100644 +index 0000000..3b6fac7 +--- /dev/null ++++ b/tests/data/test976 +@@ -0,0 +1,89 @@ ++ ++ ++ ++HTTP ++--location-trusted ++ ++ ++ ++# ++# Server-side ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/9760002 ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++HTTP/1.1 301 redirect ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 0 ++Connection: close ++Content-Type: text/html ++Location: http://firsthost.com:9999/a/path/9760002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Content-Length: 4 ++Connection: close ++Content-Type: text/html ++ ++hey ++ ++ ++ ++ ++# ++# Client-side ++ ++ ++http ++ ++ ++HTTP with auth redirected to HTTP on a diff port --location-trusted ++ ++ ++-x http://%HOSTIP:%HTTPPORT http://firsthost.com --location-trusted -u joe:secret ++ ++ ++ ++# ++# Verify data after the test has been "shot" ++ ++ ++^User-Agent:.* ++ ++ ++GET http://firsthost.com/ HTTP/1.1 ++Host: firsthost.com ++Authorization: Basic am9lOnNlY3JldA== ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://firsthost.com:9999/a/path/9760002 HTTP/1.1 ++Host: firsthost.com:9999 ++Authorization: Basic am9lOnNlY3JldA== ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +-- +2.34.1 + + +From cf98bd64b9949c50d4726eb26745c2f7fdf3a075 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Apr 2022 17:59:15 +0200 +Subject: [PATCH 4/4] openssl: don't leak the SRP credentials in redirects + either + +Follow-up to 620ea21410030 + +Reported-by: Harry Sintonen +Closes #8751 + +Upstream-commit: 139a54ed0a172adaaf1a78d6f4fff50b2c3f9e08 +Signed-off-by: Kamil Dudka +--- + lib/http.c | 10 +++++----- + lib/http.h | 6 ++++++ + lib/vtls/openssl.c | 3 ++- + 3 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/lib/http.c b/lib/http.c +index 39fc7aa..d413738 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -689,10 +689,10 @@ output_auth_headers(struct connectdata *conn, + } + + /* +- * allow_auth_to_host() tells if autentication, cookies or other "sensitive +- * data" can (still) be sent to this host. ++ * Curl_allow_auth_to_host() tells if authentication, cookies or other ++ * "sensitive data" can (still) be sent to this host. + */ +-static bool allow_auth_to_host(struct connectdata *conn) ++bool Curl_allow_auth_to_host(struct connectdata *conn) + { + struct Curl_easy *data = conn->data; + return (!data->state.this_is_a_follow || +@@ -773,7 +773,7 @@ Curl_http_output_auth(struct connectdata *conn, + + /* To prevent the user+password to get sent to other than the original host + due to a location-follow */ +- if(allow_auth_to_host(conn) ++ if(Curl_allow_auth_to_host(conn) + || conn->bits.netrc) + result = output_auth_headers(conn, authhost, request, path, FALSE); + else +@@ -1789,7 +1789,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Cookie:", headers->data)) && + /* be careful of sending this potentially sensitive header to + other hosts */ +- !allow_auth_to_host(conn)) ++ !Curl_allow_auth_to_host(conn)) + ; + else { + result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); +diff --git a/lib/http.h b/lib/http.h +index 1d373e8..56a6061 100644 +--- a/lib/http.h ++++ b/lib/http.h +@@ -252,5 +252,11 @@ Curl_http_output_auth(struct connectdata *conn, + bool proxytunnel); /* TRUE if this is the request setting + up the proxy tunnel */ + ++/* ++ * Curl_allow_auth_to_host() tells if authentication, cookies or other ++ * "sensitive data" can (still) be sent to this host. ++ */ ++bool Curl_allow_auth_to_host(struct connectdata *conn); ++ + #endif /* HEADER_CURL_HTTP_H */ + +diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c +index 28eaa6d..6c8faa2 100644 +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -2499,7 +2499,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) + #endif + + #ifdef USE_TLS_SRP +- if(ssl_authtype == CURL_TLSAUTH_SRP) { ++ if((ssl_authtype == CURL_TLSAUTH_SRP) && ++ Curl_allow_auth_to_host(conn)) { + char * const ssl_username = SSL_SET_OPTION(username); + + infof(data, "Using TLS-SRP username: %s\n", ssl_username); +-- +2.34.1 + diff --git a/SOURCES/0039-curl-7.61.1-CVE-2022-27782.patch b/SOURCES/0039-curl-7.61.1-CVE-2022-27782.patch new file mode 100644 index 0000000..58e3f98 --- /dev/null +++ b/SOURCES/0039-curl-7.61.1-CVE-2022-27782.patch @@ -0,0 +1,364 @@ +From d4247fa7baf0859729fff2fe5cf0bfab8322d1a5 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 9 May 2022 23:13:53 +0200 +Subject: [PATCH 1/2] tls: check more TLS details for connection reuse + +CVE-2022-27782 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27782.html +Closes #8825 + +Upstream-commit: f18af4f874cecab82a9797e8c7541e0990c7a64c +Signed-off-by: Kamil Dudka +--- + lib/setopt.c | 29 +++++++++++++++++------------ + lib/url.c | 19 ++++++++++++------- + lib/urldata.h | 14 +++++++------- + lib/vtls/openssl.c | 10 +++++----- + lib/vtls/vtls.c | 21 +++++++++++++++++++++ + 5 files changed, 62 insertions(+), 31 deletions(-) + +diff --git a/lib/setopt.c b/lib/setopt.c +index b07ccfe..319a010 100644 +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -2044,6 +2044,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, + + case CURLOPT_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); +@@ -2051,6 +2052,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, + + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); ++ data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + break; +@@ -2451,44 +2453,47 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, + case CURLOPT_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default to ++ SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + va_arg(param, char *)); +- if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ if(data->set.str[STRING_TLSAUTH_USERNAME] && ++ !data->set.ssl.primary.authtype) ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && +- !data->set.proxy_ssl.authtype) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ ++ !data->set.proxy_ssl.primary.authtype) ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; /* default */ + break; + case CURLOPT_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + case CURLOPT_PROXY_TLSAUTH_TYPE: + argptr = va_arg(param, char *); + if(!argptr || + strncasecompare(argptr, "SRP", strlen("SRP"))) +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_SRP; + else +- data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; ++ data->set.proxy_ssl.primary.authtype = CURL_TLSAUTH_NONE; + break; + #endif + case CURLOPT_DNS_SERVERS: +diff --git a/lib/url.c b/lib/url.c +index 7dd5267..30fc5ad 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -461,7 +461,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; + #ifdef USE_TLS_SRP +- set->ssl.authtype = CURL_TLSAUTH_NONE; ++ set->ssl.primary.authtype = CURL_TLSAUTH_NONE; + #endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ +@@ -1881,10 +1881,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; ++ conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options; + conn->proxy_ssl_config.verifystatus = + data->set.proxy_ssl.primary.verifystatus; + conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; + conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; ++ conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; + + conn->ip_version = data->set.ipver; + +@@ -4362,8 +4364,9 @@ static CURLcode create_conn(struct Curl_easy *data, + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + +- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; +- data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; ++ data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; ++ data->set.proxy_ssl.primary.CRLfile = ++ data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; +@@ -4377,10 +4380,12 @@ static CURLcode create_conn(struct Curl_easy *data, + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + #ifdef USE_TLS_SRP +- data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; +- data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; +- data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +- data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; ++ data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; ++ data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; ++ data->set.proxy_ssl.primary.username = ++ data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; ++ data->set.proxy_ssl.primary.password = ++ data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; + #endif + + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, +diff --git a/lib/urldata.h b/lib/urldata.h +index 026684b..0e48841 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -229,6 +229,13 @@ struct ssl_primary_config { + char *egdsocket; /* path to file containing the EGD daemon socket */ + char *cipher_list; /* list of ciphers to use */ + char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ ++ char *CRLfile; /* CRL to check certificate revocation */ ++#ifdef USE_TLS_SRP ++ char *username; /* TLS username (for, e.g., SRP) */ ++ char *password; /* TLS password (for, e.g., SRP) */ ++ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ ++#endif ++ unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ + }; + + struct ssl_config_data { +@@ -238,7 +245,6 @@ struct ssl_config_data { + bool no_revoke; /* disable SSL certificate revocation checks */ + bool no_partialchain; /* don't accept partial certificate chains */ + long certverifyresult; /* result from the certificate verification */ +- char *CRLfile; /* CRL to check certificate revocation */ + curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ + void *fsslctxp; /* parameter for call back */ + bool certinfo; /* gather lots of certificate info */ +@@ -249,12 +255,6 @@ struct ssl_config_data { + char *key; /* private key file name */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ +- +-#ifdef USE_TLS_SRP +- char *username; /* TLS username (for, e.g., SRP) */ +- char *password; /* TLS password (for, e.g., SRP) */ +- enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +-#endif + }; + + struct ssl_general_config { +diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c +index 6c8faa2..75ff8d8 100644 +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -2232,14 +2232,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const long int ssl_version = SSL_CONN_CONFIG(version); + #ifdef USE_TLS_SRP +- const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); ++ const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype); + #endif + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); +- const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); ++ const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile); + char error_buffer[256]; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); +@@ -2501,15 +2501,15 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) + #ifdef USE_TLS_SRP + if((ssl_authtype == CURL_TLSAUTH_SRP) && + Curl_allow_auth_to_host(conn)) { +- char * const ssl_username = SSL_SET_OPTION(username); +- ++ char * const ssl_username = SSL_SET_OPTION(primary.username); ++ char * const ssl_password = SSL_SET_OPTION(primary.password); + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +- if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { ++ if(!SSL_CTX_set_srp_password(BACKEND->ctx, ssl_password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } +diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c +index bdff93f..2b14fa6 100644 +--- a/lib/vtls/vtls.c ++++ b/lib/vtls/vtls.c +@@ -88,6 +88,7 @@ Curl_ssl_config_matches(struct ssl_primary_config* data, + { + if((data->version == needle->version) && + (data->version_max == needle->version_max) && ++ (data->ssl_options == needle->ssl_options) && + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + (data->verifystatus == needle->verifystatus) && +@@ -96,6 +97,12 @@ Curl_ssl_config_matches(struct ssl_primary_config* data, + Curl_safecmp(data->clientcert, needle->clientcert) && + Curl_safecmp(data->random_file, needle->random_file) && + Curl_safecmp(data->egdsocket, needle->egdsocket) && ++#ifdef USE_TLS_SRP ++ Curl_safecmp(data->username, needle->username) && ++ Curl_safecmp(data->password, needle->password) && ++ (data->authtype == needle->authtype) && ++#endif ++ Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && + Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13)) + return TRUE; +@@ -113,6 +120,10 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + dest->verifyhost = source->verifyhost; + dest->verifystatus = source->verifystatus; + dest->sessionid = source->sessionid; ++ dest->ssl_options = source->ssl_options; ++#ifdef USE_TLS_SRP ++ dest->authtype = source->authtype; ++#endif + + CLONE_STRING(CApath); + CLONE_STRING(CAfile); +@@ -122,6 +133,11 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + CLONE_STRING(egdsocket); + CLONE_STRING(cipher_list); + CLONE_STRING(cipher_list13); ++ CLONE_STRING(CRLfile); ++#ifdef USE_TLS_SRP ++ CLONE_STRING(username); ++ CLONE_STRING(password); ++#endif + + return TRUE; + } +@@ -136,6 +152,11 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); ++ Curl_safefree(sslc->CRLfile); ++#ifdef USE_TLS_SRP ++ Curl_safefree(sslc->username); ++ Curl_safefree(sslc->password); ++#endif + } + + #ifdef USE_SSL +-- +2.34.1 + + +From a9cf46e6c6c9a4261f3ea8500dfef87c1436908b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 9 May 2022 23:13:53 +0200 +Subject: [PATCH 2/2] url: check SSH config match on connection reuse + +CVE-2022-27782 + +Reported-by: Harry Sintonen +Bug: https://curl.se/docs/CVE-2022-27782.html +Closes #8825 + +Upstream-commit: 1645e9b44505abd5cbaf65da5282c3f33b5924a5 +Signed-off-by: Kamil Dudka +--- + lib/ssh.h | 4 ++-- + lib/url.c | 11 +++++++++++ + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/lib/ssh.h b/lib/ssh.h +index 0620aac..1114f8a 100644 +--- a/lib/ssh.h ++++ b/lib/ssh.h +@@ -117,8 +117,8 @@ struct ssh_conn { + + /* common */ + const char *passphrase; /* pass-phrase to use */ +- char *rsa_pub; /* path name */ +- char *rsa; /* path name */ ++ char *rsa_pub; /* strdup'ed public key file */ ++ char *rsa; /* strdup'ed private key file */ + bool authed; /* the connection has been authenticated fine */ + sshstate state; /* always use ssh.c:state() to change state! */ + sshstate nextstate; /* the state to goto after stopping */ +diff --git a/lib/url.c b/lib/url.c +index 30fc5ad..8653ebb 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -1030,6 +1030,12 @@ static size_t max_pipeline_length(struct Curl_multi *multi) + } + + ++static bool ssh_config_matches(struct connectdata *one, ++ struct connectdata *two) ++{ ++ return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && ++ Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub)); ++} + /* + * Given one filled in connection struct (named needle), this function should + * detect if there already is one that has all the significant details +@@ -1299,6 +1305,11 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++ if(needle->handler->protocol & (CURLPROTO_SCP|CURLPROTO_SFTP)) { ++ if(!ssh_config_matches(needle, check)) ++ continue; ++ } ++ + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + needle->bits.tunnel_proxy) { + /* The requested connection does not use a HTTP proxy or it uses SSL or +-- +2.34.1 + diff --git a/SPECS/curl.spec b/SPECS/curl.spec index 8883da4..5c43cf7 100644 --- a/SPECS/curl.spec +++ b/SPECS/curl.spec @@ -1,7 +1,7 @@ Summary: A utility for getting files from remote servers (FTP, HTTP, and others) Name: curl Version: 7.61.1 -Release: 22%{?dist} +Release: 22%{?dist}.3 License: MIT Source: https://curl.haxx.se/download/%{name}-%{version}.tar.xz @@ -100,6 +100,18 @@ Patch34: 0034-curl-7.61.1-CVE-2021-22946.patch # fix STARTTLS protocol injection via MITM (CVE-2021-22947) Patch35: 0035-curl-7.61.1-CVE-2021-22947.patch +# fix OAUTH2 bearer bypass in connection re-use (CVE-2022-22576) +Patch36: 0036-curl-7.61.1-CVE-2022-22576.patch + +# fix auth/cookie leak on redirect (CVE-2022-27776) +Patch37: 0037-curl-7.61.1-CVE-2022-27776.patch + +# fix credential leak on redirect (CVE-2022-27774) +Patch38: 0038-curl-7.61.1-CVE-2022-27774.patch + +# fix too eager reuse of TLS and SSH connections (CVE-2022-27782) +Patch39: 0039-curl-7.61.1-CVE-2022-27782.patch + # patch making libcurl multilib ready Patch101: 0101-curl-7.32.0-multilib.patch @@ -305,6 +317,13 @@ sed -e 's|%%HTTPPORT|%{?__isa_bits}90|g' -i tests/data/test1448 %patch33 -p1 %patch34 -p1 %patch35 -p1 +%patch36 -p1 +%patch37 -p1 + +%patch38 -p1 +sed -e 's|:8992/|:%{?__isa_bits}92/|g' -i tests/data/test97{3..6} + +%patch39 -p1 # make tests/*.py use Python 3 sed -e '1 s|^#!/.*python|#!%{__python3}|' -i tests/*.py @@ -467,6 +486,17 @@ rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la %{_libdir}/libcurl.so.4.[0-9].[0-9].minimal %changelog +* Wed May 11 2022 Kamil Dudka - 7.61.1-22.el8_6.3 +- fix too eager reuse of TLS and SSH connections (CVE-2022-27782) + +* Tue May 04 2022 Kamil Dudka - 7.61.1-22.el8_6.2 +- fix invalid type in printf() argument detected by Coverity + +* Thu Apr 28 2022 Kamil Dudka - 7.61.1-22.el8_6.1 +- fix credential leak on redirect (CVE-2022-27774) +- fix auth/cookie leak on redirect (CVE-2022-27776) +- fix OAUTH2 bearer bypass in connection re-use (CVE-2022-22576) + * Fri Sep 17 2021 Kamil Dudka - 7.61.1-22 - fix STARTTLS protocol injection via MITM (CVE-2021-22947) - fix protocol downgrade required TLS bypass (CVE-2021-22946)