break;
}
-/* Finally add in the signature header (with the b= tag stripped) */
+/* Finally add in the signature header (with the b= tag stripped); no CRLF */
s = ams->rawsig_no_b_val.data, len = ams->rawsig_no_b_val.len;
if (relaxed)
- len = Ustrlen(s = pdkim_relax_header_n(s, len, TRUE));
+ len = Ustrlen(s = pdkim_relax_header_n(s, len, FALSE));
DEBUG(D_acl) pdkim_quoteprint(s, len);
exim_sha_update(&hhash_ctx, s, len);
int canon_head, canon_body;
long bodylen;
+if (!ams->c.data) ams->c.data = US"simple"; /* RFC 6376 (DKIM) default */
pdkim_cstring_to_canons(ams->c.data, ams->c.len, &canon_head, &canon_body);
bodylen = ams->l.data
? strtol(CS string_copyn(ams->l.data, ams->l.len), NULL, 10) : -1;
|| arc_cv_match(as->hdr_as, US"fail")
)
{
- arc_state_reason = string_sprintf("i=%d fail"
+ arc_state_reason = string_sprintf("i=%d"
" (cv, sequence or missing header)", as->instance);
- DEBUG(D_acl) debug_printf("ARC %s\n", arc_state_reason);
- ret = US"fail";
+ DEBUG(D_acl) debug_printf("ARC chain fail at %s\n", arc_state_reason);
+ return US"fail";
}
/* Evaluate the oldest-pass AMS validation while we're here.
header canonicalization defined in Section 3.4.2 of
[RFC6376]. Pass the canonicalized result to the hash
function.
+
+Headers are CRLF-separated, but the last one is not crlf-terminated.
*/
DEBUG(D_acl) debug_printf("ARC: AS header data for verification:\n");
al = as2->hdr_as;
if (as2->instance == as->instance)
s = pdkim_relax_header_n(al->rawsig_no_b_val.data,
- al->rawsig_no_b_val.len, TRUE);
+ al->rawsig_no_b_val.len, FALSE);
else if (!(s = al->relaxed))
al->relaxed = s = pdkim_relax_header_n(al->complete->text,
al->complete->slen, TRUE);
{
DEBUG(D_acl)
debug_printf("ARC i=%d AS headers verify: %s\n", as->instance, errstr);
- arc_state_reason = US"seal sigverify init error";
+ arc_state_reason = US"seal sigverify error";
return US"fail";
}
arc_ctx ctx = { NULL };
const uschar * res;
+if (!dkim_verify_ctx)
+ {
+ DEBUG(D_acl) debug_printf("ARC: no DKIM verify context\n");
+ return NULL;
+ }
+
/* AS evaluation, per
https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-10#section-6
*/
/* Walk the given headers strings identifying each header, and construct
-a reverse-order list. Also parse ARC-chain headers and build the chain
-struct, retaining pointers into the string.
+a reverse-order list.
*/
static hdr_rlist *
g = string_catn(g, US";\r\n\tb=;", 7);
/* Include the pseudo-header in the accumulation */
-/*XXX should that be prepended rather than appended? */
-/*XXX also need to include at the verify stage */
-s = pdkim_relax_header_n(g->s + ams_off, g->ptr - ams_off, TRUE);
+s = pdkim_relax_header_n(g->s + ams_off, g->ptr - ams_off, FALSE);
hdata = string_cat(hdata, s);
/* Calculate the signature from the accumulation */
(c = *s) && c != ';' && c != ' ' && c != '\r' && c != '\n'; ) s++;
return string_copyn(methodspec, s - methodspec);
}
-return NULL;
+return US"none";
}
h = as->hdr_ams->complete;
hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, TRUE));
h = as->hdr_as->complete;
- hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, TRUE));
+ hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, !!as->next));
}
/* Calculate the signature from the accumulation */
+void
+arc_sign_init(void)
+{
+memset(&arc_sign_ctx, 0, sizeof(arc_sign_ctx));
+}
+
+
+
/* A "normal" header line, identified by DKIM processing. These arrive before
the call to arc_sign(), which carries any newly-created DKIM headers - and
those go textually before the normal ones in the message.
if ( !*identity | !*selector
|| !(privkey = string_nextinlist(&signspec, &sep, NULL, 0)) || !*privkey)
{
- log_write(0, LOG_MAIN|LOG_PANIC, "ARC: bad signing-specification");
+ log_write(0, LOG_MAIN|LOG_PANIC, "ARC: bad signing-specification (%s)",
+ !*identity ? "identity" : !*selector ? "selector" : "private-key");
return NULL;
}
if (*privkey == '/' && !(privkey = expand_file_big_buffer(privkey)))
DEBUG(D_transport) debug_printf("ARC: sign for %s\n", identity);
-/*
-- scan headers for existing ARC chain & A-R (with matching system-identfier)
- - paniclog & skip on problems (no A-R)
-*/
-
-/* Make an rlist of any new DKIM headers, then add the "normals" rlist to it */
+/* Make an rlist of any new DKIM headers, then add the "normals" rlist to it.
+Then scan the list for an A-R header. */
string_from_gstring(sigheaders);
if ((rheaders = arc_sign_scan_headers(&arc_sign_ctx, sigheaders)))
}
else
rheaders = headers_rlist;
+
/* Finally, build a normal-order headers list */
/*XXX only needed for hunt-the-AR? */
-{
-header_line * hnext = NULL;
-for (; rheaders; hnext = rheaders->h, rheaders = rheaders->prev)
- rheaders->h->next = hnext;
-headers = hnext;
-}
-
-instance = arc_sign_ctx.arcset_chain_last ? arc_sign_ctx.arcset_chain_last->instance + 1 : 1;
+ {
+ header_line * hnext = NULL;
+ for (; rheaders; hnext = rheaders->h, rheaders = rheaders->prev)
+ rheaders->h->next = hnext;
+ headers = hnext;
+ }
if (!(arc_sign_find_ar(headers, identity, &ar)))
{
return sigheaders ? sigheaders : string_get(0);
}
+/* We previously built the data-struct for the existing ARC chain, if any, using a headers
+feed from the DKIM module. Use that to give the instance number for the ARC set we are
+about to build. */
+
+DEBUG(D_transport)
+ if (arc_sign_ctx.arcset_chain_last)
+ debug_printf("ARC: existing chain highest instance: %d\n",
+ arc_sign_ctx.arcset_chain_last->instance);
+ else
+ debug_printf("ARC: no existing chain\n");
+
+instance = arc_sign_ctx.arcset_chain_last ? arc_sign_ctx.arcset_chain_last->instance + 1 : 1;
+
/*
- Generate AAR
- copy the A-R; prepend i= & identity
if (sender_host_address)
g = string_append(g, 2, US" smtp.client-ip=", sender_host_address);
}
+ else if (arc_state_reason)
+ g = string_append(g, 3, US" (", arc_state_reason, US")");
DEBUG(D_acl) debug_printf("ARC: authres '%.*s'\n",
g->ptr - start - 3, g->s + start + 3);
}