[tor-commits] [pluggable-transports/snowflake] 01/02: Fix uTLS RoundTripper Inconsistent Key for host:port

gitolite role git at cupani.torproject.org
Tue Nov 29 15:44:05 UTC 2022


This is an automated email from the git hooks/post-receive script.

shelikhoo pushed a commit to branch main
in repository pluggable-transports/snowflake.

commit d8d3e538f1fe2c60369876970900fe00a7958aca
Author: Shelikhoo <xiaokangwang at outlook.com>
AuthorDate: Fri Nov 25 14:29:58 2022 +0000

    Fix uTLS RoundTripper Inconsistent Key for host:port
    
    This commit fixes an issue described at:
    https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40224
    
    This bug has been fixed, with test case describing this bug added.
---
 common/utls/roundtripper.go      |   7 +-
 common/utls/roundtripper_test.go | 295 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 301 insertions(+), 1 deletion(-)

diff --git a/common/utls/roundtripper.go b/common/utls/roundtripper.go
index 53b997f..5b74aec 100644
--- a/common/utls/roundtripper.go
+++ b/common/utls/roundtripper.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"crypto/tls"
 	"errors"
+	"fmt"
 	"net"
 	"net/http"
 	"sync"
@@ -66,7 +67,11 @@ func (r *uTLSHTTPRoundTripperImpl) RoundTrip(req *http.Request) (*http.Response,
 		return r.backdropTransport.RoundTrip(req)
 	}
 	for retryCount := 0; retryCount < 5; retryCount++ {
-		if r.getShouldConnectWithH1(req.URL.Host) {
+		effectivePort := req.URL.Port()
+		if effectivePort == "" {
+			effectivePort = "443"
+		}
+		if r.getShouldConnectWithH1(fmt.Sprintf("%v:%v", req.URL.Hostname(), effectivePort)) {
 			resp, err := r.httpsH1Transport.RoundTrip(req)
 			if errors.Is(err, errEAGAIN) {
 				continue
diff --git a/common/utls/roundtripper_test.go b/common/utls/roundtripper_test.go
index bccb799..d21df52 100644
--- a/common/utls/roundtripper_test.go
+++ b/common/utls/roundtripper_test.go
@@ -8,6 +8,7 @@ import (
 	"math/big"
 	"math/rand"
 	"net/http"
+	"os"
 	"testing"
 	"time"
 
@@ -162,3 +163,297 @@ func TestRoundTripper(t *testing.T) {
 
 	cancel()
 }
+
+func TestRoundTripperOnH1DefaultPort(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.SkipNow()
+	}
+	var selfSignedCert []byte
+	var selfSignedPrivateKey *rsa.PrivateKey
+	httpServerContext, cancel := stdcontext.WithCancel(stdcontext.Background())
+	Convey("[Test]Set up http servers", t, func(c C) {
+		c.Convey("[Test]Generate Self-Signed Cert", func(c C) {
+			// Ported from https://gist.github.com/samuel/8b500ddd3f6118d052b5e6bc16bc4c09
+
+			// note that we use the insecure math/rand here because some platforms
+			// fail the test suite at build time in Debian, due to entropy starvation.
+			// since that's not a problem at test time, we do *not* use a secure
+			// mechanism for key generation.
+			//
+			// DO NOT REUSE THIS CODE IN PRODUCTION, IT IS DANGEROUS
+			insecureRandReader := rand.New(rand.NewSource(1337))
+			priv, err := rsa.GenerateKey(insecureRandReader, 4096)
+			c.So(err, ShouldBeNil)
+			template := x509.Certificate{
+				SerialNumber: big.NewInt(1),
+				Subject: pkix.Name{
+					CommonName: "Testing Certificate",
+				},
+				NotBefore: time.Now(),
+				NotAfter:  time.Now().Add(time.Hour * 24 * 180),
+
+				KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+				ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+				BasicConstraintsValid: true,
+			}
+			derBytes, err := x509.CreateCertificate(insecureRandReader, &template, &template, priv.Public(), priv)
+			c.So(err, ShouldBeNil)
+			selfSignedPrivateKey = priv
+			selfSignedCert = derBytes
+		})
+		c.Convey("[Test]Setup http2 server", func(c C) {
+			listener, err := tls.Listen("tcp", "127.0.0.1:23802", &tls.Config{
+				NextProtos: []string{http2.NextProtoTLS},
+				Certificates: []tls.Certificate{
+					tls.Certificate{Certificate: [][]byte{selfSignedCert}, PrivateKey: selfSignedPrivateKey},
+				},
+			})
+			c.So(err, ShouldBeNil)
+			s := http.Server{}
+			go s.Serve(listener)
+			go func() {
+				<-httpServerContext.Done()
+				s.Close()
+			}()
+		})
+		c.Convey("[Test]Setup http1 server", func(c C) {
+			listener, err := tls.Listen("tcp", "127.0.0.1:443", &tls.Config{
+				NextProtos: []string{"http/1.1"},
+				Certificates: []tls.Certificate{
+					tls.Certificate{Certificate: [][]byte{selfSignedCert}, PrivateKey: selfSignedPrivateKey},
+				},
+			})
+			c.So(err, ShouldBeNil)
+			s := http.Server{}
+			go s.Serve(listener)
+			go func() {
+				<-httpServerContext.Done()
+				s.Close()
+			}()
+		})
+	})
+	for _, v := range []struct {
+		id   utls.ClientHelloID
+		name string
+	}{
+		{
+			id:   utls.HelloChrome_58,
+			name: "HelloChrome_58",
+		},
+		{
+			id:   utls.HelloChrome_62,
+			name: "HelloChrome_62",
+		},
+		{
+			id:   utls.HelloChrome_70,
+			name: "HelloChrome_70",
+		},
+		{
+			id:   utls.HelloChrome_72,
+			name: "HelloChrome_72",
+		},
+		{
+			id:   utls.HelloChrome_83,
+			name: "HelloChrome_83",
+		},
+		{
+			id:   utls.HelloFirefox_55,
+			name: "HelloFirefox_55",
+		},
+		{
+			id:   utls.HelloFirefox_55,
+			name: "HelloFirefox_55",
+		},
+		{
+			id:   utls.HelloFirefox_63,
+			name: "HelloFirefox_63",
+		},
+		{
+			id:   utls.HelloFirefox_65,
+			name: "HelloFirefox_65",
+		},
+		{
+			id:   utls.HelloIOS_11_1,
+			name: "HelloIOS_11_1",
+		},
+		{
+			id:   utls.HelloIOS_12_1,
+			name: "HelloIOS_12_1",
+		},
+	} {
+		t.Run("Testing fingerprint for "+v.name, func(t *testing.T) {
+			rtter := NewUTLSHTTPRoundTripper(v.id, &utls.Config{
+				InsecureSkipVerify: true,
+			}, http.DefaultTransport, false)
+
+			for count := 0; count <= 10; count++ {
+				Convey("HTTP 1.1 Test", t, func(c C) {
+					{
+						req, err := http.NewRequest("GET", "https://127.0.0.1/", nil)
+						So(err, ShouldBeNil)
+						_, err = rtter.RoundTrip(req)
+						So(err, ShouldBeNil)
+					}
+				})
+
+				Convey("HTTP 2 Test", t, func(c C) {
+					{
+						req, err := http.NewRequest("GET", "https://127.0.0.1:23802/", nil)
+						So(err, ShouldBeNil)
+						_, err = rtter.RoundTrip(req)
+						So(err, ShouldBeNil)
+					}
+				})
+			}
+		})
+	}
+
+	cancel()
+}
+
+func TestRoundTripperOnH2DefaultPort(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.SkipNow()
+	}
+	var selfSignedCert []byte
+	var selfSignedPrivateKey *rsa.PrivateKey
+	httpServerContext, cancel := stdcontext.WithCancel(stdcontext.Background())
+	Convey("[Test]Set up http servers", t, func(c C) {
+		c.Convey("[Test]Generate Self-Signed Cert", func(c C) {
+			// Ported from https://gist.github.com/samuel/8b500ddd3f6118d052b5e6bc16bc4c09
+
+			// note that we use the insecure math/rand here because some platforms
+			// fail the test suite at build time in Debian, due to entropy starvation.
+			// since that's not a problem at test time, we do *not* use a secure
+			// mechanism for key generation.
+			//
+			// DO NOT REUSE THIS CODE IN PRODUCTION, IT IS DANGEROUS
+			insecureRandReader := rand.New(rand.NewSource(1337))
+			priv, err := rsa.GenerateKey(insecureRandReader, 4096)
+			c.So(err, ShouldBeNil)
+			template := x509.Certificate{
+				SerialNumber: big.NewInt(1),
+				Subject: pkix.Name{
+					CommonName: "Testing Certificate",
+				},
+				NotBefore: time.Now(),
+				NotAfter:  time.Now().Add(time.Hour * 24 * 180),
+
+				KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+				ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+				BasicConstraintsValid: true,
+			}
+			derBytes, err := x509.CreateCertificate(insecureRandReader, &template, &template, priv.Public(), priv)
+			c.So(err, ShouldBeNil)
+			selfSignedPrivateKey = priv
+			selfSignedCert = derBytes
+		})
+		c.Convey("[Test]Setup http2 server", func(c C) {
+			listener, err := tls.Listen("tcp", "127.0.0.1:443", &tls.Config{
+				NextProtos: []string{http2.NextProtoTLS},
+				Certificates: []tls.Certificate{
+					tls.Certificate{Certificate: [][]byte{selfSignedCert}, PrivateKey: selfSignedPrivateKey},
+				},
+			})
+			c.So(err, ShouldBeNil)
+			s := http.Server{}
+			go s.Serve(listener)
+			go func() {
+				<-httpServerContext.Done()
+				s.Close()
+			}()
+		})
+		c.Convey("[Test]Setup http1 server", func(c C) {
+			listener, err := tls.Listen("tcp", "127.0.0.1:23801", &tls.Config{
+				NextProtos: []string{"http/1.1"},
+				Certificates: []tls.Certificate{
+					tls.Certificate{Certificate: [][]byte{selfSignedCert}, PrivateKey: selfSignedPrivateKey},
+				},
+			})
+			c.So(err, ShouldBeNil)
+			s := http.Server{}
+			go s.Serve(listener)
+			go func() {
+				<-httpServerContext.Done()
+				s.Close()
+			}()
+		})
+	})
+	for _, v := range []struct {
+		id   utls.ClientHelloID
+		name string
+	}{
+		{
+			id:   utls.HelloChrome_58,
+			name: "HelloChrome_58",
+		},
+		{
+			id:   utls.HelloChrome_62,
+			name: "HelloChrome_62",
+		},
+		{
+			id:   utls.HelloChrome_70,
+			name: "HelloChrome_70",
+		},
+		{
+			id:   utls.HelloChrome_72,
+			name: "HelloChrome_72",
+		},
+		{
+			id:   utls.HelloChrome_83,
+			name: "HelloChrome_83",
+		},
+		{
+			id:   utls.HelloFirefox_55,
+			name: "HelloFirefox_55",
+		},
+		{
+			id:   utls.HelloFirefox_55,
+			name: "HelloFirefox_55",
+		},
+		{
+			id:   utls.HelloFirefox_63,
+			name: "HelloFirefox_63",
+		},
+		{
+			id:   utls.HelloFirefox_65,
+			name: "HelloFirefox_65",
+		},
+		{
+			id:   utls.HelloIOS_11_1,
+			name: "HelloIOS_11_1",
+		},
+		{
+			id:   utls.HelloIOS_12_1,
+			name: "HelloIOS_12_1",
+		},
+	} {
+		t.Run("Testing fingerprint for "+v.name, func(t *testing.T) {
+			rtter := NewUTLSHTTPRoundTripper(v.id, &utls.Config{
+				InsecureSkipVerify: true,
+			}, http.DefaultTransport, false)
+
+			for count := 0; count <= 10; count++ {
+				Convey("HTTP 1.1 Test", t, func(c C) {
+					{
+						req, err := http.NewRequest("GET", "https://127.0.0.1:23801/", nil)
+						So(err, ShouldBeNil)
+						_, err = rtter.RoundTrip(req)
+						So(err, ShouldBeNil)
+					}
+				})
+
+				Convey("HTTP 2 Test", t, func(c C) {
+					{
+						req, err := http.NewRequest("GET", "https://127.0.0.1/", nil)
+						So(err, ShouldBeNil)
+						_, err = rtter.RoundTrip(req)
+						So(err, ShouldBeNil)
+					}
+				})
+			}
+		})
+	}
+
+	cancel()
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tor-commits mailing list