From c1aa0bb50caa07350ecff60a0d72a97b10a674a0 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Thu, 3 Mar 2022 12:16:30 +0200 Subject: [PATCH] Make TLS session ticket extension configurable A previous commit has enabled the TLS session ticket extension (by removing SSL_OP_NO_TICKET) because Chrome uses it. This commit makes it configurable via the CURLOPT_SSL_ENABLE_TICKET libcurl option or the '--tls-session-ticker' command line flag. The goal is to impersonate Safari which, as of version 15.3, does not use TLS session tickets. --- chrome/patches/curl-impersonate.patch | 142 ++++++++++++++++++-------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 0646682..91623a7 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -22,10 +22,10 @@ index 63e320236..deb054300 100644 LDFLAGS="$LDFLAGS $LD_H2" diff --git a/include/curl/curl.h b/include/curl/curl.h -index 7b69ce2d6..1405a228e 100644 +index 7b69ce2d6..42b7604d1 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h -@@ -2135,6 +2135,26 @@ typedef enum { +@@ -2135,6 +2135,29 @@ typedef enum { /* Set MIME option flags. */ CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315), @@ -48,6 +48,9 @@ index 7b69ce2d6..1405a228e 100644 + * Supported algorithms are "zlib" and "brotli". + * See https://datatracker.ietf.org/doc/html/rfc8879 */ + CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 319), ++ ++ /* Enable/disable TLS session ticket extension (RFC5077) */ ++ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 320), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -73,7 +76,7 @@ index 2dbfb26b5..e0bf86169 100644 * NAME curl_easy_getinfo() * diff --git a/lib/easy.c b/lib/easy.c -index 20293a710..5182c56b4 100644 +index 20293a710..b9c5a80b2 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -80,6 +80,7 @@ @@ -84,7 +87,7 @@ index 20293a710..5182c56b4 100644 /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -282,6 +283,198 @@ void curl_global_cleanup(void) +@@ -282,6 +283,207 @@ void curl_global_cleanup(void) init_flags = 0; } @@ -105,6 +108,8 @@ index 20293a710..5182c56b4 100644 + bool alpn; + /* Enable TLS ALPS extension. */ + bool alps; ++ /* Enable TLS session ticket extension. */ ++ bool tls_session_ticket; + /* TLS certificate compression algorithms. + * (TLS extension 27) */ + const char *cert_compression; @@ -135,6 +140,7 @@ index 20293a710..5182c56b4 100644 + .npn = false, + .alpn = true, + .alps = true, ++ .tls_session_ticket = true, + .cert_compression = "brotli", + .http_headers = { + "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"", @@ -174,6 +180,7 @@ index 20293a710..5182c56b4 100644 + .npn = false, + .alpn = true, + .alps = true, ++ .tls_session_ticket = true, + .cert_compression = "brotli", + .http_headers = { + "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Microsoft Edge\";v=\"98\"", @@ -252,6 +259,11 @@ index 20293a710..5182c56b4 100644 + if(ret) + return ret; + ++ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_TICKET, ++ opts->tls_session_ticket ? 1 : 0); ++ if(ret) ++ return ret; ++ + if(opts->cert_compression) { + ret = curl_easy_setopt(data, + CURLOPT_SSL_CERT_COMPRESSION, @@ -283,7 +295,7 @@ index 20293a710..5182c56b4 100644 /* * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. -@@ -290,6 +483,7 @@ struct Curl_easy *curl_easy_init(void) +@@ -290,6 +492,7 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -291,7 +303,7 @@ index 20293a710..5182c56b4 100644 /* Make sure we inited the global SSL stuff */ if(!initialized) { -@@ -308,6 +502,22 @@ struct Curl_easy *curl_easy_init(void) +@@ -308,6 +511,22 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -314,7 +326,7 @@ index 20293a710..5182c56b4 100644 return data; } -@@ -878,6 +1088,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -878,6 +1097,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -329,7 +341,7 @@ index 20293a710..5182c56b4 100644 * note: the engine name has already been copied by dupset */ if(outcurl->set.str[STRING_SSL_ENGINE]) { diff --git a/lib/easyoptions.c b/lib/easyoptions.c -index 04871ad1e..99c17e35a 100644 +index 04871ad1e..385eab2e6 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -130,6 +130,7 @@ struct curl_easyoption Curl_easyopts[] = { @@ -340,7 +352,7 @@ index 04871ad1e..99c17e35a 100644 {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, -@@ -297,8 +298,11 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -297,8 +298,12 @@ struct curl_easyoption Curl_easyopts[] = { {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0}, {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0}, {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0}, @@ -349,15 +361,16 @@ index 04871ad1e..99c17e35a 100644 {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0}, {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0}, + {"SSL_ENABLE_ALPS", CURLOPT_SSL_ENABLE_ALPS, CURLOT_LONG, 0}, ++ {"SSL_ENABLE_TICKET", CURLOPT_SSL_ENABLE_TICKET, CURLOT_LONG, 0}, {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0}, {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0}, {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0}, -@@ -360,6 +364,6 @@ struct curl_easyoption Curl_easyopts[] = { +@@ -360,6 +365,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (315 + 1)); -+ return ((CURLOPT_LASTENTRY%10000) != (319 + 1)); ++ return ((CURLOPT_LASTENTRY%10000) != (320 + 1)); } #endif diff --git a/lib/http.c b/lib/http.c @@ -661,7 +674,7 @@ index f8dcc63b4..e6b728592 100644 #ifdef USE_WINSOCK diff --git a/lib/setopt.c b/lib/setopt.c -index 599ed5d99..fc7ec2a7c 100644 +index 599ed5d99..7a3880b0e 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -48,6 +48,7 @@ @@ -724,12 +737,15 @@ index 599ed5d99..fc7ec2a7c 100644 #endif case CURLOPT_IPRESOLVE: arg = va_arg(param, long); -@@ -2871,6 +2910,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +@@ -2871,6 +2910,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_SSL_ENABLE_ALPN: data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_SSL_ENABLE_ALPS: + data->set.ssl_enable_alps = (0 != va_arg(param, long)) ? TRUE : FALSE; ++ break; ++ case CURLOPT_SSL_ENABLE_TICKET: ++ data->set.ssl_enable_ticket = (0 != va_arg(param, long)) ? TRUE : FALSE; + break; #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: @@ -756,7 +772,7 @@ index 22704fa15..1e100140c 100644 Curl_headersep(head->data[thislen]) ) return head->data; diff --git a/lib/url.c b/lib/url.c -index 9f1013554..7aa3ccf00 100644 +index 9f1013554..0eff9c354 100644 --- a/lib/url.c +++ b/lib/url.c @@ -469,6 +469,11 @@ CURLcode Curl_close(struct Curl_easy **datap) @@ -771,7 +787,15 @@ index 9f1013554..7aa3ccf00 100644 #ifndef CURL_DISABLE_DOH if(data->req.doh) { Curl_dyn_free(&data->req.doh->probe[0].serverdoh); -@@ -3808,6 +3813,9 @@ static CURLcode create_conn(struct Curl_easy *data, +@@ -622,6 +627,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) + set->tcp_nodelay = TRUE; + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; ++ set->ssl_enable_ticket = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; +@@ -3808,6 +3814,9 @@ static CURLcode create_conn(struct Curl_easy *data, data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; @@ -781,20 +805,26 @@ index 9f1013554..7aa3ccf00 100644 #ifndef CURL_DISABLE_PROXY data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; -@@ -3925,6 +3933,11 @@ static CURLcode create_conn(struct Curl_easy *data, +@@ -3925,8 +3934,17 @@ static CURLcode create_conn(struct Curl_easy *data, conn->bits.tls_enable_alpn = TRUE; if(data->set.ssl_enable_npn) conn->bits.tls_enable_npn = TRUE; + -+ /* curl-impersonatE: Turn on ALPS if ALPN is enabled and the bit is ++ /* curl-impersonate: Turn on ALPS if ALPN is enabled and the bit is + * enabled. */ + if(data->set.ssl_enable_alps) + conn->bits.tls_enable_alps = TRUE; } ++ /* curl-impersonate: Add the TLS session ticket extension. */ ++ if(data->set.ssl_enable_ticket) ++ conn->bits.tls_enable_ticket = TRUE; ++ if(waitpipe) + /* There is a connection that *might* become usable for multiplexing + "soon", and we wait for that */ diff --git a/lib/urldata.h b/lib/urldata.h -index cc9c88870..0c6d56614 100644 +index cc9c88870..3f268bf14 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -257,6 +257,8 @@ struct ssl_primary_config { @@ -806,15 +836,16 @@ index cc9c88870..0c6d56614 100644 BIT(verifypeer); /* set TRUE if this is desired */ BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ BIT(verifystatus); /* set TRUE if certificate status must be checked */ -@@ -517,6 +519,7 @@ struct ConnectBits { +@@ -517,6 +519,8 @@ struct ConnectBits { BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ + BIT(tls_enable_alps); /* TLS ALPS extension? */ ++ BIT(tls_enable_ticket); /* TLS session ticket extension? */ BIT(connect_only); #ifndef CURL_DISABLE_DOH BIT(doh); -@@ -1421,6 +1424,19 @@ struct UrlState { +@@ -1421,6 +1425,19 @@ struct UrlState { CURLcode hresult; /* used to pass return codes back from hyper callbacks */ #endif @@ -834,7 +865,7 @@ index cc9c88870..0c6d56614 100644 /* Dynamically allocated strings, MUST be freed before this struct is killed. */ struct dynamically_allocated_data { -@@ -1579,6 +1595,8 @@ enum dupstring { +@@ -1579,6 +1596,8 @@ enum dupstring { STRING_DNS_LOCAL_IP4, STRING_DNS_LOCAL_IP6, STRING_SSL_EC_CURVES, @@ -843,16 +874,17 @@ index cc9c88870..0c6d56614 100644 /* -- end of null-terminated strings -- */ -@@ -1849,6 +1867,7 @@ struct UserDefined { +@@ -1849,6 +1868,8 @@ struct UserDefined { BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(ssl_enable_npn); /* TLS NPN extension? */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ + BIT(ssl_enable_alps);/* TLS ALPS extension? */ ++ BIT(ssl_enable_ticket); /* TLS session ticket extension */ BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new connection */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c -index f836c63b0..6ef19b840 100644 +index f836c63b0..c310f65ba 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -76,6 +76,13 @@ @@ -1146,19 +1178,23 @@ index f836c63b0..6ef19b840 100644 static CURLcode ossl_connect_step1(struct Curl_easy *data, struct connectdata *conn, int sockindex) { -@@ -2767,7 +3030,10 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, +@@ -2767,7 +3030,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, ctx_options = SSL_OP_ALL; #ifdef SSL_OP_NO_TICKET - ctx_options |= SSL_OP_NO_TICKET; -+ /* curl-impersonate patch. ++ if(conn->bits.tls_enable_ticket) { ++ /* curl-impersonate: + * Turn off SSL_OP_NO_TICKET, we want TLS extension 35 (session_ticket) -+ * to be sent. */ -+ ctx_options &= ~SSL_OP_NO_TICKET; ++ * to be present in the client hello. */ ++ ctx_options &= ~SSL_OP_NO_TICKET; ++ } else { ++ ctx_options |= SSL_OP_NO_TICKET; ++ } #endif #ifdef SSL_OP_NO_COMPRESSION -@@ -2912,6 +3178,35 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, +@@ -2912,6 +3182,35 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } #endif @@ -1194,7 +1230,7 @@ index f836c63b0..6ef19b840 100644 #ifdef USE_OPENSSL_SRP if(ssl_authtype == CURL_TLSAUTH_SRP) { char * const ssl_username = SSL_SET_OPTION(username); -@@ -2937,6 +3232,20 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, +@@ -2937,6 +3236,20 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } #endif @@ -1215,7 +1251,7 @@ index f836c63b0..6ef19b840 100644 #if defined(USE_WIN32_CRYPTO) /* Import certificates from the Windows root certificate store if requested. -@@ -3236,6 +3545,33 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, +@@ -3236,6 +3549,33 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, SSL_set_connect_state(backend->handle); @@ -1282,7 +1318,7 @@ index 6007bbba0..3c79e0d30 100644 #ifdef USE_SSL diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h -index 227b914e3..151b7b6dd 100644 +index 227b914e3..91ffa283b 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -165,6 +165,8 @@ struct OperationConfig { @@ -1294,29 +1330,31 @@ index 227b914e3..151b7b6dd 100644 char *krblevel; char *request_target; long httpversion; -@@ -274,6 +276,7 @@ struct OperationConfig { +@@ -274,6 +276,8 @@ struct OperationConfig { char *oauth_bearer; /* OAuth 2.0 bearer token */ bool nonpn; /* enable/disable TLS NPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */ + bool alps; /* enable/disable TLS ALPS extension */ ++ bool noticket; /* enable/disable TLS session ticket */ char *unix_socket_path; /* path to Unix domain socket */ bool abstract_unix_socket; /* path to an abstract Unix domain socket */ bool falsestart; diff --git a/src/tool_getparam.c b/src/tool_getparam.c -index 7abbcc639..09cd4dbc5 100644 +index 7abbcc639..e6165dc18 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c -@@ -279,6 +279,9 @@ static const struct LongShort aliases[]= { +@@ -279,6 +279,10 @@ static const struct LongShort aliases[]= { {"EC", "etag-save", ARG_FILENAME}, {"ED", "etag-compare", ARG_FILENAME}, {"EE", "curves", ARG_STRING}, + {"EG", "signature-hashes", ARG_STRING}, + {"EH", "alps", ARG_BOOL}, + {"EI", "cert-compression", ARG_STRING}, ++ {"EJ", "tls-session-ticket", ARG_BOOL}, {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, -@@ -1794,6 +1797,21 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ +@@ -1794,6 +1798,26 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ GetStr(&config->ssl_ec_curves, nextarg); break; @@ -1334,15 +1372,20 @@ index 7abbcc639..09cd4dbc5 100644 + /* --cert-compression */ + GetStr(&config->ssl_cert_compression, nextarg); + break; ++ ++ case 'J': ++ /* --tls-session-ticket */ ++ config->noticket = (!toggle)?TRUE:FALSE; ++ break; + default: /* unknown flag */ return PARAM_OPTION_UNKNOWN; } diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c -index 448fc7cb3..24e26b96e 100644 +index 448fc7cb3..43201c639 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c -@@ -106,6 +106,12 @@ const struct helptxt helptext[] = { +@@ -106,6 +106,15 @@ const struct helptxt helptext[] = { {" --curves ", "(EC) TLS key exchange algorithm(s) to request", CURLHELP_TLS}, @@ -1351,11 +1394,14 @@ index 448fc7cb3..24e26b96e 100644 + CURLHELP_TLS}, + {" --cert-compression ", + "TLS cert compressions algorithm(s) to use", ++ CURLHELP_TLS}, ++ {" --no-tls-session-ticket", ++ "Disable the TLS session ticket extension", + CURLHELP_TLS}, {"-d, --data ", "HTTP POST data", CURLHELP_IMPORTANT | CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, -@@ -379,6 +385,9 @@ const struct helptxt helptext[] = { +@@ -379,6 +388,9 @@ const struct helptxt helptext[] = { {" --no-alpn", "Disable the ALPN TLS extension", CURLHELP_TLS | CURLHELP_HTTP}, @@ -1366,7 +1412,7 @@ index 448fc7cb3..24e26b96e 100644 "Disable buffering of the output stream", CURLHELP_CURL}, diff --git a/src/tool_operate.c b/src/tool_operate.c -index fe2c43b55..843a94a76 100644 +index fe2c43b55..c829515dd 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1520,6 +1520,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, @@ -1384,14 +1430,30 @@ index fe2c43b55..843a94a76 100644 if(curlinfo->features & CURL_VERSION_SSL) { /* Check if config->cert is a PKCS#11 URI and set the * config->cert_type if necessary */ -@@ -2061,6 +2069,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2061,6 +2069,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } + if(config->alps) { + my_setopt(curl, CURLOPT_SSL_ENABLE_ALPS, 1L); + } ++ ++ if (config->noticket) { ++ my_setopt(curl, CURLOPT_SSL_ENABLE_TICKET, 0L); ++ } + /* new in 7.40.0, abstract support added in 7.53.0 */ if(config->unix_socket_path) { if(config->abstract_unix_socket) { +diff --git a/src/tool_setopt.c b/src/tool_setopt.c +index 4c86eb321..eef8b187f 100644 +--- a/src/tool_setopt.c ++++ b/src/tool_setopt.c +@@ -179,6 +179,7 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { + NV1(CURLOPT_SSL_VERIFYHOST, 1), + NV1(CURLOPT_SSL_ENABLE_NPN, 1), + NV1(CURLOPT_SSL_ENABLE_ALPN, 1), ++ NV1(CURLOPT_SSL_ENABLE_TICKET, 1), + NV1(CURLOPT_TCP_NODELAY, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),