From 7c6ec81b9594697a5b916db1aabbb1c8b6c4e342 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Mon, 25 Sep 2017 16:36:47 +0100 Subject: [PATCH] DKIM: support specifying alternate-identity tag for signing. Bug 2170 --- doc/doc-docbook/spec.xfpt | 20 +++++++++---- doc/doc-txt/NewStuff | 2 +- src/src/dkim.c | 60 ++++++++++++++++----------------------- src/src/structs.h | 1 + src/src/transports/smtp.c | 5 +++- test/confs/4520 | 2 ++ test/log/4520 | 3 +- test/log/4523 | 3 +- 8 files changed, 50 insertions(+), 46 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 44a274b98..4a8e1d06e 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -23800,6 +23800,7 @@ of the message. Its value must not be zero. See also &%final_timeout%&. .option dkim_strict smtp string&!! unset .option dkim_sign_headers smtp string&!! unset .option dkim_hash smtp string&!! sha256 +.option dkim_identity smtp string&!! unset DKIM signing options. For details see section &<>&. @@ -38553,6 +38554,19 @@ is set. .endlist If the option is empty after expansion, DKIM signing is not done. +.new +.option dkim_hash smtp string&!! sha256 +Can be set alternatively to &"sha1"& to use an alternate hash +method. Note that sha1 is now condidered insecure, and deprecated. + +.option dkim_identity smtp string&!! unset +If set after expansion, the value is used to set an "i=" tag in +the signing header. The DKIM standards restrict the permissible +syntax of this optional tag to a mail address, with possibly-empty +local part, an @, and a domain identical to or subdomain of the "d=" +tag value. Note that Exim does not check the value. +.wen + .option dkim_canon smtp string&!! unset This option sets the canonicalization method used when signing a message. The DKIM RFC currently supports two methods: "simple" and "relaxed". @@ -38572,12 +38586,6 @@ list of header names. Headers with these names will be included in the message signature. When unspecified, the header names recommended in RFC4871 will be used. -.new -.option dkim_hash smtp string&!! sha256 -Can be set alternatively to &"sha1"& to use an alternate hash -method. Note that sha1 is now condidered insecure, and deprecated. -.wen - .section "Verifying DKIM signatures in incoming mail" "SECID514" .cindex "DKIM" "verification" diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 88def2629..39fce1eab 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -52,7 +52,7 @@ Version 4.90 is opened with a TFO cookie. 13. DKIM support for multiple signing, by domain and/or key-selector. - DKIM support for multiple hashes. + DKIM support for multiple hashes, and for alternate-identity tags. 14. Exipick understands -C|--config for an alternative Exim configuration file. diff --git a/src/src/dkim.c b/src/src/dkim.c index ea2007225..cd8a16ae6 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -471,18 +471,15 @@ int sread; uschar buf[4096]; int save_errno = 0; int old_pool = store_pool; +uschar * errwhen; store_pool = POOL_MAIN; pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt); if (!(dkim_domain = expand_cstring(dkim->dkim_domain))) - { /* expansion error, do not send message. */ - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_domain: %s", expand_string_message); - goto bad; - } + { errwhen = US"dkim_domain"; goto expand_bad; } /* Set $dkim_domain expansion variable to each unique domain in list. */ @@ -509,11 +506,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) if (!(dkim_sel = expand_string(dkim->dkim_selector))) if (!(dkim_signing_selector = expand_string(dkim->dkim_selector))) - { - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_selector: %s", expand_string_message); - goto bad; - } + { errwhen = US"dkim_selector"; goto expand_bad; } while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep, NULL, 0))) @@ -523,18 +516,14 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) uschar * dkim_sign_headers_expanded = NULL; uschar * dkim_private_key_expanded; uschar * dkim_hash_expanded; + uschar * dkim_identity_expanded = NULL; /* Get canonicalization to use */ dkim_canon_expanded = dkim->dkim_canon ? expand_string(dkim->dkim_canon) : US"relaxed"; - if (!dkim_canon_expanded) - { - /* expansion error, do not send message. */ - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_canon: %s", expand_string_message); - goto bad; - } + if (!dkim_canon_expanded) /* expansion error, do not send message. */ + { errwhen = US"dkim_canon"; goto expand_bad; } if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0) pdkim_canon = PDKIM_CANON_RELAXED; @@ -548,23 +537,15 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) pdkim_canon = PDKIM_CANON_RELAXED; } - if (dkim->dkim_sign_headers) - if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers))) - { - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_sign_headers: %s", expand_string_message); - goto bad; - } - /* else pass NULL, which means default header list */ + if ( dkim->dkim_sign_headers + && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers))) + { errwhen = US"dkim_sign_header"; goto expand_bad; } + /* else pass NULL, which means default header list */ /* Get private key to use. */ if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key))) - { - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_private_key: %s", expand_string_message); - goto bad; - } + { errwhen = US"dkim_private_key"; goto expand_bad; } if ( Ustrlen(dkim_private_key_expanded) == 0 || Ustrcmp(dkim_private_key_expanded, "0") == 0 @@ -607,11 +588,13 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) } if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash))) - { - log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand " - "dkim_hash: %s", expand_string_message); - goto bad; - } + { errwhen = US"dkim_hash"; goto expand_bad; } + + if (dkim->dkim_identity) + if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity))) + { errwhen = US"dkim_identity"; goto expand_bad; } + else if (!*dkim_identity_expanded) + dkim_identity_expanded = NULL; /*XXX so we currently nail signing to RSA + this hash. Need to extract algo from privkey and check for disallowed combos. */ @@ -627,7 +610,7 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0))) pdkim_set_optional(sig, CS dkim_sign_headers_expanded, - NULL, + dkim_identity_expanded, pdkim_canon, pdkim_canon, -1, 0, 0); @@ -694,6 +677,11 @@ pk_bad: bad: sigbuf = NULL; goto CLEANUP; + +expand_bad: + log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s", + errwhen, expand_string_message); + goto bad; } #endif diff --git a/src/src/structs.h b/src/src/structs.h index 06fcd4188..d8ac19ab8 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -867,6 +867,7 @@ typedef BOOL (*oicf) (uschar *message_id, void *data); /* DKIM information for transport */ struct ob_dkim { uschar *dkim_domain; + uschar *dkim_identity; uschar *dkim_private_key; uschar *dkim_selector; uschar *dkim_canon; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 557d650ae..461b26c4a 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -45,6 +45,8 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) }, { "dkim_hash", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) }, + { "dkim_identity", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, dkim.dkim_identity) }, { "dkim_private_key", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) }, { "dkim_selector", opt_stringptr, @@ -278,10 +280,11 @@ smtp_transport_options_block smtp_transport_option_defaults = { #ifndef DISABLE_DKIM .dkim = {.dkim_domain = NULL, + .dkim_identity = NULL, .dkim_private_key = NULL, .dkim_selector = NULL, .dkim_canon = NULL, - .dkim_sign_headers = NULL, + .dkim_sign_headers = NULL, .dkim_strict = NULL, .dkim_hash = US"sha256", .dot_stuffed = FALSE}, diff --git a/test/confs/4520 b/test/confs/4520 index 5f4649846..897c1a675 100644 --- a/test/confs/4520 +++ b/test/confs/4520 @@ -50,6 +50,8 @@ send_to_server: .ifndef HEADERS_MAXSIZE dkim_sign_headers = OPT +.else + dkim_identity = allheaders@$dkim_domain .endif .ifdef VALUE dkim_hash = VALUE diff --git a/test/log/4520 b/test/log/4520 index 73854cfc1..8daa636c0 100644 --- a/test/log/4520 +++ b/test/log/4520 @@ -23,8 +23,9 @@ 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex 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 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 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 <= 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 Completed diff --git a/test/log/4523 b/test/log/4523 index 45eb89c9c..d1e5ebba3 100644 --- a/test/log/4523 +++ b/test/log/4523 @@ -4,8 +4,9 @@ ******** SERVER ******** 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 -1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 [verification succeeded] +1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 i=allheaders@test.ex [verification succeeded] 1999-03-02 09:44:33 10HmaY-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 10HmaY-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 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex 1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=server_dump 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed -- 2.30.2