From fb07ec9e7323788ae953eea6797a1dddb8a13106 Mon Sep 17 00:00:00 2001 From: Ludovico Russo Date: Thu, 28 May 2020 15:09:20 +0200 Subject: [PATCH] Fix folding signature algorithm Closes: https://github.com/emersion/go-msgauth/issues/18 Co-authored-by: Ludovico Russo --- dkim/header.go | 55 ++++++++++++++++++++++++--------------- dkim/header_test.go | 38 +++++++++++++++++++++++++-- dkim/sign.go | 4 +-- dkim/sign_ed25519_test.go | 9 ++++--- dkim/sign_test.go | 11 ++++---- 5 files changed, 83 insertions(+), 34 deletions(-) diff --git a/dkim/header.go b/dkim/header.go index f940e12..45f3f6b 100644 --- a/dkim/header.go +++ b/dkim/header.go @@ -92,35 +92,48 @@ func parseHeaderParams(s string) (map[string]string, error) { return params, nil } -func formatHeaderParams(params map[string]string) string { - keys := make([]string, 0, len(params)) - found := false - for k := range params { - if k == "b" { - found = true - } else { - keys = append(keys, k) +func formatHeaderParams(headerFieldName string, params map[string]string) string { + keys, bvalue, bfound := sortParams(params) + + s := headerFieldName + ":" + var line string + + for _, k := range keys { + v := params[k] + nextLength := 3 + len(line) + len(v) + len(k) + if nextLength > 75 { + s += line + crlf + line = "" } + line = fmt.Sprintf("%v %v=%v;", line, k, v) } - sort.Strings(keys) - if found { - keys = append(keys, "b") + + if line != "" { + s += line } - var s string - first := true - for _, k := range keys { - v := params[k] + if bfound { + bfiled := foldHeaderField(" b=" + bvalue) + s += crlf + bfiled + } - if first { - first = false + return s +} + +func sortParams(params map[string]string) ([]string, string, bool) { + keys := make([]string, 0, len(params)) + bfound := false + var bvalue string + for k := range params { + if k == "b" { + bvalue = params["b"] + bfound = true } else { - s += " " + keys = append(keys, k) } - - s += k + "=" + v + ";" } - return s + sort.Strings(keys) + return keys, bvalue, bfound } type headerPicker struct { diff --git a/dkim/header_test.go b/dkim/header_test.go index 2315d57..16379b5 100644 --- a/dkim/header_test.go +++ b/dkim/header_test.go @@ -55,14 +55,48 @@ func TestFormatHeaderParams(t *testing.T) { "d": "example.org", } - expected := "a=rsa-sha256; d=example.org; v=1;" + expected := "DKIM-Signature: a=rsa-sha256; d=example.org; v=1;" - s := formatHeaderParams(params) + s := formatHeaderParams("DKIM-Signature", params) if s != expected { t.Errorf("Expected formatted params to be %q, but got %q", expected, s) } } +func TestLongHeaderFolding(t *testing.T) { + // see #29 and #27 + + params := map[string]string{ + "v": "1", + "a": "rsa-sha256", + "d": "example.org", + "h": "From:To:Subject:Date:Message-ID:Long-Header-Name", + } + + expected := "DKIM-Signature: a=rsa-sha256; d=example.org;\r\n h=From:To:Subject:Date:Message-ID:Long-Header-Name; v=1;" + + s := formatHeaderParams("DKIM-Signature", params) + if s != expected { + t.Errorf("Expected formatted params to be\n\n %q\n\n, but got\n\n %q", expected, s) + } +} + +func TestSignedHeaderFolding(t *testing.T) { + hValue := "From:To:Subject:Date:Message-ID:Long-Header-Name:Another-Long-Header-Name" + + params := map[string]string{ + "v": "1", + "a": "rsa-sha256", + "d": "example.org", + "h": hValue, + } + + s := formatHeaderParams("DKIM-Signature", params) + if !strings.Contains(s, hValue) { + t.Errorf("Signed Headers names (%v) are not well folded in the signed header %q", hValue, s) + } +} + func TestParseHeaderParams_malformed(t *testing.T) { _, err := parseHeaderParams("abc; def") if err == nil { diff --git a/dkim/sign.go b/dkim/sign.go index 843ce18..effb7d4 100644 --- a/dkim/sign.go +++ b/dkim/sign.go @@ -333,8 +333,8 @@ func Sign(w io.Writer, r io.Reader, options *SignOptions) error { } func formatSignature(params map[string]string) string { - sig := headerFieldName + ": " + formatHeaderParams(params) - return foldHeaderField(sig) + sig := formatHeaderParams(headerFieldName, params) + return sig } func formatTagList(l []string) string { diff --git a/dkim/sign_ed25519_test.go b/dkim/sign_ed25519_test.go index 207c66d..b8fd33b 100644 --- a/dkim/sign_ed25519_test.go +++ b/dkim/sign_ed25519_test.go @@ -7,10 +7,11 @@ import ( "testing" ) -const signedEd25519MailString = "DKIM-Signature: a=ed25519-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJ" + "\r\n" + - " " + "VOzv8=; c=simple/simple; d=football.example.com; h=From:To:Subject:Date:Mes" + "\r\n" + - " " + "sage-ID; s=brisbane; t=424242; v=1; b=ZduPZq83AOTqjhScIfHll6W90tMG1nf34a34Q" + "\r\n" + - " " + "XKat3iFtP7NQE/3AwnHOrcsR2r5nVNoW+LeZURpT2obCthPCw==;" + "\r\n" + +const signedEd25519MailString = "DKIM-Signature: a=ed25519-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;" + "\r\n" + + " " + "c=simple/simple; d=football.example.com;" + "\r\n" + + " " + "h=From:To:Subject:Date:Message-ID; s=brisbane; t=424242; v=1;" + "\r\n" + + " " + "b=k1LzRxs9/DfN/whlMICYKNIJhqUSmup0d5yw8tpi+Cfiqe6I3oSBmJ+HEp+moWy7/XvcUY/t" + "\r\n" + + " " + "ERHc3D2m7vw1AA==" + "\r\n" + mailHeaderString + "\r\n" + mailBodyString diff --git a/dkim/sign_test.go b/dkim/sign_test.go index 68a3ab7..3cf7529 100644 --- a/dkim/sign_test.go +++ b/dkim/sign_test.go @@ -22,11 +22,12 @@ const mailBodyString = "Hi.\r\n" + const mailString = mailHeaderString + "\r\n" + mailBodyString -const signedMailString = "DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv" + "\r\n" + - " " + "8=; c=simple/simple; d=example.org; h=From:To:Subject:Date:Message-ID; s=br" + "\r\n" + - " " + "isbane; t=424242; v=1; b=bXtqB8uOEvtd1Xv/DHatdjb9onP0+vnzdYBbPMZm1qrRmhSuFH" + "\r\n" + - " " + "WsbkETafswNvJ4VqNX0gMoaYvzcmoMkUhW9m4pgZqR5y+62yA+B7WJCd6mz82UVkS1qEJeGjMxX" + "\r\n" + - " " + "mmPDkmLDA5HHL5LLTc3DLrxkwWMLzwrhQL48WhNFD1d6L4=;" + "\r\n" + +const signedMailString = "DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;" + "\r\n" + + " " + "c=simple/simple; d=example.org; h=From:To:Subject:Date:Message-ID;" + "\r\n" + + " " + "s=brisbane; t=424242; v=1;" + "\r\n" + + " " + "b=MobyyDTeHhMhNJCEI6ATNK63ZQ7deSXK9umyzAvYwFqE6oGGvlQBQwqr1aC11hWpktjMLP1/" + "\r\n" + + " " + "m0PBi9v7cRLKMXXBIv2O0B1mIWdZPqd9jveRJqKzCb7SpqH2u5kK6i2vZI639ENTQzRQdxSAGXc" + "\r\n" + + " " + "PcPYjrgkqj7xklnrNBs0aIUA=" + "\r\n" + mailHeaderString + "\r\n" + mailBodyString