mirror of
https://github.com/jhillyerd/inbucket.git
synced 2026-10-29 13:42:30 +00:00
fix(pop3): reject deleted messages and failed TLS handshakes (#620)
- RETR and TOP now respond "-ERR You deleted message N" for messages marked deleted, as RFC 1939 sections 5 (RETR) and 7 (TOP) require; previously the message content was still sent. - STLS: a failed TLS handshake previously continued the session with the dead TLS connection installed as s.conn and a bogus tlsState, producing confusing follow-on errors. RFC 2595 section 4 requires the negotiation to complete before further commands, so a failure is now fatal: log it and terminate the session. Updates the scripted tests that previously pinned the old behavior, and adds a STLS handshake failure regression test. Signed-off-by: James Hillyerd <james@hillyerd.com>
This commit is contained in:
@@ -288,6 +288,51 @@ func TestForceTLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 2595 §4: after the +OK response to STLS, a TLS negotiation begins
|
||||
// immediately and the client must not issue further commands until it
|
||||
// completes. A failed negotiation is therefore fatal to the session: the
|
||||
// server must not keep the session running on the dead connection.
|
||||
func TestSTLSHandshakeFailure(t *testing.T) {
|
||||
ds := test.NewStore()
|
||||
server := setupPOPServer(t, ds, true, false)
|
||||
pipe := setupPOPSession(t, server)
|
||||
c := textproto.NewConn(pipe)
|
||||
defer func() {
|
||||
_ = c.Close()
|
||||
server.Drain()
|
||||
}()
|
||||
|
||||
reply, err := c.ReadLine()
|
||||
if err != nil {
|
||||
t.Fatalf("Reading initial line failed %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(reply, "+OK") {
|
||||
t.Fatalf("Initial line is not +OK")
|
||||
}
|
||||
|
||||
if err := c.PrintfLine("STLS"); err != nil {
|
||||
t.Fatalf("Failed to send STLS; %v.", err)
|
||||
}
|
||||
reply, err = c.ReadLine()
|
||||
if err != nil {
|
||||
t.Fatalf("Reading STLS reply line failed %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(reply, "+OK") {
|
||||
t.Fatalf("STLS failed: %s", reply)
|
||||
}
|
||||
|
||||
// Send bytes that cannot begin a TLS handshake.
|
||||
if _, err := pipe.Write([]byte("this is not a TLS handshake\r\n")); err != nil {
|
||||
t.Fatalf("Failed to write garbage; %v.", err)
|
||||
}
|
||||
|
||||
// The server must terminate the session without further responses.
|
||||
_, err = c.ReadLine()
|
||||
if err == nil {
|
||||
t.Fatal("Expected connection close after failed handshake")
|
||||
}
|
||||
}
|
||||
|
||||
// net.Pipe does not implement deadlines
|
||||
type mockConn struct {
|
||||
net.Conn
|
||||
|
||||
Reference in New Issue
Block a user