X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/044152b326039eaaefc45e88ef501c4b7e615cef..a85c067ba6c6940512cf57ec213277a370d87e70:/src/src/pdkim/pdkim.c diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index ca16e2b74..eb26b3864 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -1,8 +1,10 @@ /* * PDKIM - a RFC4871 (DKIM) implementation * + * Copyright (c) The Exim Maintainers 2021 - 2022 * Copyright (C) 2009 - 2016 Tom Kistner * Copyright (C) 2016 - 2020 Jeremy Harris + * SPDX-License-Identifier: GPL-2.0-or-later * * http://duncanthrax.net/pdkim/ * @@ -107,7 +109,7 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = { }; -static blob lineending = {.data = US"\r\n", .len = 2}; +static const blob lineending = {.data = US"\r\n", .len = 2}; /* -------------------------------------------------------------------------- */ uschar * @@ -247,7 +249,7 @@ debug_printf("\n"); static pdkim_stringlist * pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str) { -pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), FALSE); +pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), GET_UNTAINTED); memset(new_entry, 0, sizeof(pdkim_stringlist)); new_entry->value = string_copy(str); @@ -337,7 +339,7 @@ pdkim_relax_header_n(const uschar * header, int len, BOOL append_crlf) { BOOL past_field_name = FALSE; BOOL seen_wsp = FALSE; -uschar * relaxed = store_get(len+3, TRUE); /* tainted */ +uschar * relaxed = store_get(len+3, GET_TAINTED); uschar * q = relaxed; for (const uschar * p = header; p - header < len; p++) @@ -417,7 +419,7 @@ pdkim_decode_qp(const uschar * str) int nchar = 0; uschar * q; const uschar * p = str; -uschar * n = store_get(Ustrlen(str)+1, TRUE); +uschar * n = store_get(Ustrlen(str)+1, GET_TAINTED); *n = '\0'; q = n; @@ -474,7 +476,7 @@ BOOL past_hname = FALSE; BOOL in_b_val = FALSE; int where = PDKIM_HDR_LIMBO; -sig = store_get(sizeof(pdkim_signature), FALSE); +sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED); memset(sig, 0, sizeof(pdkim_signature)); sig->bodylength = -1; @@ -483,7 +485,7 @@ sig->version = 0; sig->keytype = -1; sig->hashtype = -1; -q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, TRUE); /* tainted */ +q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, GET_TAINTED); for (uschar * p = raw_hdr; ; p++) { @@ -663,7 +665,7 @@ const uschar * ele; int sep = ';'; pdkim_pubkey * pub; -pub = store_get(sizeof(pdkim_pubkey), TRUE); /* tainted */ +pub = store_get(sizeof(pdkim_pubkey), GET_TAINTED); memset(pub, 0, sizeof(pdkim_pubkey)); while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0))) @@ -720,9 +722,11 @@ return NULL; If we have to relax the data for this sig, return our copy of it. */ static blob * -pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, blob * orig_data, blob * relaxed_data) +pdkim_update_ctx_bodyhash(pdkim_bodyhash * b, const blob * orig_data, blob * relaxed_data) { -blob * canon_data = orig_data; +const blob * canon_data = orig_data; +size_t left; + /* Defaults to simple canon (no further treatment necessary) */ if (b->canon_method == PDKIM_CANON_RELAXED) @@ -767,16 +771,17 @@ if (b->canon_method == PDKIM_CANON_RELAXED) } /* Make sure we don't exceed the to-be-signed body length */ +left = canon_data->len; if ( b->bodylength >= 0 - && b->signed_body_bytes + (unsigned long)canon_data->len > b->bodylength + && left > (unsigned long)b->bodylength - b->signed_body_bytes ) - canon_data->len = b->bodylength - b->signed_body_bytes; + left = (unsigned long)b->bodylength - b->signed_body_bytes; -if (canon_data->len > 0) +if (left > 0) { - exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, canon_data->len); - b->signed_body_bytes += canon_data->len; - DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len); + exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, left); + b->signed_body_bytes += left; + DEBUG(D_acl) pdkim_quoteprint(canon_data->data, left); } return relaxed_data; @@ -790,8 +795,9 @@ pdkim_finish_bodyhash(pdkim_ctx * ctx) { for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next) /* Finish hashes */ { - DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %d/%d/%ld len %ld\n", - b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes); + DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %s/%s/%ld len %ld\n", + pdkim_hashes[b->hashtype].dkim_hashname, pdkim_canons[b->canon_method], + b->bodylength, b->signed_body_bytes); exim_sha_finish(&b->body_hash_ctx, &b->bh); } @@ -802,10 +808,10 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) DEBUG(D_acl) { - debug_printf("DKIM [%s] Body bytes (%s) hashed: %lu\n" - "DKIM [%s] Body %s computed: ", - sig->domain, pdkim_canons[b->canon_method], b->signed_body_bytes, - sig->domain, pdkim_hashes[b->hashtype].dkim_hashname); + debug_printf("DKIM [%s]%s Body bytes (%s) hashed: %lu\n" + "DKIM [%s]%s Body %s computed: ", + sig->domain, sig->selector, pdkim_canons[b->canon_method], b->signed_body_bytes, + sig->domain, sig->selector, pdkim_hashes[b->hashtype].dkim_hashname); pdkim_hexprint(CUS b->bh.data, b->bh.len); } @@ -822,7 +828,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) /* VERIFICATION --------------------------------------------------------- */ /* Be careful that the header sig included a bodyash */ - if ( sig->bodyhash.data + if (sig->bodyhash.data && sig->bodyhash.len == b->bh.len && memcmp(b->bh.data, sig->bodyhash.data, b->bh.len) == 0) { DEBUG(D_acl) debug_printf("DKIM [%s] Body hash compared OK\n", sig->domain); @@ -1003,7 +1009,7 @@ else last_sig->next = sig; } - if (--dkim_collect_input == 0) + if (dkim_collect_input && --dkim_collect_input == 0) { ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s); ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; @@ -1261,7 +1267,7 @@ if (sig->identity) if (sig->created > 0) { - uschar minibuf[20]; + uschar minibuf[21]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created); hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf); @@ -1269,7 +1275,7 @@ if (sig->created > 0) if (sig->expires > 0) { - uschar minibuf[20]; + uschar minibuf[21]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires); hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf); @@ -1277,7 +1283,7 @@ if (sig->expires > 0) if (sig->bodylength >= 0) { - uschar minibuf[20]; + uschar minibuf[21]; snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength); hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf); @@ -1608,7 +1614,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */ /* Feed header to the hash algorithm */ - exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh)); + exim_sha_update_string(&hhash_ctx, CUS rh); /* Remember headers block for signing (when the library cannot do incremental) */ /*XXX we could avoid doing this for all but the GnuTLS/RSA case */ @@ -1669,7 +1675,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) : string_copy(CUS hdrs->value); /* Feed header to the hash algorithm */ - exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh)); + exim_sha_update_string(&hhash_ctx, CUS rh); DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh)); hdrs->tag = 1; @@ -1710,7 +1716,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) } /* Finalize header hash */ - exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr)); + exim_sha_update_string(&hhash_ctx, CUS sig_hdr); exim_sha_finish(&hhash_ctx, &hhash); DEBUG(D_acl) @@ -1915,14 +1921,14 @@ pdkim_init_verify(uschar * (*dns_txt_callback)(const uschar *), BOOL dot_stuffin { pdkim_ctx * ctx; -ctx = store_get(sizeof(pdkim_ctx), FALSE); +ctx = store_get(sizeof(pdkim_ctx), GET_UNTAINTED); memset(ctx, 0, sizeof(pdkim_ctx)); if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM; /* The line-buffer is for message data, hence tainted */ -ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE); +ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED); ctx->dns_txt_callback = dns_txt_callback; -ctx->cur_header = string_get_tainted(36, TRUE); +ctx->cur_header = string_get_tainted(36, GET_TAINTED); return ctx; } @@ -1943,7 +1949,7 @@ if (!domain || !selector || !privkey) /* Allocate & init one signature struct */ -sig = store_get(sizeof(pdkim_signature), FALSE); +sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED); memset(sig, 0, sizeof(pdkim_signature)); sig->bodylength = -1; @@ -2024,14 +2030,14 @@ for (b = ctx->bodyhash; b; b = b->next) && canon_method == b->canon_method && bodylength == b->bodylength) { - DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %d/%d/%ld\n", - hashtype, canon_method, bodylength); + DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %s/%s/%ld\n", + pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength); return b; } -DEBUG(D_receive) debug_printf("DKIM: new bodyhash %d/%d/%ld\n", - hashtype, canon_method, bodylength); -b = store_get(sizeof(pdkim_bodyhash), FALSE); +DEBUG(D_receive) debug_printf("DKIM: new bodyhash %s/%s/%ld\n", + pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength); +b = store_get(sizeof(pdkim_bodyhash), GET_UNTAINTED); b->next = ctx->bodyhash; b->hashtype = hashtype; b->canon_method = canon_method; @@ -2076,7 +2082,7 @@ pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed, memset(ctx, 0, sizeof(pdkim_ctx)); ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN; /* The line buffer is for message data, hence tainted */ -ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE); +ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED); DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback; }