70 lines
1.5 KiB
Go
70 lines
1.5 KiB
Go
package checker
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
func init() {
|
|
registerStartTLS("pop3", starttlsPOP3)
|
|
}
|
|
|
|
// starttlsPOP3 implements RFC 2595 STLS.
|
|
func starttlsPOP3(conn net.Conn, sni string) error {
|
|
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
|
|
|
greeting, err := rw.ReadString('\n')
|
|
if err != nil {
|
|
return fmt.Errorf("read greeting: %w", err)
|
|
}
|
|
if !strings.HasPrefix(greeting, "+OK") {
|
|
return fmt.Errorf("unexpected POP3 greeting: %s", strings.TrimSpace(greeting))
|
|
}
|
|
|
|
if _, err := rw.WriteString("CAPA\r\n"); err != nil {
|
|
return err
|
|
}
|
|
if err := rw.Flush(); err != nil {
|
|
return err
|
|
}
|
|
first, err := rw.ReadString('\n')
|
|
if err != nil {
|
|
return fmt.Errorf("read CAPA: %w", err)
|
|
}
|
|
supportsSTLS := false
|
|
if strings.HasPrefix(first, "+OK") {
|
|
for {
|
|
line, err := rw.ReadString('\n')
|
|
if err != nil {
|
|
return fmt.Errorf("read CAPA body: %w", err)
|
|
}
|
|
line = strings.TrimRight(line, "\r\n")
|
|
if line == "." {
|
|
break
|
|
}
|
|
if strings.EqualFold(line, "STLS") {
|
|
supportsSTLS = true
|
|
}
|
|
}
|
|
}
|
|
if !supportsSTLS {
|
|
return fmt.Errorf("%w: POP3 CAPA did not advertise STLS", errStartTLSNotOffered)
|
|
}
|
|
|
|
if _, err := rw.WriteString("STLS\r\n"); err != nil {
|
|
return err
|
|
}
|
|
if err := rw.Flush(); err != nil {
|
|
return err
|
|
}
|
|
resp, err := rw.ReadString('\n')
|
|
if err != nil {
|
|
return fmt.Errorf("read STLS response: %w", err)
|
|
}
|
|
if !strings.HasPrefix(resp, "+OK") {
|
|
return fmt.Errorf("server refused STLS: %s", strings.TrimSpace(resp))
|
|
}
|
|
return nil
|
|
}
|