From a7629ee1ff393078fecf2fd51d44f2c444d06dcc Mon Sep 17 00:00:00 2001 From: Yifei Kong Date: Tue, 16 Apr 2024 17:30:24 +0800 Subject: [PATCH] First working version for extension order --- chrome/curl_chrome100 | 1 + chrome/curl_chrome101 | 1 + chrome/curl_chrome104 | 1 + chrome/curl_chrome107 | 1 + chrome/curl_chrome110 | 1 + chrome/curl_chrome116 | 1 + chrome/curl_chrome119 | 1 + chrome/curl_chrome120 | 1 + chrome/curl_chrome99 | 1 + chrome/curl_chrome99_android | 1 + chrome/curl_edge101 | 1 + chrome/curl_edge99 | 1 + chrome/curl_safari15_3 | 1 + chrome/curl_safari15_5 | 1 + chrome/curl_safari17_0 | 1 + chrome/curl_safari17_2_ios | 1 + chrome/patches/boringssl-old-ciphers.patch | 75 +++++++---- chrome/patches/curl-impersonate.patch | 140 ++++++++++++++++----- 18 files changed, 181 insertions(+), 50 deletions(-) diff --git a/chrome/curl_chrome100 b/chrome/curl_chrome100 index 6f81a1f4..085e1a63 100755 --- a/chrome/curl_chrome100 +++ b/chrome/curl_chrome100 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome101 b/chrome/curl_chrome101 index 9921089d..d77ef41d 100755 --- a/chrome/curl_chrome101 +++ b/chrome/curl_chrome101 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome104 b/chrome/curl_chrome104 index 7b04cd81..0d9ed592 100755 --- a/chrome/curl_chrome104 +++ b/chrome/curl_chrome104 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome107 b/chrome/curl_chrome107 index 7ee02c2f..32fad580 100755 --- a/chrome/curl_chrome107 +++ b/chrome/curl_chrome107 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome110 b/chrome/curl_chrome110 index 79472092..50826dbd 100755 --- a/chrome/curl_chrome110 +++ b/chrome/curl_chrome110 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome116 b/chrome/curl_chrome116 index df9fd879..d5b14d45 100755 --- a/chrome/curl_chrome116 +++ b/chrome/curl_chrome116 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome119 b/chrome/curl_chrome119 index 7875027a..dd3629c9 100755 --- a/chrome/curl_chrome119 +++ b/chrome/curl_chrome119 @@ -27,4 +27,5 @@ dir=${0%/*} --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome120 b/chrome/curl_chrome120 index a9b1d18b..8218e242 100755 --- a/chrome/curl_chrome120 +++ b/chrome/curl_chrome120 @@ -27,4 +27,5 @@ dir=${0%/*} --ech GREASE \ --tlsv1.2 --alps --tls-permute-extensions \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome99 b/chrome/curl_chrome99 index ea1c537a..20ef1cf4 100755 --- a/chrome/curl_chrome99 +++ b/chrome/curl_chrome99 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_chrome99_android b/chrome/curl_chrome99_android index 0e56cd7a..79277699 100755 --- a/chrome/curl_chrome99_android +++ b/chrome/curl_chrome99_android @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_edge101 b/chrome/curl_edge101 index ff3c261c..6193dec1 100755 --- a/chrome/curl_edge101 +++ b/chrome/curl_edge101 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_edge99 b/chrome/curl_edge99 index 696a848b..cd8e1a65 100755 --- a/chrome/curl_edge99 +++ b/chrome/curl_edge99 @@ -26,4 +26,5 @@ dir=${0%/*} --compressed \ --tlsv1.2 --alps \ --cert-compression brotli \ + --tls-grease \ "$@" diff --git a/chrome/curl_safari15_3 b/chrome/curl_safari15_3 index 982e3b28..0d78f445 100755 --- a/chrome/curl_safari15_3 +++ b/chrome/curl_safari15_3 @@ -20,4 +20,5 @@ dir=${0%/*} --http2-window-update 10485760 \ --compressed \ --tlsv1.0 --no-tls-session-ticket \ + --tls-grease \ "$@" diff --git a/chrome/curl_safari15_5 b/chrome/curl_safari15_5 index 83100dc3..a565cd6a 100755 --- a/chrome/curl_safari15_5 +++ b/chrome/curl_safari15_5 @@ -21,4 +21,5 @@ dir=${0%/*} --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ + --tls-grease \ "$@" diff --git a/chrome/curl_safari17_0 b/chrome/curl_safari17_0 index 66f7dc03..7c06c1dc 100755 --- a/chrome/curl_safari17_0 +++ b/chrome/curl_safari17_0 @@ -24,4 +24,5 @@ dir=${0%/*} --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ + --tls-grease \ "$@" diff --git a/chrome/curl_safari17_2_ios b/chrome/curl_safari17_2_ios index d579b09a..ca5c576d 100755 --- a/chrome/curl_safari17_2_ios +++ b/chrome/curl_safari17_2_ios @@ -24,4 +24,5 @@ dir=${0%/*} --compressed \ --tlsv1.0 --no-tls-session-ticket \ --cert-compression zlib \ + --tls-grease \ "$@" diff --git a/chrome/patches/boringssl-old-ciphers.patch b/chrome/patches/boringssl-old-ciphers.patch index 0e880f50..098f63fe 100644 --- a/chrome/patches/boringssl-old-ciphers.patch +++ b/chrome/patches/boringssl-old-ciphers.patch @@ -33,18 +33,10 @@ index e500dd76e..487945969 100644 // permute extensions. For now, this is only implemented for the ClientHello. OPENSSL_EXPORT void SSL_set_permute_extensions(SSL *ssl, int enabled); diff --git a/ssl/extensions.cc b/ssl/extensions.cc -index b13400097..6cd8bd750 100644 +index b13400097..a59db770c 100644 --- a/ssl/extensions.cc +++ b/ssl/extensions.cc -@@ -115,6 +115,7 @@ - - #include - #include -+#include - - #include - #include -@@ -3313,6 +3314,7 @@ bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs) { +@@ -3313,6 +3313,7 @@ bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs) { !permutation.Init(kNumExtensions)) { return false; } @@ -52,23 +44,33 @@ index b13400097..6cd8bd750 100644 for (size_t i = 0; i < kNumExtensions; i++) { permutation[i] = i; } -@@ -3337,6 +3339,44 @@ static const struct tls_extension *tls_extension_find(uint32_t *out_index, +@@ -3320,6 +3321,11 @@ bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs) { + // Set element |i| to a randomly-selected element 0 <= j <= i. + std::swap(permutation[i], permutation[seeds[i - 1] % (i + 1)]); + } ++ // fprintf(stderr, "the permuated order is set to:"); ++ // for (size_t i = 0; i < kNumExtensions; i++) { ++ // fprintf(stderr, "%d, ", permutation[i]); ++ // } ++ // fprintf(stderr, "\n"); + hs->extension_permutation = std::move(permutation); + return true; + } +@@ -3337,6 +3343,50 @@ static const struct tls_extension *tls_extension_find(uint32_t *out_index, return NULL; } +// curl-impersonate: set customized extension order +// -+// Generate the extension_permutation array from the customized extension order -+// string. ++// Generate the extension_permutation array from a customized extension order string. +// -+// The customized extension order string is a dash-separated list of -+// extensions. Each extension is a string of the form "extension_name[:index]". -+// The index is optional and defaults to 0. ++// The customized extension order string is a dash-separated list of extensions. +// +bool ssl_set_extension_order(SSL_HANDSHAKE *hs) { + if (hs->config->extension_order == nullptr) { + return true; + } ++ // fprintf(stderr, "order %s\n", hs->config->extension_order); + Array order; + if (!order.Init(kNumExtensions)) { + return false; @@ -85,10 +87,18 @@ index b13400097..6cd8bd750 100644 + while (ext != nullptr) { + unsigned ext_index; + tls_extension_find(&ext_index, atoi(ext)); ++ // fprintf(stderr, "found %d -> %d, ", atoi(ext), ext_index); + order[idx] = ext_index; + ext = strtok(NULL, delimiter); + idx++; + } ++ // fprintf(stderr, "\n"); ++ // fprintf(stderr, "the order is set to:"); ++ // for (size_t i = 0; i < kNumExtensions; i++) { ++ // fprintf(stderr, "%d, ", order[i]); ++ // } ++ // fprintf(stderr, "\n"); ++ free(tmp); + + hs->extension_permutation = std::move(order); + return true; @@ -97,16 +107,29 @@ index b13400097..6cd8bd750 100644 static bool add_padding_extension(CBB *cbb, uint16_t ext, size_t len) { CBB child; if (!CBB_add_u16(cbb, ext) || // -@@ -3383,6 +3423,9 @@ static bool ssl_add_clienthello_tlsext_inner(SSL_HANDSHAKE *hs, CBB *out, +@@ -3379,10 +3429,14 @@ static bool ssl_add_clienthello_tlsext_inner(SSL_HANDSHAKE *hs, CBB *out, + } + } + ++ fprintf(stderr, "starting to numeratez\n"); + for (size_t unpermuted = 0; unpermuted < kNumExtensions; unpermuted++) { size_t i = hs->extension_permutation.empty() ? unpermuted : hs->extension_permutation[unpermuted]; -+ // curl-impersonate: skip non-exist extensions -+ if (i == 255) { continue; } -+ // end of curl-impersonate ++ fprintf(stderr, "extension %zu,", i); ++ fprintf(stderr, "\n"); ++ if (i == 255) { continue; } // curl-impersonate: skip non-exist extensions const size_t len_before = CBB_len(&extensions); const size_t len_compressed_before = CBB_len(compressed.get()); if (!kExtensions[i].add_clienthello(hs, &extensions, compressed.get(), +@@ -3492,6 +3546,7 @@ bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, CBB *out_encoded, + size_t i = hs->extension_permutation.empty() + ? unpermuted + : hs->extension_permutation[unpermuted]; ++ if (i == 255) { continue; } // curl-impersonate: skip non-exist extensions + const size_t len_before = CBB_len(&extensions); + if (!kExtensions[i].add_clienthello(hs, &extensions, &extensions, type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 971ebd0b1..0005c6d79 100644 --- a/ssl/handshake_client.cc @@ -445,10 +468,18 @@ index fd8cef95d..3d2c8ff6d 100644 "Not all ciphers are included in the cipher order"); diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc -index 58b68e675..d9849f3be 100644 +index 58b68e675..15eb823b3 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc -@@ -3015,6 +3015,12 @@ void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) { +@@ -657,6 +657,7 @@ SSL *SSL_new(SSL_CTX *ctx) { + ssl->config->retain_only_sha256_of_client_certs = + ctx->retain_only_sha256_of_client_certs; + ssl->config->permute_extensions = ctx->permute_extensions; ++ ssl->config->extension_order = ctx->extension_order; + ssl->config->aes_hw_override = ctx->aes_hw_override; + ssl->config->aes_hw_override_value = ctx->aes_hw_override_value; + ssl->config->tls13_cipher_policy = ctx->tls13_cipher_policy; +@@ -3015,6 +3016,12 @@ void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) { ctx->permute_extensions = !!enabled; } diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index bacda220..75b57e41 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -433,7 +433,7 @@ index 3b536000a..d7135698f 100644 /** * Return the n-th header entry or NULL if it does not exist. diff --git a/lib/easy.c b/lib/easy.c -index 322d1a41b..e201fbc43 100644 +index 322d1a41b..f90f8b82b 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -74,6 +74,8 @@ @@ -445,7 +445,7 @@ index 322d1a41b..e201fbc43 100644 #include "easy_lock.h" -@@ -341,6 +343,202 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, +@@ -341,6 +343,203 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, return rc; } @@ -586,6 +586,7 @@ index 322d1a41b..e201fbc43 100644 + } + + if(opts->tls_extension_order) { ++ printf("setting extension order as: %s\n", opts->tls_extension_order); + ret = curl_easy_setopt(data, CURLOPT_TLS_EXTENSION_ORDER, opts->tls_extension_order); + } + @@ -648,7 +649,7 @@ index 322d1a41b..e201fbc43 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. -@@ -349,6 +547,8 @@ struct Curl_easy *curl_easy_init(void) +@@ -349,6 +548,8 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -657,7 +658,7 @@ index 322d1a41b..e201fbc43 100644 /* Make sure we inited the global SSL stuff */ global_init_lock(); -@@ -371,6 +571,29 @@ struct Curl_easy *curl_easy_init(void) +@@ -371,6 +572,29 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -687,7 +688,7 @@ index 322d1a41b..e201fbc43 100644 return data; } -@@ -945,6 +1168,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -945,6 +1169,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -701,7 +702,7 @@ index 322d1a41b..e201fbc43 100644 /* Reinitialize an SSL engine for the new handle * note: the engine name has already been copied by dupset */ if(outcurl->set.str[STRING_SSL_ENGINE]) { -@@ -1004,6 +1234,9 @@ fail: +@@ -1004,6 +1235,9 @@ fail: */ void curl_easy_reset(struct Curl_easy *data) { @@ -711,7 +712,7 @@ index 322d1a41b..e201fbc43 100644 Curl_free_request_state(data); /* zero out UserDefined data: */ -@@ -1028,6 +1261,23 @@ void curl_easy_reset(struct Curl_easy *data) +@@ -1028,6 +1262,23 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) Curl_http_auth_cleanup_digest(data); #endif @@ -1431,10 +1432,10 @@ index 80e183480..8ee390b7e 100644 * Store nghttp2 version info in this buffer. diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..f40d085ad +index 000000000..c2aa709f2 --- /dev/null +++ b/lib/impersonate.c -@@ -0,0 +1,818 @@ +@@ -0,0 +1,876 @@ +#include "curl_setup.h" + +#include @@ -2208,7 +2209,65 @@ index 000000000..f40d085ad + .tls_grease = true + }, + { -+ .target = "firefox120", ++ .target = "okhttp4", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," ++ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," ++ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," ++ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," ++ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," ++ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," ++ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," ++ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," ++ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," ++ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," ++ "TLS_RSA_WITH_AES_256_GCM_SHA384," ++ "TLS_RSA_WITH_AES_128_GCM_SHA256," ++ "TLS_RSA_WITH_AES_256_CBC_SHA," ++ "TLS_RSA_WITH_AES_128_CBC_SHA," ++ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," ++ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," ++ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ++ .curves = "X25519:P-256:P-384:P-521", ++ .sig_hash_algs = ++ "ecdsa_secp256r1_sha256," ++ "rsa_pss_rsae_sha256," ++ "rsa_pkcs1_sha256," ++ "ecdsa_secp384r1_sha384," ++ "ecdsa_sha1," ++ "rsa_pss_rsae_sha384," ++ "rsa_pss_rsae_sha384," ++ "rsa_pkcs1_sha384," ++ "rsa_pss_rsae_sha512," ++ "rsa_pkcs1_sha512," ++ "rsa_pkcs1_sha1", ++ .npn = false, ++ .alpn = true, ++ .alps = false, ++ .tls_session_ticket = false, ++ .cert_compression = "zlib", ++ .http_headers = { ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", ++ "Sec-Fetch-Site: none", ++ "Accept-Encoding: gzip, deflate, br", ++ "Sec-Fetch-Mode: navigate", ++ "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", ++ "Accept-Language: en-US,en;q=0.9", ++ "Sec-Fetch-Dest: document" ++ }, ++ .http2_settings = "2:0;4:4194304;3:100", ++ .http2_window_update = 10485760, ++ .http2_pseudo_headers_order = "mspa", ++ .tls_extension_order = NULL, ++ .tls_grease = true ++ }, ++ { ++ .target = "firefox120", /* not working */ + .httpversion = CURL_HTTP_VERSION_2_0, + .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, + .ciphers = @@ -2632,7 +2691,7 @@ index ff661482e..29b9d37fa 100644 struct Names { diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c -index 8c8f43e83..2ded499c4 100644 +index 8c8f43e83..78c349b90 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -79,9 +79,24 @@ @@ -2997,7 +3056,7 @@ index 8c8f43e83..2ded499c4 100644 #ifdef USE_OPENSSL_SRP if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { char * const ssl_username = ssl_config->primary.username; -@@ -3716,6 +4031,37 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3716,6 +4031,40 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3020,8 +3079,11 @@ index 8c8f43e83..2ded499c4 100644 + SSL_CTX_set_permute_extensions(backend->ctx, 1); + } + -+ /* curl-impersonate: Set TLS extensions order. */ ++ /* curl-impersonate: Set TLS extensions order. ++ * TODO: fix string memleak ++ */ + if(data->set.str[STRING_TLS_EXTENSION_ORDER]) { ++ printf("setting extension order before boringssl: %s\n", data->set.str[STRING_TLS_EXTENSION_ORDER]); + SSL_CTX_set_extension_order(backend->ctx, data->set.str[STRING_TLS_EXTENSION_ORDER]); + } + @@ -3035,7 +3097,7 @@ index 8c8f43e83..2ded499c4 100644 /* OpenSSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with -@@ -3771,6 +4117,24 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3771,6 +4120,24 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, SSL_set_app_data(backend->handle, cf); @@ -3060,7 +3122,7 @@ index 8c8f43e83..2ded499c4 100644 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(conn_config->verifystatus) -@@ -3794,6 +4158,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, +@@ -3794,6 +4161,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, } #endif @@ -3082,7 +3144,7 @@ index 8c8f43e83..2ded499c4 100644 SSL_set_app_data(backend->handle, cf); connssl->reused_session = FALSE; -@@ -4005,6 +4384,60 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, +@@ -4005,6 +4387,60 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, negotiated_group_name? negotiated_group_name : "[blank]", OBJ_nid2sn(psigtype_nid)); @@ -3516,10 +3578,10 @@ index 57e8fce52..b5d7019b1 100644 struct GlobalConfig { diff --git a/src/tool_getparam.c b/src/tool_getparam.c -index 5fa1ace10..199f5746b 100644 +index 5fa1ace10..80277bbd9 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c -@@ -296,6 +296,18 @@ static const struct LongShort aliases[]= { +@@ -296,6 +296,20 @@ static const struct LongShort aliases[]= { {"EC", "etag-save", ARG_FILENAME}, {"ED", "etag-compare", ARG_FILENAME}, {"EE", "curves", ARG_STRING}, @@ -3535,10 +3597,12 @@ index 5fa1ace10..199f5746b 100644 + {"ER", "ech", ARG_STRING}, +#endif + {"EV", "http2-streams", ARG_STRING}, ++ {"EW", "tls-extension-order", ARG_STRING}, ++ {"EX", "tls-grease", ARG_BOOL}, {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, -@@ -2124,6 +2136,67 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ +@@ -2124,6 +2138,78 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ GetStr(&config->ssl_ec_curves, nextarg); break; @@ -3573,9 +3637,9 @@ index 5fa1ace10..199f5746b 100644 + break; + + case 'M': -+ /* --tls-permute-extensions */ -+ config->ssl_permute_extensions = toggle; -+ break; ++ /* --tls-permute-extensions */ ++ config->ssl_permute_extensions = toggle; ++ break; + + case 'N': + /* --http2-window-update */ @@ -3591,6 +3655,17 @@ index 5fa1ace10..199f5746b 100644 + GetStr(&config->http2_streams, nextarg); + break; + ++ case 'W': ++ /* --tls-extension-order */ ++ GetStr(&config->tls_extension_order, nextarg); ++ // printf("setting is %s\n", config->tls_extension_order); ++ break; ++ ++ case 'X': ++ /* --tls-grease */ ++ config->tls_grease = toggle; ++ break; ++ +#ifdef USE_ECH + case 'R': + if(strlen(nextarg) != 6 || !strncasecompare("GREASE", nextarg, 6)) { @@ -3661,7 +3736,7 @@ index 4e7a6dd63..8093b7f8e 100644 "Disable buffering of the output stream", CURLHELP_CURL}, diff --git a/src/tool_operate.c b/src/tool_operate.c -index c805b7732..01743da1c 100644 +index c805b7732..4f948b09c 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1522,6 +1522,26 @@ static CURLcode single_transfer(struct GlobalConfig *global, @@ -3706,18 +3781,27 @@ index c805b7732..01743da1c 100644 if(config->writeout) my_setopt_str(curl, CURLOPT_CERTINFO, 1L); -@@ -1942,6 +1970,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -1942,6 +1970,19 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, config->proxy_cipher13_list); -+ /* curl-impersonate */ ++ /* curl-impersonate */ + if(config->ssl_permute_extensions) -+ my_setopt(curl, CURLOPT_SSL_PERMUTE_EXTENSIONS, 1L); ++ my_setopt(curl, CURLOPT_SSL_PERMUTE_EXTENSIONS, 1L); ++ ++ /* curl-impersonate */ ++ if (config->tls_grease) ++ my_setopt(curl, CURLOPT_TLS_GREASE, 1L); ++ ++ /* curl-impersonate */ ++ if(config->tls_extension_order) ++ // printf("setting is %s\n", config->tls_extension_order); ++ my_setopt_str(curl, CURLOPT_TLS_EXTENSION_ORDER, config->tls_extension_order); + /* new in libcurl 7.9.2: */ if(config->disable_epsv) /* disable it */ -@@ -2151,6 +2183,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2151,6 +2192,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } @@ -3732,7 +3816,7 @@ index c805b7732..01743da1c 100644 /* new in 7.40.0, abstract support added in 7.53.0 */ if(config->unix_socket_path) { if(config->abstract_unix_socket) { -@@ -2199,6 +2239,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, +@@ -2199,6 +2248,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->hsts) my_setopt_str(curl, CURLOPT_HSTS, config->hsts);