From 484cc1a938bec2546c2475deecdd11d34866a257 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Fri, 3 Nov 2017 11:02:19 +0000 Subject: [PATCH] DKIM: better syntax for control of oversigning. Bug 2180 --- doc/doc-docbook/spec.xfpt | 11 ++++++++ doc/doc-txt/NewStuff | 1 + src/src/pdkim/pdkim.c | 54 ++++++++++++++++++++----------------- test/log/4520 | 54 ++++++++++++++++++++++++++++++------- test/scripts/4500-DKIM/4520 | 33 +++++++++++++++++++++++ test/stderr/4520 | 4 +-- 6 files changed, 121 insertions(+), 36 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 13fcad724..a0eb53c58 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -38608,6 +38608,17 @@ When unspecified, the header names listed in RFC4871 will be used, whether or not each header is present in the message. The default list is available for the expansion in the macro "_DKIM_SIGN_HEADERS". + +If a name is repeated, multiple headers by that name (or the absence therof) +will be signed. The textually later headers in the headers part of the +message are signed first, if there are multiples. + +A name can be prefixed with either an '=' or a '+' character. +If an '=' prefix is used, all headers that are present with this name +will be signed. +If a '+' prefix if used, all headers that are present with this name +will be signed, and one signtature added for a missing header with the +name will be appended. .wen diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 22af13554..e77095c8d 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -54,6 +54,7 @@ Version 4.90 13. DKIM support for multiple signing, by domain and/or key-selector. DKIM support for multiple hashes, and for alternate-identity tags. Builtin macro with default list of signed headers. + Better syntax for specifying oversigning. 14. Exipick understands -C|--config for an alternative Exim configuration file. diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 1420b1a79..138861815 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -250,16 +250,19 @@ pdkim_free_ctx(pdkim_ctx *ctx) /* -------------------------------------------------------------------------- */ /* Matches the name of the passed raw "header" against the passed colon-separated "tick", and invalidates - the entry in tick. Returns OK or fail-code */ -/*XXX might be safer done using a pdkim_stringlist for "tick" */ + the entry in tick. Entries can be prefixed for multi- or over-signing, + in which case do not invalidate. + + Returns OK for a match, or fail-code +*/ static int header_name_match(const uschar * header, uschar * tick) { -uschar * hname; -uschar * lcopy; -uschar * p; -uschar * q; +const uschar * ticklist = tick; +int sep = ':'; +BOOL multisign; +uschar * hname, * p, * ele; uschar * hcolon = Ustrchr(header, ':'); /* Get header name */ if (!hcolon) @@ -268,27 +271,22 @@ if (!hcolon) /* if we had strncmpic() we wouldn't need this copy */ hname = string_copyn(header, hcolon-header); -/* Copy tick-off list locally, so we can punch zeroes into it */ -p = lcopy = string_copy(tick); - -for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':')) +while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0)) { - *q = '\0'; - if (strcmpic(p, hname) == 0) - goto found; - - p = q+1; + switch (*ele) + { + case '=': case '+': multisign = TRUE; ele++; break; + default: multisign = FALSE; break; } -if (strcmpic(p, hname) == 0) - goto found; - + if (strcmpic(ele, hname) == 0) + { + if (!multisign) + *p = '_'; /* Invalidate this header name instance in tick-off list */ + return PDKIM_OK; + } + } return PDKIM_FAIL; - -found: - /* Invalidate header name instance in tick-off list */ - tick[p-lcopy] = '_'; - return PDKIM_OK; } @@ -1445,11 +1443,17 @@ for (sig = ctx->sig; sig; sig = sig->next) } } - /* Any headers we wanted to sign but were not present must also be listed */ + /* Any headers we wanted to sign but were not present must also be listed. + Ignore elements that have been ticked-off or are marked as never-oversign. */ + l = sig->sign_headers; while((s = string_nextinlist(&l, &sep, NULL, 0))) - if (*s != '_') + { + if (*s == '+') /* skip oversigning marker */ + s++; + if (*s != '_' && *s != '=') g = string_append_listele(g, ':', s); + } sig->headernames = string_from_gstring(g); /* Create signature header with b= omitted */ diff --git a/test/log/4520 b/test/log/4520 index b0ddcd64e..7bee5d786 100644 --- a/test/log/4520 +++ b/test/log/4520 @@ -5,11 +5,23 @@ 1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbA-0005vi-00" 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed 1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss -1999-03-02 09:44:33 10HmbB-0005vi-00 => c@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbC-0005vi-00" +1999-03-02 09:44:33 10HmbB-0005vi-00 => b10@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbC-0005vi-00" 1999-03-02 09:44:33 10HmbB-0005vi-00 Completed 1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss -1999-03-02 09:44:33 10HmbD-0005vi-00 => d@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbE-0005vi-00" +1999-03-02 09:44:33 10HmbD-0005vi-00 => b12@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbE-0005vi-00" 1999-03-02 09:44:33 10HmbD-0005vi-00 Completed +1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbF-0005vi-00 => b20@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbG-0005vi-00" +1999-03-02 09:44:33 10HmbF-0005vi-00 Completed +1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbH-0005vi-00 => b22@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbI-0005vi-00" +1999-03-02 09:44:33 10HmbH-0005vi-00 Completed +1999-03-02 09:44:33 10HmbJ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbJ-0005vi-00 => c@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbK-0005vi-00" +1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed +1999-03-02 09:44:33 10HmbL-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbL-0005vi-00 => d@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbM-0005vi-00" +1999-03-02 09:44:33 10HmbL-0005vi-00 Completed ******** SERVER ******** 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 @@ -26,15 +38,39 @@ 1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: R=server_dump 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed 1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive -1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 i=allheaders@test.ex [verification succeeded] -1999-03-02 09:44:33 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive -1999-03-02 09:44:33 10HmbC-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=From 1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbB-0005vi-00@myhost.test.ex -1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: R=server_dump 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed 1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive -1999-03-02 09:44:33 10HmbE-0005vi-00 DKIM: d=test.ex s=sel_bad c=relaxed/relaxed a=rsa-sha256 b=1024 [invalid - syntax error in public key record] -1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=From +1999-03-02 09:44:33 10HmbE-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=X-mine:X-mine:From 1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbD-0005vi-00@myhost.test.ex -1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: R=server_dump 1999-03-02 09:44:33 10HmbE-0005vi-00 Completed +1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbG-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmbG-0005vi-00 signer: test.ex bits: 1024 h=X-Mine +1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbF-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbG-0005vi-00 Completed +1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbI-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmbI-0005vi-00 signer: test.ex bits: 1024 h=X-mine:X-mine:X-Mine +1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbH-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 10HmbI-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbI-0005vi-00 Completed +1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbK-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 i=allheaders@test.ex [verification succeeded] +1999-03-02 09:44:33 10HmbK-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbK-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbK-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbJ-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbK-0005vi-00 Completed +1999-03-02 09:44:33 macro: From:Sender:Reply-To:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive +1999-03-02 09:44:33 10HmbM-0005vi-00 DKIM: d=test.ex s=sel_bad c=relaxed/relaxed a=rsa-sha256 b=1024 [invalid - syntax error in public key record] +1999-03-02 09:44:33 10HmbM-0005vi-00 signer: test.ex bits: 1024 h=From +1999-03-02 09:44:33 10HmbM-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbL-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 10HmbM-0005vi-00 => :blackhole: R=server_dump +1999-03-02 09:44:33 10HmbM-0005vi-00 Completed diff --git a/test/scripts/4500-DKIM/4520 b/test/scripts/4500-DKIM/4520 index 3e5879972..1bc4c6030 100644 --- a/test/scripts/4500-DKIM/4520 +++ b/test/scripts/4500-DKIM/4520 @@ -15,6 +15,39 @@ content exim -DOPT=From:From -odf b@test.ex From: nobody@example.com +content +**** +# +# no header, multi-sign +exim -DOPT=From:=X-Mine -odf b10@test.ex +From: nobody@example.com + +content +**** +# +# double header, multi-sign +exim -DOPT=From:=X-Mine -odf b12@test.ex +From: nobody@example.com +X-mine: one +X-mine: two + +content +**** +# +# +# no header, always-oversign +exim -DOPT=+X-Mine -odf b20@test.ex +From: nobody@example.com + +content +**** +# +# double header, always-oversign +exim -DOPT=+X-Mine -odf b22@test.ex +From: nobody@example.com +X-mine: one +X-mine: two + content **** # diff --git a/test/stderr/4520 b/test/stderr/4520 index 3d7957c03..499716fc1 100644 --- a/test/stderr/4520 +++ b/test/stderr/4520 @@ -45,12 +45,12 @@ DKIM-Signature:{SP}v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP} PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>> dkim-signature:v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{SP}s=sel_bad;{SP}h=From;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=; PDKIM [test.ex] Header sha256 computed: 241e16230df5723d899cfae9474c6b376a2ab1f81d1094e358f50ffd0e0067b3 - SMTP<< 250 OK id=10HmbE-0005vi-00 + SMTP<< 250 OK id=10HmbM-0005vi-00 SMTP>> QUIT cmd buf flush ddd bytes SMTP(close)>> LOG: MAIN - => d@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbE-0005vi-00" + => d@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmbM-0005vi-00" LOG: MAIN Completed >>>>>>>>>>>>>>>> Exim pid=pppp (main) terminating with rc=0 >>>>>>>>>>>>>>>> -- 2.25.1