From 9d9e393d0ec23c7a9243ec681b888171881614b2 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Sun, 3 Jul 2022 22:02:09 +0300 Subject: [PATCH 1/4] Move curl-impersonate options to separate files For better organization, move the curl-impersonate impersonation definitions to a separate impersonate.c and impersonate.h files. --- chrome/patches/curl-impersonate.patch | 731 ++++++++++++++------------ 1 file changed, 385 insertions(+), 346 deletions(-) diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 9969b59..1f3e120 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -243,356 +243,35 @@ index 769363941..cd59ad4b2 100644 libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) CHECKSRC = $(CS_$(V)) +diff --git a/lib/Makefile.inc b/lib/Makefile.inc +index 3e9ddec12..fb883832d 100644 +--- a/lib/Makefile.inc ++++ b/lib/Makefile.inc +@@ -157,6 +157,7 @@ LIB_CFILES = \ + idn_win32.c \ + if2ip.c \ + imap.c \ ++ impersonate.c \ + inet_ntop.c \ + inet_pton.c \ + krb5.c \ diff --git a/lib/easy.c b/lib/easy.c -index 20293a710..8b6a0f4e1 100644 +index 20293a710..79e0ea1e6 100644 --- a/lib/easy.c +++ b/lib/easy.c -@@ -80,6 +80,7 @@ +@@ -80,6 +80,8 @@ #include "dynbuf.h" #include "altsvc.h" #include "hsts.h" +#include "strcase.h" ++#include "impersonate.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" -@@ -282,6 +283,454 @@ void curl_global_cleanup(void) +@@ -282,6 +284,119 @@ void curl_global_cleanup(void) init_flags = 0; } -+/* -+ * curl-impersonate: Options to be set for each supported target browser. -+ * Note: this does not include the HTTP headers, which are handled separately -+ * in Curl_http(). -+ */ -+#define IMPERSONATE_MAX_HEADERS 32 -+static const struct impersonate_opts { -+ const char *target; -+ int httpversion; -+ int ssl_version; -+ const char *ciphers; -+ /* Elliptic curves (TLS extension 10). -+ * Passed to CURLOPT_SSL_EC_CURVES */ -+ const char *curves; -+ /* Signature hash algorithms (TLS extension 13). -+ * Passed to CURLOPT_SSL_SIG_HASH_ALGS */ -+ const char *sig_hash_algs; -+ /* Enable TLS NPN extension. */ -+ bool npn; -+ /* Enable TLS ALPN extension. */ -+ 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; -+ const char *http_headers[IMPERSONATE_MAX_HEADERS]; -+ const char *http2_pseudo_headers_order; -+ /* Other TLS options will come here in the future once they are -+ * configurable through curl_easy_setopt() */ -+} impersonations[] = { -+ { -+ .target = "chrome99", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"99\", \"Google Chrome\";v=\"99\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "chrome100", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"100\", \"Google Chrome\";v=\"100\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "chrome101", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"101\", \"Google Chrome\";v=\"101\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "chrome99_android", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"99\", \"Google Chrome\";v=\"99\"", -+ "sec-ch-ua-mobile: ?1", -+ "sec-ch-ua-platform: \"Android\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.58 Mobile Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "edge99", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"99\", \"Microsoft Edge\";v=\"99\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "edge101", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .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=\"101\", \"Microsoft Edge\";v=\"101\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.47", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ } -+ }, -+ { -+ .target = "safari15_3", -+ .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_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256," -+ "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_SHA256," -+ "TLS_RSA_WITH_AES_128_CBC_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, -+ .http_headers = { -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Accept-Language: en-us", -+ "Accept-Encoding: gzip, deflate, br" -+ }, -+ .http2_pseudo_headers_order = "mspa" -+ } -+}; -+ -+#define NUM_IMPERSONATIONS \ -+ sizeof(impersonations) / sizeof(impersonations[0]) -+ +/* + * curl-impersonate: + * Call curl_easy_setopt() with all the needed options as defined in the @@ -605,14 +284,13 @@ index 20293a710..8b6a0f4e1 100644 + const struct impersonate_opts *opts = NULL; + struct curl_slist *headers = NULL; + -+ for(i = 0; i < NUM_IMPERSONATIONS; i++) { -+ if (Curl_safe_strcasecompare(target, impersonations[i].target)) { -+ opts = &impersonations[i]; ++ for(opts = impersonations; opts->target != NULL; opts++) { ++ if (Curl_safe_strcasecompare(target, opts->target)) { + break; + } + } + -+ if(!opts) { ++ if(opts->target == NULL) { + DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", + target)); + return CURLE_BAD_FUNCTION_ARGUMENT; @@ -710,7 +388,7 @@ index 20293a710..8b6a0f4e1 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 +739,7 @@ struct Curl_easy *curl_easy_init(void) +@@ -290,6 +405,7 @@ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; @@ -718,7 +396,7 @@ index 20293a710..8b6a0f4e1 100644 /* Make sure we inited the global SSL stuff */ if(!initialized) { -@@ -308,6 +758,22 @@ struct Curl_easy *curl_easy_init(void) +@@ -308,6 +424,22 @@ struct Curl_easy *curl_easy_init(void) return NULL; } @@ -741,7 +419,7 @@ index 20293a710..8b6a0f4e1 100644 return data; } -@@ -878,6 +1344,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -878,6 +1010,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->state.referer_alloc = TRUE; } @@ -755,7 +433,7 @@ index 20293a710..8b6a0f4e1 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]) { -@@ -967,6 +1440,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) +@@ -967,6 +1106,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) */ void curl_easy_reset(struct Curl_easy *data) { @@ -764,7 +442,7 @@ index 20293a710..8b6a0f4e1 100644 Curl_free_request_state(data); /* zero out UserDefined data: */ -@@ -991,6 +1466,12 @@ void curl_easy_reset(struct Curl_easy *data) +@@ -991,6 +1132,12 @@ void curl_easy_reset(struct Curl_easy *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif @@ -1267,6 +945,367 @@ index d6986d97f..fa5c90e7f 100644 /* * Store nghttp2 version info in this buffer. +diff --git a/lib/impersonate.c b/lib/impersonate.c +new file mode 100644 +index 000000000..10154a5bc +--- /dev/null ++++ b/lib/impersonate.c +@@ -0,0 +1,306 @@ ++#include "curl_setup.h" ++ ++#include "impersonate.h" ++ ++const struct impersonate_opts impersonations[] = { ++ { ++ .target = "chrome99", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"99\", \"Google Chrome\";v=\"99\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "chrome100", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"100\", \"Google Chrome\";v=\"100\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "chrome101", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"101\", \"Google Chrome\";v=\"101\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "chrome99_android", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"99\", \"Google Chrome\";v=\"99\"", ++ "sec-ch-ua-mobile: ?1", ++ "sec-ch-ua-platform: \"Android\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.58 Mobile Safari/537.36", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "edge99", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"99\", \"Microsoft Edge\";v=\"99\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "edge101", ++ .httpversion = CURL_HTTP_VERSION_2_0, ++ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, ++ .ciphers = ++ "TLS_AES_128_GCM_SHA256," ++ "TLS_AES_256_GCM_SHA384," ++ "TLS_CHACHA20_POLY1305_SHA256," ++ "ECDHE-ECDSA-AES128-GCM-SHA256," ++ "ECDHE-RSA-AES128-GCM-SHA256," ++ "ECDHE-ECDSA-AES256-GCM-SHA384," ++ "ECDHE-RSA-AES256-GCM-SHA384," ++ "ECDHE-ECDSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-CHACHA20-POLY1305," ++ "ECDHE-RSA-AES128-SHA," ++ "ECDHE-RSA-AES256-SHA," ++ "AES128-GCM-SHA256," ++ "AES256-GCM-SHA384," ++ "AES128-SHA," ++ "AES256-SHA", ++ .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=\"101\", \"Microsoft Edge\";v=\"101\"", ++ "sec-ch-ua-mobile: ?0", ++ "sec-ch-ua-platform: \"Windows\"", ++ "Upgrade-Insecure-Requests: 1", ++ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.47", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", ++ "Sec-Fetch-Site: none", ++ "Sec-Fetch-Mode: navigate", ++ "Sec-Fetch-User: ?1", ++ "Sec-Fetch-Dest: document", ++ "Accept-Encoding: gzip, deflate, br", ++ "Accept-Language: en-US,en;q=0.9" ++ } ++ }, ++ { ++ .target = "safari15_3", ++ .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_SHA384," ++ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256," ++ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," ++ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," ++ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384," ++ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256," ++ "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_SHA256," ++ "TLS_RSA_WITH_AES_128_CBC_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, ++ .http_headers = { ++ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", ++ "Accept-Language: en-us", ++ "Accept-Encoding: gzip, deflate, br" ++ }, ++ .http2_pseudo_headers_order = "mspa" ++ }, ++ { ++ /* Last one must be NULL. */ ++ .target = NULL ++ } ++}; +diff --git a/lib/impersonate.h b/lib/impersonate.h +new file mode 100644 +index 000000000..9546a7833 +--- /dev/null ++++ b/lib/impersonate.h +@@ -0,0 +1,43 @@ ++#ifndef HEADER_CURL_IMPERSONATE_H ++#define HEADER_CURL_IMPERSONATE_H ++ ++#define IMPERSONATE_MAX_HEADERS 32 ++ ++/* ++ * curl-impersonate: Options to be set for each supported target browser. ++ */ ++struct impersonate_opts { ++ const char *target; ++ int httpversion; ++ int ssl_version; ++ const char *ciphers; ++ /* Elliptic curves (TLS extension 10). ++ * Passed to CURLOPT_SSL_EC_CURVES */ ++ const char *curves; ++ /* Signature hash algorithms (TLS extension 13). ++ * Passed to CURLOPT_SSL_SIG_HASH_ALGS */ ++ const char *sig_hash_algs; ++ /* Enable TLS NPN extension. */ ++ bool npn; ++ /* Enable TLS ALPN extension. */ ++ 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; ++ const char *http_headers[IMPERSONATE_MAX_HEADERS]; ++ const char *http2_pseudo_headers_order; ++ /* Other TLS options will come here in the future once they are ++ * configurable through curl_easy_setopt() */ ++}; ++ ++/* ++ * curl-impersonate: Global array of supported browsers and their ++ * impersonation options. ++ */ ++extern const struct impersonate_opts impersonations[]; ++ ++#endif /* HEADER_CURL_IMPERSONATE_H */ diff --git a/lib/multi.c b/lib/multi.c index f8dcc63b4..e6b728592 100644 --- a/lib/multi.c From d417eb5c5cbd061c070f563965e441c86a1b0a13 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 5 Jul 2022 08:20:47 +0300 Subject: [PATCH 2/4] Rotate URLs in tests script and increase timeout The tests fail sometimes with timeout for fetching the wikipedia URL. Try to reduce the chance it happens by increasing the timeout and rotating URLs. --- tests/test_impersonate.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 605c222..21e4626 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -2,6 +2,7 @@ import os import io import re import sys +import random import asyncio import logging import pathlib @@ -131,7 +132,12 @@ class TestImpersonation: TEST_URLS = [ "https://www.wikimedia.org", - "https://www.wikipedia.org" + "https://www.wikipedia.org", + "https://www.archive.org", + "https://www.mozilla.org/en-US", + "https://www.apache.org", + "https://www.kernel.org", + "https://git-scm.com" ] # List of binaries and their expected signatures @@ -251,6 +257,11 @@ class TestImpersonation: ) ] + @pytest.fixture + def test_urls(self): + # Shuffle TEST_URLS randomly + return random.sample(self.TEST_URLS, k=len(self.TEST_URLS)) + @pytest.fixture def tcpdump(self, pytestconfig): """Initialize a sniffer to capture curl's traffic.""" @@ -368,7 +379,7 @@ class TestImpersonation: args.extend(urls) curl = subprocess.Popen(args, env=env) - return curl.wait(timeout=10) + return curl.wait(timeout=15) def _extract_client_hello(self, pcap: bytes) -> List[bytes]: """Find and return the Client Hello TLS record from a pcap. @@ -448,7 +459,8 @@ class TestImpersonation: env_vars, ld_preload, browser_signatures, - expected_signature): + expected_signature, + test_urls): """ Check that curl's TLS signature is identical to that of a real browser. @@ -471,10 +483,11 @@ class TestImpersonation: pytestconfig.getoption("install_dir"), "lib", ld_preload )) + test_urls = test_urls[0:2] ret = self._run_curl(curl_binary, env_vars=env_vars, extra_args=None, - urls=self.TEST_URLS) + urls=test_urls) assert ret == 0 try: @@ -494,7 +507,7 @@ class TestImpersonation: client_hellos = self._extract_client_hello(pcap) # A client hello message for each URL - assert len(client_hellos) == len(self.TEST_URLS) + assert len(client_hellos) == len(test_urls) logging.debug(f"Found {len(client_hellos)} Client Hello messages, " f"comparing to signature '{expected_signature}'") @@ -572,7 +585,8 @@ class TestImpersonation: curl_binary, env_vars, ld_preload, - expected_signature): + expected_signature, + test_urls): """ Ensure the output of curl-impersonate is correct, i.e. that compressed responses are decoded correctly. @@ -595,9 +609,14 @@ class TestImpersonation: ret = self._run_curl(curl_binary, env_vars=env_vars, extra_args=None, - urls=[self.TEST_URLS[0]], + urls=[test_urls[0]], output=output) assert ret == 0 with open(output, "r") as f: - assert "" in f.read() + body = f.read() + assert ( + "" in body or + "" in body or + "" in body + ) From e5670826ba43a802a9253fa3708cb956230834bf Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 5 Jul 2022 08:22:07 +0300 Subject: [PATCH 3/4] Add impersonation support for Safari 15.5 --- README.md | 1 + browsers.json | 10 ++++ chrome/curl_safari15_5 | 21 +++++++ chrome/patches/curl-impersonate.patch | 55 ++++++++++++++++- tests/signatures/safari.yaml | 85 +++++++++++++++++++++++++++ tests/test_impersonate.py | 9 +++ 6 files changed, 179 insertions(+), 2 deletions(-) create mode 100755 chrome/curl_safari15_5 diff --git a/README.md b/README.md index 0d12763..c9e0e34 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ The following browsers can be impersonated. | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox_24x24.png "Firefox") | 100 | 100.0 | Windows 10 | `ff100` | [curl_ff100](firefox/curl_ff100) | | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox_24x24.png "Firefox") | 102 | 102.0 | Windows 10 | `ff102` | [curl_ff102](firefox/curl_ff102) | | ![Safari](https://github.com/alrra/browser-logos/blob/main/src/safari/safari_24x24.png "Safari") | 15.3 | 16612.4.9.1.8 | MacOS Big Sur | `safari15_3` | [curl_safari15_3](chrome/curl_safari15_3) | +| ![Safari](https://github.com/alrra/browser-logos/blob/main/src/safari/safari_24x24.png "Safari") | 15.5 | 17613.2.7.1.8 | MacOS Monterey | `safari15_5` | [curl_safari15_5](chrome/curl_safari15_5) | This list is also available in the [browsers.json](browsers.json) file. diff --git a/browsers.json b/browsers.json index d711075..3851aab 100644 --- a/browsers.json +++ b/browsers.json @@ -120,6 +120,16 @@ }, "binary": "curl-impersonate-chrome", "wrapper_script": "curl_safari15_3" + }, + { + "name": "safari15_5", + "browser": { + "name": "safari", + "version": "15.5", + "os": "macos12.4" + }, + "binary": "curl-impersonate-chrome", + "wrapper_script": "curl_safari15_5" } ] } diff --git a/chrome/curl_safari15_5 b/chrome/curl_safari15_5 new file mode 100755 index 0000000..61cdfb1 --- /dev/null +++ b/chrome/curl_safari15_5 @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Find the directory of this script +dir=${0%/*} + +# The list of ciphers can be obtained by looking at the Client Hello message in +# Wireshark, then converting it using this reference +# https://wiki.mozilla.org/Security/Cipher_Suites +"$dir/curl-impersonate-chrome" \ + --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 \ + --signature-hashes 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 \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \ + -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \ + -H 'Accept-Encoding: gzip, deflate, br' \ + --http2 --false-start --compressed \ + --tlsv1.0 --no-npn --no-tls-session-ticket \ + --cert-compression zlib \ + --http2-pseudo-headers-order 'mspa' \ + "$@" diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 1f3e120..034cf57 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -947,10 +947,10 @@ index d6986d97f..fa5c90e7f 100644 * Store nghttp2 version info in this buffer. diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..10154a5bc +index 000000000..bba3f5788 --- /dev/null +++ b/lib/impersonate.c -@@ -0,0 +1,306 @@ +@@ -0,0 +1,357 @@ +#include "curl_setup.h" + +#include "impersonate.h" @@ -1253,6 +1253,57 @@ index 000000000..10154a5bc + .http2_pseudo_headers_order = "mspa" + }, + { ++ .target = "safari15_5", ++ .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 = { ++ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15", ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", ++ "Accept-Language: en-GB,en-US;q=0.9,en;q=0.8", ++ "Accept-Encoding: gzip, deflate, br" ++ }, ++ .http2_pseudo_headers_order = "mspa" ++ }, ++ { + /* Last one must be NULL. */ + .target = NULL + } diff --git a/tests/signatures/safari.yaml b/tests/signatures/safari.yaml index 59a33e2..6e5f2a3 100644 --- a/tests/signatures/safari.yaml +++ b/tests/signatures/safari.yaml @@ -82,3 +82,88 @@ signature: - 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' - 'accept-language: en-us' - 'accept-encoding: gzip, deflate, br' +--- +name: safari_15.5_macos12.4 +browser: + name: safari + version: 15.5 + os: macos12.4 + mode: regular +signature: + tls_client_hello: + record_version: 'TLS_VERSION_1_0' + handshake_version: 'TLS_VERSION_1_2' + session_id_length: 32 + ciphersuites: [ + 'GREASE', + 0x1301, 0x1302, 0x1303, 0xc02c, 0xc02b, 0xcca9, 0xc030, 0xc02f, + 0xcca8, 0xc00a, 0xc009, 0xc014, 0xc013, 0x009d, 0x009c, 0x0035, + 0x002f, 0xc008, 0xc012, 0x000a + ] + comp_methods: [0x00] + extensions: + - type: GREASE + length: 0 + - type: server_name + - type: extended_master_secret + length: 0 + - type: renegotiation_info + length: 1 + - type: supported_groups + length: 12 + supported_groups: [ + 'GREASE', + 0x001d, 0x0017, 0x0018, 0x0019 + ] + - type: ec_point_formats + length: 2 + ec_point_formats: [0] + - type: application_layer_protocol_negotiation + length: 14 + alpn_list: ['h2', 'http/1.1'] + - type: status_request + length: 5 + status_request_type: 0x01 + - type: signature_algorithms + length: 24 + sig_hash_algs: [ + 0x0403, 0x0804, 0x0401, 0x0503, 0x0203, 0x0805, 0x0805, + 0x0501, 0x0806, 0x0601, 0x0201 + ] + - type: signed_certificate_timestamp + length: 0 + - type: keyshare + length: 43 + key_shares: + - group: 'GREASE' + length: 1 + - group: 29 + length: 32 + - type: psk_key_exchange_modes + length: 2 + psk_ke_mode: 1 + - type: supported_versions + length: 11 + supported_versions: [ + 'GREASE', + 'TLS_VERSION_1_3', 'TLS_VERSION_1_2', + 'TLS_VERSION_1_1', 'TLS_VERSION_1_0' + ] + - type: compress_certificate + length: 3 + algorithms: [0x01] + - type: GREASE + length: 1 + data: !!binary AA== + - type: padding + http2: + pseudo_headers: + - ':method' + - ':scheme' + - ':path' + - ':authority' + headers: + - 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15' + - 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + - 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' + - 'accept-encoding: gzip, deflate, br' diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 21e4626..4624d2c 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -150,6 +150,7 @@ class TestImpersonation: ("curl_edge99", None, None, "edge_99.0.1150.30_win10"), ("curl_edge101", None, None, "edge_101.0.1210.47_win10"), ("curl_safari15_3", None, None, "safari_15.3_macos11.6.4"), + ("curl_safari15_5", None, None, "safari_15.5_macos12.4"), ("curl_ff91esr", None, None, "firefox_91.6.0esr_win10"), ("curl_ff95", None, None, "firefox_95.0.2_win10"), ("curl_ff98", None, None, "firefox_98.0_win10"), @@ -215,6 +216,14 @@ class TestImpersonation: "libcurl-impersonate-chrome", "safari_15.3_macos11.6.4" ), + ( + "minicurl", + { + "CURL_IMPERSONATE": "safari15_5" + }, + "libcurl-impersonate-chrome", + "safari_15.5_macos12.4" + ), ( "minicurl", { From c2adb51d086453bf63839a0decc3d7b97657cd88 Mon Sep 17 00:00:00 2001 From: lwthiker Date: Tue, 5 Jul 2022 08:49:32 +0300 Subject: [PATCH 4/4] Remove archive.org from test urls archive.org rejects connections which makes our test fail. --- tests/test_impersonate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_impersonate.py b/tests/test_impersonate.py index 4624d2c..c73dc9b 100644 --- a/tests/test_impersonate.py +++ b/tests/test_impersonate.py @@ -133,7 +133,6 @@ class TestImpersonation: TEST_URLS = [ "https://www.wikimedia.org", "https://www.wikipedia.org", - "https://www.archive.org", "https://www.mozilla.org/en-US", "https://www.apache.org", "https://www.kernel.org",