X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/f3ebb786e451da973560f1c9d8cdb151d25108b5..40bffa31bd7057a0e88e29bb76fa63382d4aa1bc:/src/src/arc.c diff --git a/src/src/arc.c b/src/src/arc.c index c266849ca..391af077d 100644 --- a/src/src/arc.c +++ b/src/src/arc.c @@ -2,15 +2,13 @@ * Exim - an Internet mail transport agent * *************************************************/ /* Experimental ARC support for Exim - Copyright (c) Jeremy Harris 2018 + Copyright (c) Jeremy Harris 2018 - 2020 License: GPL */ #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 @@ -383,7 +381,7 @@ adding instances as needed and checking for duplicate lines. static uschar * arc_insert_hdr(arc_ctx * ctx, header_line * h, unsigned off, unsigned hoff, - BOOL instance_only) + BOOL instance_only, arc_line ** alp_ret) { unsigned i; arc_set * as; @@ -403,6 +401,7 @@ if (!(as = arc_find_set(ctx, i))) return US"set find"; if (*(alp = (arc_line **)(US as + hoff))) return US"dup hdr"; *alp = al; +if (alp_ret) *alp_ret = al; return NULL; } @@ -426,7 +425,7 @@ if (strncmpic(ARC_HDR_AAR, h->text, ARC_HDRLEN_AAR) == 0) debug_printf("ARC: found AAR: %.*s\n", len, h->text); } if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AAR, offsetof(arc_set, hdr_aar), - TRUE))) + TRUE, NULL))) { DEBUG(D_acl) debug_printf("inserting AAR: %s\n", e); return US"inserting AAR"; @@ -445,15 +444,13 @@ else if (strncmpic(ARC_HDR_AMS, h->text, ARC_HDRLEN_AMS) == 0) debug_printf("ARC: found AMS: %.*s\n", len, h->text); } if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AMS, offsetof(arc_set, hdr_ams), - instance_only))) + instance_only, &ams))) { DEBUG(D_acl) debug_printf("inserting AMS: %s\n", e); return US"inserting AMS"; } /* defaults */ - /*XXX dubious selection of ams here */ - ams = ctx->arcset_chain->hdr_ams; if (!ams->c.data) { ams->c_head.data = US"simple"; ams->c_head.len = 6; @@ -471,7 +468,7 @@ else if (strncmpic(ARC_HDR_AS, h->text, ARC_HDRLEN_AS) == 0) debug_printf("ARC: found AS: %.*s\n", len, h->text); } if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AS, offsetof(arc_set, hdr_as), - instance_only))) + instance_only, NULL))) { DEBUG(D_acl) debug_printf("inserting AS: %s\n", e); return US"inserting AS"; @@ -544,7 +541,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"); @@ -599,7 +597,7 @@ uschar * dns_txt; pdkim_pubkey * p; if (!(dns_txt = dkim_exim_query_dns_txt(string_sprintf("%.*s._domainkey.%.*s", - al->s.len, al->s.data, al->d.len, al->d.data)))) + (int)al->s.len, al->s.data, (int)al->d.len, al->d.data)))) { DEBUG(D_acl) debug_printf("pubkey dns lookup fail\n"); return NULL; @@ -639,7 +637,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 */ @@ -737,7 +735,7 @@ arc_get_verify_hhash(ctx, ams, &hhash); /* Setup the interface to the signing library */ -if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx))) +if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx, NULL))) { DEBUG(D_acl) debug_printf("ARC verify init: %s\n", errstr); as->ams_verify_done = arc_state_reason = US"internal sigverify init error"; @@ -745,6 +743,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 +874,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"); @@ -960,14 +964,12 @@ if (!(p = arc_line_to_pubkey(hdr_as))) /* We know the b-tag blob is of a nul-term string, so safe as a string */ pdkim_decode_base64(hdr_as->b.data, &sighash); -if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx))) +if ((errstr = exim_dkim_verify_init(&p->key, KEYFMT_DER, &vctx, NULL))) { DEBUG(D_acl) debug_printf("ARC verify init: %s\n", errstr); 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))) @@ -1190,7 +1192,7 @@ static gstring * arc_sign_append_aar(gstring * g, arc_ctx * ctx, const uschar * identity, int instance, blob * ar) { -int aar_off = g ? g->ptr : 0; +int aar_off = gstring_length(g); arc_set * as = store_get(sizeof(arc_set) + sizeof(arc_line) + sizeof(header_line), FALSE); arc_line * al = (arc_line *)(as+1); @@ -1416,10 +1418,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 +1439,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 +1463,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 +1498,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 +1753,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 +1778,9 @@ if (!(b = arc_ams_setup_vfy_bodyhash(&al))) should have been created here. */ return NULL; + +badline: + return US"line parsing error"; } @@ -1848,7 +1872,7 @@ return g; } -# endif /* SUPPORT_SPF */ +# endif /* DISABLE_DKIM */ #endif /* EXPERIMENTAL_ARC */ /* vi: aw ai sw=2 */