refraction-networking / utls Goto Github PK
View Code? Open in Web Editor NEWFork of the Go standard TLS library, providing low-level access to the ClientHello for mimicry purposes.
License: BSD 3-Clause "New" or "Revised" License
Fork of the Go standard TLS library, providing low-level access to the ClientHello for mimicry purposes.
License: BSD 3-Clause "New" or "Revised" License
Hi, all utls developers, I wonder if this project still being actively developed?
I am unable instantiate a utls.ClientHelloSpec
containing a functional utls.RenegotiationInfoExtension
because its renegotiation
field is not exported.
E.g., I need to construct something like the following outside the utls
package, and then use it with utls.HelloCustom
.
utls.ClientHelloSpec{
Extensions: []utls.TLSExtension{
&utls.RenegotiationInfoExtension{
renegotiation: RenegotiateOnceAsClient}
}
}
RenegotiationInfoExtension
does have an exported field, SecureRenegotiation
, but looking at RenegotiationInfoExtension.writeToUConn/Len/Read
, it appears that renegotiation
must be set to something other than its zero value of RenegotiateNever
for the extension to get added to the ClientHello and for the HandshakeState.Hello.SecureRenegotiationSupported
flag to get set.
Lines 217 to 231 in 4da6795
Incidentally, this code in RenegotiationInfoExtension.Read
looks odd. When e.SecureRenegotiation
is not empty, secureRenegBody
points to e.SecureRenegotiation
. And then that data is copied first starting at offset 4 and again at offset 5?
Lines 241 to 255 in 4da6795
In addition, I can't instantiate a utls.GenericExtension
as both of its fields are unexported.
Lines 367 to 370 in 4da6795
Since master secrets and PRF are both exposed deriving session keys should be simple, but I just want to check if there is already an API for that :)
Hello, I was trying to achieve Chrome's CipherSuite using utls while I got this:
on the left is Chrome's Client Hello
compared to that of utls on the left
This is the JA3 I'm trying with
771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0
The issue is this server is blocking requests without GREASE, so I get a Decode Error
when I send with utls right now
$ go version
go version go1.16.7 windows/amd64
I'm using utls commit b84d7d5. Running this program:
package main
import (
"fmt"
"os"
"net"
tls "github.com/refraction-networking/utls"
)
func run() error {
conn, err := net.Dial("tcp", "tlsfingerprint.io:443")
if err != nil {
return err
}
uconn := tls.UClient(conn, nil, tls.HelloRandomized)
uconn.SetSNI("tlsfingerprint.io")
return uconn.Handshake()
}
func main() {
err := run()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Fails with the error message:
uTLS does not support 0x0 as min version
It also happens with HelloRandomizedALPN
and HelloRandomizedNoALPN
. It doesn't happen with HelloChrome_70
and HelloFirefox_63
.
BoringSSL has a fork of golang's tls implementation as well that it uses as a runner for it's test suite. There are a number of potential holes in uTls that could be plugged with implementations already written in this wrapper (certificate compression, channel ids, upcoming quic, etc). I'm still trying to understand exactly how this could work (still poking through utls to understand it), but it seems like a promising option to keep in sync as tls signatures change.
While attempting to construct a TLS 1.2 parrot that omits the SessionID, I have observed via packet capture that utls
always sends a SessionID in the ClientHello, regardless of whether a session ticket is attached.
I believe this is due to changes in the upstream crypto/tls
when TLS 1.3 support was added.
As far as I understand it, utls
calls makeClientHello
here, and uses the results as the base ClientHello:
Lines 494 to 500 in 4da6795
Here's where the current makeClientHello
, from crypto/tls
, unconditionally sets the SessionID:
Lines 111 to 116 in 4da6795
This is probably desired for TLS 1.3 parrots, as my brief testing shows similar behavior in at least one browser ("compatibility" mode).
In older crypto/tls
and utls
, makeClientHello
doesn't have this unconditional code block and the SessionID is set conditionally, when there's a session ticket, here:
Lines 150 to 159 in 03d875d
Has the on-the-wire format of parrots such as HelloIOS_11_1
changed since utls
was upgraded to support TLS 1.3?
Of the bundled TLS 1.2 parrots, I can't tell whether the SessionID should or should not be set when there is no session ticket. I didn't find any stats regarding SessionID here, https://tlsfingerprint.io. Is this information in your raw database?
With the existing API, I don't see how to create a parrot that omits the SessionID. It appears not difficult to implement, as something like this can be added after the makeClientHello
call in ApplyPreset
:
if p.NoDefaultSessionID {
uconn.HandshakeState.Hello.SessionId = nil
}
NoDefaultSessionID
would be a new ClientHelloSpec
boolean field that defaults to false. When a session ticket is used, other code already sets a SessionID [again] as required.
It would be simpler to skip the new field and remove the default SessionID for TLS 1.2. I'm not sure that produces correct results in all cases though?
Chrome 65 TLS 1.3 ciphers are PSK-only, so they shouldn't get picked in the wild.
Included extensions do worry me, they totally have distinctive content, but current tlsfingerprint.io infrastructure doesn't handle them yet. Deeper dive is needed.
Seeing how tls 1.2 ClientHello messages are still relevant, I'd rather for Golang crypto/tls
to implement tls 1.3, pull it, and then start parroting 1.3 stuff.
go test fails on ppc64el system:
error log:
> === RUN TestPPC64minimalFeatures
> cpu_test.go:32: IsPOWER8 expected true, got false
> --- FAIL: TestPPC64minimalFeatures (0.00s)
I've tried the top four specs from tlsfingerprint.io and all have issues.
The top three fail with similar error messages (all top three seem to be chrome-related). I've assembled a list of potential error messages outputted when attempting to use these configurations:
Top | Fingerprint Hash | Errors received (in no particular order) |
---|---|---|
1 | 8466c4390d4bc355 | uTLS does not support 0x**** as max version |
2 | 133e933dd1dfea90 | uTLS does not support 0x**** as max version |
3 | 256c61ee90fe805f | unsupported Curve in KeyShareExtension: 43690. uTLS does not support 0x**** as max version |
4 | cd9f86e32edc16fb | x509: certificate is valid for *.example-1.com, not example-2.com |
Of course for the purpose of this issue, i've compressed my code and removed arbitrary error handling code. This is my approach to making TLS requests using uTLS.
dial, _ := net.DialTimeout("tcp", u.Host, time.Duration(15)*time.Second)
utlsConn := tls.UClient(dial, config, tls.HelloCustom)
defer utlsConn.Close()
_ := utlsConn.ApplyPreset(&Fingerprints.HASH_TOP_4) // top 1-4
_ := utlsConn.Handshake()
request, _ := http.NewRequest(method, u.String(), bytes.NewBuffer(body))
request.Close = true
defer request.Body.Close()
switch utlsConn.ConnectionState().NegotiatedProtocol {
case "h2":
request.Proto = "HTTP/2.0"
request.ProtoMajor = 2
request.ProtoMinor = 0
tr := http2.Transport{}
cConn, _ := tr.NewClientConn(connection)
response_obj, response_err = cConn.RoundTrip(request)
case "http/1.1", "":
request.Proto = "HTTP/1.1"
request.ProtoMajor = 1
request.ProtoMinor = 1
_ := request.Write(connection)
response_obj, response_err = http.ReadResponse(bufio.NewReader(connection), request)
default:
panic(fmt.Errorf("ALPN not supported"))
}
resp, _ := httputil.DumpResponse(response_obj, true)
println(string(resp))
I would like to add that tlsfingerprint.io's "generated code" is invalid. tls.SignatureScheme
is formatted as just SignatureScheme
, the renegotiation
field should be capitalized, and other small bugs.
x
Would it be possible to add support for TLS 1.3 record padding to thwart traffic analysis?
thanks for this library. i use it to connect some website, but response is error( tls: server selected unsupported protocol version 304)
var ja3 = '771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0';
var ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36';
Hi, not sure if this is the right place (apologies if it's not) however https://tlsfingerprint.io/ returns 500 Internal Server Errors on most endpoints and the fingerprinting endpoint https://client.tlsfingerprint.io:8443/ is also down for me.
It was a very useful way to quickly generate a uTLS config, any insight on this would be appreciated.
I have a script in Go that uses uTLS however when I try to compile it to wasm using GOOS=js GOARCH=wasm go build -o main.wasm client.go
I get the error shown below:
#github.com/refraction-networking/utls/cpu
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:16:16: undefined: CacheLineSize
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:33:16: undefined: CacheLineSize
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:46:14: undefined: CacheLineSize
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:58:14: undefined: CacheLineSize
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:66:14: undefined: CacheLineSize
../go/pkg/mod/github.com/refraction-networking/[email protected]/cpu/cpu.go:76:14: undefined: CacheLineSize
What I expected to happen: build to succeed without error
When building to Linux or Windows binaries it works fine. However I get this issue with building to wasm. Please can someone let me know what I would need to do to make this build work, or if this build isn't possible.
Can we change the tls packet in Client-TLSv12-UTLS-ECDHE-ECDSA-AES128-GCM-SHA256-Firefox-63, etc. so that we can have a fingerprint similar to Chrome or ...?
We seem to be having some issues with some of the parrots and session ticket resumption.
It looks to me like session ticket resumption is not currently supported with tls 1.3 and custom parrots. This snippet of loadSession
seems to be re-marshalling the client hello with updateBinders
, which assumes that the raw
bytes have a extensionPreSharedKey
at the end:
https://github.com/getlantern/utls/blob/0c02248f7ce1fa1928b137ff77d6bad4cb0486aa/handshake_client.go#L281-L333
Lines 323 to 351 in 33a2903
This has garbled the ends of ClientHello
s that we've generated when using session tickets and parrots that support tls1.3.
It seems to me that basically, utls
in its present form doesn't support the combination of:
Am I wrong about that? Are we somehow holding the library incorrectly? I've included some pcaps demonstrating the issue we've been encountering and if it would help, I think I could write up a test which demonstrates the behavior we're encountering. I'd be happy to find out that I'm just missing some key piece somewhere.
If I'm not wrong about this, is there some way to put up stronger guards against doing this?
Lastly, is implementing the pre_shared_key extension on your radar/something you'd be interested in? If it's just a matter of your time/energy/resources, I think our org could at least attempt a PR?
As always, thank you so much for your time, energy and patience on this!!!
chrome-83-clienthello-errs.pcap.gz
firefox-65-clienthello-errs.pcap.gz
We have encountered this panic in utls
:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xd1690b88]goroutine 24162 [running]:
github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction- networking/utls.(*clientHandshakeState).toPublic12(0x935a81e0, 0xd1f18f78)
/go/src/github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction- networking/utls/u_public.go:136 +0x12c
github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction-networking/utls.(*UConn).clientHandshake(0x934ea2d0, 0xd1f18f78, 0x936b40e0)
/go/src/github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction-networking/utls/u_conn.go:372 +0x4a4
github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction-networking/utls.(*UConn).Handshake(0x934ea2d0, 0x0, 0x0)
/go/src/github.com/Psiphon-Labs/psiphon-tunnel-core/vendor/github.com/refraction-networking/utls/u_conn.go:189 +0x11c
The panic is here:
Lines 131 to 136 in b7c656e
I suspect suite
is nil?
toPublic12
is called from here, and is called even when hs12.handshake
returns an error:
Lines 371 to 375 in b7c656e
handshake
calls processServerHello
which calls pickCipherSuite
which can fail and leave suite
nil:
Lines 429 to 433 in b7c656e
So it appears that when the "server chose an unconfigured cipher suite" error occurs, suite
is nil and toPublic12
will panic since it's called before the err
check?
There's a similar case where toPublic13
is called before checking err
here:
Lines 363 to 365 in b7c656e
I see you also developing in rust, so any plans to reimplement same functionality(or like a lite version) in rust(probably using boringssl or openssl)?
Hi,
Does anyone have any idea of the status of tlsfingerprint.io? it seems the cluster / database is dead... there are no id's on the site... client.tlsfingerprint.io does not work...
if this site is now dead, will it be made open source? it was a really great tool to use... and if it is indeed dead, it a very sad day for the security community
Hello
If you call Read
before Handshake
or Write
, the default go ciphers will be used. This is because the Write
method is implemented for UConn
and the handshake in it will call the utls handshake. But the Read
method is implemented by Conn
and executing it will cause the Read
to call the tls handshake instead of utls one.
Is this intended? And if so, is there anyway (except Handshake) to establish the connection with fingerprints by calling Read
at first?
Thanks
At #16 (comment) I had to adapt utls to the interface of http2.Transport
. The DialTLS
callback receives a golang net/crypto tls.Config
. To create a UClient
I need a utls.Config
. I can't just pass on the tls.Config
, because the two types are incompatible.
I manually created a new utls.Config
and copied the NextProtos
member because it was important for my example, but in general there are other important fields that may need to be copied.
uconn := utls.UClient(conn, &utls.Config{NextProtos: cfg.NextProtos}, *utlsClientHelloID)
Mainline crypto/tls provides a Config.Clone
method that internally knows which fields are safe to copy (not all are safe to copy, for example locks). Does it make sense to have something similar to create a utls.Config
from an existing tls.Config
?
HelloRandomized
and friends provide a randomized fingerprint, but it is re-randomized for each new connection. Is there a way to get a "handle" to a specific randomized fingerprint so it can be re-used within a process?
Here's a sample program that makes 10 connections with HelloRandomizedNoALPN
:
package main
import (
"fmt"
tls "github.com/refraction-networking/utls"
"net"
)
const hostName = "golang.org"
func connect() error {
conn, err := net.Dial("tcp", net.JoinHostPort(hostName, "443"))
if err != nil {
return err
}
uconn := tls.UClient(conn, nil, tls.HelloRandomizedNoALPN)
uconn.SetSNI(hostName)
err = uconn.Handshake()
if err != nil {
return err
}
return uconn.Close()
}
func main() {
for i := 0; i < 10; i++ {
err := connect()
if err == nil {
fmt.Println(i, "ok")
} else {
fmt.Println(i, err)
}
}
}
Sample output is:
0 ok
1 remote error: tls: handshake failure
2 ok
3 remote error: tls: handshake failure
4 ok
5 ok
6 ok
7 ok
8 ok
9 ok
I am using tshark
to verify that the fingerprint changes with each connection:
tshark -V -f 'host golang.org' -Y ssl.handshake.ciphersuites
Incidentally, the reason this came up is because I'm trying to use UClient
inside the DialTLS
of http.Transport
in order to get TLS fingerprint obfuscation along with connection reuse, keepalive, and the other features that http.Transport
provides. When used with utls
, http.Transport
seems to create 10 independent connections (each with its own randomized fingerprint). I'll file a separate issue about that.
How to use proxy
I received reports that GFW is blocking censorship circumvention tools that are using Chrome 72 fingerprint. Chrome 72 fingerprint (https://tlsfingerprint.io/id/0a4a74aeebd1bb66) is still popular in the wild, and I tested it looks like Chrome 81.0.4044.138, so it's isn't lack of real-world use that may cause issues for this fingerprint.
Randomized fingerprint reportedly works.
In testing, it appears that session states/tickets set using SetSessionCache
are not added to ClientHellos. Individual session states/tickets explicitly set using SetSessionState
are added to ClientHellos, as long as SetSessionState
is called before BuildHandshakeState
.
I suspect the issue with the cache is that Handshake
calls BuildHandshakeState
before clientHandshake
is called here:
Lines 182 to 189 in f8425e6
clientHandshake
consults the session cache and attempts to use session tickets, but its call to SetSessionState
comes too late:
Lines 312 to 334 in f8425e6
There's a call to hello.marshal
after the session cache is checked, but it will just use the previously marshaled value stored in hello.Raw
set in MarshalClientHello
which is called by BuildHandshakeState
:
Line 468 in f8425e6
As a result, it appears that TLS session resumption won't work, as session tickets received from servers and stored in the cache will never be sent in ClientHellos?
I didn't try setting a cache directly using Config.ClientSessionCache
; it appears that would have the same issue?
Need more tests than what was covered at release time.
GREASE values are sometimes repeated in the current setup. There are some CDNs and sites that are running something on the backend that is rejecting this, but it happens very infrequently, so it's hard to pickup on. I do not know how to write a unit test for this, so I've been putting off submitting a pr for you. You can see the basic code changes here:
ulixee@3b28961
Basically, the current version doesn't actually check if the resulting value is changed.
We think it could be useful to generate client hello messages from recorded bytes.
Ideally we would like to contribute this upstream, so I wanted to see if you had any thoughts/concerns/ideas about this approach towards the outset.
We had two ideas about how we might proceed:
Attempt to create a ClientHelloSpec
from a []byte
slice, something along the lines of: func FingerPrintClientHello(data []byte) (*ClientHelloSpec, error)
This seems to mostly require figuring out how to populate the []TLSExtension
slice. We could use the clientHelloMsg.unmarshal
to get information about the Extensions that go's crypto/tls
library understands/parses, but that leaves us with at least a handful of []TLSExtension
s that we'd have to go back through the raw bytes and attempt to re-parse. As we re-parse the hello, we could look specifically for extensions which go doesn't support/parse and then use the GenericExtension
type to just stuff those bytes into our hello.
It occurs to me that re-parsing likely suffers from 2 problems:
At this point it might be worth just writing a parallel unmarshal
function which does what we need, but I guess I get a little nervy at making a parallel copy of so much core crypto/tls
code?
Use the recorded bytes to populate a clientHelloMsg.raw
, unmarshal those bytes to fill out the rest of the relevant clientHelloMsg
fields, update Config
and UConn
state to reflect any necessary changes, and update the ClientHello
as appropriate (random, etc).
In the Custom Handshake section of the README, it says:
If you need to manually control all the bytes on the wire(certainly not recommended!), you can set UConn.HandshakeStateBuilt = true, and marshal clientHello into UConn.HandshakeState.Hello.raw yourself. In this case you will be responsible for modifying other parts of Config and ClientHelloMsg to reflect your setup and not confuse "crypto/tls", which will be processing response from server.
I'm not actually seeing that field on the UConn
struct? Additionally, it looks to me that currently BuildHandshakeState()
and then consequently the MarshalClientHello()
are called by Handshake()
and that they will modify raw bytes in any constructed ClientHelloMsg
So this approach doesn't seem possible with the current u_conn.go
behavior and also I worry that it could suffer from some tricky state/config translations.
Thanks so much for your time and patience with this! We'd love to hear what you think about it!
I'm using commit a89e7e6. The examples I have found of using utls with HTTPS all make a single request on a single connection, then throw the connection away. For example, httpGetOverConn
in examples.go.
I'm trying to use utls with http.Transport
, to take advantage of persistent connections and reasonable default timeouts. To do this, I'm hooking into the DialTLS
callback. There is a problem when using a utls fingerprint that includes h2
in ALPN and a server that supports HTTP/2. The server switches to HTTP/2 mode, but the client stays in HTTP/1.1 mode, because net/http disables automatic HTTP/2 support whenever DialTLS
is set. The end result is an HTTP/1.1 client speaking to an HTTP/2 server; i.e, a similar problem as what was reported in golang/go#14275 (comment). The error message differs depending on the fingerprint:
HelloFirefox_63
net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x00\x00\x12\x04\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00d\x00\x04\x00\x10\x00\x00\x00\x06\x00\x00@\x00\x00\x00\x04\b\x00\x00\x00\x00\x00\x00\x0f\x00\x01\x00\x00\x1e\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01http2_handshake_failed"
HelloChrome_70
local error: tls: unexpected message
HelloIOS_11_1
2019/01/11 14:48:56 Unsolicited response received on idle HTTP channel starting with "\x00\x00\x12\x04\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00d\x00\x04\x00\x10\x00\x00\x00\x06\x00\x00@\x00\x00\x00\x04\b\x00\x00\x00\x00\x00\x00\x0f\x00\x01"; err=<nil>
readLoopPeekFailLocked: <nil>
I get the same results even if I pre-configure the http.Transport
with HTTP/2 support by calling http2.ConfigureTransport(tr)
.
I wrote a test program to reproduce these results. It takes a -utls
option to select a utls client hello ID, and a -callhandshake
option to control whether to call UConn.Handshake
within DialTLS
, or allow it to be called implicitly by the next Read
or Write
. I included the latter option because I found that not calling UConn.Handshake
inside DialTLS
avoids the HTTP version mismatch; however it also results in a client hello that lacks ALPN and differs from the requested one in other ways, so it's not an adequate workaround.
package main
import (
"flag"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"os"
"strings"
utls "github.com/refraction-networking/utls"
)
func main() {
utlsClientHelloIDName := flag.String("utls", "", "use utls with the given ClientHelloID (e.g. HelloGolang)")
callHandshake := flag.Bool("callhandshake", false, "call UConn.Handshake inside DialTLS")
flag.Parse()
if *callHandshake && *utlsClientHelloIDName == "" {
fmt.Fprintf(os.Stderr, "error: -callhandshake only makes sense with -utls\n")
os.Exit(1)
}
if flag.NArg() != 1 {
fmt.Fprintf(os.Stderr, "error: need a URL\n")
os.Exit(1)
}
url := flag.Arg(0)
utlsClientHelloID, ok := map[string]*utls.ClientHelloID{
"": nil,
"HelloGolang": &utls.HelloGolang,
"HelloRandomized": &utls.HelloRandomized,
"HelloRandomizedALPN": &utls.HelloRandomizedALPN,
"HelloRandomizedNoALPN": &utls.HelloRandomizedNoALPN,
"HelloFirefox_Auto": &utls.HelloFirefox_Auto,
"HelloFirefox_55": &utls.HelloFirefox_55,
"HelloFirefox_56": &utls.HelloFirefox_56,
"HelloFirefox_63": &utls.HelloFirefox_63,
"HelloChrome_Auto": &utls.HelloChrome_Auto,
"HelloChrome_58": &utls.HelloChrome_58,
"HelloChrome_62": &utls.HelloChrome_62,
"HelloChrome_70": &utls.HelloChrome_70,
"HelloIOS_Auto": &utls.HelloIOS_Auto,
"HelloIOS_11_1": &utls.HelloIOS_11_1,
}[*utlsClientHelloIDName]
if !ok {
fmt.Fprintf(os.Stderr, "unknown client hello ID %q\n", *utlsClientHelloIDName)
os.Exit(1)
}
tr := http.DefaultTransport.(*http.Transport)
if utlsClientHelloID != nil {
tr.DialContext = nil
tr.Dial = func(network, addr string) (net.Conn, error) { panic("Dial should not be called") }
tr.DialTLS = func(network, addr string) (net.Conn, error) {
fmt.Printf("DialTLS(%q, %q)\n", network, addr)
if tr.TLSClientConfig != nil {
fmt.Printf("warning: ignoring TLSClientConfig %v\n", tr.TLSClientConfig)
}
conn, err := net.Dial(network, addr)
if err != nil {
return nil, err
}
uconn := utls.UClient(conn, nil, *utlsClientHelloID)
colonPos := strings.LastIndex(addr, ":")
if colonPos == -1 {
colonPos = len(addr)
}
uconn.SetSNI(addr[:colonPos])
if *callHandshake {
err = uconn.Handshake()
}
return uconn, err
}
}
for i := 0; i < 4; i++ {
resp, err := get(tr, url)
if err != nil {
fmt.Printf("%2d err %v\n", i, err)
} else {
fmt.Printf("%2d %s %s\n", i, resp.Proto, resp.Status)
}
}
}
func get(rt http.RoundTripper, url string) (*http.Response, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
resp, err := rt.RoundTrip(req)
if err != nil {
return nil, err
}
// Read and close the body to enable connection reuse with HTTP/1.1.
_, err = io.Copy(ioutil.Discard, resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
return resp, nil
}
Sample usage:
test -utls HelloFirefox_63 -callhandshake https://golang.org/robots.txt
The output of the program appears in the following table. Things to notice:
DialTLS
with HelloGolang
produces a fingerprint that is different from using http.Transport
without DialTLS
set.HelloFirefox_63
, HelloChrome_70
, and HelloIOS_11_1
all provide a usable connection (but with an incorrect fingerprint), as long as you don't call UConn.Handshake
before returning from DialTLS
.HelloFirefox_63
, HelloChrome_70
, and HelloIOS_11_1
all give the correct fingerprint, but fail with an HTTP version mismatch, when UConn.Handshake
is called inside DialTLS
.Client Hello ID | call Handshake ? |
client ALPN | result |
---|---|---|---|
none | N/A | [h2, http/1.1] | ok HTTP/2 |
-utls HelloGolang |
none | ok HTTP/1.1 | |
-utls HelloGolang |
-callhandshake |
none | ok HTTP/1.1 |
-utls HelloFirefox_63 |
none | ok HTTP/1.1 | |
-utls HelloFirefox_63 |
-callhandshake |
[h2, http/1.1] | malformed HTTP response (HTTP/1.1 client, HTTP/2 server) |
-utls HelloChrome_70 |
none | ok HTTP/1.1 | |
-utls HelloChrome_70 |
-callhandshake |
[h2, http/1.1] | local error: tls: unexpected message |
-utls HelloIOS_11_1 |
none | ok HTTP/1.1 | |
-utls HelloIOS_11_1 |
-callhandshake |
[h2, h2-16, h2-15, h2-14, spdy/3.1, spdy/3, http/1.1] | readLoopPeekFailLocked: <nil> (HTTP/1.1 client, HTTP/2 server) |
Is there a way to accomplish what I am trying to do?
What's the best way to use forward proxies with this tls implementation? Right now I'm creating a HTTP tunnel followed by a custom Handshake, but by using a proxy the server blocks my request. Everything works fine without the proxy. I also tested the proxy in Chrome, which also works without any issues.
I send the final requests with the function httpGetOverConn that is given in examples.go. This is the code I am using for creating the HTTP tunnel.
func connToProxy(proxyURL string, proxyPort string, remoteAddress string,
remotePort string, credentials string) (TLSConn, error) {
addr, err := net.LookupHost(proxyURL)
if err != nil {
return TLSConn{}, err
}
dialConn, err := net.DialTimeout("tcp", addr[0] + ":" + proxyPort, dialTimeout)
if err != nil {
return TLSConn{}, fmt.Errorf("net.DialTimeout error: %+v", err)
}
parsedURL, err := url.Parse("https://" + remoteAddress + ":" + remotePort)
credentials = base64.StdEncoding.EncodeToString([]byte(credentials))
_, err = dialConn.Write([]byte("CONNECT " + parsedURL.Host + " HTTP/1.1\r\n" +
"Host: " + parsedURL.Host + "\r\n" +
"Proxy-Connection: keep-alive\r\n" +
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36\r\n" +
"Proxy-Authorization: Basic " + credentials +
"\r\n\r\n",
))
br := make([]byte, 1024)
_, err = dialConn.Read(br)
if err != nil {
return TLSConn{}, err
}
config := tls.Config{ServerName: remoteAddress}
uTlsConn := tls.UClient(dialConn, &config, tls.HelloCustom)
spec := getClientHello()
err = uTlsConn.ApplyPreset(&spec)
err = uTlsConn.Handshake()
if err != nil {
return TLSConn{}, fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
}
return TLSConn{CustomConn: uTlsConn, Alpn: uTlsConn.HandshakeState.ServerHello.AlpnProtocol}, nil
}
Hello,
I am currently facing an issue with sending a GET
request to https://http2.pro/api/v1
.
The steps to reproduce:
git clone https://github.com/mehtaabGill/utls-test.git
cd utls-test
go get
go run main.go
The error i am receiving:
panic: Get "https://http2.pro/api/v1": net/http: HTTP/1.x transport connection broken: malformed HTTP status code "bad"
goroutine 1 [running]:
main.main()
C:/Users/mehta/go/src/github.com/mehtaabGill/utls-test/main.go:23 +0x4f3
exit status 2
What I expected to see:
A proper JSON response which indicates I sent a request with a connection that supports HTTP2
Note - I am using the HelloChrome_83
ClientHelloID
Env: Go 1.14, Windows amd64
Whenever I use the client hello of chrome for version 70, 72, or 83, the program will run into this error
HttpGetByHelloID(HelloChrome_70) failed: uTlsConn.Handshake() error: local error: tls: unexpected message
How to reproduce:
If you use a utls.Config
with a ServerName
that is an IP address, uTLS v1.0.0 sends a server_name extension, whereas the real implementations that uTLS is mimicking do not send server_name when it would contain an IP address. (Neither does crypto/tls.)
uTLS should omit the server_name extension when it would contain an IP address. (But it should still use the IP address for certificate validation. There are TLS servers that have certificates for IP addresses, for example https://1.1.1.1/.)
It is actually a protocol violation to put an IP address in server_name:
Literal IPv4 and IPv6 addresses are not permitted in "HostName".
Here is where crypto/tls internally checks whether the SNI string is an IP address, and removes the extension if it is:
https://github.com/golang/go/blob/4300f105147dc0da9d1034704ad1cd24bedde5da/src/crypto/tls/handshake_client.go#L1004-L1006
if net.ParseIP(host) != nil { return "" }
And here it is in Firefox (I think):
https://searchfox.org/mozilla-central/source/security/nss/lib/ssl/ssl3exthandle.c#30-34
/* must not be an IPv4 or IPv6 address */ if (PR_SUCCESS == PR_StringToNetAddr(url, &netAddr)) { /* is an IP address (v4 or v6) */ return PR_FALSE; }
A workaround for uTLS is to inspect ServerName
after calling UClient
but before calling Handshake
, and calling RemoveSNIExtension
(from #51) if it is an IP address.
Here is a demo program (go run ip-sni.go
):
package main import ( // "crypto/tls" "fmt" "net" "os" utls "github.com/refraction-networking/utls" ) func run() error { conn, err := net.Dial("tcp", "1.1.1.1:853") if err != nil { return err } defer conn.Close() // config := utls.Config{} // "either ServerName or InsecureSkipVerify must be specified in the tls.Config" config := utls.Config{ServerName: "1.1.1.1"} tlsConn := utls.UClient(conn, &config, utls.HelloFirefox_65) /* // workaround: if net.ParseIP(config.ServerName) != nil { err := tlsConn.RemoveSNIExtension() if err != nil { return err } } */ err = tlsConn.Handshake() if err != nil { return err } defer tlsConn.Close() /* // crypto/tls version: config := tls.Config{ServerName: "1.1.1.1"} tlsConn := tls.Client(conn, &config) err = tlsConn.Handshake() if err != nil { return err } defer tlsConn.Close() */ fmt.Printf("%s connected\n", tlsConn.RemoteAddr()) return nil } func main() { err := run() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }
I cannot give a fingerprint ID because https://tlsfingerprint.io/pcap is not working for me. But here is the Client Hello produced by the above program with uTLS v1.0.0 and go1.15.9:
Secure Sockets Layer TLSv1 Record Layer: Handshake Protocol: Client Hello Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 512 Handshake Protocol: Client Hello Handshake Type: Client Hello (1) Length: 508 Version: TLS 1.2 (0x0303) Random: d479fe839284e6cd5a05a57ac3c614480443718e0b4801b6... GMT Unix Time: Dec 17, 2082 13:26:43.000000000 MST Random Bytes: 9284e6cd5a05a57ac3c614480443718e0b4801b61c3ed70b... Session ID Length: 32 Session ID: f89a6e0030c3f0d579e6fd47aa9bf3ba8f8666caf5d76c8c... Cipher Suites Length: 36 Cipher Suites (18 suites) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9) Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a) Compression Methods Length: 1 Compression Methods (1 method) Compression Method: null (0) Extensions Length: 399 Extension: server_name (len=12) Type: server_name (0) Length: 12 Server Name Indication extension Server Name list length: 10 Server Name Type: host_name (0) Server Name length: 7 Server Name: 1.1.1.1 Extension: extended_master_secret (len=0) Type: extended_master_secret (23) Length: 0 Extension: renegotiation_info (len=1) Type: renegotiation_info (65281) Length: 1 Renegotiation Info extension Renegotiation info extension length: 0 Extension: supported_groups (len=14) Type: supported_groups (10) Length: 14 Supported Groups List Length: 12 Supported Groups (6 groups) Supported Group: x25519 (0x001d) Supported Group: secp256r1 (0x0017) Supported Group: secp384r1 (0x0018) Supported Group: secp521r1 (0x0019) Supported Group: ffdhe2048 (0x0100) Supported Group: ffdhe3072 (0x0101) Extension: ec_point_formats (len=2) Type: ec_point_formats (11) Length: 2 EC point formats Length: 1 Elliptic curves point formats (1) EC point format: uncompressed (0) Extension: SessionTicket TLS (len=0) Type: SessionTicket TLS (35) Length: 0 Data (0 bytes) Extension: application_layer_protocol_negotiation (len=14) Type: application_layer_protocol_negotiation (16) Length: 14 ALPN Extension Length: 12 ALPN Protocol ALPN string length: 2 ALPN Next Protocol: h2 ALPN string length: 8 ALPN Next Protocol: http/1.1 Extension: status_request (len=5) Type: status_request (5) Length: 5 Certificate Status Type: OCSP (1) Responder ID list Length: 0 Request Extensions Length: 0 Extension: key_share (len=107) Type: key_share (51) Length: 107 Key Share extension Client Key Share Length: 105 Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: 7dd4286f301e1cc5570f4a90f5d0a100a32fe3fdced1188a... Key Share Entry: Group: secp256r1, Key Exchange length: 65 Group: secp256r1 (23) Key Exchange Length: 65 Key Exchange: 04151d7a0b38c12aa32e4cef4f4a4abfdd17f9d00141a05a... Extension: supported_versions (len=9) Type: supported_versions (43) Length: 9 Supported Versions length: 8 Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303) Supported Version: TLS 1.1 (0x0302) Supported Version: TLS 1.0 (0x0301) Extension: signature_algorithms (len=24) Type: signature_algorithms (13) Length: 24 Signature Hash Algorithms Length: 22 Signature Hash Algorithms (11 algorithms) Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403) Signature Hash Algorithm Hash: SHA256 (4) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503) Signature Hash Algorithm Hash: SHA384 (5) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603) Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (4) Signature Algorithm: rsa_pss_rsae_sha384 (0x0805) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (5) Signature Algorithm: rsa_pss_rsae_sha512 (0x0806) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (6) Signature Algorithm: rsa_pkcs1_sha256 (0x0401) Signature Hash Algorithm Hash: SHA256 (4) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: rsa_pkcs1_sha384 (0x0501) Signature Hash Algorithm Hash: SHA384 (5) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: rsa_pkcs1_sha512 (0x0601) Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: ecdsa_sha1 (0x0203) Signature Hash Algorithm Hash: SHA1 (2) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: rsa_pkcs1_sha1 (0x0201) Signature Hash Algorithm Hash: SHA1 (2) Signature Hash Algorithm Signature: RSA (1) Extension: psk_key_exchange_modes (len=2) Type: psk_key_exchange_modes (45) Length: 2 PSK Key Exchange Modes Length: 1 PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1) Extension: Unknown type 28 (len=2) Type: Unknown (28) Length: 2 Data: 4001 Extension: padding (len=151) Type: padding (21) Length: 151 Padding Data: 000000000000000000000000000000000000000000000000...
RemoveSNIExtension
workaround (note absence of server_name)Secure Sockets Layer TLSv1 Record Layer: Handshake Protocol: Client Hello Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 512 Handshake Protocol: Client Hello Handshake Type: Client Hello (1) Length: 508 Version: TLS 1.2 (0x0303) Random: c5ea2e01d674d7e7e280bbf68dc8faca6308bd5552a7fede... GMT Unix Time: Mar 21, 2075 23:39:13.000000000 MDT Random Bytes: d674d7e7e280bbf68dc8faca6308bd5552a7feded6ad774d... Session ID Length: 32 Session ID: 74f6ba412c1e3c606bd4a361624485bc93880c2d5994884f... Cipher Suites Length: 36 Cipher Suites (18 suites) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9) Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a) Compression Methods Length: 1 Compression Methods (1 method) Compression Method: null (0) Extensions Length: 399 Extension: extended_master_secret (len=0) Type: extended_master_secret (23) Length: 0 Extension: renegotiation_info (len=1) Type: renegotiation_info (65281) Length: 1 Renegotiation Info extension Renegotiation info extension length: 0 Extension: supported_groups (len=14) Type: supported_groups (10) Length: 14 Supported Groups List Length: 12 Supported Groups (6 groups) Supported Group: x25519 (0x001d) Supported Group: secp256r1 (0x0017) Supported Group: secp384r1 (0x0018) Supported Group: secp521r1 (0x0019) Supported Group: ffdhe2048 (0x0100) Supported Group: ffdhe3072 (0x0101) Extension: ec_point_formats (len=2) Type: ec_point_formats (11) Length: 2 EC point formats Length: 1 Elliptic curves point formats (1) EC point format: uncompressed (0) Extension: SessionTicket TLS (len=0) Type: SessionTicket TLS (35) Length: 0 Data (0 bytes) Extension: application_layer_protocol_negotiation (len=14) Type: application_layer_protocol_negotiation (16) Length: 14 ALPN Extension Length: 12 ALPN Protocol ALPN string length: 2 ALPN Next Protocol: h2 ALPN string length: 8 ALPN Next Protocol: http/1.1 Extension: status_request (len=5) Type: status_request (5) Length: 5 Certificate Status Type: OCSP (1) Responder ID list Length: 0 Request Extensions Length: 0 Extension: key_share (len=107) Type: key_share (51) Length: 107 Key Share extension Client Key Share Length: 105 Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: de3a466a3bdbbd2d2368fedd56c6d9315cd4006dc88a4da0... Key Share Entry: Group: secp256r1, Key Exchange length: 65 Group: secp256r1 (23) Key Exchange Length: 65 Key Exchange: 047ec6d114b9d95ba1fbd2241740dcaa05033e186d8d6af0... Extension: supported_versions (len=9) Type: supported_versions (43) Length: 9 Supported Versions length: 8 Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303) Supported Version: TLS 1.1 (0x0302) Supported Version: TLS 1.0 (0x0301) Extension: signature_algorithms (len=24) Type: signature_algorithms (13) Length: 24 Signature Hash Algorithms Length: 22 Signature Hash Algorithms (11 algorithms) Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403) Signature Hash Algorithm Hash: SHA256 (4) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503) Signature Hash Algorithm Hash: SHA384 (5) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603) Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (4) Signature Algorithm: rsa_pss_rsae_sha384 (0x0805) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (5) Signature Algorithm: rsa_pss_rsae_sha512 (0x0806) Signature Hash Algorithm Hash: Unknown (8) Signature Hash Algorithm Signature: Unknown (6) Signature Algorithm: rsa_pkcs1_sha256 (0x0401) Signature Hash Algorithm Hash: SHA256 (4) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: rsa_pkcs1_sha384 (0x0501) Signature Hash Algorithm Hash: SHA384 (5) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: rsa_pkcs1_sha512 (0x0601) Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: RSA (1) Signature Algorithm: ecdsa_sha1 (0x0203) Signature Hash Algorithm Hash: SHA1 (2) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: rsa_pkcs1_sha1 (0x0201) Signature Hash Algorithm Hash: SHA1 (2) Signature Hash Algorithm Signature: RSA (1) Extension: psk_key_exchange_modes (len=2) Type: psk_key_exchange_modes (45) Length: 2 PSK Key Exchange Modes Length: 1 PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1) Extension: Unknown type 28 (len=2) Type: Unknown (28) Length: 2 Data: 4001 Extension: padding (len=167) Type: padding (21) Length: 167 Padding Data: 000000000000000000000000000000000000000000000000...
Hello I am quite intrigued with the concept of TLS fingerprinting I want to implement it into a webserver of mine as a layer on top of nodejs however I have minimal experience in go and the language is unlike anything I have ever seen, I did as much digging as I could and saw that https://client.tlsfingerprint.io:8443/ is what is requested to essentially meet an endpoint and gain all the information that is sent back as a response, based of the parameters of the request I see that its some sort of amalgamation of the class ClientHelloMsg from crypto/tls and backend access to your own TLS fingerprinting analytics you have collected, I don't want the analytical part just 100% of the information from the client hello in the same format you have primarily the cipher suites and extensions, if you don't mind I feel like it would be very beneficial if something like this was open sourced but its up to you
🤦 I feel like an idiot about this one. It looks like I left a hardcoded false
as the argument here instead of correctly passing through omitSNI
. I'm honestly a little confused that the compiler allowed it since it's an unused variable.
I'll open a quick PR to fix this. Sorry!!!
Line 390 in 219d12d
I can't find pre_shared_key in TLSExtension
As discussed in this Tor ticket, https://trac.torproject.org/projects/tor/ticket/29077#comment:19, there are some fixes in this fork, https://gitlab.com/yawning/utls/activity, that improve TLS 1.3 compatibility with certain CDNs.
Are these fixes suitable to be merged upstream?
Like github.com/cloudflare/tls-tris
The Let's Encrypt certificate seems expired :-(
In the latest commit: Yawning/chacha20@644b09a, the author did some non backward-compatible changes. One of them is:
NewCipher
->New
We should fix this piece here:
Lines 119 to 120 in 7c97cdb
Hello, is it possible to connect using HTTP / SOCKS5 Proxy?
My connection is currently done using default HttpGetConsistentRandomized
Hi, first off hats off for such an awesome tool!
Is there any possibility to set a custom Timestamp inside the TLS Handshake instead of the random generated one?
from my testing on multiple devices, https://client.tlsfingerprint.io:8443/ no longer returns the correct stats. from what i see, cluster , cluster_seen, seen, seen_total, frac_seen, rank, custer_fps & clusterfrac
are all returning erroneous values, i cannot assess the validity of the other values returned.
Chrome 88 will send a fallback cipher list that includes TLS_RSA_WITH_3DES_EDE_CBC_SHA on top of it's regular list if a server replies with a server rejection to the client hello. (see esaj.tjsp.jus.br for an example site).
Is there anything built-in at the moment to do a fallback cipher list?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.