2021-09-05 14:49:38 +02:00
|
|
|
package netxlite
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
//
|
|
|
|
// Code to use yawning/utls or refraction-networking/utls
|
|
|
|
//
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
import (
|
2021-09-05 21:23:47 +02:00
|
|
|
"context"
|
2021-09-05 14:49:38 +02:00
|
|
|
"crypto/tls"
|
2021-09-05 21:41:49 +02:00
|
|
|
"errors"
|
2021-09-05 14:49:38 +02:00
|
|
|
"net"
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
2021-09-05 14:49:38 +02:00
|
|
|
utls "gitlab.com/yawning/utls.git"
|
|
|
|
)
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// NewTLSHandshakerUTLS creates a new TLS handshaker using
|
|
|
|
// gitlab.com/yawning/utls for TLS.
|
|
|
|
//
|
|
|
|
// The id is the address of something like utls.HelloFirefox_55.
|
2021-09-08 22:48:10 +02:00
|
|
|
//
|
|
|
|
// The handshaker guarantees:
|
|
|
|
//
|
|
|
|
// 1. logging
|
|
|
|
//
|
|
|
|
// 2. error wrapping
|
|
|
|
//
|
|
|
|
// Passing a nil `id` will make this function panic.
|
2022-01-03 13:53:23 +01:00
|
|
|
func NewTLSHandshakerUTLS(logger model.DebugLogger, id *utls.ClientHelloID) model.TLSHandshaker {
|
2021-09-08 22:48:10 +02:00
|
|
|
return newTLSHandshaker(&tlsHandshakerConfigurable{
|
|
|
|
NewConn: newConnUTLS(id),
|
|
|
|
}, logger)
|
2021-09-05 20:59:42 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// utlsConn implements TLSConn and uses a utls UConn as its underlying connection
|
|
|
|
type utlsConn struct {
|
|
|
|
*utls.UConn
|
2021-09-05 21:23:47 +02:00
|
|
|
testableHandshake func() error
|
2021-09-05 14:49:38 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 21:23:47 +02:00
|
|
|
// Ensures that a utlsConn implements the TLSConn interface.
|
|
|
|
var _ TLSConn = &utlsConn{}
|
|
|
|
|
|
|
|
// newConnUTLS returns a NewConn function for creating utlsConn instances.
|
2021-09-05 20:59:42 +02:00
|
|
|
func newConnUTLS(clientHello *utls.ClientHelloID) func(conn net.Conn, config *tls.Config) TLSConn {
|
2021-09-05 14:49:38 +02:00
|
|
|
return func(conn net.Conn, config *tls.Config) TLSConn {
|
|
|
|
uConfig := &utls.Config{
|
|
|
|
RootCAs: config.RootCAs,
|
|
|
|
NextProtos: config.NextProtos,
|
|
|
|
ServerName: config.ServerName,
|
|
|
|
InsecureSkipVerify: config.InsecureSkipVerify,
|
|
|
|
DynamicRecordSizingDisabled: config.DynamicRecordSizingDisabled,
|
|
|
|
}
|
|
|
|
tlsConn := utls.UClient(conn, uConfig, *clientHello)
|
2021-09-05 21:23:47 +02:00
|
|
|
return &utlsConn{UConn: tlsConn}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-05 21:41:49 +02:00
|
|
|
// ErrUTLSHandshakePanic indicates that there was panic handshaking
|
|
|
|
// when we were using the yawning/utls library for parroting.
|
2021-09-29 20:21:25 +02:00
|
|
|
// See https://github.com/ooni/probe/issues/1770 for more information.
|
2021-09-05 21:41:49 +02:00
|
|
|
var ErrUTLSHandshakePanic = errors.New("utls: handshake panic")
|
|
|
|
|
|
|
|
func (c *utlsConn) HandshakeContext(ctx context.Context) (err error) {
|
2021-09-05 21:23:47 +02:00
|
|
|
errch := make(chan error, 1)
|
|
|
|
go func() {
|
2021-09-05 21:41:49 +02:00
|
|
|
defer func() {
|
|
|
|
// See https://github.com/ooni/probe/issues/1770
|
|
|
|
if recover() != nil {
|
|
|
|
errch <- ErrUTLSHandshakePanic
|
|
|
|
}
|
|
|
|
}()
|
2021-09-05 21:23:47 +02:00
|
|
|
errch <- c.handshakefn()()
|
|
|
|
}()
|
|
|
|
select {
|
2021-09-05 21:41:49 +02:00
|
|
|
case err = <-errch:
|
2021-09-05 21:23:47 +02:00
|
|
|
case <-ctx.Done():
|
2021-09-05 21:41:49 +02:00
|
|
|
err = ctx.Err()
|
2021-09-05 21:23:47 +02:00
|
|
|
}
|
2021-09-05 21:41:49 +02:00
|
|
|
return
|
2021-09-05 21:23:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *utlsConn) handshakefn() func() error {
|
|
|
|
if c.testableHandshake != nil {
|
|
|
|
return c.testableHandshake
|
2021-09-05 14:49:38 +02:00
|
|
|
}
|
2021-09-05 21:23:47 +02:00
|
|
|
return c.UConn.Handshake
|
2021-09-05 14:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *utlsConn) ConnectionState() tls.ConnectionState {
|
|
|
|
uState := c.Conn.ConnectionState()
|
|
|
|
return tls.ConnectionState{
|
|
|
|
Version: uState.Version,
|
|
|
|
HandshakeComplete: uState.HandshakeComplete,
|
|
|
|
DidResume: uState.DidResume,
|
|
|
|
CipherSuite: uState.CipherSuite,
|
|
|
|
NegotiatedProtocol: uState.NegotiatedProtocol,
|
|
|
|
NegotiatedProtocolIsMutual: uState.NegotiatedProtocolIsMutual,
|
|
|
|
ServerName: uState.ServerName,
|
|
|
|
PeerCertificates: uState.PeerCertificates,
|
|
|
|
VerifiedChains: uState.VerifiedChains,
|
|
|
|
SignedCertificateTimestamps: uState.SignedCertificateTimestamps,
|
|
|
|
OCSPResponse: uState.OCSPResponse,
|
|
|
|
TLSUnique: uState.TLSUnique,
|
|
|
|
}
|
|
|
|
}
|