git » chasquid » commit 49030cb

dkim: Messages without a blank line should have an empty body

author Alberto Bertogli
2026-10-09 10:07:20 UTC
committer Alberto Bertogli
2026-10-09 20:34:17 UTC
parent ce236e91bc15b612cc7e433a2db45dd7bd4e2b24

dkim: Messages without a blank line should have an empty body

Today, if a message does not have a blank line (which separates headers
and body), we also include all lines except the first as the body (even
the ones parsed as headers). This is incorrect.

This patch fixes the code so that in those messages, all the lines are
headers, and the body is empty.

Note that since SMTP messages have to end with a new line, that final
line will act as the separator if there is no body. So this bug only
impacts signing/verification of files on disk via chasquid-util.

internal/dkim/message.go +10 -2
internal/dkim/message_test.go +5 -2

diff --git a/internal/dkim/message.go b/internal/dkim/message.go
index a8da856..0cc31dd 100644
--- a/internal/dkim/message.go
+++ b/internal/dkim/message.go
@@ -37,7 +37,9 @@ func parseMessage(message string) (headers, string, error) {
 	// Group the lines of each header: the first line, followed by its
 	// continuation lines (if any).
 	groups := [][]string{}
-	eoh := 0
+
+	// End of headers. If there's no blank line, all the lines are headers.
+	eoh := len(lines)
 	for i, line := range lines {
 		if line == "" {
 			eoh = i
@@ -67,7 +69,13 @@ func parseMessage(message string) (headers, string, error) {
 		headers = append(headers, h)
 	}
 
-	return headers, strings.Join(lines[eoh+1:], "\r\n"), nil
+	// The body is everything after the blank line (if there is one).
+	body := ""
+	if eoh < len(lines) {
+		body = strings.Join(lines[eoh+1:], "\r\n")
+	}
+
+	return headers, body, nil
 }
 
 // Parse a header, given its lines (the first one, followed by the
diff --git a/internal/dkim/message_test.go b/internal/dkim/message_test.go
index 9006ea4..1425832 100644
--- a/internal/dkim/message_test.go
+++ b/internal/dkim/message_test.go
@@ -116,8 +116,8 @@ func TestParseMessageWithErrors(t *testing.T) {
 
 func TestParseMessageWithoutBlankLine(t *testing.T) {
 	// If there's no blank line, all the lines are headers, including the
-	// continuation lines of the last one.
-	hs, _, err := parseMessage("From: a@b\r\nTo: c@d\r\n e@f")
+	// continuation lines of the last one, and the body is empty.
+	hs, body, err := parseMessage("From: a@b\r\nTo: c@d\r\n e@f")
 	if err != nil {
 		t.Fatalf("parseMessage error: %v", err)
 	}
@@ -128,6 +128,9 @@ func TestParseMessageWithoutBlankLine(t *testing.T) {
 	if diff := cmp.Diff(want, hs); diff != "" {
 		t.Errorf("parseMessage headers mismatch (-want +got):\n%s", diff)
 	}
+	if body != "" {
+		t.Errorf("parseMessage body: wanted empty, got %q", body)
+	}
 }
 
 func TestParseMessageManyContinuations(t *testing.T) {