X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Farc.c;h=f4ae096bc26731a6dbd15eb19dcb15392c59c75b;hp=1323a451a530079a8ce656997f06c66f0728ac6f;hb=3d0a6e0fcf175e8416f344939b60c918c0f0f418;hpb=617d39327e65b7fccc41a12b4a5e2940d6327c9f diff --git a/src/src/arc.c b/src/src/arc.c index 1323a451a..f4ae096bc 100644 --- a/src/src/arc.c +++ b/src/src/arc.c @@ -66,7 +66,7 @@ typedef struct arc_set { arc_line * hdr_ams; arc_line * hdr_as; - BOOL ams_verify_done; + const uschar * ams_verify_done; BOOL ams_verify_passed; } arc_set; @@ -96,9 +96,9 @@ Return 0 on error */ static unsigned arc_instance_from_hdr(const arc_line * al) { -uschar * s = al->i.data; +const uschar * s = al->i.data; if (!s || !al->i.len) return 0; -return (unsigned) atoi(s); +return (unsigned) atoi(CCS s); } @@ -186,7 +186,7 @@ static uschar * arc_parse_line(arc_line * al, header_line * h, unsigned off, BOOL instance_only) { uschar * s = h->text + off; -uschar * r; +uschar * r = NULL; /* compiler-quietening */ uschar c; al->complete = h; @@ -482,7 +482,7 @@ static const uschar * arc_vfy_collect_hdrs(arc_ctx * ctx) { header_line * h; -hdr_rlist * r, * rprev = NULL; +hdr_rlist * r = NULL, * rprev = NULL; const uschar * e; DEBUG(D_acl) debug_printf("ARC: collecting arc sets\n"); @@ -495,7 +495,10 @@ for (h = header_list; h; h = h->next) rprev = r; if ((e = arc_try_header(ctx, h, FALSE))) - return e; + { + arc_state_reason = string_sprintf("collecting headers: %s", e); + return US"fail"; + } } headers_rlist = r; @@ -561,11 +564,11 @@ while ((hn = string_nextinlist(&headernames, &sep, NULL, 0))) 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); @@ -612,7 +615,7 @@ if (p->hashes) if (!ele) { DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%.*s\n", - p->hashes, al->a.len, al->a.data); + p->hashes, (int)al->a.len, al->a.data); return NULL; } } @@ -644,7 +647,7 @@ return pdkim_set_bodyhash(dkim_verify_ctx, and without a DKIM v= tag. */ -static uschar * +static const uschar * arc_ams_verify(arc_ctx * ctx, arc_set * as) { arc_line * ams = as->hdr_ams; @@ -656,7 +659,7 @@ ev_ctx vctx; int hashtype; const uschar * errstr; -as->ams_verify_done = TRUE; +as->ams_verify_done = US"in-progress"; /* Check the AMS has all the required tags: "a=" algorithm @@ -668,21 +671,27 @@ as->ams_verify_done = TRUE; */ if ( !ams->a.data || !ams->b.data || !ams->bh.data || !ams->d.data || !ams->h.data || !ams->s.data) + { + as->ams_verify_done = arc_state_reason = US"required tag missing"; return US"fail"; + } /* The bodyhash should have been created earlier, and the dkim code should have managed calculating it during message input. Find the reference to it. */ if (!(b = arc_ams_setup_vfy_bodyhash(ams))) + { + as->ams_verify_done = arc_state_reason = US"internal hash setup error"; return US"fail"; + } DEBUG(D_acl) { debug_printf("ARC i=%d AMS Body bytes hashed: %lu\n" " Body %.*s computed: ", as->instance, b->signed_body_bytes, - ams->a_hash.len, ams->a_hash.data); + (int)ams->a_hash.len, ams->a_hash.data); pdkim_hexprint(CUS b->bh.data, b->bh.len); } @@ -699,7 +708,7 @@ if ( !ams->bh.data pdkim_hexprint(sighash.data, sighash.len); debug_printf("ARC i=%d AMS Body hash did NOT match\n", as->instance); } - return US"body hash compare mismatch"; + return as->ams_verify_done = arc_state_reason = US"AMS body hash miscompare"; } DEBUG(D_acl) debug_printf("ARC i=%d AMS Body hash compared OK\n", as->instance); @@ -707,7 +716,7 @@ DEBUG(D_acl) debug_printf("ARC i=%d AMS Body hash compared OK\n", as->instance); /* Get the public key from DNS */ if (!(p = arc_line_to_pubkey(ams))) - return US"pubkey problem"; + return as->ams_verify_done = arc_state_reason = US"pubkey problem"; /* We know the b-tag blob is of a nul-term string, so safe as a string */ pdkim_decode_base64(ams->b.data, &sighash); @@ -719,6 +728,7 @@ arc_get_verify_hhash(ctx, ams, &hhash); if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx))) { DEBUG(D_acl) debug_printf("ARC verify init: %s\n", errstr); + as->ams_verify_done = arc_state_reason = US"internal sigverify init error"; return US"fail"; } @@ -728,7 +738,7 @@ if ((errstr = exim_dkim_verify(&vctx, pdkim_hashes[hashtype].exim_hashmethod, &hhash, &sighash))) { DEBUG(D_acl) debug_printf("ARC i=%d AMS verify %s\n", as->instance, errstr); - return US"ams sig verify fail"; + return as->ams_verify_done = arc_state_reason = US"AMS sig nonverify"; } DEBUG(D_acl) debug_printf("ARC i=%d AMS verify pass\n", as->instance); @@ -761,8 +771,9 @@ for(inst = 0; as; as = as->next) || arc_cv_match(as->hdr_as, US"fail") ) { - DEBUG(D_acl) debug_printf("ARC i=%d fail" - " (cv, sequence or missing header)\n", as->instance); + arc_state_reason = string_sprintf("i=%d fail" + " (cv, sequence or missing header)", as->instance); + DEBUG(D_acl) debug_printf("ARC %s\n", arc_state_reason); ret = US"fail"; } @@ -775,6 +786,7 @@ for(inst = 0; as; as = as->next) ams_fail_found = TRUE; else arc_oldest_pass = inst; + arc_state_reason = NULL; } arc_received = ctx->arcset_chain_last; @@ -785,7 +797,12 @@ if (ret) /* We can skip the latest-AMS validation, if we already did it. */ as = ctx->arcset_chain_last; -if (as->ams_verify_done ? !as->ams_verify_passed : !!arc_ams_verify(ctx, as)) +if (as->ams_verify_done && !as->ams_verify_passed) + { + arc_state_reason = as->ams_verify_done; + return US"fail"; + } +if (!!arc_ams_verify(ctx, as)) return US"fail"; return NULL; @@ -822,7 +839,10 @@ DEBUG(D_acl) debug_printf("ARC: AS vfy i=%d\n", as->instance); if ( as->instance == 1 && !arc_cv_match(hdr_as, US"none") || arc_cv_match(hdr_as, US"none") && as->instance != 1 ) + { + arc_state_reason = US"seal cv state"; return US"fail"; + } /* 3. Initialize a hash function corresponding to the "a" tag of @@ -835,6 +855,7 @@ if (!exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod)) { DEBUG(D_acl) debug_printf("ARC: hash setup error, possibly nonhandled hashtype\n"); + arc_state_reason = US"seal hash setup error"; return US"fail"; } @@ -844,6 +865,8 @@ if (!exim_sha_init(&hhash_ctx, pdkim_hashes[hashtype].exim_hashmethod)) 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"); @@ -874,7 +897,7 @@ for (as2 = ctx->arcset_chain; 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); @@ -891,7 +914,7 @@ exim_sha_finish(&hhash_ctx, &hhash_computed); DEBUG(D_acl) { debug_printf("ARC i=%d AS Header %.*s computed: ", - as->instance, hdr_as->a_hash.len, hdr_as->a_hash.data); + as->instance, (int)hdr_as->a_hash.len, hdr_as->a_hash.data); pdkim_hexprint(hhash_computed.data, hhash_computed.len); } @@ -931,6 +954,7 @@ if ((errstr = exim_dkim_verify(&vctx, { DEBUG(D_acl) debug_printf("ARC i=%d AS headers verify: %s\n", as->instance, errstr); + arc_state_reason = US"seal sigverify error"; return US"fail"; } @@ -1085,7 +1109,7 @@ hdr_rlist * rheaders = NULL; s = sigheaders ? sigheaders->s : NULL; if (s) while (*s) { - uschar * s2; + const uschar * s2 = s; /* This works for either NL or CRLF lines; also nul-termination */ while (*++s2) @@ -1306,10 +1330,8 @@ if (g->s[g->ptr - 1] == ':') g->ptr--; 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 */ @@ -1353,7 +1375,7 @@ while ((methodspec = string_nextinlist(&resinfo, &sep, NULL, 0))) (c = *s) && c != ';' && c != ' ' && c != '\r' && c != '\n'; ) s++; return string_copyn(methodspec, s - methodspec); } -return NULL; +return US"none"; } @@ -1370,7 +1392,6 @@ arc_set * as; uschar * status = arc_ar_cv_status(ar); arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line)); header_line * h = (header_line *)(al+1); -uschar * s; gstring * hdata = NULL; int hashtype = pdkim_hashname_to_hashtype(US"sha256", 6); /*XXX hardwired */ @@ -1395,7 +1416,7 @@ arcset = string_append(NULL, 10, ARC_HDR_AS, US" i=", string_sprintf("%d", instance), US"; cv=", status, - US"; a=rsa-sha256; c=relaxed; d=", identity, /*XXX hardwired */ + US"; a=rsa-sha256; d=", identity, /*XXX hardwired */ US"; s=", selector, /*XXX same as AMS */ US";\r\n\t b=;"); @@ -1419,7 +1440,7 @@ for (as = Ustrcmp(status, US"fail") == 0 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 */ @@ -1684,14 +1705,17 @@ authres_arc(gstring * g) if (arc_state) { arc_line * highest_ams; - int start; + int start = 0; /* Compiler quietening */ DEBUG(D_acl) start = g->ptr; g = string_append(g, 2, US";\n\tarc=", arc_state); if (arc_received_instance > 0) { g = string_append(g, 3, US" (i=", - string_sprintf("%d", arc_received_instance), US") header.s="); + string_sprintf("%d", arc_received_instance), US")"); + if (arc_state_reason) + g = string_append(g, 3, US"(", arc_state_reason, US")"); + g = string_catn(g, US" header.s=", 10); highest_ams = arc_received->hdr_ams; g = string_catn(g, highest_ams->s.data, highest_ams->s.len);