From 407d415ceb058a275e7847bb51c6f94123cd276b Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Thu, 19 Mar 2026 16:01:54 -0600 Subject: [PATCH 1/4] Remove tlsdialer dependency by inlining TLS dial logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tlsdialer wrapped utls with DNS resolution, timeout management, and cert verification — most of which fronted doesn't need since it passes pre-resolved IPs and handles its own cert verification via VerifyPeerCertificate. This inlines the ~25 lines of actually needed logic (UClient creation, handshake with deadline, manual cert verification for non-SNI path) and drops tlsdialer plus its transitive deps (mtime, netx). Co-Authored-By: Claude Opus 4.6 (1M context) --- front.go | 64 +++++++++++++++++++++++++++++++++++------ go.mod | 13 +-------- go.sum | 86 +------------------------------------------------------- 3 files changed, 57 insertions(+), 106 deletions(-) diff --git a/front.go b/front.go index 94ab00c..d8c810d 100644 --- a/front.go +++ b/front.go @@ -16,7 +16,6 @@ import ( "time" "github.com/getlantern/ops" - "github.com/getlantern/tlsdialer/v3" tls "github.com/refraction-networking/utls" ) @@ -133,19 +132,46 @@ func (fr *front) dial(rootCAs *x509.CertPool, clientHelloID tls.ClientHelloID) ( doDial = dialWithTimeout } - dialer := &tlsdialer.Dialer{ - DoDial: doDial, - Timeout: dialTimeout, - SendServerName: sendServerNameExtension, - Config: tlsConfig, - ClientHelloID: clientHelloID, - } _, _, err := net.SplitHostPort(addr) if err != nil { // If there is no port, we default to 443 addr = net.JoinHostPort(addr, "443") } - return dialer.Dial("tcp", addr) + + deadline := time.Now().Add(dialTimeout) + + rawConn, err := doDial("tcp", addr, dialTimeout) + if err != nil { + return nil, err + } + + configCopy := tlsConfig.Clone() + configCopy.InsecureSkipVerify = true + if !sendServerNameExtension { + configCopy.ServerName = "" + } + + chid := clientHelloID + if chid.Client == "" { + chid = tls.HelloGolang + } + + conn := tls.UClient(rawConn, configCopy, chid) + rawConn.SetDeadline(deadline) + if err := conn.Handshake(); err != nil { + rawConn.Close() + return nil, err + } + rawConn.SetDeadline(time.Time{}) + + if !tlsConfig.InsecureSkipVerify { + if _, err := verifyServerCerts(conn, tlsConfig.ServerName, tlsConfig.RootCAs); err != nil { + rawConn.Close() + return nil, err + } + } + + return conn.Conn, nil } func dialWithTimeout(network string, addr string, timeout time.Duration) (net.Conn, error) { @@ -153,6 +179,26 @@ func dialWithTimeout(network string, addr string, timeout time.Duration) (net.Co return dialer.Dial(network, addr) } +func verifyServerCerts(conn *tls.UConn, serverName string, rootCAs *x509.CertPool) ([][]*x509.Certificate, error) { + certs := conn.ConnectionState().PeerCertificates + if len(certs) == 0 { + return nil, fmt.Errorf("no peer certificates provided") + } + opts := x509.VerifyOptions{ + Roots: rootCAs, + CurrentTime: time.Now(), + DNSName: serverName, + Intermediates: x509.NewCertPool(), + } + for i, cert := range certs { + if i == 0 { + continue + } + opts.Intermediates.AddCert(cert) + } + return certs[0].Verify(opts) +} + // verifyWithPost does a post with invalid data to verify domain-fronting works func (fr *front) verifyWithPost(conn net.Conn, testURL string) bool { client := &http.Client{ diff --git a/go.mod b/go.mod index 996e18b..564584a 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/alitto/pond/v2 v2.1.5 github.com/getlantern/keepcurrent v0.0.0-20240126172110-2e0264ca385d github.com/getlantern/ops v0.0.0-20231025133620-f368ab734534 - github.com/getlantern/tlsdialer/v3 v3.0.6-0.20260105215053-2a1cd54af4d5 github.com/getlantern/waitforserver v1.0.1 github.com/goccy/go-yaml v1.15.13 github.com/refraction-networking/utls v1.7.1 @@ -21,22 +20,14 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 // indirect - github.com/getlantern/errors v1.0.3 // indirect - github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 // indirect - github.com/getlantern/hex v0.0.0-20220104173244-ad7e4b9194dc // indirect - github.com/getlantern/hidden v0.0.0-20220104173330-f221c5a24770 // indirect - github.com/getlantern/iptool v0.0.0-20230112135223-c00e863b2696 // indirect - github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7 // indirect - github.com/getlantern/netx v0.0.0-20240814210628-0984f52e2d18 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/pgzip v1.2.5 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mholt/archiver/v3 v3.5.1 // indirect github.com/nwaples/rardecode v1.1.0 // indirect - github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect @@ -45,8 +36,6 @@ require ( go.opentelemetry.io/otel v1.19.0 // indirect go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/trace v1.19.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/sys v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 40c08d3..ad0c213 100644 --- a/go.sum +++ b/go.sum @@ -3,57 +3,29 @@ github.com/alitto/pond/v2 v2.1.5/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+ github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 h1:oEZYEpZo28Wdx+5FZo4aU7JFXu0WG/4wJWese5reQSA= github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201/go.mod h1:Y9WZUHEb+mpra02CbQ/QczLUe6f0Dezxaw5DCJlJQGo= -github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= github.com/getlantern/errors v1.0.3 h1:Ne4Ycj7NI1BtSyAfVeAT/DNoxz7/S2BUc3L2Ht1YSHE= github.com/getlantern/errors v1.0.3/go.mod h1:m8C7H1qmouvsGpwQqk/6NUpIVMpfzUPn608aBZDYV04= -github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4 h1:JdD4XSaT6/j6InM7MT1E4WRvzR8gurxfq53A3ML3B/Q= -github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4/go.mod h1:XZwE+iIlAgr64OFbXKFNCllBwV4wEipPx8Hlo2gZdbM= -github.com/getlantern/golog v0.0.0-20210606115803-bce9f9fe5a5f/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA= -github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 h1:NlQedYmPI3pRAXJb+hLVVDGqfvvXGRPV8vp7XOjKAZ0= -github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65/go.mod h1:+ZU1h+iOVqWReBpky6d5Y2WL0sF2Llxu+QcxJFs2+OU= -github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= -github.com/getlantern/hex v0.0.0-20220104173244-ad7e4b9194dc h1:sue+aeVx7JF5v36H1HfvcGFImLpSD5goj8d+MitovDU= -github.com/getlantern/hex v0.0.0-20220104173244-ad7e4b9194dc/go.mod h1:D9RWpXy/EFPYxiKUURo2TB8UBosbqkiLhttRrZYtvqM= -github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= -github.com/getlantern/hidden v0.0.0-20220104173330-f221c5a24770 h1:cSrD9ryDfTV2yaur9Qk3rHYD414j3Q1rl7+L0AylxrE= -github.com/getlantern/hidden v0.0.0-20220104173330-f221c5a24770/go.mod h1:GOQsoDnEHl6ZmNIL+5uVo+JWRFWozMEp18Izcb++H+A= -github.com/getlantern/iptool v0.0.0-20230112135223-c00e863b2696 h1:D7wbL2Ww6QN5SblEDMiQcFulqz2jgcvawKaNBTzHLvQ= -github.com/getlantern/iptool v0.0.0-20230112135223-c00e863b2696/go.mod h1:hfspzdRcvJ130tpTPL53/L92gG0pFtvQ6ln35ppwhHE= github.com/getlantern/keepcurrent v0.0.0-20240126172110-2e0264ca385d h1:2/9rPC1xT+jWBnAe4mD6Q0LWkByFYGcTiKsmDWbv2T4= github.com/getlantern/keepcurrent v0.0.0-20240126172110-2e0264ca385d/go.mod h1:enUAvxkJ15QUtTKOKoO9WJV2L5u33P8YmqkC+iu8iT4= -github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848 h1:2MhMMVBTnaHrst6HyWFDhwQCaJ05PZuOv1bE2gN8WFY= -github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8= -github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7 h1:03J6Cb42EG06lHgpOFGm5BOax4qFqlSbSeKO2RGrj2g= -github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7/go.mod h1:GfzwugvtH7YcmNIrHHizeyImsgEdyL88YkdnK28B14c= -github.com/getlantern/netx v0.0.0-20240814210628-0984f52e2d18 h1:I5xFq/HkvWGUPysqC8LQH9oks1WaM9BpcB+fjmvMRic= -github.com/getlantern/netx v0.0.0-20240814210628-0984f52e2d18/go.mod h1:4WkWbHy7Mqri9lxpLFN6dOU5nUy3kyNCpHxSRQZocv0= -github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= -github.com/getlantern/ops v0.0.0-20220713155959-1315d978fff7/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= github.com/getlantern/ops v0.0.0-20231025133620-f368ab734534 h1:3BwvWj0JZzFEvNNiMhCu4bf60nqcIuQpTYb00Ezm1ag= github.com/getlantern/ops v0.0.0-20231025133620-f368ab734534/go.mod h1:ZsLfOY6gKQOTyEcPYNA9ws5/XHZQFroxqCOhHjGcs9Y= -github.com/getlantern/tlsdialer/v3 v3.0.6-0.20260105215053-2a1cd54af4d5 h1:+Ai5I/vz3jitmogrCWCAJCBsiP+afn3PDeCJ42LeOrs= -github.com/getlantern/tlsdialer/v3 v3.0.6-0.20260105215053-2a1cd54af4d5/go.mod h1:QrBr/wjs8AHmtRxIIsTqk5fTsflPN5PwDtIFEG2szlU= github.com/getlantern/waitforserver v1.0.1 h1:xBjqJ3GgEk9JMWnDgRSiNHXINi6Lv2tGNjJR0hCkHFY= github.com/getlantern/waitforserver v1.0.1/go.mod h1:K1oSA8lNKgQ9iC00OFpMfMNm4UMrsxoGCdHf0NT9LGs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg= @@ -62,7 +34,6 @@ github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -72,36 +43,23 @@ github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6K github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= -github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0= github.com/refraction-networking/utls v1.7.1/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -110,61 +68,19 @@ github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo= go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 6893543fc650966c6dfbc708b9fac33cd2e66605 Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Thu, 19 Mar 2026 16:18:29 -0600 Subject: [PATCH 2/4] Fix TestVerifyPeerCertificate: update expired certs, add DigiCert G3 root The test used hardcoded Akamai certs that expired 2026-03-18. Updated with fresh certs (valid until 2026-12-22) which chain through DigiCert Global G3 (new intermediate), so added the DigiCert Global Root G3 CA to DefaultTrustedCAs. Also added an early skip guard that parses the leaf cert expiry so future expiration produces a clear skip message instead of a cryptic failure. Co-Authored-By: Claude Opus 4.6 (1M context) --- default_masquerades.go | 4 ++++ fronted_test.go | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/default_masquerades.go b/default_masquerades.go index eb7b364..a9b6255 100644 --- a/default_masquerades.go +++ b/default_masquerades.go @@ -9,6 +9,10 @@ var DefaultTrustedCAs = []*CA{ CommonName: "DigiCert Global Root G2", Cert: "-----BEGIN CERTIFICATE-----\nMIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\nMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\nb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\nq2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\ntCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\nvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\nNeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\nFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\npLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\nMrY=\n-----END CERTIFICATE-----\n", }, + { + CommonName: "DigiCert Global Root G3", + Cert: "-----BEGIN CERTIFICATE-----\nMIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw\nCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\nZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe\nFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw\nEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x\nIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG\nfp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO\nZ9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd\nBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx\nAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/\noAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8\nsycX\n-----END CERTIFICATE-----\n", + }, { CommonName: "DigiCert Global Root CA", Cert: "-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\nQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\nMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\nb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\nCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\nnh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\nT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\ngdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\nBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\nTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\nDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\nhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\nPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\nYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\nCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n-----END CERTIFICATE-----\n", diff --git a/fronted_test.go b/fronted_test.go index fbde58c..9db6896 100644 --- a/fronted_test.go +++ b/fronted_test.go @@ -624,8 +624,16 @@ func corruptMasquerades(cacheFile string) (int, error) { } func TestVerifyPeerCertificate(t *testing.T) { - // raw certs generated by printing the received rawCerts from TestDirectDomainFrontingWithSNIConfig - rawCerts := [][]byte{{48, 130, 5, 201, 48, 130, 5, 79, 160, 3, 2, 1, 2, 2, 16, 10, 104, 174, 217, 200, 97, 246, 117, 233, 137, 207, 239, 166, 251, 207, 173, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 48, 86, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 48, 48, 46, 6, 3, 85, 4, 3, 19, 39, 68, 105, 103, 105, 67, 101, 114, 116, 32, 84, 76, 83, 32, 72, 121, 98, 114, 105, 100, 32, 69, 67, 67, 32, 83, 72, 65, 51, 56, 52, 32, 50, 48, 50, 48, 32, 67, 65, 49, 48, 30, 23, 13, 50, 53, 48, 51, 49, 56, 48, 48, 48, 48, 48, 48, 90, 23, 13, 50, 54, 48, 51, 49, 56, 50, 51, 53, 57, 53, 57, 90, 48, 121, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 8, 19, 13, 77, 97, 115, 115, 97, 99, 104, 117, 115, 101, 116, 116, 115, 49, 18, 48, 16, 6, 3, 85, 4, 7, 19, 9, 67, 97, 109, 98, 114, 105, 100, 103, 101, 49, 34, 48, 32, 6, 3, 85, 4, 10, 19, 25, 65, 107, 97, 109, 97, 105, 32, 84, 101, 99, 104, 110, 111, 108, 111, 103, 105, 101, 115, 44, 32, 73, 110, 99, 46, 49, 26, 48, 24, 6, 3, 85, 4, 3, 19, 17, 97, 50, 52, 56, 46, 101, 46, 97, 107, 97, 109, 97, 105, 46, 110, 101, 116, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 137, 179, 173, 36, 7, 148, 115, 87, 89, 242, 68, 18, 67, 219, 1, 116, 170, 189, 59, 31, 134, 167, 129, 151, 124, 33, 237, 233, 140, 3, 235, 210, 253, 232, 46, 212, 95, 18, 33, 192, 156, 90, 87, 31, 233, 17, 0, 194, 110, 216, 164, 93, 216, 34, 45, 203, 136, 211, 69, 207, 17, 17, 92, 225, 163, 130, 3, 218, 48, 130, 3, 214, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 10, 188, 8, 41, 23, 140, 165, 57, 109, 122, 14, 206, 51, 199, 46, 179, 237, 251, 195, 122, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 84, 136, 107, 213, 162, 51, 87, 199, 43, 162, 19, 8, 242, 17, 240, 170, 80, 244, 78, 184, 48, 110, 6, 3, 85, 29, 17, 4, 103, 48, 101, 130, 17, 97, 50, 52, 56, 46, 101, 46, 97, 107, 97, 109, 97, 105, 46, 110, 101, 116, 130, 15, 42, 46, 97, 107, 97, 109, 97, 105, 122, 101, 100, 46, 110, 101, 116, 130, 23, 42, 46, 97, 107, 97, 109, 97, 105, 122, 101, 100, 45, 115, 116, 97, 103, 105, 110, 103, 46, 110, 101, 116, 130, 14, 42, 46, 97, 107, 97, 109, 97, 105, 104, 100, 46, 110, 101, 116, 130, 22, 42, 46, 97, 107, 97, 109, 97, 105, 104, 100, 45, 115, 116, 97, 103, 105, 110, 103, 46, 110, 101, 116, 48, 62, 6, 3, 85, 29, 32, 4, 55, 48, 53, 48, 51, 6, 6, 103, 129, 12, 1, 2, 2, 48, 41, 48, 39, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 27, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 67, 80, 83, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 3, 136, 48, 29, 6, 3, 85, 29, 37, 4, 22, 48, 20, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 129, 155, 6, 3, 85, 29, 31, 4, 129, 147, 48, 129, 144, 48, 70, 160, 68, 160, 66, 134, 64, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 51, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 84, 76, 83, 72, 121, 98, 114, 105, 100, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 49, 46, 99, 114, 108, 48, 70, 160, 68, 160, 66, 134, 64, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 52, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 84, 76, 83, 72, 121, 98, 114, 105, 100, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 49, 46, 99, 114, 108, 48, 129, 133, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 121, 48, 119, 48, 36, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, 134, 24, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 48, 79, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, 134, 67, 104, 116, 116, 112, 58, 47, 47, 99, 97, 99, 101, 114, 116, 115, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 84, 76, 83, 72, 121, 98, 114, 105, 100, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 49, 46, 99, 114, 116, 48, 12, 6, 3, 85, 29, 19, 1, 1, 255, 4, 2, 48, 0, 48, 130, 1, 127, 6, 10, 43, 6, 1, 4, 1, 214, 121, 2, 4, 2, 4, 130, 1, 111, 4, 130, 1, 107, 1, 105, 0, 119, 0, 14, 87, 148, 188, 243, 174, 169, 62, 51, 27, 44, 153, 7, 179, 247, 144, 223, 155, 194, 61, 113, 50, 37, 221, 33, 169, 37, 172, 97, 197, 78, 33, 0, 0, 1, 149, 170, 99, 183, 135, 0, 0, 4, 3, 0, 72, 48, 70, 2, 33, 0, 235, 0, 242, 233, 98, 214, 73, 85, 137, 193, 228, 5, 25, 30, 42, 94, 189, 169, 209, 120, 117, 2, 217, 215, 176, 205, 75, 242, 208, 168, 238, 17, 2, 33, 0, 198, 118, 215, 89, 151, 11, 1, 238, 193, 90, 1, 193, 70, 74, 22, 58, 217, 225, 104, 133, 172, 94, 20, 99, 124, 128, 254, 138, 79, 55, 54, 123, 0, 118, 0, 73, 156, 155, 105, 222, 29, 124, 236, 252, 54, 222, 205, 135, 100, 166, 184, 91, 175, 10, 135, 128, 25, 209, 85, 82, 251, 233, 235, 41, 221, 248, 195, 0, 0, 1, 149, 170, 99, 183, 201, 0, 0, 4, 3, 0, 71, 48, 69, 2, 33, 0, 214, 242, 234, 42, 116, 165, 172, 238, 126, 119, 200, 152, 85, 19, 124, 2, 180, 24, 8, 241, 20, 135, 91, 42, 14, 66, 55, 214, 136, 129, 23, 27, 2, 32, 113, 102, 37, 203, 235, 86, 220, 129, 181, 162, 156, 200, 129, 80, 125, 97, 82, 224, 31, 181, 77, 27, 136, 123, 70, 2, 130, 127, 3, 92, 16, 2, 0, 118, 0, 203, 56, 247, 21, 137, 124, 132, 161, 68, 95, 91, 193, 221, 251, 201, 110, 242, 154, 89, 205, 71, 10, 105, 5, 133, 176, 203, 20, 195, 20, 88, 231, 0, 0, 1, 149, 170, 99, 183, 157, 0, 0, 4, 3, 0, 71, 48, 69, 2, 32, 74, 67, 53, 194, 171, 185, 139, 172, 120, 13, 130, 224, 25, 132, 23, 1, 186, 169, 182, 193, 127, 84, 186, 57, 200, 221, 58, 255, 253, 149, 89, 203, 2, 33, 0, 222, 152, 192, 126, 210, 194, 215, 227, 190, 66, 199, 219, 75, 231, 144, 230, 249, 77, 28, 106, 124, 143, 55, 68, 212, 178, 188, 36, 28, 126, 135, 152, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 3, 104, 0, 48, 101, 2, 48, 74, 189, 221, 93, 21, 162, 48, 200, 90, 164, 63, 233, 219, 209, 90, 6, 177, 129, 252, 19, 92, 4, 173, 221, 13, 8, 160, 9, 229, 206, 17, 220, 154, 107, 76, 136, 54, 79, 185, 131, 246, 235, 144, 87, 215, 248, 58, 246, 2, 49, 0, 179, 157, 243, 87, 121, 153, 72, 22, 90, 230, 197, 138, 127, 234, 20, 45, 23, 37, 48, 186, 234, 163, 23, 206, 103, 92, 5, 159, 100, 167, 161, 141, 193, 223, 215, 23, 62, 4, 91, 91, 103, 13, 39, 75, 50, 14, 60, 43}, {48, 130, 4, 23, 48, 130, 2, 255, 160, 3, 2, 1, 2, 2, 16, 7, 242, 243, 92, 135, 168, 119, 175, 122, 239, 233, 71, 153, 53, 37, 189, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 12, 5, 0, 48, 97, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 25, 48, 23, 6, 3, 85, 4, 11, 19, 16, 119, 119, 119, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 49, 32, 48, 30, 6, 3, 85, 4, 3, 19, 23, 68, 105, 103, 105, 67, 101, 114, 116, 32, 71, 108, 111, 98, 97, 108, 32, 82, 111, 111, 116, 32, 67, 65, 48, 30, 23, 13, 50, 49, 48, 52, 49, 52, 48, 48, 48, 48, 48, 48, 90, 23, 13, 51, 49, 48, 52, 49, 51, 50, 51, 53, 57, 53, 57, 90, 48, 86, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 48, 48, 46, 6, 3, 85, 4, 3, 19, 39, 68, 105, 103, 105, 67, 101, 114, 116, 32, 84, 76, 83, 32, 72, 121, 98, 114, 105, 100, 32, 69, 67, 67, 32, 83, 72, 65, 51, 56, 52, 32, 50, 48, 50, 48, 32, 67, 65, 49, 48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 193, 27, 198, 154, 91, 152, 217, 164, 41, 160, 233, 212, 4, 181, 219, 235, 166, 178, 108, 85, 192, 255, 237, 152, 198, 73, 47, 6, 39, 81, 203, 191, 112, 193, 5, 122, 195, 177, 157, 135, 137, 186, 173, 180, 19, 23, 201, 168, 180, 131, 200, 184, 144, 209, 204, 116, 53, 54, 60, 131, 114, 176, 181, 208, 247, 34, 105, 200, 241, 128, 196, 123, 64, 143, 207, 104, 135, 38, 92, 57, 137, 241, 77, 145, 77, 218, 137, 139, 228, 3, 195, 67, 229, 191, 47, 115, 163, 130, 1, 130, 48, 130, 1, 126, 48, 18, 6, 3, 85, 29, 19, 1, 1, 255, 4, 8, 48, 6, 1, 1, 255, 2, 1, 0, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 10, 188, 8, 41, 23, 140, 165, 57, 109, 122, 14, 206, 51, 199, 46, 179, 237, 251, 195, 122, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 3, 222, 80, 53, 86, 209, 76, 187, 102, 240, 163, 226, 27, 27, 195, 151, 178, 61, 209, 85, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 134, 48, 29, 6, 3, 85, 29, 37, 4, 22, 48, 20, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 118, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 106, 48, 104, 48, 36, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, 134, 24, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 48, 64, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, 134, 52, 104, 116, 116, 112, 58, 47, 47, 99, 97, 99, 101, 114, 116, 115, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 82, 111, 111, 116, 67, 65, 46, 99, 114, 116, 48, 66, 6, 3, 85, 29, 31, 4, 59, 48, 57, 48, 55, 160, 53, 160, 51, 134, 49, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 51, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 82, 111, 111, 116, 67, 65, 46, 99, 114, 108, 48, 61, 6, 3, 85, 29, 32, 4, 54, 48, 52, 48, 11, 6, 9, 96, 134, 72, 1, 134, 253, 108, 2, 1, 48, 7, 6, 5, 103, 129, 12, 1, 1, 48, 8, 6, 6, 103, 129, 12, 1, 2, 1, 48, 8, 6, 6, 103, 129, 12, 1, 2, 2, 48, 8, 6, 6, 103, 129, 12, 1, 2, 3, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 12, 5, 0, 3, 130, 1, 1, 0, 71, 89, 129, 127, 212, 27, 31, 176, 113, 246, 152, 93, 24, 186, 152, 71, 152, 176, 126, 118, 43, 234, 255, 26, 139, 172, 38, 179, 66, 141, 49, 230, 74, 232, 25, 208, 239, 218, 20, 231, 215, 20, 146, 161, 146, 242, 167, 46, 45, 175, 251, 29, 246, 251, 83, 176, 138, 63, 252, 216, 22, 10, 233, 176, 46, 182, 165, 11, 24, 144, 53, 38, 162, 218, 246, 168, 183, 50, 252, 149, 35, 75, 198, 69, 185, 196, 207, 228, 124, 238, 230, 201, 248, 144, 189, 114, 227, 153, 195, 29, 11, 5, 124, 106, 151, 109, 178, 171, 2, 54, 216, 194, 188, 44, 1, 146, 63, 4, 163, 139, 117, 17, 199, 185, 41, 188, 17, 208, 134, 186, 146, 188, 38, 249, 101, 200, 55, 205, 38, 246, 134, 19, 12, 4, 170, 137, 229, 120, 177, 193, 78, 121, 188, 118, 163, 11, 81, 228, 197, 208, 158, 106, 254, 26, 44, 86, 174, 6, 54, 39, 163, 115, 28, 8, 125, 147, 50, 208, 194, 68, 25, 218, 141, 244, 14, 123, 29, 40, 3, 43, 9, 138, 118, 202, 119, 220, 135, 122, 172, 123, 82, 38, 85, 167, 114, 15, 157, 210, 136, 79, 254, 177, 33, 197, 26, 161, 170, 57, 245, 86, 219, 194, 132, 196, 53, 31, 112, 218, 187, 70, 240, 134, 191, 100, 0, 196, 62, 247, 159, 70, 27, 157, 35, 5, 185, 125, 179, 79, 15, 169, 69, 58, 227, 116, 48, 152}} + // raw certs fetched from a248.e.akamai.net on 2026-03-19 (leaf valid 2025-12-22 to 2026-12-22) + // To refresh: connect to a248.e.akamai.net:443 and extract PeerCertificates as raw bytes. + rawCerts := [][]byte{{48, 130, 5, 201, 48, 130, 5, 79, 160, 3, 2, 1, 2, 2, 16, 3, 115, 171, 66, 15, 84, 148, 27, 85, 87, 66, 217, 172, 137, 6, 38, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 48, 89, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 68, 105, 103, 105, 67, 101, 114, 116, 32, 71, 108, 111, 98, 97, 108, 32, 71, 51, 32, 84, 76, 83, 32, 69, 67, 67, 32, 83, 72, 65, 51, 56, 52, 32, 50, 48, 50, 48, 32, 67, 65, 49, 48, 30, 23, 13, 50, 53, 49, 50, 50, 50, 48, 48, 48, 48, 48, 48, 90, 23, 13, 50, 54, 49, 50, 50, 50, 50, 51, 53, 57, 53, 57, 90, 48, 121, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 8, 19, 13, 77, 97, 115, 115, 97, 99, 104, 117, 115, 101, 116, 116, 115, 49, 18, 48, 16, 6, 3, 85, 4, 7, 19, 9, 67, 97, 109, 98, 114, 105, 100, 103, 101, 49, 34, 48, 32, 6, 3, 85, 4, 10, 19, 25, 65, 107, 97, 109, 97, 105, 32, 84, 101, 99, 104, 110, 111, 108, 111, 103, 105, 101, 115, 44, 32, 73, 110, 99, 46, 49, 26, 48, 24, 6, 3, 85, 4, 3, 19, 17, 97, 50, 52, 56, 46, 101, 46, 97, 107, 97, 109, 97, 105, 46, 110, 101, 116, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 111, 186, 198, 28, 140, 210, 95, 69, 166, 32, 10, 8, 148, 120, 2, 169, 163, 29, 116, 53, 247, 176, 207, 132, 247, 126, 133, 217, 90, 254, 197, 204, 161, 221, 162, 45, 40, 93, 124, 215, 173, 109, 242, 231, 189, 68, 138, 78, 158, 124, 200, 219, 211, 208, 130, 202, 71, 245, 147, 123, 110, 135, 176, 174, 163, 130, 3, 215, 48, 130, 3, 211, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 138, 35, 235, 158, 107, 215, 249, 55, 93, 249, 109, 33, 57, 118, 154, 161, 103, 222, 16, 168, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 175, 50, 71, 249, 169, 75, 98, 88, 227, 19, 56, 139, 138, 197, 234, 121, 107, 93, 97, 180, 48, 110, 6, 3, 85, 29, 17, 4, 103, 48, 101, 130, 17, 97, 50, 52, 56, 46, 101, 46, 97, 107, 97, 109, 97, 105, 46, 110, 101, 116, 130, 15, 42, 46, 97, 107, 97, 109, 97, 105, 122, 101, 100, 46, 110, 101, 116, 130, 23, 42, 46, 97, 107, 97, 109, 97, 105, 122, 101, 100, 45, 115, 116, 97, 103, 105, 110, 103, 46, 110, 101, 116, 130, 14, 42, 46, 97, 107, 97, 109, 97, 105, 104, 100, 46, 110, 101, 116, 130, 22, 42, 46, 97, 107, 97, 109, 97, 105, 104, 100, 45, 115, 116, 97, 103, 105, 110, 103, 46, 110, 101, 116, 48, 62, 6, 3, 85, 29, 32, 4, 55, 48, 53, 48, 51, 6, 6, 103, 129, 12, 1, 2, 2, 48, 41, 48, 39, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 27, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 67, 80, 83, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 3, 136, 48, 19, 6, 3, 85, 29, 37, 4, 12, 48, 10, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 48, 129, 159, 6, 3, 85, 29, 31, 4, 129, 151, 48, 129, 148, 48, 72, 160, 70, 160, 68, 134, 66, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 51, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 71, 51, 84, 76, 83, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 50, 46, 99, 114, 108, 48, 72, 160, 70, 160, 68, 134, 66, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 52, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 71, 51, 84, 76, 83, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 50, 46, 99, 114, 108, 48, 129, 135, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 123, 48, 121, 48, 36, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, 134, 24, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 48, 81, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, 134, 69, 104, 116, 116, 112, 58, 47, 47, 99, 97, 99, 101, 114, 116, 115, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 71, 51, 84, 76, 83, 69, 67, 67, 83, 72, 65, 51, 56, 52, 50, 48, 50, 48, 67, 65, 49, 45, 50, 46, 99, 114, 116, 48, 12, 6, 3, 85, 29, 19, 1, 1, 255, 4, 2, 48, 0, 48, 130, 1, 128, 6, 10, 43, 6, 1, 4, 1, 214, 121, 2, 4, 2, 4, 130, 1, 112, 4, 130, 1, 108, 1, 106, 0, 119, 0, 216, 9, 85, 59, 148, 79, 122, 255, 200, 22, 25, 111, 148, 79, 133, 171, 176, 248, 252, 94, 135, 85, 38, 15, 21, 209, 46, 114, 187, 69, 75, 20, 0, 0, 1, 155, 71, 44, 132, 37, 0, 0, 4, 3, 0, 72, 48, 70, 2, 33, 0, 158, 239, 46, 20, 200, 22, 143, 122, 32, 169, 168, 36, 34, 171, 17, 160, 242, 99, 250, 113, 52, 152, 147, 215, 65, 170, 144, 115, 138, 2, 209, 143, 2, 33, 0, 241, 103, 177, 230, 12, 45, 78, 165, 173, 93, 247, 231, 142, 233, 1, 84, 78, 188, 128, 104, 48, 175, 194, 219, 199, 202, 188, 108, 185, 246, 140, 168, 0, 118, 0, 200, 163, 196, 127, 199, 179, 173, 185, 53, 107, 1, 63, 106, 122, 18, 109, 227, 58, 78, 67, 165, 198, 70, 249, 151, 173, 57, 117, 153, 29, 207, 154, 0, 0, 1, 155, 71, 44, 132, 94, 0, 0, 4, 3, 0, 71, 48, 69, 2, 32, 30, 43, 243, 178, 133, 25, 152, 197, 50, 214, 210, 84, 47, 137, 244, 144, 108, 208, 20, 112, 231, 241, 170, 95, 140, 160, 173, 229, 147, 32, 32, 130, 2, 33, 0, 244, 24, 46, 179, 140, 173, 98, 78, 147, 190, 97, 173, 133, 157, 31, 31, 40, 155, 114, 124, 249, 209, 107, 71, 77, 183, 52, 179, 54, 127, 243, 103, 0, 119, 0, 194, 49, 126, 87, 69, 25, 163, 69, 238, 127, 56, 222, 178, 144, 65, 235, 199, 194, 33, 90, 34, 191, 127, 213, 181, 173, 118, 154, 217, 14, 82, 205, 0, 0, 1, 155, 71, 44, 132, 51, 0, 0, 4, 3, 0, 72, 48, 70, 2, 33, 0, 136, 72, 13, 74, 213, 175, 80, 26, 100, 90, 38, 231, 231, 13, 200, 54, 16, 62, 160, 225, 74, 11, 232, 106, 210, 170, 57, 127, 106, 163, 3, 128, 2, 33, 0, 129, 9, 223, 236, 95, 171, 3, 167, 165, 117, 237, 65, 73, 5, 166, 58, 150, 57, 136, 11, 171, 61, 39, 189, 153, 90, 222, 175, 199, 66, 159, 172, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 3, 104, 0, 48, 101, 2, 48, 107, 182, 71, 108, 4, 218, 17, 79, 182, 69, 42, 22, 248, 54, 241, 143, 118, 155, 201, 39, 83, 15, 165, 234, 140, 53, 63, 223, 164, 29, 44, 76, 81, 64, 204, 38, 27, 143, 88, 24, 224, 126, 22, 106, 173, 134, 123, 182, 2, 49, 0, 238, 81, 173, 172, 28, 31, 243, 138, 237, 192, 179, 6, 131, 198, 133, 126, 181, 63, 143, 84, 161, 243, 146, 74, 168, 108, 249, 164, 34, 232, 22, 87, 70, 121, 197, 36, 208, 94, 88, 253, 223, 101, 108, 73, 217, 244, 239, 225}, {48, 130, 3, 121, 48, 130, 2, 255, 160, 3, 2, 1, 2, 2, 16, 11, 0, 233, 45, 77, 109, 115, 31, 202, 48, 89, 199, 203, 30, 24, 134, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 48, 97, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 25, 48, 23, 6, 3, 85, 4, 11, 19, 16, 119, 119, 119, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 49, 32, 48, 30, 6, 3, 85, 4, 3, 19, 23, 68, 105, 103, 105, 67, 101, 114, 116, 32, 71, 108, 111, 98, 97, 108, 32, 82, 111, 111, 116, 32, 71, 51, 48, 30, 23, 13, 50, 49, 48, 52, 49, 52, 48, 48, 48, 48, 48, 48, 90, 23, 13, 51, 49, 48, 52, 49, 51, 50, 51, 53, 57, 53, 57, 90, 48, 89, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 68, 105, 103, 105, 67, 101, 114, 116, 32, 71, 108, 111, 98, 97, 108, 32, 71, 51, 32, 84, 76, 83, 32, 69, 67, 67, 32, 83, 72, 65, 51, 56, 52, 32, 50, 48, 50, 48, 32, 67, 65, 49, 48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 120, 169, 156, 117, 174, 136, 93, 99, 164, 173, 93, 134, 216, 16, 73, 214, 175, 146, 89, 99, 67, 35, 133, 244, 72, 101, 48, 205, 74, 52, 149, 166, 14, 62, 217, 124, 8, 215, 87, 5, 40, 72, 158, 11, 171, 235, 194, 211, 150, 158, 237, 69, 210, 139, 138, 206, 1, 75, 23, 67, 225, 115, 207, 109, 115, 72, 52, 220, 0, 70, 9, 181, 86, 84, 201, 95, 122, 199, 19, 7, 208, 108, 24, 23, 108, 202, 219, 199, 11, 38, 86, 46, 141, 7, 245, 103, 163, 130, 1, 130, 48, 130, 1, 126, 48, 18, 6, 3, 85, 29, 19, 1, 1, 255, 4, 8, 48, 6, 1, 1, 255, 2, 1, 0, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 138, 35, 235, 158, 107, 215, 249, 55, 93, 249, 109, 33, 57, 118, 154, 161, 103, 222, 16, 168, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 179, 219, 72, 164, 249, 161, 197, 216, 174, 54, 65, 204, 17, 99, 105, 98, 41, 188, 75, 198, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 134, 48, 29, 6, 3, 85, 29, 37, 4, 22, 48, 20, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 118, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 106, 48, 104, 48, 36, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, 134, 24, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 48, 64, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, 134, 52, 104, 116, 116, 112, 58, 47, 47, 99, 97, 99, 101, 114, 116, 115, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 82, 111, 111, 116, 71, 51, 46, 99, 114, 116, 48, 66, 6, 3, 85, 29, 31, 4, 59, 48, 57, 48, 55, 160, 53, 160, 51, 134, 49, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 51, 46, 100, 105, 103, 105, 99, 101, 114, 116, 46, 99, 111, 109, 47, 68, 105, 103, 105, 67, 101, 114, 116, 71, 108, 111, 98, 97, 108, 82, 111, 111, 116, 71, 51, 46, 99, 114, 108, 48, 61, 6, 3, 85, 29, 32, 4, 54, 48, 52, 48, 11, 6, 9, 96, 134, 72, 1, 134, 253, 108, 2, 1, 48, 7, 6, 5, 103, 129, 12, 1, 1, 48, 8, 6, 6, 103, 129, 12, 1, 2, 1, 48, 8, 6, 6, 103, 129, 12, 1, 2, 2, 48, 8, 6, 6, 103, 129, 12, 1, 2, 3, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 3, 3, 104, 0, 48, 101, 2, 48, 126, 38, 88, 110, 238, 136, 236, 12, 221, 21, 65, 238, 122, 184, 153, 153, 112, 209, 98, 101, 79, 160, 32, 158, 71, 177, 91, 193, 178, 103, 49, 29, 204, 114, 122, 175, 34, 114, 64, 66, 110, 101, 132, 254, 135, 75, 15, 25, 2, 49, 0, 230, 191, 214, 174, 52, 135, 91, 63, 103, 199, 29, 168, 111, 213, 18, 120, 181, 230, 135, 49, 68, 169, 93, 198, 184, 120, 204, 207, 239, 212, 50, 88, 17, 255, 58, 133, 6, 60, 29, 132, 111, 211, 245, 249, 218, 51, 28, 164}} + + // Check if the leaf cert has expired; skip with a clear message if so. + if leafCert, err := x509.ParseCertificate(rawCerts[0]); err == nil { + if time.Now().After(leafCert.NotAfter) { + t.Skipf("Test leaf certificate expired on %s — fetch fresh certs from a248.e.akamai.net:443", leafCert.NotAfter.Format("2006-01-02")) + } + } var tests = []struct { name string From 2a34af5070d51d3804a58de9874d3523d119ebea Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Thu, 19 Mar 2026 16:23:01 -0600 Subject: [PATCH 3/4] Address PR review: reuse verifyPeerCertificate, return *tls.UConn - Return conn (*tls.UConn) instead of conn.Conn (*tls.Conn); both do encrypted I/O but returning the UConn directly is cleaner. - Remove verifyServerCerts helper and reuse the existing verifyPeerCertificate function from fronted.go, eliminating duplicate verification logic between SNI and non-SNI paths. Co-Authored-By: Claude Opus 4.6 (1M context) --- front.go | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/front.go b/front.go index d8c810d..b21d25d 100644 --- a/front.go +++ b/front.go @@ -165,13 +165,18 @@ func (fr *front) dial(rootCAs *x509.CertPool, clientHelloID tls.ClientHelloID) ( rawConn.SetDeadline(time.Time{}) if !tlsConfig.InsecureSkipVerify { - if _, err := verifyServerCerts(conn, tlsConfig.ServerName, tlsConfig.RootCAs); err != nil { + state := conn.ConnectionState() + rawCerts := make([][]byte, len(state.PeerCertificates)) + for i, cert := range state.PeerCertificates { + rawCerts[i] = cert.Raw + } + if err := verifyPeerCertificate(rawCerts, tlsConfig.RootCAs, tlsConfig.ServerName); err != nil { rawConn.Close() return nil, err } } - return conn.Conn, nil + return conn, nil } func dialWithTimeout(network string, addr string, timeout time.Duration) (net.Conn, error) { @@ -179,26 +184,6 @@ func dialWithTimeout(network string, addr string, timeout time.Duration) (net.Co return dialer.Dial(network, addr) } -func verifyServerCerts(conn *tls.UConn, serverName string, rootCAs *x509.CertPool) ([][]*x509.Certificate, error) { - certs := conn.ConnectionState().PeerCertificates - if len(certs) == 0 { - return nil, fmt.Errorf("no peer certificates provided") - } - opts := x509.VerifyOptions{ - Roots: rootCAs, - CurrentTime: time.Now(), - DNSName: serverName, - Intermediates: x509.NewCertPool(), - } - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - return certs[0].Verify(opts) -} - // verifyWithPost does a post with invalid data to verify domain-fronting works func (fr *front) verifyWithPost(conn net.Conn, testURL string) bool { client := &http.Client{ From 863c5abe72bb41c42d502f9c573db1c9dd113896 Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Thu, 19 Mar 2026 16:49:44 -0600 Subject: [PATCH 4/4] Fix flaky TestDomainFrontingWithoutSNIConfig Two issues caused this test to fail intermittently: 1. defaultFrontedProviderID was a package-level global mutated by tests, leaking state between them. Added WithDefaultProviderID option so each test sets its provider ID on its own Fronted instance instead of mutating the global. 2. The embedded config loads akamai fronts which get added alongside the test's cloudfront fronts. When an akamai front was randomly picked, the akamai provider lacked the test host mappings, causing "no domain fronting mapping" errors. Fixed by registering test hosts with the akamai provider in testProvidersWithHosts. Co-Authored-By: Claude Opus 4.6 (1M context) --- fronted.go | 8 ++++++++ fronted_test.go | 19 +++++++------------ test_support.go | 12 +++++++----- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/fronted.go b/fronted.go index bbd6178..e4ee2c4 100644 --- a/fronted.go +++ b/fronted.go @@ -171,6 +171,14 @@ func WithCountryCode(cc string) Option { } } +// WithDefaultProviderID sets the default provider ID used when a front has no +// provider (e.g. from a cache file). Defaults to "cloudfront". +func WithDefaultProviderID(id string) Option { + return func(f *fronted) { + f.defaultProviderID = id + } +} + // WithConfigURL sets the URL from which to continually fetch updated domain fronting configurations. func WithConfigURL(configURL string) Option { return func(f *fronted) { diff --git a/fronted_test.go b/fronted_test.go index 9db6896..f3a5765 100644 --- a/fronted_test.go +++ b/fronted_test.go @@ -95,8 +95,7 @@ func TestDomainFrontingWithSNIConfig(t *testing.T) { UseArbitrarySNIs: true, ArbitrarySNIs: []string{"mercadopago.com", "amazon.com.br", "facebook.com", "google.com", "twitter.com", "youtube.com", "instagram.com", "linkedin.com", "whatsapp.com", "netflix.com", "microsoft.com", "yahoo.com", "bing.com", "wikipedia.org", "github.com"}, }) - defaultFrontedProviderID = "akamai" - transport := NewFronted(WithCacheFile(cacheFile), WithCountryCode("test"), WithEmbeddedConfigName("noconfig.yaml")) + transport := NewFronted(WithCacheFile(cacheFile), WithCountryCode("test"), WithEmbeddedConfigName("noconfig.yaml"), WithDefaultProviderID("akamai")) transport.onNewFronts(certs, p) client := &http.Client{ @@ -110,6 +109,7 @@ func newTransportFromDialer(f Fronted) http.RoundTripper { return rt } + func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtEnd int) int { getURL := "https://config.example.com/global.yaml.gz" getHost := "config.example.com" @@ -128,8 +128,7 @@ func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtE } certs := trustedCACerts(t) p := testProvidersWithHosts(hosts) - defaultFrontedProviderID = testProviderID - transport := NewFronted(WithCacheFile(cacheFile)) + transport := NewFronted(WithCacheFile(cacheFile), WithDefaultProviderID(testProviderID)) transport.onNewFronts(certs, p) rt := newTransportFromDialer(transport) @@ -139,8 +138,7 @@ func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtE } require.True(t, doCheck(client, http.MethodPost, http.StatusAccepted, pingURL)) - defaultFrontedProviderID = testProviderID - transport = NewFronted(WithCacheFile(cacheFile)) + transport = NewFronted(WithCacheFile(cacheFile), WithDefaultProviderID(testProviderID)) transport.onNewFronts(certs, p) client = &http.Client{ Transport: newTransportFromDialer(transport), @@ -256,8 +254,7 @@ func TestHostAliasesBasic(t *testing.T) { certs := x509.NewCertPool() certs.AddCert(cloudSack.Certificate()) - defaultFrontedProviderID = "cloudsack" - rt := NewFronted() + rt := NewFronted(WithDefaultProviderID("cloudsack")) rt.onNewFronts(certs, map[string]*Provider{"cloudsack": p}) for _, test := range tests { @@ -365,8 +362,7 @@ func TestHostAliasesMulti(t *testing.T) { "sadcloud": p2, } - defaultFrontedProviderID = "cloudsack" - rt := NewFronted() + rt := NewFronted(WithDefaultProviderID("cloudsack")) rt.onNewFronts(certs, providers) providerCounts := make(map[string]int) @@ -489,8 +485,7 @@ func TestPassthrough(t *testing.T) { certs := x509.NewCertPool() certs.AddCert(cloudSack.Certificate()) - defaultFrontedProviderID = "cloudsack" - rt := NewFronted() + rt := NewFronted(WithDefaultProviderID("cloudsack")) rt.onNewFronts(certs, map[string]*Provider{"cloudsack": p}) for _, test := range tests { diff --git a/test_support.go b/test_support.go index cb47761..4a8e9e8 100644 --- a/test_support.go +++ b/test_support.go @@ -21,8 +21,7 @@ func ConfigureForTest(t *testing.T) Fronted { func ConfigureCachingForTest(t *testing.T, cacheFile string) Fronted { certs := trustedCACerts(t) p := testProviders() - defaultFrontedProviderID = testProviderID - f := NewFronted(WithCacheFile(cacheFile)) + f := NewFronted(WithCacheFile(cacheFile), WithDefaultProviderID(testProviderID)) f.onNewFronts(certs, p) return f } @@ -30,8 +29,7 @@ func ConfigureCachingForTest(t *testing.T, cacheFile string) Fronted { func ConfigureHostAlaisesForTest(t *testing.T, hosts map[string]string) Fronted { certs := trustedCACerts(t) p := testProvidersWithHosts(hosts) - defaultFrontedProviderID = testProviderID - f := NewFronted() + f := NewFronted(WithDefaultProviderID(testProviderID)) f.onNewFronts(certs, p) return f } @@ -59,9 +57,13 @@ func testProviders() map[string]*Provider { } func testProvidersWithHosts(hosts map[string]string) map[string]*Provider { - return map[string]*Provider{ + p := map[string]*Provider{ testProviderID: NewProvider(hosts, pingTestURL, testMasquerades, nil, nil, nil, ""), } + // Also register the test hosts with the akamai provider so that akamai fronts + // loaded from the embedded config don't cause "no domain fronting mapping" errors. + p["akamai"] = NewProvider(hosts, pingTestURL, nil, nil, nil, nil, "") + return p } func testAkamaiProvidersWithHosts(hosts map[string]string, sniConfig *SNIConfig) map[string]*Provider { frontingSNIs := map[string]*SNIConfig{