Skip to content

Commit 5294351

Browse files
committed
adds support for DKIM flags. fixes emersion#44
1 parent 5995b67 commit 5294351

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

dkim/query_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ const dnsPublicKey = "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ" +
1616
"/RtdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhi" +
1717
"tdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB"
1818

19+
const dnsPublicKeySFlag = "v=DKIM1; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ" +
20+
"KBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYt" +
21+
"IxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v" +
22+
"/RtdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhi" +
23+
"tdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB"
24+
1925
const dnsEd25519PublicKey = "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="
2026

2127
func init() {
@@ -31,6 +37,8 @@ func queryTest(domain, selector string, txtLookup txtLookupFunc) (*queryResult,
3137
return parsePublicKey(dnsRawRSAPublicKey)
3238
case "brisbane._domainkey.football.example.com":
3339
return parsePublicKey(dnsEd25519PublicKey)
40+
case "helsinki._domainkey.example.com":
41+
return parsePublicKey(dnsPublicKeySFlag)
3442
}
3543
return nil, fmt.Errorf("unknown test DNS record %v", record)
3644
}

dkim/sign.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ type SignOptions struct {
7474
//
7575
// The whole message header and body must be written to the Signer. Close should
7676
// always be called (either after the whole message has been written, or after
77-
// an error occured and the signer won't be used anymore). Close may return an
77+
// an error occurred and the signer won't be used anymore). Close may return an
7878
// error in case signing fails.
7979
//
8080
// After a successful Close, Signature can be called to retrieve the

dkim/verify.go

+14
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,20 @@ func verify(h header, r io.Reader, sigField, sigValue string, options *VerifyOpt
292292
return verif, permFailError("unsupported public key query method")
293293
}
294294

295+
// Parse flags
296+
for _, flag := range res.Flags {
297+
switch flag {
298+
case "y":
299+
// domain is testing DKIM.
300+
return verif, nil
301+
case "s":
302+
// i domain and d domain should be equal
303+
if !strings.HasSuffix(verif.Identifier, "@"+verif.Domain) {
304+
return verif, permFailError("identifier and domain mismatch")
305+
}
306+
}
307+
}
308+
295309
// Parse algos
296310
algos := strings.SplitN(stripWhitespace(params["a"]), "-", 2)
297311
if len(algos) != 2 {

dkim/verify_test.go

+90
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,93 @@ func TestVerify_tooManySignatures(t *testing.T) {
294294
t.Fatalf("Expected %v verifications, got %v", options.MaxVerifications, len(verifs))
295295
}
296296
}
297+
298+
const validSignatureWithSFlag = `DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
299+
c=simple/simple; d=example.com;
300+
h=Received:From:To:Subject:Date:Message-ID; s=helsinki; t=1627654546; v=1;
301+
b=IKIukw2EoRWxb86Ke2ingZFWLoAeNnKYAwGghFe1y0bbn5QLSoyk78o36JXT8z1DzmPquMHt
302+
C//jnBna6DtqBneiKAUo3OyYmv1+EbTWWEvHGGtUkrKge2VdIXM3ttaOpuTHJRG+6irPKq0Ul4T
303+
Ofa99PVg4o6nfY6Ctakv3aYc=
304+
Received: from helsinki.example.com [192.0.2.1]
305+
by submitserver.example.com with SUBMISSION;
306+
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
307+
From: Joe Helsinki <[email protected]>
308+
To: Suzie Q <[email protected]>
309+
Subject: Is dinner ready?
310+
Date: Fri, 11 Jul 2021 21:00:37 -0700 (PDT)
311+
Message-ID: <[email protected]>
312+
313+
Hi.
314+
315+
We lost the game. Are you hungry yet?
316+
317+
Joe.`
318+
319+
var testSFlagVerification = &Verification{
320+
Domain: "example.com",
321+
Identifier: "@example.com",
322+
HeaderKeys: []string{"Received", "From", "To", "Subject", "Date", "Message-ID"},
323+
Time: time.Unix(1627654546, 0),
324+
}
325+
326+
func TestVerify_SFlag(t *testing.T) {
327+
r := newMailStringReader(validSignatureWithSFlag)
328+
329+
verifications, err := Verify(r)
330+
if err != nil {
331+
t.Fatalf("Expected no error while verifying signature with flags, got: %v", err)
332+
} else if len(verifications) != 1 {
333+
t.Fatalf("Expected exactly one verification with flags, got %v", len(verifications))
334+
}
335+
336+
v := verifications[0]
337+
if !reflect.DeepEqual(testSFlagVerification, v) {
338+
t.Errorf("Expected verification with flags to be \n%+v\n but got \n%+v", testSFlagVerification, v)
339+
}
340+
}
341+
342+
const invalidSignatureWithSFlag = `DKIM-Signature: a=rsa-sha256; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
343+
c=simple/simple; d=example.com;
344+
h=Received:From:To:Subject:Date:Message-ID; [email protected];
345+
s=helsinki; t=1627654996; v=1;
346+
b=k07JuWvk3PZkanimQ0QtIXRwXC5W4EhG/0sPH+r7zWKQ731fNZE//9+ofz+vcA3K5YQ0cOR2
347+
EXY9qjriMPHFlaYsKZ4gj5YebNhRHyjJ9xlsTPNtFLqs9wnnaKCZu3VxJpualfTaY+Vs3RMjYLq
348+
7IvOY4tqxnifJg2uFC/5kRbY=
349+
Received: from helsinki.example.com [192.0.2.1]
350+
by submitserver.example.com with SUBMISSION;
351+
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
352+
From: Joe Helsinki <[email protected]>
353+
To: Suzie Q <[email protected]>
354+
Subject: Is dinner ready?
355+
Date: Fri, 11 Jul 2021 21:00:37 -0700 (PDT)
356+
Message-ID: <[email protected]>
357+
358+
Hi.
359+
360+
We lost the game. Are you hungry yet?
361+
362+
Joe.`
363+
364+
var testSFlagVerificationFail = &Verification{
365+
Domain: "example.com",
366+
Identifier: "[email protected]",
367+
HeaderKeys: []string{"Received", "From", "To", "Subject", "Date", "Message-ID"},
368+
Time: time.Unix(1627654996, 0),
369+
Err: permFailError("identifier and domain mismatch"),
370+
}
371+
372+
func TestVerify_InvalidSFlag(t *testing.T) {
373+
r := newMailStringReader(invalidSignatureWithSFlag)
374+
375+
verifications, err := Verify(r)
376+
if err != nil {
377+
t.Fatalf("Expected no error while verifying signature with flags, got: %v", err)
378+
} else if len(verifications) != 1 {
379+
t.Fatalf("Expected exactly one verification with flags, got %v", len(verifications))
380+
}
381+
382+
v := verifications[0]
383+
if !reflect.DeepEqual(testSFlagVerificationFail, v) {
384+
t.Errorf("Expected verification with flags to be \n%+v\n but got \n%+v", testSFlagVerificationFail, v)
385+
}
386+
}

0 commit comments

Comments
 (0)