package faketls import ( "crypto/tls" "net" "strings" "testing" "time" "go.mau.fi/mautrix-telegram/pkg/gotd/bin" ) // TestClientHelloStructure verifies that what we generate is a syntactically // valid TLS ClientHello — i.e., the Go crypto/tls server can parse it without // returning a "decode_error"-like syntax error. We don't care that the TLS // handshake then fails (it will, since we're using a fake cert / random data); // we only care that parsing succeeds. func TestClientHelloStructure(t *testing.T) { // Render with deterministic rng + sessionID + key. var session [32]byte for i := range session { session[i] = byte(i) } var key [32]byte for i := range key { key[i] = 0xAA } var grease [7]byte for i := range grease { grease[i] = byte(0x0A + i*0x10) } if grease[3] == grease[4] { grease[3] ^= 0x10 } b := &bin.Buffer{Buf: make([]byte, 0, 576)} createClientHello(b, session, "example.com", key, grease) if len(b.Buf) != clientHelloLength { t.Fatalf("expected %d bytes, got %d", clientHelloLength, len(b.Buf)) } // Wire it through a real TLS server. The server reads bytes from // our pipe; if it accepts ClientHello but fails on cert/MAC, we get // a non-syntax error. If it returns "decode_error", we know we're // still busted. clientConn, serverConn := net.Pipe() defer clientConn.Close() defer serverConn.Close() go func() { clientConn.Write(b.Buf) // keep the pipe open until done }() cfg := &tls.Config{ Certificates: []tls.Certificate{generateSelfSigned(t)}, } srv := tls.Server(serverConn, cfg) srv.SetDeadline(time.Now().Add(2 * time.Second)) err := srv.Handshake() if err == nil { return // unexpectedly succeeded — fine for our purpose } t.Logf("server handshake error (expected non-syntax): %v", err) msg := err.Error() for _, marker := range []string{"decode_error", "syntax", "malformed", "bad ClientHello"} { if strings.Contains(msg, marker) { t.Fatalf("structural parse failure (%q) — ClientHello is malformed: %v", marker, err) } } } // generateSelfSigned builds a throwaway cert for the test TLS server. func generateSelfSigned(t *testing.T) tls.Certificate { cert, err := tls.X509KeyPair(testCertPEM, testKeyPEM) if err != nil { t.Fatal(err) } return cert } // Generated with `go run filippo.io/mkcert@latest -ecdsa example.com`-ish. // Embedded here for deterministic test environment. var testCertPEM = []byte(`-----BEGIN CERTIFICATE----- MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d 7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B 5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1 NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc 6MF9+Yw1Yy0t -----END CERTIFICATE-----`) var testKeyPEM = []byte(`-----BEGIN EC PRIVATE KEY----- MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49 AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA== -----END EC PRIVATE KEY-----`)