Merge branch '4.next'
[exim.git] / src / src / arc.c
index 773b34c28da25758105d4f861072b98a292ed410..857e0c0468ca6095f0832e9ba6f81ec6afb1cdbb 100644 (file)
@@ -7,10 +7,8 @@
 */
 
 #include "exim.h"
-#ifdef EXPERIMENTAL_ARC
-# if !defined SUPPORT_SPF
-#  error SPF must also be enabled for ARC
-# elif defined DISABLE_DKIM
+#if defined EXPERIMENTAL_ARC
+# if defined DISABLE_DKIM
 #  error DKIM must also be enabled for ARC
 # else
 
@@ -544,7 +542,8 @@ hctx hhash_ctx;
 const uschar * s;
 int len;
 
-if (!exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
+if (  hashtype == -1
+   || !exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
   {
   DEBUG(D_acl)
       debug_printf("ARC: hash setup error, possibly nonhandled hashtype\n");
@@ -639,7 +638,7 @@ return p;
 static pdkim_bodyhash *
 arc_ams_setup_vfy_bodyhash(arc_line * ams)
 {
-int canon_head, canon_body;
+int canon_head = -1, canon_body = -1;
 long bodylen;
 
 if (!ams->c.data) ams->c.data = US"simple";    /* RFC 6376 (DKIM) default */
@@ -745,6 +744,11 @@ if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx)))
   }
 
 hashtype = pdkim_hashname_to_hashtype(ams->a_hash.data, ams->a_hash.len);
+if (hashtype == -1)
+  {
+  DEBUG(D_acl) debug_printf("ARC i=%d AMS verify bad a_hash\n", as->instance);
+  return as->ams_verify_done = arc_state_reason = US"AMS sig nonverify";
+  }
 
 if ((errstr = exim_dkim_verify(&vctx,
          pdkim_hashes[hashtype].exim_hashmethod, &hhash, &sighash)))
@@ -871,7 +875,8 @@ if (  as->instance == 1 && !arc_cv_match(hdr_as, US"none")
 
 hashtype = pdkim_hashname_to_hashtype(hdr_as->a_hash.data, hdr_as->a_hash.len);
 
-if (!exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
+if (  hashtype == -1
+   || !exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
   {
   DEBUG(D_acl)
       debug_printf("ARC: hash setup error, possibly nonhandled hashtype\n");
@@ -966,8 +971,6 @@ if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx)))
   return US"fail";
   }
 
-hashtype = pdkim_hashname_to_hashtype(hdr_as->a_hash.data, hdr_as->a_hash.len);
-
 if ((errstr = exim_dkim_verify(&vctx,
              pdkim_hashes[hashtype].exim_hashmethod,
              &hhash_computed, &sighash)))
@@ -1416,10 +1419,10 @@ arc_sign_prepend_as(gstring * arcset_interim, arc_ctx * ctx,
   const uschar * privkey, unsigned options)
 {
 gstring * arcset;
-arc_set * as;
 uschar * status = arc_ar_cv_status(ar);
 arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), FALSE);
 header_line * h = (header_line *)(al+1);
+uschar * badline_str;
 
 gstring * hdata = NULL;
 int hashtype = pdkim_hashname_to_hashtype(US"sha256", 6);      /*XXX hardwired */
@@ -1437,6 +1440,7 @@ blob sig;
       - all ARC set headers, set-number order, aar then ams then as,
         including self (but with an empty b= in self)
 */
+DEBUG(D_transport) debug_printf("ARC: building AS for status '%s'\n", status);
 
 /* Construct the AS except for the signature */
 
@@ -1460,18 +1464,25 @@ ctx->arcset_chain_last->hdr_as = al;
 /* For any but "fail" chain-verify status, walk the entire chain in order by
 instance.  For fail, only the new arc-set.  Accumulate the elements walked. */
 
-for (as = Ustrcmp(status, US"fail") == 0
+for (arc_set * as = Ustrcmp(status, US"fail") == 0
        ? ctx->arcset_chain_last : ctx->arcset_chain;
      as; as = as->next)
   {
+  arc_line * l;
   /* Accumulate AAR then AMS then AS.  Relaxed canonicalisation
   is required per standard. */
 
-  h = as->hdr_aar->complete;
+  badline_str = US"aar";
+  if (!(l = as->hdr_aar)) goto badline;
+  h = l->complete;
   hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, TRUE));
-  h = as->hdr_ams->complete;
+  badline_str = US"ams";
+  if (!(l = as->hdr_ams)) goto badline;
+  h = l->complete;
   hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, TRUE));
-  h = as->hdr_as->complete;
+  badline_str = US"as";
+  if (!(l = as->hdr_as)) goto badline;
+  h = l->complete;
   hdata = string_cat(hdata, pdkim_relax_header_n(h->text, h->slen, !!as->next));
   }
 
@@ -1488,6 +1499,11 @@ DEBUG(D_transport) debug_printf("ARC: AS  '%.*s'\n", arcset->ptr - 2, arcset->s)
 /* Finally, append the AMS and AAR to the new AS */
 
 return string_catn(arcset, arcset_interim->s, arcset_interim->ptr);
+
+badline:
+  DEBUG(D_transport)
+    debug_printf("ARC: while building AS, missing %s in chain\n", badline_str);
+  return NULL;
 }
 
 
@@ -1738,7 +1754,13 @@ memset(&al, 0, sizeof(arc_line));
 if ((errstr = arc_parse_line(&al, &h, ARC_HDRLEN_AMS, FALSE)))
   {
   DEBUG(D_acl) if (errstr) debug_printf("ARC: %s\n", errstr);
-  return US"line parsing error";
+  goto badline;
+  }
+
+if (!al.a_hash.data)
+  {
+  DEBUG(D_acl) debug_printf("ARC: no a_hash from '%.*s'\n", h.slen, h.text);
+  goto badline;
   }
 
 /* defaults */
@@ -1757,6 +1779,9 @@ if (!(b = arc_ams_setup_vfy_bodyhash(&al)))
 should have been created here. */
 
 return NULL;
+
+badline:
+  return US"line parsing error";
 }
 
 
@@ -1848,7 +1873,7 @@ return g;
 }
 
 
-# endif /* SUPPORT_SPF */
+# endif /* DISABLE_DKIM */
 #endif /* EXPERIMENTAL_ARC */
 /* vi: aw ai sw=2
  */