2022-05-31 21:53:01 +02:00
|
|
|
package tracex
|
2021-06-08 11:24:13 +02:00
|
|
|
|
2022-06-01 07:44:54 +02:00
|
|
|
//
|
|
|
|
// TLS
|
|
|
|
//
|
|
|
|
|
2021-06-08 11:24:13 +02:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
2022-06-01 07:44:54 +02:00
|
|
|
"crypto/x509"
|
|
|
|
"errors"
|
2021-06-08 11:24:13 +02:00
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
|
2022-01-07 18:33:37 +01:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
2021-06-25 12:39:45 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
2021-06-08 11:24:13 +02:00
|
|
|
)
|
|
|
|
|
2022-06-01 07:44:54 +02:00
|
|
|
// SaverTLSHandshaker saves events occurring during the TLS handshake.
|
2021-06-08 11:24:13 +02:00
|
|
|
type SaverTLSHandshaker struct {
|
2022-06-01 07:44:54 +02:00
|
|
|
// TLSHandshaker is the underlying TLS handshaker.
|
|
|
|
TLSHandshaker model.TLSHandshaker
|
|
|
|
|
|
|
|
// Saver is the saver in which to save events.
|
2022-05-31 21:53:01 +02:00
|
|
|
Saver *Saver
|
2021-06-08 11:24:13 +02:00
|
|
|
}
|
|
|
|
|
2022-06-01 07:44:54 +02:00
|
|
|
// WrapTLSHandshaker wraps a model.TLSHandshaker with a SaverTLSHandshaker
|
|
|
|
// that will save the TLS handshake results into this Saver.
|
|
|
|
//
|
|
|
|
// When this function is invoked on a nil Saver, it will directly return
|
|
|
|
// the original TLSHandshaker without any wrapping.
|
|
|
|
func (s *Saver) WrapTLSHandshaker(thx model.TLSHandshaker) model.TLSHandshaker {
|
|
|
|
if s == nil {
|
|
|
|
return thx
|
|
|
|
}
|
|
|
|
return &SaverTLSHandshaker{
|
|
|
|
TLSHandshaker: thx,
|
|
|
|
Saver: s,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handshake implements model.TLSHandshaker.Handshake
|
|
|
|
func (h *SaverTLSHandshaker) Handshake(
|
|
|
|
ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) {
|
2021-06-08 11:24:13 +02:00
|
|
|
start := time.Now()
|
2022-05-31 21:53:01 +02:00
|
|
|
h.Saver.Write(Event{
|
2021-06-08 11:24:13 +02:00
|
|
|
Name: "tls_handshake_start",
|
|
|
|
NoTLSVerify: config.InsecureSkipVerify,
|
|
|
|
TLSNextProtos: config.NextProtos,
|
|
|
|
TLSServerName: config.ServerName,
|
|
|
|
Time: start,
|
|
|
|
})
|
2022-05-06 11:09:54 +02:00
|
|
|
remoteAddr := conn.RemoteAddr().String()
|
2021-06-08 11:24:13 +02:00
|
|
|
tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config)
|
|
|
|
stop := time.Now()
|
2022-05-31 21:53:01 +02:00
|
|
|
h.Saver.Write(Event{
|
2022-05-06 11:09:54 +02:00
|
|
|
Address: remoteAddr,
|
2021-06-08 11:24:13 +02:00
|
|
|
Duration: stop.Sub(start),
|
|
|
|
Err: err,
|
|
|
|
Name: "tls_handshake_done",
|
|
|
|
NoTLSVerify: config.InsecureSkipVerify,
|
2021-06-25 12:39:45 +02:00
|
|
|
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
|
2021-06-08 11:24:13 +02:00
|
|
|
TLSNegotiatedProto: state.NegotiatedProtocol,
|
|
|
|
TLSNextProtos: config.NextProtos,
|
2022-06-01 07:44:54 +02:00
|
|
|
TLSPeerCerts: tlsPeerCerts(state, err),
|
2021-06-08 11:24:13 +02:00
|
|
|
TLSServerName: config.ServerName,
|
2021-06-25 12:39:45 +02:00
|
|
|
TLSVersion: netxlite.TLSVersionString(state.Version),
|
2021-06-08 11:24:13 +02:00
|
|
|
Time: stop,
|
|
|
|
})
|
|
|
|
return tlsconn, state, err
|
|
|
|
}
|
|
|
|
|
2022-06-01 07:44:54 +02:00
|
|
|
var _ model.TLSHandshaker = &SaverTLSHandshaker{}
|
|
|
|
|
|
|
|
// tlsPeerCerts returns the certificates presented by the peer regardless
|
|
|
|
// of whether the TLS handshake was successful
|
|
|
|
func tlsPeerCerts(state tls.ConnectionState, err error) []*x509.Certificate {
|
|
|
|
var x509HostnameError x509.HostnameError
|
|
|
|
if errors.As(err, &x509HostnameError) {
|
|
|
|
// Test case: https://wrong.host.badssl.com/
|
|
|
|
return []*x509.Certificate{x509HostnameError.Certificate}
|
|
|
|
}
|
|
|
|
var x509UnknownAuthorityError x509.UnknownAuthorityError
|
|
|
|
if errors.As(err, &x509UnknownAuthorityError) {
|
|
|
|
// Test case: https://self-signed.badssl.com/. This error has
|
|
|
|
// never been among the ones returned by MK.
|
|
|
|
return []*x509.Certificate{x509UnknownAuthorityError.Cert}
|
|
|
|
}
|
|
|
|
var x509CertificateInvalidError x509.CertificateInvalidError
|
|
|
|
if errors.As(err, &x509CertificateInvalidError) {
|
|
|
|
// Test case: https://expired.badssl.com/
|
|
|
|
return []*x509.Certificate{x509CertificateInvalidError.Cert}
|
|
|
|
}
|
|
|
|
return state.PeerCertificates
|
|
|
|
}
|