Bound line reads with readLineLimited to prevent a peer from exhausting memory by withholding line terminators, wrap previously bare error returns for consistent context, surface XML decoder Skip errors, and replace the goto in the XMPP feature scan with a labeled break. New starttls_test.go exercises SMTP/IMAP/POP3/XMPP/LDAP success and not-advertised paths through net.Pipe-mocked servers.
64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
package checker
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
func init() {
|
|
registerStartTLS("imap", starttlsIMAP)
|
|
}
|
|
|
|
// starttlsIMAP implements RFC 3501 STARTTLS.
|
|
func starttlsIMAP(conn net.Conn, sni string) error {
|
|
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
|
|
|
if _, err := readLineLimited(rw.Reader); err != nil {
|
|
return fmt.Errorf("read greeting: %w", err)
|
|
}
|
|
|
|
if _, err := rw.WriteString("A001 CAPABILITY\r\n"); err != nil {
|
|
return fmt.Errorf("write CAPABILITY: %w", err)
|
|
}
|
|
if err := rw.Flush(); err != nil {
|
|
return fmt.Errorf("flush CAPABILITY: %w", err)
|
|
}
|
|
|
|
supportsSTARTTLS := false
|
|
for {
|
|
line, err := readLineLimited(rw.Reader)
|
|
if err != nil {
|
|
return fmt.Errorf("read CAPABILITY: %w", err)
|
|
}
|
|
if strings.Contains(strings.ToUpper(line), "STARTTLS") {
|
|
supportsSTARTTLS = true
|
|
}
|
|
if strings.HasPrefix(line, "A001 ") {
|
|
break
|
|
}
|
|
}
|
|
if !supportsSTARTTLS {
|
|
return fmt.Errorf("%w: IMAP CAPABILITY did not advertise STARTTLS", errStartTLSNotOffered)
|
|
}
|
|
|
|
if _, err := rw.WriteString("A002 STARTTLS\r\n"); err != nil {
|
|
return fmt.Errorf("write STARTTLS: %w", err)
|
|
}
|
|
if err := rw.Flush(); err != nil {
|
|
return fmt.Errorf("flush STARTTLS: %w", err)
|
|
}
|
|
for {
|
|
line, err := readLineLimited(rw.Reader)
|
|
if err != nil {
|
|
return fmt.Errorf("read STARTTLS response: %w", err)
|
|
}
|
|
if strings.HasPrefix(line, "A002 OK") {
|
|
return nil
|
|
}
|
|
if strings.HasPrefix(line, "A002 ") {
|
|
return fmt.Errorf("server refused STARTTLS: %s", strings.TrimSpace(line))
|
|
}
|
|
}
|
|
}
|