Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Observing differences in the fingerprint between chrome131 impersonate and chrome 132 #103

Open
charliedelta02 opened this issue Feb 4, 2025 · 11 comments

Comments

@charliedelta02
Copy link

charliedelta02 commented Feb 4, 2025

The question

We have chrome v131 impersonate support on curl-cffi with chrome131 for desktop (Mac, Windows) and chrome131_android for Mobile devices.
I was verifying my chrome browsers on mac and on android device and found that Google has updated their chrome browser versions to chrome v132 on desktop and mobile.

As far as my understanding goes, the ja3n hash will remain the same for a given browser version. Correct?

As per https://tls.browserleaks.com/json:

  • The ja3n hash for chrome131 impersonate is:
"ja3n_hash": "dee19b855b658c6aa0f575eda2525e19",
"ja3n_text": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-5-10-11-13-16-18-23-27-35-43-45-51-17513-65037-65281,4588-29-23-24,0"
  • The ja3n hash for chrome131_android impersonate is:
"ja3n_hash": "473f0e7c0b6a0f7b049072f4e683068b",
"ja3n_text": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-5-10-11-13-16-18-23-27-35-43-45-51-17513-65037-65281,29-23-24,0"
  • On my Mac OS chrome browser, I observe the following ja3n fingerprint for chrome v132:
"ja3n_hash": "8e19337e7524d2573be54efb2b0784c9",
"ja3n_text": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-5-10-11-13-16-18-23-27-35-43-45-51-17613-65037-65281,4588-29-23-24,0"
  • On my Android device chrome browser, I observe the following ja3n fingerprint for chrome v132:
"ja3n_hash": "8e19337e7524d2573be54efb2b0784c9",
"ja3n_text": "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-5-10-11-13-16-18-23-27-35-43-45-51-17613-65037-65281,4588-29-23-24,0"

Following are my questions:

  • ja3n hash will remain the same for a given browser version. Correct?
  • Is the data available on https://tls.browserleaks.com/json correct and can it be trusted?
  • It appears to me that the chrome fingerprint for v132 has changed from the fingerprint for chrome v131 both for Desktop and Mobile. Is this not the case?
  • If it has, would we be able to expect a new chrome v132 impersonate support for Desktop and Mobile?
  • If my understanding is incorrect, how can I obtain the ja3n string for a device? I do not see anything related to ja3n using Wireshark and Wireshark is also not usable with android devices.

Versions

If it's related to a specific environment, paste your env info here.

  • OS: [MacOS, Android]
  • curl_cffi version [0.8.0b7]
@charliedelta02 charliedelta02 added the question Further information is requested label Feb 4, 2025
@lexiforest
Copy link
Owner

Thanks for the heads up. I can confirm this on my Chrome 132 on macOS. Update is on my TODO list now. But I think there are some other high priority issues, such as lexiforest/curl_cffi#471.

For you questions:

ja3n hash will remain the same for a given browser version. Correct?

Yes, that's what we observed.

Is the data available on https://tls.browserleaks.com/json correct and can it be trusted?

Yes, I personally trust them. But be aware that js3(n) string does not cover all the details in a TLS fingerprint.

If my understanding is incorrect, how can I obtain the ja3n string for a device? I do not see anything related to ja3n using Wireshark and Wireshark is also not usable with android devices.

Two ways, first, you CAN capture the packet with network sniff tools, just dig deeper. Second, you can write a simple app with the target http lib, e.g. okhttp, and point the url to one of the fingerprint websites.

@charliedelta02
Copy link
Author

charliedelta02 commented Feb 4, 2025

Thanks for the heads up. I can confirm this on my Chrome 132 on macOS. Update is on my TODO list now. But I think there are some other high priority issues, such as #471.

Thank you for acknowledging this. As mentioned by you, there appears to be other high priority fixes. Since chrome fingerprint for Desktop and Mobile both have changed, what approach must we follow to avoid detection until there is support?

It looks like Safari has also been updated to version 18_3 for Mac and iOS. I did not observe a change in the fingerprint form Safari18_0 and Safari18_0_ios with version 18_3 at my end. Have you verified this at your end as well? Should we continue with Safari 18_3 for MacOS and iOS?

I saw somewhere that we will have Firefox support with curl-cffi. Will this be available anytime soon?

Another option that I see is this: https://curl-cffi.readthedocs.io/en/latest/impersonate.html#how-to-use-my-own-fingerprints-other-than-the-builtin-ones-e-g-okhttp
Does it make sense to use the custom fingerprint support to pass the ja3(n) string for chrome v132 to mimic it?

Two ways, first, you CAN capture the packet with network sniff tools, just dig deeper. Second, you can write a simple app with the target http lib, e.g. okhttp, and point the url to one of the fingerprint websites.

If it isn't too much to ask, would you be able to elaborate on the second approach? I did not quite understand it. Would be great if you can share a reference article or possibly an example.

@lexiforest
Copy link
Owner

Firefox support with curl-cffi. Will this be available anytime soon?

Yes, once I figure out how to build against the new Windows binary.

share a reference article or possibly an example.

https://github.com/ProxymanApp/OKHTTP-Android-Sample

@lexiforest
Copy link
Owner

It looks like Safari has also been updated to version 18_3 for Mac and iOS.

Let me verify that later tomorrow after my scheduled midnight macOS update.

@charliedelta02
Copy link
Author

charliedelta02 commented Feb 4, 2025

It looks like Safari has also been updated to version 18_3 for Mac and iOS.

Let me verify that later tomorrow after my scheduled midnight macOS update.

Sounds good. Please do let me know the status of the fingerprint post the update.
As far as I can see, the fingerprint appears to be the same for MacOS and iOS.

@lexiforest
Copy link
Owner

It seems that this new Chrome TLS extension is still behind a feature flag in A/B testing.

@charliedelta02
Copy link
Author

charliedelta02 commented Feb 5, 2025

this new Chrome TLS extension

Does this mean we must continue using v131 instead of v132 until google chrome settles on a specific fingerprint?

What about Safari 18_3? Were you able to verify at your end that it matches the fingerprint of safari18_0 and safari18_0_ios?

@lexiforest lexiforest transferred this issue from lexiforest/curl_cffi Feb 6, 2025
@lexiforest lexiforest added Impersonate target and removed question Further information is requested labels Feb 6, 2025
@lexiforest
Copy link
Owner

A new impersonate target version named chrome132a will be added. a means A/B testing or alternative, since this behavior of Chrome is not offcially launched but have been enabled for a small portion of real world users.

@jjsaunier
Copy link

jjsaunier commented Feb 6, 2025

17613 is the new alps codepoint, from boringSSL SSL_set_alps_use_new_codepoint https://chromestatus.com/feature/5149147365900288

So 17513 becomes 17613 on chrome having it enabled

@jjsaunier
Copy link

jjsaunier commented Feb 6, 2025

if you want to quickly check I have this patch (I only use libcurl directly in c, so I didn't test the cli args, but it's implem tho

diff --git a/configure.ac b/configure.ac
index a19c12b95..9b676c506 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4918,6 +4918,9 @@ if test "x$USE_LIBRTMP" = "x1"; then
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTMP"
 fi

+AC_CHECK_FUNCS([SSL_set_alps_use_new_codepoint])
+
+
 dnl replace spaces with newlines
 dnl sort the lines
 dnl replace the newlines back to spaces
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 2dd803c96..efd1232cf 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -2295,6 +2295,8 @@ typedef enum {
   /* curl-impersonate: firefox key_shares_limit */
   CURLOPT(CURLOPT_TLS_KEY_SHARES_LIMIT, CURLOPTTYPE_LONG, 1019),

+  CURLOPT(CURLOPT_TLS_USE_NEW_ALPN_CODEPOINT, CURLOPTTYPE_LONG, 1020),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;

diff --git a/lib/easy.c b/lib/easy.c
index 27891695e..8b8f4cc77 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -490,6 +490,10 @@ static CURLcode _do_impersonate(struct Curl_easy *data,
     ret = curl_easy_setopt(data, CURLOPT_TLS_GREASE, opts->tls_grease);
   }

+  if(opts->tls_use_alps_new_codepoint) {
+      ret = curl_easy_setopt(data, CURLOPT_TLS_USE_NEW_ALPN_CODEPOINT, opts->tls_use_alps_new_codepoint);
+  }
+
   if(opts->tls_extension_order) {
     ret = curl_easy_setopt(data, CURLOPT_TLS_EXTENSION_ORDER, opts->tls_extension_order);
   }
diff --git a/lib/easyoptions.c b/lib/easyoptions.c
index 528201881..b58ceb9d0 100644
--- a/lib/easyoptions.c
+++ b/lib/easyoptions.c
@@ -358,6 +358,7 @@ struct curl_easyoption Curl_easyopts[] = {
   {"TLS_DELEGATED_CREDENTIALS", CURLOPT_TLS_DELEGATED_CREDENTIALS, CURLOT_STRING, 0},
   {"TLS_EXTENSION_ORDER", CURLOPT_TLS_EXTENSION_ORDER, CURLOT_STRING, 0},
   {"TLS_GREASE", CURLOPT_TLS_GREASE, CURLOT_LONG, 0},
+  {"TLS_NEW_ALPN_CODEPOINT", CURLOPT_TLS_USE_NEW_ALPN_CODEPOINT, CURLOT_LONG, 0},
   {"TLS_KEY_SHARES_LIMIT", CURLOPT_TLS_KEY_SHARES_LIMIT, CURLOT_LONG, 0},
   {"TLS_KEY_USAGE_NO_CHECK", CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOT_LONG, 0},
   {"TLS_RECORD_SIZE_LIMIT", CURLOPT_TLS_RECORD_SIZE_LIMIT, CURLOT_LONG, 0},
diff --git a/lib/impersonate.c b/lib/impersonate.c
index edb2f18ae..878c296de 100644
--- a/lib/impersonate.c
+++ b/lib/impersonate.c
@@ -49,6 +49,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -95,6 +96,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -141,6 +143,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -187,6 +190,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -233,6 +237,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -280,6 +285,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -327,6 +333,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -375,6 +382,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -423,6 +431,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -471,6 +480,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -521,6 +531,7 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
   {
@@ -571,8 +582,60 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
+    .tls_use_alps_new_codepoint = false,
     .tls_grease = true
   },
+{
+      .target = "chrome132",
+      .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",
+      .curves = "X25519MLKEM768:X25519:P-256:P-384",
+      .npn = false,
+      .alpn = true,
+      .alps = true,
+      .tls_permute_extensions = true,
+      .tls_session_ticket = true,
+      .cert_compression = "brotli",
+      .http_headers = {
+              "sec-ch-ua: \"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+              "sec-ch-ua-mobile: ?0",
+              "sec-ch-ua-platform: \"macOS\"",
+              "Upgrade-Insecure-Requests: 1",
+              "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 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.7",
+              "Sec-Fetch-Site: none",
+              "Sec-Fetch-Mode: navigate",
+              "Sec-Fetch-User: ?1",
+              "Sec-Fetch-Dest: document",
+              "Accept-Encoding: gzip, deflate, br, zstd",
+              "Accept-Language: en-US,en;q=0.9",
+              "Priority: u=0, i"
+      },
+      .http2_settings = "1:65536;2:0;4:6291456;6:262144",
+      .http2_window_update = 15663105,
+      .http2_stream_weight = 256,
+      .http2_stream_exclusive = 1,
+      .ech = "GREASE",
+      .tls_extension_order = NULL,
+      .tls_use_alps_new_codepoint = true,
+      .tls_grease = true
+  },
   {
     .target = "chrome99_android",
     .httpversion = CURL_HTTP_VERSION_2_0,
@@ -617,7 +680,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "chrome131_android",
@@ -667,7 +731,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_exclusive = 1,
     .ech = "GREASE",
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "edge99",
@@ -713,7 +778,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "edge101",
@@ -759,7 +825,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 1,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari15_3",
@@ -821,7 +888,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 255,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari15_5",
@@ -878,7 +946,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 255,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari17_2_ios",
@@ -938,7 +1007,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 255,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari18_0_ios",
@@ -998,7 +1068,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari17_0",
@@ -1058,7 +1129,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 255,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "safari18_0",
@@ -1118,7 +1190,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_stream_weight = 256,
     .http2_stream_exclusive = 0,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "okhttp4", /* not working */
@@ -1177,7 +1250,8 @@ const struct impersonate_opts impersonations[] = {
     .http2_pseudo_headers_order = "mspa",
     .http2_stream_weight = 255,
     .tls_extension_order = NULL,
-    .tls_grease = true
+.tls_use_alps_new_codepoint = false,
+.tls_grease = true
   },
   {
     .target = "firefox133",
diff --git a/lib/impersonate.h b/lib/impersonate.h
index e88e78f51..50c7c39fd 100644
--- a/lib/impersonate.h
+++ b/lib/impersonate.h
@@ -34,6 +34,7 @@ struct impersonate_opts {
   int http2_window_update;
   const char *http2_streams;
   bool tls_permute_extensions;
+  bool tls_use_alps_new_codepoint;
   const char *ech;
   const char *tls_extension_order;
   const char *tls_delegated_credentials;
diff --git a/lib/setopt.c b/lib/setopt.c
index b7d8a479a..74a226e5c 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -2984,6 +2984,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
   case CURLOPT_SSL_PERMUTE_EXTENSIONS:
     data->set.ssl_permute_extensions = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
+  case CURLOPT_TLS_USE_NEW_ALPN_CODEPOINT:
+    data->set.ssl_use_new_alpn_codepoint = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
   case CURLOPT_TLS_GREASE:
     data->set.tls_grease = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
diff --git a/lib/url.c b/lib/url.c
index 23dfc266e..09229afc7 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -474,6 +474,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
   set->ssl_enable_alpn = TRUE;
   set->ssl_enable_ticket = TRUE;
   set->tls_grease = FALSE;
+  set->ssl_use_new_alpn_codepoint = FALSE;
   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;
diff --git a/lib/urldata.h b/lib/urldata.h
index 7d24e8171..d6abcc13d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -560,6 +560,7 @@ struct ConnectBits {
   BIT(tls_enable_alps); /* TLS ALPS extension? */
   BIT(tls_enable_ticket); /* TLS session ticket extension? */
   BIT(tls_permute_extensions); /* TLS extension permutations */
+  BIT(tls_use_new_alpn_codepoint); /* TLS ALPN new codepoint */
   BIT(tls_grease);  /* TLS grease? */
 #ifndef CURL_DISABLE_DOH
   BIT(doh);
@@ -1832,6 +1833,7 @@ struct UserDefined {
   BIT(ssl_enable_alps);/* TLS ALPS extension? */
   BIT(ssl_enable_ticket); /* TLS session ticket extension */
   BIT(ssl_permute_extensions); /* TLS Permute extensions */
+  BIT(ssl_use_new_alpn_codepoint); /* TLS use new alpn codepoint */
   BIT(tls_grease);  /* TLS grease? */
   BIT(tls_key_usage_no_check);  /* TLS key_usage_check? */
   BIT(tls_signed_cert_timestamps);  /* TLS signed cert timestamps? */
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 33ef3fe88..5c54d11ad 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -4219,9 +4219,13 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,

 #ifdef HAS_ALPN
   if(connssl->alps) {
-    size_t i;
-    struct alpn_proto_buf proto;

+    if(data->set.ssl_use_new_alpn_codepoint) {
+        /* Set new ALPS codepoint before adding any ALPS settings */
+        SSL_set_alps_use_new_codepoint(backend->handle, 1);
+    }
+
+    size_t i;
     for(i = 0; i < connssl->alps->count; ++i) {
       /* curl-impersonate: Add the ALPS extension (17513) like Chrome does. */
       // XXX: Firefox does not enable this.
@@ -4230,6 +4234,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
                                    0);
     }

+    struct alpn_proto_buf proto;
     Curl_alpn_to_proto_str(&proto, connssl->alps);
     infof(data, VTLS_INFOF_ALPS_OFFER_1STR, proto.data);
   }
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 0594d91c6..3f72d7dd8 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -172,6 +172,7 @@ struct OperationConfig {
   long http2_stream_exclusive;
   char *http2_streams;
   bool tls_grease;
+  bool tls_use_new_alpn_codepoint; /* curl-impersonate */
   char *tls_extension_order;
   char *tls_delegated_credentials;
   long tls_record_size_limit;
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index e8f59eff3..74a44d3aa 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -329,6 +329,7 @@ typedef enum {
   C_TLS_EXTENSION_ORDER,
   C_TLS_PERMUTE_EXTENSIONS,
   C_TLS_GREASE,
+  C_TLS_USE_NEW_ALPN_CODEPOINT,
   C_TLS13_CIPHERS,
   C_TLSAUTHTYPE,
   C_TLSPASSWORD,
@@ -624,6 +625,7 @@ static const struct LongShort aliases[]= {
   {"tls-delegated-credentials",  ARG_STRG, ' ', C_TLS_DELEGATED_CREDENTIALS},  // curl-impersonate
   {"tls-extension-order",        ARG_STRG, ' ', C_TLS_EXTENSION_ORDER},  // curl-impersonate
   {"tls-grease",                 ARG_BOOL, ' ', C_TLS_GREASE},  // curl-impersonate
+  {"tls-use-new-alpn-codepoint", ARG_BOOL, ' ', C_TLS_USE_NEW_ALPN_CODEPOINT},  // curl-impersonate
   {"tls-key-shares-limit",       ARG_STRG, ' ', C_TLS_KEY_SHARES_LIMIT},  // curl-impersonate
   {"tls-max",                    ARG_STRG, ' ', C_TLS_MAX},
   {"tls-permute-extensions",     ARG_BOOL, ' ', C_TLS_PERMUTE_EXTENSIONS},  // curl-impersonate
@@ -1925,6 +1927,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
     case C_TLS_GREASE:  /* --tls-grease curl-impersonate */
       config->tls_grease = toggle;
       break;
+    case C_TLS_USE_NEW_ALPN_CODEPOINT: /* --tls-use-new-alpn-codepoint curl-impersonate */
+        config->tls_use_new_alpn_codepoint = toggle;
+        break;
     case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */
       config->suppress_connect_headers = toggle;
       break;
diff --git a/src/tool_operate.c b/src/tool_operate.c
index a97f86011..04f289016 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1976,6 +1976,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         if (config->tls_grease)
           my_setopt(curl, CURLOPT_TLS_GREASE, 1L);

+        /* curl-impersonate */
+        if (config->tls_use_new_alpn_codepoint)
+            my_setopt(curl, CURLOPT_TLS_USE_NEW_ALPN_CODEPOINT, 1L);
+
         /* curl-impersonate */
         if(config->tls_extension_order)
           my_setopt_str(curl, CURLOPT_TLS_EXTENSION_ORDER, config->tls_extension_order);

@lexiforest
Copy link
Owner

@jjsaunier cool! That's exactly what I would implement it, if you have the bandwidth, a PR is always welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants