From 143b813e9ef23037cd7453ddfec6291c2fac4fc2 Mon Sep 17 00:00:00 2001 From: Christian Roessner Date: Fri, 6 Dec 2024 12:31:22 +0100 Subject: [PATCH] Fix: Enhance TLS handling and simplify response checks Added TLS minimum version enforcement to improve security. Refactored the sieve response parsing to centralize logic and streamline error handling, improving maintainability and reducing redundancy. Signed-off-by: Christian Roessner --- server/monitoring/connection.go | 48 ++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/server/monitoring/connection.go b/server/monitoring/connection.go index 1a36fe97..69a6eb83 100644 --- a/server/monitoring/connection.go +++ b/server/monitoring/connection.go @@ -85,6 +85,7 @@ func checkBackendConnection(server *config.BackendServer) error { tlsConfig := &tls.Config{ InsecureSkipVerify: server.TLSSkipVerify, ServerName: server.Host, + MinVersion: tls.VersionTLS12, } tlsConn := tls.Client(conn, tlsConfig) @@ -336,27 +337,21 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif defer fmt.Fprintf(conn, "LOGOUT\r\n") - // Read server greeting - greeting, err := tp.ReadLine() - if err != nil { + // Wait for initial greeting + if response, err := isOkResponseSieve(tp); err != nil { return err - } - - if !isOkResponseSieve(greeting) { + } else if response != "OK" { //goland:noinspection GoErrorStringFormat - return fmt.Errorf("Sieve greeting failed: %s", greeting) + return fmt.Errorf("Sieve greeting failed: %s", response) } // Send STARTTLS command fmt.Fprintf(conn, "STARTTLS\r\n") // Read STARTTLS response - response, err := tp.ReadLine() - if err != nil { + if response, err := isOkResponseSieve(tp); err != nil { return err - } - - if !isOkResponseSieve(response) { + } else if response != "OK" { return fmt.Errorf("STARTTLS command failed: %s", response) } @@ -364,10 +359,11 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif tlsConfig := &tls.Config{ InsecureSkipVerify: tlsSkipVerify, ServerName: hostname, + MinVersion: tls.VersionTLS12, } tlsConn := tls.Client(conn, tlsConfig) - if err = tlsConn.Handshake(); err != nil { + if err := tlsConn.Handshake(); err != nil { return fmt.Errorf("TLS handshake failed: %s", err) } @@ -375,7 +371,7 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif return nil } - if !isTLSConnection(conn) { + if !isTLSConnection(tlsConn) { return errors.ErrMissingTLS } @@ -388,12 +384,9 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif authString := fmt.Sprintf("\x00%s\x00%s", username, password) fmt.Fprintf(conn, "AUTHENTICATE \"PLAIN\" {%d+}\r\n%s", len(authString), authString) - response, err = tp.ReadLine() - if err != nil { + if response, err := isOkResponseSieve(tp); err != nil { return err - } - - if !isOkResponseSieve(response) { + } else if response != "OK" { //goland:noinspection GoErrorStringFormat return fmt.Errorf("Sieve AUTHENTICATE command failed: %s", response) } @@ -402,8 +395,21 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif } // isOkResponseSieve checks if the Sieve server response starts with "OK", indicating a successful operation. -func isOkResponseSieve(response string) bool { - return response[:2] == "OK" +func isOkResponseSieve(tp *textproto.Reader) (response string, err error) { + for { + response, err = tp.ReadLine() + if err != nil { + return "", err + } + + if response[:2] == "OK" { + return response[:2], nil + } + + if response[:2] == "NO" { + return response, nil + } + } } // checkHTTP performs an HTTP GET request with Basic Authentication using a given username and password.