64 lines
1.4 KiB
Go
64 lines
1.4 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 := rw.ReadString('\n'); 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 err
|
|
}
|
|
|
|
supportsSTARTTLS := false
|
|
for {
|
|
line, err := rw.ReadString('\n')
|
|
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 err
|
|
}
|
|
if err := rw.Flush(); err != nil {
|
|
return err
|
|
}
|
|
for {
|
|
line, err := rw.ReadString('\n')
|
|
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))
|
|
}
|
|
}
|
|
}
|