commit 31ffb91656af56afa7b2c13755f0a99862715b1f from: Martijn van Duren date: Sun Mar 27 11:41:00 2022 UTC rewrite dkim_body_parse, so that we don't copy the line. This means that we don't limit the line length anymore, but might cost a little extra computing overhead. Let's see how bad this can get. commit - 6eeac6a1096594678d2c82bc76aeebd8d631eea9 commit + 31ffb91656af56afa7b2c13755f0a99862715b1f blob - a27dd0e9f2a422391fdddab1e51e9567868f4c1a blob + 7d0f869c34860926dcf880ecb9cfd094a8ce18d3 --- main.c +++ main.c @@ -1373,20 +1373,12 @@ dkim_key_text_parse(struct signature *sig, const char void dkim_body_parse(struct message *msg, const char *line) { - char buf[999]; /* Line limit + 1 */ struct signature *sig; - size_t r, w; - ssize_t linelen; - size_t hashn, hashlf; - size_t i; - int canon = CANON_BODY_SIMPLE; + const char *end = line, *hash, *prev; + size_t hashn, len, i; + int wsp, ret; - linelen = (ssize_t)strlcpy(buf, line, sizeof(buf)); - if (linelen >= (ssize_t)sizeof(buf)) { - dkim_errx(msg, "Line too long"); - return; - } - if (buf[0] == '\0') { + if (line[0] == '\0') { msg->body_whitelines++; return; } @@ -1395,10 +1387,10 @@ dkim_body_parse(struct message *msg, const char *line) for (i = 0; i < msg->nheaders; i++) { if ((sig = msg->header[i].sig) == NULL) continue; - hashlf = sig->l == -1 ? 2 : MIN(2, sig->l); - sig->l -= sig->l == -1 ? 0 : hashlf; - if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) { - dkim_errx(msg, "Can't update hash context"); + hashn = sig->l == -1 ? 2 : MIN(2, sig->l); + sig->l -= sig->l == -1 ? 0 : hashn; + if (EVP_DigestUpdate(sig->bhctx, "\r\n", hashn) == 0) { + dkim_errx(msg, "EVP_DigestUpdate"); return; } } @@ -1406,38 +1398,53 @@ dkim_body_parse(struct message *msg, const char *line) msg->body_whitelines = 0; msg->has_body = 1; - hash: + while (line[0] != '\0') { + while (1) { + prev = end; + if ((end = osmtpd_ltok_skip_wsp(end, 0)) == NULL) + break; + } + end = prev; + wsp = end != line; + if (!wsp) { + while (osmtpd_ltok_skip_wsp(end, 0) == NULL && + end[0] != '\0') + end++; + } + for (i = 0; i < msg->nheaders; i++) { + sig = msg->header[i].sig; + if (sig == NULL || sig->state != DKIM_UNKNOWN) + continue; + if (wsp && + (sig->c & CANON_BODY) == CANON_BODY_RELAXED) { + hash = " "; + len = end[0] == '\0' ? 0 : 1; + } else { + hash = line; + len = (size_t)(end - line); + } + hashn = sig->l == -1 ? len : MIN(len, (size_t)sig->l); + sig->l -= sig->l == -1 ? 0 : hashn; + ret = EVP_DigestUpdate(sig->bhctx, hash, hashn); + if (ret == 0) { + dkim_errx(msg, "EVP_DigestUpdate"); + return; + } + } + line = end; + } for (i = 0; i < msg->nheaders; i++) { sig = msg->header[i].sig; - if (sig == NULL || ((sig->c & CANON_BODY) != canon) || - sig->state != DKIM_UNKNOWN) + if (sig == NULL || sig->state != DKIM_UNKNOWN) continue; - hashn = sig->l == -1 ? linelen : MIN(linelen, sig->l); + hashn = sig->l == -1 ? 2 : MIN(2, sig->l); sig->l -= sig->l == -1 ? 0 : hashn; - hashlf = sig->l == -1 ? 2 : MIN(2, sig->l); - sig->l -= sig->l == -1 ? 0 : hashlf; - if (EVP_DigestUpdate(sig->bhctx, buf, hashn) == 0 || - EVP_DigestUpdate(sig->bhctx, "\r\n", hashlf) == 0) { - dkim_errx(msg, "Can't update hash context"); + ret = EVP_DigestUpdate(sig->bhctx, "\r\n", hashn); + if (ret == 0) { + dkim_errx(msg, "EVP_DigestUpdate"); return; } } - if (canon == CANON_BODY_RELAXED) - return; - canon = CANON_BODY_RELAXED; - for (r = w = 0; buf[r] != '\0'; r++) { - if (buf[r] == ' ' || buf[r] == '\t') { - if (r != 0 && buf[w - 1] == ' ') - continue; - else - buf[w++] = ' '; - } else - buf[w++] = buf[r]; - } - linelen = (w != 0 && buf[w - 1] == ' ') ? w - 1 : w; - buf[linelen] = '\0'; - - goto hash; } void