X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/bd8fbe3606d80e5a3fc02fe71b521146c6938448..7b83389d47d53105c1c52b551033706b3d62e744:/src/src/pdkim/pdkim.c diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 4309675e6..178f8f6a5 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -2,7 +2,7 @@ * PDKIM - a RFC4871 (DKIM) implementation * * Copyright (C) 2009 - 2016 Tom Kistner - * Copyright (C) 2016 Jeremy Harris + * Copyright (C) 2016 - 2017 Jeremy Harris * * http://duncanthrax.net/pdkim/ * @@ -192,7 +192,8 @@ static void pdkim_hexprint(const uschar *data, int len) { int i; -for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]); +if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]); +else debug_printf(""); debug_printf("\n"); } @@ -493,10 +494,8 @@ for (p = raw_hdr; ; p++) switch (*cur_tag) { case 'b': - if (cur_tag[1] == 'h') - pdkim_decode_base64(cur_val, &sig->bodyhash); - else - pdkim_decode_base64(cur_val, &sig->sigdata); + pdkim_decode_base64(cur_val, + cur_tag[1] == 'h' ? &sig->bodyhash : &sig->sighash); break; case 'v': /* We only support version 1, and that is currently the @@ -578,12 +577,17 @@ DEBUG(D_acl) "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val)); debug_printf( - "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8); + "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8); debug_printf( "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } -exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256); +if (!exim_sha_init(&sig->body_hash_ctx, + sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256)) + { + DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n"); + return NULL; + } return sig; } @@ -697,15 +701,14 @@ return NULL; /* -------------------------------------------------------------------------- */ static int -pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len) +pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len) { -pdkim_signature *sig = ctx->sig; -/* Cache relaxed version of data */ -uschar *relaxed_data = NULL; -int relaxed_len = 0; +pdkim_signature * sig; +uschar * relaxed_data = NULL; /* Cache relaxed version of data */ +int relaxed_len = 0; /* Traverse all signatures, updating their hashes. */ -while (sig) +for (sig = ctx->sig; sig; sig = sig->next) { /* Defaults to simple canon (no further treatment necessary) */ const uschar *canon_data = CUS data; @@ -761,12 +764,10 @@ while (sig) if (canon_len > 0) { - exim_sha_update(&sig->body_hash, CUS canon_data, canon_len); + exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len); sig->signed_body_bytes += canon_len; DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len); } - - sig = sig->next; } if (relaxed_data) store_free(relaxed_data); @@ -786,7 +787,7 @@ for (sig = ctx->sig; sig; sig = sig->next) { /* Finish hashes */ blob bh; - exim_sha_finish(&sig->body_hash, &bh); + exim_sha_finish(&sig->body_hash_ctx, &bh); DEBUG(D_acl) { @@ -807,11 +808,11 @@ for (sig = ctx->sig; sig; sig = sig->next) sig->bodylength = -1; } - /* VERIFICATION --------------------------------------------------------- */ else - { - /* Compare bodyhash */ - if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0) + /* VERIFICATION --------------------------------------------------------- */ + /* Be careful that the header sig included a bodyash */ + + if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0) { DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain); } @@ -820,14 +821,12 @@ for (sig = ctx->sig; sig; sig = sig->next) DEBUG(D_acl) { debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain); - pdkim_hexprint(sig->bodyhash.data, - exim_sha_hashlen(&sig->body_hash)); + pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len); debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain); } sig->verify_status = PDKIM_VERIFY_FAIL; sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY; } - } } } @@ -968,32 +967,28 @@ else DKIM_SIGNATURE_HEADERNAME, Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0) { - pdkim_signature *new_sig; + pdkim_signature * new_sig, * last_sig; + + /* Create and chain new signature block. We could error-check for all + required tags here, but prefer to create the internal sig and expicitly + fail verification of it later. */ - /* Create and chain new signature block */ DEBUG(D_acl) debug_printf( "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header))) + new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header); + + if (!(last_sig = ctx->sig)) + ctx->sig = new_sig; + else { - pdkim_signature *last_sig = ctx->sig; - if (!last_sig) - ctx->sig = new_sig; - else - { - while (last_sig->next) last_sig = last_sig->next; - last_sig->next = new_sig; - } + while (last_sig->next) last_sig = last_sig->next; + last_sig->next = new_sig; } - else - DEBUG(D_acl) debug_printf( - "Error while parsing signature header\n" - "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } - /* every other header is stored for signature verification */ - else - ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header); + /* all headers are stored for signature verification */ + ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header); } BAIL: @@ -1010,7 +1005,7 @@ return PDKIM_OK; DLLEXPORT int pdkim_feed(pdkim_ctx *ctx, char *data, int len) { -int p; +int p, rc; /* Alternate EOD signal, used in non-dotstuffing mode */ if (!data) @@ -1035,7 +1030,6 @@ else for (p = 0; pflags |= PDKIM_SEEN_CR; else if (c == '\n') { - int rc; ctx->flags &= ~PDKIM_SEEN_CR; if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK) return rc; @@ -1055,14 +1049,14 @@ else for (p = 0; pcur_header = string_catn(ctx->cur_header, &ctx->cur_header_size, &ctx->cur_header_len, CUS "\r", 1); - if (ctx->flags & PDKIM_SEEN_LF) + if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */ { - int rc = pdkim_header_complete(ctx); /* Seen last header line */ - if (rc != PDKIM_OK) return rc; + if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK) + return rc; ctx->flags = ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR) | PDKIM_PAST_HDRS; DEBUG(D_acl) debug_printf( - "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n"); + "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); continue; } else @@ -1070,11 +1064,9 @@ else for (p = 0; pflags & PDKIM_SEEN_LF) { - if (!(c == '\t' || c == ' ')) - { - int rc = pdkim_header_complete(ctx); /* End of header */ - if (rc != PDKIM_OK) return rc; - } + if (!(c == '\t' || c == ' ')) /* End of header */ + if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK) + return rc; ctx->flags &= ~PDKIM_SEEN_LF; } @@ -1309,7 +1301,7 @@ if (sig->bodylength >= 0) } /* Preliminary or final version? */ -base64_b = final ? pdkim_encode_base64(&sig->sigdata) : US""; +base64_b = final ? pdkim_encode_base64(&sig->sighash) : US""; hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b); /* add trailing semicolon: I'm not sure if this is actually needed */ @@ -1423,7 +1415,11 @@ while (sig) hdata.data = NULL; hdata.len = 0; - exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256); + if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256)) + { + DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n"); + break; + } DEBUG(D_acl) debug_printf( "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n"); @@ -1585,7 +1581,7 @@ while (sig) hdata = hhash; #endif - if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata))) + if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sighash))) { DEBUG(D_acl) debug_printf("signing: %s\n", errstr); return PDKIM_ERR_RSA_SIGNING; @@ -1594,7 +1590,7 @@ while (sig) DEBUG(D_acl) { debug_printf( "PDKIM [%s] b computed: ", sig->domain); - pdkim_hexprint(sig->sigdata.data, sig->sigdata.len); + pdkim_hexprint(sig->sighash.data, sig->sighash.len); } sig->signature_header = pdkim_create_header(sig, TRUE); @@ -1612,7 +1608,7 @@ while (sig) && sig->selector && *sig->selector && sig->headernames && *sig->headernames && sig->bodyhash.data - && sig->sigdata.data + && sig->sighash.data && sig->algo > -1 && sig->version ) ) @@ -1642,7 +1638,7 @@ while (sig) goto NEXT_VERIFY; /* Check the signature */ - if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata))) + if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash))) { DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr); sig->verify_status = PDKIM_VERIFY_FAIL; @@ -1729,7 +1725,12 @@ sig->selector = string_copy(US selector); sig->rsa_privkey = string_copy(US rsa_privkey); sig->algo = algo; -exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256); +if (!exim_sha_init(&sig->body_hash_ctx, + algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256)) + { + DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n"); + return NULL; + } DEBUG(D_acl) { @@ -1741,7 +1742,6 @@ DEBUG(D_acl) debug_printf("WARNING: bad dkim key in dns\n"); debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } - return ctx; }