nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.48k stars 284 forks source link

Change ec point formats #2905

Closed zedd3v closed 3 years ago

zedd3v commented 4 years ago

https://github.com/nodejs/node/blob/9f14584f2aa10fe7eb3496f9665f1caf81d23419/deps/openssl/openssl/ssl/t1_lib.c#L534 https://github.com/nodejs/node/blob/7816e5f7b911125919a2af4d71f67c34c52b0a27/deps/openssl/openssl/ssl/ssl_lib.c#L777

The function tls1_get_formatlist mentions "If we have a custom point format list use it otherwise use default" but I don't see an option to define them anywhere. Would someone help me pinpoint the location where I can define it myself?

bnoordhuis commented 4 years ago

I'm fairly sure s->ext.ecpointformats field is dead, unused.

s->ext.peer_ecpointformats is in use but that's parsed from the cipher announcements in the peer's handshake, you don't set it manually.

If the above doesn't answer your question, can you tell more about what you're trying to do and to what end?

zedd3v commented 4 years ago

I'm trying to use same tls as chromium because a lot of websites block nodejs fingerprint.

One part of it are point formats. Node uses uncompressed, ansiX962_compressed_prime, ansiX962_compressed_char2 by default but chromium uses only uncompressed. So I need to change them

bnoordhuis commented 4 years ago

I don't think openssl actually lets you tweak that. Do you have examples of such websites?

openssl (and therefore node) uses the ec_point_formats TLS extension to advertise that it supports both compressed and uncompressed formats. The remote end can just pick what it's comfortable with.

Remotes that don't support the extension can just assume uncompressed because that's always supported when EC is.

If you're saying those remotes are tripping over the presence of the extension itself (unlikely, but then again, there are tons of misconfigured servers out there), then you can either:

  1. fix those sites, or

  2. switch to TLSv1.3 - the ec_points_format extensions is <= TLSv1.2 - or,

  3. hack openssl to make it stop sending the extension:

    diff --git a/deps/openssl/openssl/ssl/statem/extensions.c b/deps/openssl/openssl/ssl/statem/extensions.c
    index be09afbe71..2ef0e37cf6 100644
    --- a/deps/openssl/openssl/ssl/statem/extensions.c
    +++ b/deps/openssl/openssl/ssl/statem/extensions.c
    @@ -163,7 +163,7 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
         | SSL_EXT_TLS1_2_AND_BELOW_ONLY,
         NULL, tls_parse_ctos_ec_pt_formats, tls_parse_stoc_ec_pt_formats,
    -        tls_construct_stoc_ec_pt_formats, tls_construct_ctos_ec_pt_formats,
    +        NULL, NULL,
         final_ec_pt_formats
     },
     {
zedd3v commented 4 years ago

You misunderstood my question. I don't want to change the extensions, I want to change the default point formats defined on https://github.com/nodejs/node/blob/9f14584f2aa10fe7eb3496f9665f1caf81d23419/deps/openssl/openssl/ssl/t1_lib.c#L174 without rebuilding node (because I plan to make this into a library)

And yes the remote server itself checks the client's available points specifically because chromium only sends uncompressed and not those 2 compressed points.

Hopefully, this explained it better.

bnoordhuis commented 4 years ago

Then you misunderstood my explanation. :-)

I don't think openssl actually lets you tweak that.

zedd3v commented 4 years ago

Then you misunderstood my explanation. :-)

I don't think openssl actually lets you tweak that.

It's supported in other languages, and it must be supported if chromium also uses openssl and has different settings.

bnoordhuis commented 4 years ago

Chromium doesn't use openssl. What other languages are you referring to? And do you have examples of misbehaving websites?

zedd3v commented 4 years ago

golang, rust, ...

Also, read this article so you will understand why its needed: https://medium.com/cu-cyber/impersonating-ja3-fingerprints-b9f555880e42

bnoordhuis commented 4 years ago

Those don't use openssl either.

zedd3v commented 4 years ago

So you are telling me this is entirely impossible in node, unlike other languages?

What do I have to do to request an option like this?

bnoordhuis commented 4 years ago

The first step would be to file a feature request or pull request with the openssl project.

stryker2k2 commented 3 years ago

Arise from the dead, old necrotic (and closed) post!

Good news: What you are asking is possible and you are in the right place. It can be done by commenting out the values you don't want in OpenSSL's t1_lib.c.

static const unsigned char ecformats_default[] = {
    TLSEXT_ECPOINTFORMAT_uncompressed,
    // TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
    // TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
};

Bad news: You have to recompile OpenSSL and subsequently recompile Node... which goes against your stated requirements of:

without rebuilding node

Most things in OpenSSL have an API attached to them that can be accessed from Node, like:

SSL_set_cipher_list(ssl, ssl_ciphers);
SSL_set_ciphersuites(ssl, ssl_suites);
SSL_set_alpn_protos(ssl, protos, protos_len);

But, alas, there is not one for "set_ecpoint_formats" or anything closely related.

@bnoordhuis hit it on the head when they stated that:

I'm fairly sure s->ext.ecpointformats field is dead, unused.

It seems that OpenSSL attempted to make ecpoint_formats modifiable from the outside but decided to not actually go through with it.

You could create your own outward facing API to do this dynamically from Node. You would add in your function declaration called tls1_set_formatlist into ssl_locl.h and then define it in t1_lib.c so that it receives (SSL struct, const char *str) and perform a s->ext.ecpointformats = str. That just might electrify the tls1_get_formatlist to life and only activate the Point Formats you want.

But, then again, it requires a recompile OpenSSL and subsequently recompile Node.

TL;DR - it is 100% possible with a lot of extra work.