summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-txt/experimental-spec.txt9
-rw-r--r--src/src/arc.c41
2 files changed, 39 insertions, 11 deletions
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 0eeb22758..d51169073 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -800,13 +800,20 @@ Receive log lines for an ARC pass will be tagged "ARC".
Signing
--
-arc_sign = <admd-identifier> : <selector> : <privkey>
+arc_sign = <admd-identifier> : <selector> : <privkey> [ : <options> ]
An option on the smtp transport, which constructs and prepends to the message
an ARC set of headers. The textually-first Authentication-Results: header
is used as a basis (you must have added one on entry to the ADMD).
Expanded as a whole; if unset, empty or forced-failure then no signing is done.
If it is set, all three elements must be non-empty.
+The fourth element is optional, and if present consists of a comma-separated list
+of options. The only option implemented so far is
+ timestamps Add a t= tag to the generated AMS and AS headers, with the
+ current time.
+
+[As of writing, gmail insist that a t= tag on the AS is mandatory]
+
Caveats:
* There must be an Authentication-Results header, presumably added by an ACL
while receiving the message, for the same ADMD, for arc_sign to succeed.
diff --git a/src/src/arc.c b/src/src/arc.c
index 6f567dc5f..f3c567a8c 100644
--- a/src/src/arc.c
+++ b/src/src/arc.c
@@ -21,6 +21,8 @@
extern pdkim_ctx * dkim_verify_ctx;
extern pdkim_ctx dkim_sign_ctx;
+#define ARC_SIGN_OPT_TSTAMP BIT(0)
+
/******************************************************************************/
typedef struct hdr_rlist {
@@ -1272,7 +1274,7 @@ return g;
static gstring *
arc_sign_append_ams(gstring * g, arc_ctx * ctx, int instance,
const uschar * identity, const uschar * selector, blob * bodyhash,
- hdr_rlist * rheaders, const uschar * privkey)
+ hdr_rlist * rheaders, const uschar * privkey, unsigned options)
{
uschar * s;
gstring * hdata = NULL;
@@ -1288,11 +1290,15 @@ header_line * h = (header_line *)(al+1);
/* Construct the to-be-signed AMS pseudo-header: everything but the sig. */
ams_off = g->ptr;
-g = string_append(g, 10,
+g = string_append(g, 7,
ARC_HDR_AMS,
US" i=", string_sprintf("%d", instance),
US"; a=rsa-sha256; c=relaxed; d=", identity, /*XXX hardwired */
- US"; s=", selector,
+ US"; s=", selector);
+if (options & ARC_SIGN_OPT_TSTAMP)
+ g = string_append(g, 2,
+ US"; t=", string_sprintf("%lu", (u_long)time(NULL)));
+g = string_append(g, 3,
US";\r\n\tbh=", pdkim_encode_base64(bodyhash),
US";\r\n\th=");
@@ -1390,7 +1396,7 @@ return US"none";
static gstring *
arc_sign_prepend_as(gstring * arcset_interim, arc_ctx * ctx,
int instance, const uschar * identity, const uschar * selector, blob * ar,
- const uschar * privkey)
+ const uschar * privkey, unsigned options)
{
gstring * arcset;
arc_set * as;
@@ -1417,12 +1423,16 @@ blob sig;
/* Construct the AS except for the signature */
-arcset = string_append(NULL, 10,
+arcset = string_append(NULL, 9,
ARC_HDR_AS,
US" i=", string_sprintf("%d", instance),
US"; cv=", status,
US"; a=rsa-sha256; d=", identity, /*XXX hardwired */
- US"; s=", selector, /*XXX same as AMS */
+ US"; s=", selector); /*XXX same as AMS */
+if (options & ARC_SIGN_OPT_TSTAMP)
+ arcset = string_append(arcset, 2,
+ US"; t=", string_sprintf("%lu", (u_long)time(NULL)));
+arcset = string_cat(arcset,
US";\r\n\t b=;");
h->slen = arcset->ptr;
@@ -1520,7 +1530,8 @@ The dkim_exim_sign() function has already been called, so will have hashed the
message body for us so long as we requested a hash previously.
Arguments:
- signspec Three-element colon-sep list: identity, selector, privkey
+ signspec Three-element colon-sep list: identity, selector, privkey.
+ Optional fourth element: comma-sep list of options.
Already expanded
sigheaders Any signature headers already generated, eg. by DKIM, or NULL
errstr Error string
@@ -1533,7 +1544,8 @@ Return value
gstring *
arc_sign(const uschar * signspec, gstring * sigheaders, uschar ** errstr)
{
-const uschar * identity, * selector, * privkey;
+const uschar * identity, * selector, * privkey, * opts, * s;
+unsigned options = 0;
int sep = 0;
header_line * headers;
hdr_rlist * rheaders;
@@ -1556,6 +1568,14 @@ if ( !*identity | !*selector
if (*privkey == '/' && !(privkey = expand_file_big_buffer(privkey)))
return sigheaders ? sigheaders : string_get(0);
+if ((opts = string_nextinlist(&signspec, &sep, NULL, 0)))
+ {
+ int osep = ',';
+ while ((s = string_nextinlist(&opts, &osep, NULL, 0)))
+ if (Ustrcmp(s, "timestamps") == 0)
+ options |= ARC_SIGN_OPT_TSTAMP;
+ }
+
DEBUG(D_transport) debug_printf("ARC: sign for %s\n", identity);
/* Make an rlist of any new DKIM headers, then add the "normals" rlist to it.
@@ -1617,7 +1637,7 @@ g = arc_sign_append_aar(g, &arc_sign_ctx, identity, instance, &ar);
b = arc_ams_setup_sign_bodyhash();
g = arc_sign_append_ams(g, &arc_sign_ctx, instance, identity, selector,
- &b->bh, headers_rlist, privkey);
+ &b->bh, headers_rlist, privkey, options);
/*
- Generate AS
@@ -1632,7 +1652,8 @@ g = arc_sign_append_ams(g, &arc_sign_ctx, instance, identity, selector,
including self (but with an empty b= in self)
*/
-g = arc_sign_prepend_as(g, &arc_sign_ctx, instance, identity, selector, &ar, privkey);
+g = arc_sign_prepend_as(g, &arc_sign_ctx, instance, identity, selector, &ar,
+ privkey, options);
/* Finally, append the dkim headers and return the lot. */