X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c5db348c5e29e93e51389fa0079f829967c5da82..1eedc10f0c518d1878a5d94ff17b84cad233b23e:/src/src/pdkim/pdkim.c?ds=sidebyside diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 1420b1a79..679607dbd 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -224,13 +224,13 @@ static void pdkim_strtrim(gstring * str) { uschar * p = str->s; -uschar * q = p + str->ptr; +uschar * q; while (*p == '\t' || *p == ' ') /* dump the leading whitespace */ { str->size--; str->ptr--; str->s++; } while ( str->ptr > 0 - && (q = str->s + str->ptr - 1), *q == '\t' || *q == ' ' + && ((q = str->s + str->ptr - 1), (*q == '\t' || *q == ' ')) ) str->ptr--; /* dump trailing whitespace */ @@ -250,16 +250,19 @@ pdkim_free_ctx(pdkim_ctx *ctx) /* -------------------------------------------------------------------------- */ /* Matches the name of the passed raw "header" against the passed colon-separated "tick", and invalidates - the entry in tick. Returns OK or fail-code */ -/*XXX might be safer done using a pdkim_stringlist for "tick" */ + the entry in tick. Entries can be prefixed for multi- or over-signing, + in which case do not invalidate. + + Returns OK for a match, or fail-code +*/ static int header_name_match(const uschar * header, uschar * tick) { -uschar * hname; -uschar * lcopy; -uschar * p; -uschar * q; +const uschar * ticklist = tick; +int sep = ':'; +BOOL multisign; +uschar * hname, * p, * ele; uschar * hcolon = Ustrchr(header, ':'); /* Get header name */ if (!hcolon) @@ -268,27 +271,22 @@ if (!hcolon) /* if we had strncmpic() we wouldn't need this copy */ hname = string_copyn(header, hcolon-header); -/* Copy tick-off list locally, so we can punch zeroes into it */ -p = lcopy = string_copy(tick); - -for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':')) +while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0)) { - *q = '\0'; - if (strcmpic(p, hname) == 0) - goto found; - - p = q+1; + switch (*ele) + { + case '=': case '+': multisign = TRUE; ele++; break; + default: multisign = FALSE; break; } -if (strcmpic(p, hname) == 0) - goto found; - + if (strcmpic(ele, hname) == 0) + { + if (!multisign) + *p = '_'; /* Invalidate this header name instance in tick-off list */ + return PDKIM_OK; + } + } return PDKIM_FAIL; - -found: - /* Invalidate header name instance in tick-off list */ - tick[p-lcopy] = '_'; - return PDKIM_OK; } @@ -492,7 +490,12 @@ for (p = raw_hdr; ; p++) if (c == ';' || c == '\0') { - if (cur_tag && cur_val) + /* We must have both tag and value, and tags must be one char except + for the possibility of "bh". */ + + if ( cur_tag && cur_val + && (cur_tag->ptr == 1 || *cur_tag->s == 'b') + ) { (void) string_from_gstring(cur_val); pdkim_strtrim(cur_val); @@ -502,8 +505,14 @@ for (p = raw_hdr; ; p++) switch (*cur_tag->s) { case 'b': - pdkim_decode_base64(cur_val->s, - cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash); + switch (cur_tag->s[1]) + { + case '\0': pdkim_decode_base64(cur_val->s, &sig->sighash); break; + case 'h': if (cur_tag->ptr == 2) + pdkim_decode_base64(cur_val->s, &sig->bodyhash); + break; + default: break; + } break; case 'v': /* We only support version 1, and that is currently the @@ -645,7 +654,8 @@ while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0))) } /* Set fallback defaults */ -if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION); +if (!pub->version) + pub->version = string_copy(PDKIM_PUB_RECORD_VERSION); else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) { DEBUG(D_acl) debug_printf(" Bad v= field\n"); @@ -1296,10 +1306,7 @@ pdkim_pubkey * p; dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain); -dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN); -memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN); - -if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK +if ( !(dns_txt_reply = ctx->dns_txt_callback(CS dns_txt_name)) || dns_txt_reply[0] == '\0' ) { @@ -1445,11 +1452,17 @@ for (sig = ctx->sig; sig; sig = sig->next) } } - /* Any headers we wanted to sign but were not present must also be listed */ + /* Any headers we wanted to sign but were not present must also be listed. + Ignore elements that have been ticked-off or are marked as never-oversign. */ + l = sig->sign_headers; while((s = string_nextinlist(&l, &sep, NULL, 0))) - if (*s != '_') + { + if (*s == '+') /* skip oversigning marker */ + s++; + if (*s != '_' && *s != '=') g = string_append_listele(g, ':', s); + } sig->headernames = string_from_gstring(g); /* Create signature header with b= omitted */ @@ -1697,7 +1710,7 @@ return PDKIM_OK; /* -------------------------------------------------------------------------- */ DLLEXPORT pdkim_ctx * -pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing) +pdkim_init_verify(uschar * (*dns_txt_callback)(char *), BOOL dot_stuffing) { pdkim_ctx * ctx; @@ -1801,7 +1814,7 @@ return; void pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed, - int(*dns_txt_callback)(char *, char *)) + uschar * (*dns_txt_callback)(char *)) { memset(ctx, 0, sizeof(pdkim_ctx)); ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;