2021-09-05 14:49:38 +02:00
|
|
|
package netxlite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-05-22 19:53:37 +02:00
|
|
|
"crypto/tls"
|
2021-09-05 21:23:47 +02:00
|
|
|
"errors"
|
2022-05-22 19:53:37 +02:00
|
|
|
"net"
|
2021-09-05 21:23:47 +02:00
|
|
|
"sync"
|
2021-09-05 14:49:38 +02:00
|
|
|
"testing"
|
2021-09-05 21:23:47 +02:00
|
|
|
"time"
|
2021-09-05 14:49:38 +02:00
|
|
|
|
2021-09-05 20:59:42 +02:00
|
|
|
"github.com/apex/log"
|
2022-08-23 13:04:00 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
2021-09-05 14:49:38 +02:00
|
|
|
utls "gitlab.com/yawning/utls.git"
|
|
|
|
)
|
|
|
|
|
2021-09-08 11:39:27 +02:00
|
|
|
func TestNewTLSHandshakerUTLS(t *testing.T) {
|
2021-09-05 20:59:42 +02:00
|
|
|
th := NewTLSHandshakerUTLS(log.Log, &utls.HelloChrome_83)
|
2021-09-08 11:39:27 +02:00
|
|
|
logger := th.(*tlsHandshakerLogger)
|
2022-01-03 13:53:23 +01:00
|
|
|
if logger.DebugLogger != log.Log {
|
2021-09-05 20:59:42 +02:00
|
|
|
t.Fatal("invalid logger")
|
|
|
|
}
|
2022-07-01 12:22:22 +02:00
|
|
|
configurable := logger.TLSHandshaker.(*tlsHandshakerConfigurable)
|
2021-09-08 11:39:27 +02:00
|
|
|
if configurable.NewConn == nil {
|
2021-09-05 20:59:42 +02:00
|
|
|
t.Fatal("expected non-nil NewConn")
|
|
|
|
}
|
|
|
|
}
|
2021-09-05 21:23:47 +02:00
|
|
|
|
2021-09-08 11:39:27 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
2021-09-05 21:23:47 +02:00
|
|
|
|
2021-09-08 11:39:27 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
2021-09-05 21:41:49 +02:00
|
|
|
|
2021-09-08 11:39:27 +02:00
|
|
|
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()
|
|
|
|
})
|
2021-09-05 21:41:49 +02:00
|
|
|
|
2021-09-08 11:39:27 +02:00
|
|
|
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()
|
|
|
|
})
|
|
|
|
})
|
2022-08-19 11:26:50 +02:00
|
|
|
|
2022-08-23 13:04:00 +02:00
|
|
|
t.Run("NetConn", func(t *testing.T) {
|
|
|
|
factory := newConnUTLS(&utls.HelloChrome_70)
|
|
|
|
conn := &mocks.Conn{}
|
|
|
|
tconn, err := factory(conn, &tls.Config{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// TODO(https://github.com/ooni/probe/issues/2222): we cannot avoid
|
|
|
|
// castedTconn until we use oocrypto >= v0.2 which uses go1.19. In turn,
|
|
|
|
// we cannot use go1.19 as our main version until we upgrade psiphon
|
|
|
|
// such that it builds using go1.19, which is the issue in #2222.
|
|
|
|
castedTconn := tconn.(*utlsConn)
|
|
|
|
if castedTconn.NetConn() != conn {
|
|
|
|
t.Fatal("NetConn is not WAI")
|
|
|
|
}
|
|
|
|
})
|
2021-09-05 21:41:49 +02:00
|
|
|
}
|
2022-05-22 19:53:37 +02:00
|
|
|
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|