ebc00a95fe
Rather than building for Android using ooni/go, we're now using ooni/oocryto as the TLS dependency. Such a repository only forks crypto/tls and some minor crypto packages and includes the same set of patches that we have been using in ooni/go. This new strategy should be better than the previous one in terms of building for Android, because we can use the vanilla go1.18.2 build. It also seems that it is easier to track and merge from upstream with ooni/oocrypto than it is with ooni/go. Should this assessment be wrong, we can revert back to the previous scenario where we used ooni/go. See https://github.com/ooni/probe/issues/2106 for extra context.
145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package netxlite
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"errors"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/apex/log"
|
|
utls "gitlab.com/yawning/utls.git"
|
|
)
|
|
|
|
func TestNewTLSHandshakerUTLS(t *testing.T) {
|
|
th := NewTLSHandshakerUTLS(log.Log, &utls.HelloChrome_83)
|
|
logger := th.(*tlsHandshakerLogger)
|
|
if logger.DebugLogger != log.Log {
|
|
t.Fatal("invalid logger")
|
|
}
|
|
errWrapper := logger.TLSHandshaker.(*tlsHandshakerErrWrapper)
|
|
configurable := errWrapper.TLSHandshaker.(*tlsHandshakerConfigurable)
|
|
if configurable.NewConn == nil {
|
|
t.Fatal("expected non-nil NewConn")
|
|
}
|
|
}
|
|
|
|
func TestUTLSConn(t *testing.T) {
|
|
t.Run("Handshake", func(t *testing.T) {
|
|
t.Run("not interrupted with success", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn := &utlsConn{
|
|
testableHandshake: func() error {
|
|
return nil
|
|
},
|
|
}
|
|
err := conn.HandshakeContext(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
|
|
t.Run("not interrupted with failure", func(t *testing.T) {
|
|
expected := errors.New("mocked error")
|
|
ctx := context.Background()
|
|
conn := &utlsConn{
|
|
testableHandshake: func() error {
|
|
return expected
|
|
},
|
|
}
|
|
err := conn.HandshakeContext(ctx)
|
|
if !errors.Is(err, expected) {
|
|
t.Fatal("not the error we expected", err)
|
|
}
|
|
})
|
|
|
|
t.Run("interrupted", func(t *testing.T) {
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(1)
|
|
sigch := make(chan interface{})
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
|
|
defer cancel()
|
|
conn := &utlsConn{
|
|
testableHandshake: func() error {
|
|
defer wg.Done()
|
|
<-sigch
|
|
return nil
|
|
},
|
|
}
|
|
err := conn.HandshakeContext(ctx)
|
|
if !errors.Is(err, context.DeadlineExceeded) {
|
|
t.Fatal("not the error we expected", err)
|
|
}
|
|
close(sigch)
|
|
wg.Wait()
|
|
})
|
|
|
|
t.Run("with panic", func(t *testing.T) {
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(1)
|
|
ctx := context.Background()
|
|
conn := &utlsConn{
|
|
testableHandshake: func() error {
|
|
defer wg.Done()
|
|
panic("mascetti")
|
|
},
|
|
}
|
|
err := conn.HandshakeContext(ctx)
|
|
if !errors.Is(err, ErrUTLSHandshakePanic) {
|
|
t.Fatal("not the error we expected", err)
|
|
}
|
|
wg.Wait()
|
|
})
|
|
})
|
|
}
|
|
|
|
func Test_newConnUTLSWithHelloID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *tls.Config
|
|
cid *utls.ClientHelloID
|
|
wantNilConn bool
|
|
wantErr error
|
|
}{{
|
|
name: "with only supported fields",
|
|
config: &tls.Config{
|
|
DynamicRecordSizingDisabled: true,
|
|
InsecureSkipVerify: true,
|
|
NextProtos: []string{"h3"},
|
|
RootCAs: NewDefaultCertPool(),
|
|
ServerName: "ooni.org",
|
|
},
|
|
cid: &utls.HelloFirefox_55,
|
|
wantNilConn: false,
|
|
wantErr: nil,
|
|
}, {
|
|
name: "with unsupported fields",
|
|
config: &tls.Config{
|
|
Time: func() time.Time {
|
|
return time.Now()
|
|
},
|
|
},
|
|
cid: &utls.HelloChrome_58,
|
|
wantNilConn: true,
|
|
wantErr: errUTLSIncompatibleStdlibConfig,
|
|
}}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
conn, err := net.Dial("udp", "8.8.8.8:443") // we just need a conn
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer conn.Close()
|
|
got, err := newConnUTLSWithHelloID(conn, tt.config, tt.cid)
|
|
if !errors.Is(err, tt.wantErr) {
|
|
t.Fatal("unexpected err", err)
|
|
}
|
|
if got != nil && tt.wantNilConn {
|
|
t.Fatal("expected nil conn here")
|
|
}
|
|
})
|
|
}
|
|
}
|