|
| 1 | +package unit |
| 2 | + |
| 3 | +import ( |
| 4 | + "crypto/tls" |
| 5 | + "net/http" |
| 6 | + "net/http/httptest" |
| 7 | + "testing" |
| 8 | + |
| 9 | + "github.com/Danny-Dasilva/CycleTLS/cycletls" |
| 10 | + utls "github.com/refraction-networking/utls" |
| 11 | +) |
| 12 | + |
| 13 | +func TestIssue409_JA4RHandshake(t *testing.T) { |
| 14 | + ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 15 | + w.WriteHeader(http.StatusOK) |
| 16 | + _, _ = w.Write([]byte("ok")) |
| 17 | + })) |
| 18 | + ts.TLS = &tls.Config{ |
| 19 | + MinVersion: tls.VersionTLS12, |
| 20 | + MaxVersion: tls.VersionTLS13, |
| 21 | + } |
| 22 | + ts.StartTLS() |
| 23 | + defer ts.Close() |
| 24 | + |
| 25 | + client := cycletls.Init() |
| 26 | + defer client.Close() |
| 27 | + |
| 28 | + ja4r := "t13d1516h2_002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0000,0005,000a,000b,000d,0012,0017,001b,0023,002b,002d,0033,44cd,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601" |
| 29 | + |
| 30 | + resp, err := client.Do(ts.URL, cycletls.Options{ |
| 31 | + Ja4r: ja4r, |
| 32 | + UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", |
| 33 | + InsecureSkipVerify: true, |
| 34 | + }, "GET") |
| 35 | + |
| 36 | + if err != nil { |
| 37 | + t.Fatalf("client.Do failed: %v", err) |
| 38 | + } |
| 39 | + if resp.Status != 200 { |
| 40 | + t.Fatalf("expected status 200, got %d, body: %s", resp.Status, resp.Body) |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +func TestIssue409_CreateExtensionECH(t *testing.T) { |
| 45 | + // When GREASE is enabled, 0xfe0d should return valid BoringGREASEECH extension |
| 46 | + ext := cycletls.CreateExtensionFromID(0xfe0d, utls.VersionTLS13, nil, false, "example.com") |
| 47 | + if ext == nil { |
| 48 | + t.Fatal("expected non-nil extension for 0xfe0d when disableGrease is false") |
| 49 | + } |
| 50 | + if _, ok := ext.(*utls.GREASEEncryptedClientHelloExtension); !ok { |
| 51 | + t.Fatalf("expected *utls.GREASEEncryptedClientHelloExtension, got %T", ext) |
| 52 | + } |
| 53 | + |
| 54 | + // When GREASE is disabled, 0xfe0d should return nil |
| 55 | + extDisabled := cycletls.CreateExtensionFromID(0xfe0d, utls.VersionTLS13, nil, true, "example.com") |
| 56 | + if extDisabled != nil { |
| 57 | + t.Fatalf("expected nil extension for 0xfe0d when disableGrease is true, got %T", extDisabled) |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +func TestIssue409_SupportedCurvesNoDuplicate(t *testing.T) { |
| 62 | + ext := cycletls.CreateExtensionFromID(0x000a, utls.VersionTLS13, nil, false, "example.com") |
| 63 | + if ext == nil { |
| 64 | + t.Fatal("expected non-nil SupportedCurves extension") |
| 65 | + } |
| 66 | + curvesExt, ok := ext.(*utls.SupportedCurvesExtension) |
| 67 | + if !ok { |
| 68 | + t.Fatalf("expected *utls.SupportedCurvesExtension, got %T", ext) |
| 69 | + } |
| 70 | + |
| 71 | + seen := make(map[utls.CurveID]bool) |
| 72 | + for _, c := range curvesExt.Curves { |
| 73 | + if seen[c] { |
| 74 | + t.Fatalf("duplicate curve %v found in SupportedCurvesExtension: %v", c, curvesExt.Curves) |
| 75 | + } |
| 76 | + seen[c] = true |
| 77 | + } |
| 78 | + |
| 79 | + if len(curvesExt.Curves) == 0 || curvesExt.Curves[0] != utls.X25519MLKEM768 { |
| 80 | + t.Fatalf("expected first curve to be X25519MLKEM768 in TLS 1.3, got %v", curvesExt.Curves) |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +func TestIssue409_KeyShare(t *testing.T) { |
| 85 | + ext := cycletls.CreateExtensionFromID(0x0033, utls.VersionTLS13, nil, false, "example.com") |
| 86 | + if ext == nil { |
| 87 | + t.Fatal("expected non-nil KeyShare extension") |
| 88 | + } |
| 89 | + ksExt, ok := ext.(*utls.KeyShareExtension) |
| 90 | + if !ok { |
| 91 | + t.Fatalf("expected *utls.KeyShareExtension, got %T", ext) |
| 92 | + } |
| 93 | + if len(ksExt.KeyShares) < 2 { |
| 94 | + t.Fatalf("expected at least 2 key shares, got %d", len(ksExt.KeyShares)) |
| 95 | + } |
| 96 | + if ksExt.KeyShares[0].Group != utls.X25519MLKEM768 { |
| 97 | + t.Fatalf("expected first key share to be X25519MLKEM768, got %v", ksExt.KeyShares[0].Group) |
| 98 | + } |
| 99 | + if ksExt.KeyShares[1].Group != utls.X25519 { |
| 100 | + t.Fatalf("expected second key share to be X25519, got %v", ksExt.KeyShares[1].Group) |
| 101 | + } |
| 102 | +} |
0 commit comments