Skip to content

Commit fb07ec9

Browse files
ludusrussoLudovico Russo
andauthored
Fix folding signature algorithm
Closes: #18 Co-authored-by: Ludovico Russo <l.russo@hoplo.com>
1 parent e4c8736 commit fb07ec9

File tree

5 files changed

+83
-34
lines changed

5 files changed

+83
-34
lines changed

dkim/header.go

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,35 +92,48 @@ func parseHeaderParams(s string) (map[string]string, error) {
9292
return params, nil
9393
}
9494

95-
func formatHeaderParams(params map[string]string) string {
96-
keys := make([]string, 0, len(params))
97-
found := false
98-
for k := range params {
99-
if k == "b" {
100-
found = true
101-
} else {
102-
keys = append(keys, k)
95+
func formatHeaderParams(headerFieldName string, params map[string]string) string {
96+
keys, bvalue, bfound := sortParams(params)
97+
98+
s := headerFieldName + ":"
99+
var line string
100+
101+
for _, k := range keys {
102+
v := params[k]
103+
nextLength := 3 + len(line) + len(v) + len(k)
104+
if nextLength > 75 {
105+
s += line + crlf
106+
line = ""
103107
}
108+
line = fmt.Sprintf("%v %v=%v;", line, k, v)
104109
}
105-
sort.Strings(keys)
106-
if found {
107-
keys = append(keys, "b")
110+
111+
if line != "" {
112+
s += line
108113
}
109114

110-
var s string
111-
first := true
112-
for _, k := range keys {
113-
v := params[k]
115+
if bfound {
116+
bfiled := foldHeaderField(" b=" + bvalue)
117+
s += crlf + bfiled
118+
}
114119

115-
if first {
116-
first = false
120+
return s
121+
}
122+
123+
func sortParams(params map[string]string) ([]string, string, bool) {
124+
keys := make([]string, 0, len(params))
125+
bfound := false
126+
var bvalue string
127+
for k := range params {
128+
if k == "b" {
129+
bvalue = params["b"]
130+
bfound = true
117131
} else {
118-
s += " "
132+
keys = append(keys, k)
119133
}
120-
121-
s += k + "=" + v + ";"
122134
}
123-
return s
135+
sort.Strings(keys)
136+
return keys, bvalue, bfound
124137
}
125138

126139
type headerPicker struct {

dkim/header_test.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,48 @@ func TestFormatHeaderParams(t *testing.T) {
5555
"d": "example.org",
5656
}
5757

58-
expected := "a=rsa-sha256; d=example.org; v=1;"
58+
expected := "DKIM-Signature: a=rsa-sha256; d=example.org; v=1;"
5959

60-
s := formatHeaderParams(params)
60+
s := formatHeaderParams("DKIM-Signature", params)
6161
if s != expected {
6262
t.Errorf("Expected formatted params to be %q, but got %q", expected, s)
6363
}
6464
}
6565

66+
func TestLongHeaderFolding(t *testing.T) {
67+
// see #29 and #27
68+
69+
params := map[string]string{
70+
"v": "1",
71+
"a": "rsa-sha256",
72+
"d": "example.org",
73+
"h": "From:To:Subject:Date:Message-ID:Long-Header-Name",
74+
}
75+
76+
expected := "DKIM-Signature: a=rsa-sha256; d=example.org;\r\n h=From:To:Subject:Date:Message-ID:Long-Header-Name; v=1;"
77+
78+
s := formatHeaderParams("DKIM-Signature", params)
79+
if s != expected {
80+
t.Errorf("Expected formatted params to be\n\n %q\n\n, but got\n\n %q", expected, s)
81+
}
82+
}
83+
84+
func TestSignedHeaderFolding(t *testing.T) {
85+
hValue := "From:To:Subject:Date:Message-ID:Long-Header-Name:Another-Long-Header-Name"
86+
87+
params := map[string]string{
88+
"v": "1",
89+
"a": "rsa-sha256",
90+
"d": "example.org",
91+
"h": hValue,
92+
}
93+
94+
s := formatHeaderParams("DKIM-Signature", params)
95+
if !strings.Contains(s, hValue) {
96+
t.Errorf("Signed Headers names (%v) are not well folded in the signed header %q", hValue, s)
97+
}
98+
}
99+
66100
func TestParseHeaderParams_malformed(t *testing.T) {
67101
_, err := parseHeaderParams("abc; def")
68102
if err == nil {

dkim/sign.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,8 @@ func Sign(w io.Writer, r io.Reader, options *SignOptions) error {
333333
}
334334

335335
func formatSignature(params map[string]string) string {
336-
sig := headerFieldName + ": " + formatHeaderParams(params)
337-
return foldHeaderField(sig)
336+
sig := formatHeaderParams(headerFieldName, params)
337+
return sig
338338
}
339339

340340
func formatTagList(l []string) string {

dkim/sign_ed25519_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
"testing"
88
)
99

10-
const signedEd25519MailString = "DKIM-Signature: a=ed25519-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJ" + "\r\n" +
11-
" " + "VOzv8=; c=simple/simple; d=football.example.com; h=From:To:Subject:Date:Mes" + "\r\n" +
12-
" " + "sage-ID; s=brisbane; t=424242; v=1; b=ZduPZq83AOTqjhScIfHll6W90tMG1nf34a34Q" + "\r\n" +
13-
" " + "XKat3iFtP7NQE/3AwnHOrcsR2r5nVNoW+LeZURpT2obCthPCw==;" + "\r\n" +
10+
const signedEd25519MailString = "DKIM-Signature: a=ed25519-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;" + "\r\n" +
11+
" " + "c=simple/simple; d=football.example.com;" + "\r\n" +
12+
" " + "h=From:To:Subject:Date:Message-ID; s=brisbane; t=424242; v=1;" + "\r\n" +
13+
" " + "b=k1LzRxs9/DfN/whlMICYKNIJhqUSmup0d5yw8tpi+Cfiqe6I3oSBmJ+HEp+moWy7/XvcUY/t" + "\r\n" +
14+
" " + "ERHc3D2m7vw1AA==" + "\r\n" +
1415
mailHeaderString +
1516
"\r\n" +
1617
mailBodyString

dkim/sign_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ const mailBodyString = "Hi.\r\n" +
2222

2323
const mailString = mailHeaderString + "\r\n" + mailBodyString
2424

25-
const signedMailString = "DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv" + "\r\n" +
26-
" " + "8=; c=simple/simple; d=example.org; h=From:To:Subject:Date:Message-ID; s=br" + "\r\n" +
27-
" " + "isbane; t=424242; v=1; b=bXtqB8uOEvtd1Xv/DHatdjb9onP0+vnzdYBbPMZm1qrRmhSuFH" + "\r\n" +
28-
" " + "WsbkETafswNvJ4VqNX0gMoaYvzcmoMkUhW9m4pgZqR5y+62yA+B7WJCd6mz82UVkS1qEJeGjMxX" + "\r\n" +
29-
" " + "mmPDkmLDA5HHL5LLTc3DLrxkwWMLzwrhQL48WhNFD1d6L4=;" + "\r\n" +
25+
const signedMailString = "DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;" + "\r\n" +
26+
" " + "c=simple/simple; d=example.org; h=From:To:Subject:Date:Message-ID;" + "\r\n" +
27+
" " + "s=brisbane; t=424242; v=1;" + "\r\n" +
28+
" " + "b=MobyyDTeHhMhNJCEI6ATNK63ZQ7deSXK9umyzAvYwFqE6oGGvlQBQwqr1aC11hWpktjMLP1/" + "\r\n" +
29+
" " + "m0PBi9v7cRLKMXXBIv2O0B1mIWdZPqd9jveRJqKzCb7SpqH2u5kK6i2vZI639ENTQzRQdxSAGXc" + "\r\n" +
30+
" " + "PcPYjrgkqj7xklnrNBs0aIUA=" + "\r\n" +
3031
mailHeaderString +
3132
"\r\n" +
3233
mailBodyString

0 commit comments

Comments
 (0)