X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fpdkim%2Fpdkim.c;h=6e76b8e9fa2555e0a8e422b618d87a0bf424940d;hb=f6ee24a2b56b9365b948dd9e501c0e4627e6fa4f;hp=d3ff03108c683885b60e82e68173435285041e66;hpb=cd1a5fe0ed22087c6afbe585ab0206c2a4a267aa;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index d3ff03108..6e76b8e9f 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; } - } } } @@ -876,7 +875,7 @@ ctx->linebuf[ctx->linebuf_offset] = '\0'; /* Terminate on EOD marker */ if (ctx->flags & PDKIM_DOT_TERM) { - if ( memcmp(p, ".\r\n", 3) == 0) + if (memcmp(p, ".\r\n", 3) == 0) return pdkim_body_complete(ctx); /* Unstuff dots */ @@ -959,36 +958,39 @@ if (ctx->flags & PDKIM_MODE_SIGN) /* DKIM-Signature: headers are added to the verification list */ else { +#ifdef notdef + DEBUG(D_acl) + { + debug_printf("PDKIM >> raw hdr: "); + pdkim_quoteprint(CUS ctx->cur_header, Ustrlen(ctx->cur_header)); + } +#endif if (strncasecmp(CCS ctx->cur_header, 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: @@ -1005,7 +1007,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) @@ -1017,45 +1019,57 @@ else for (p = 0; pflags & PDKIM_PAST_HDRS) { + if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */ + { + ctx->linebuf[ctx->linebuf_offset++] = '\r'; + if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1) + return PDKIM_ERR_LONG_LINE; + } + /* Processing body byte */ ctx->linebuf[ctx->linebuf_offset++] = c; - if (c == '\n') + if (c == '\r') + ctx->flags |= PDKIM_SEEN_CR; + else if (c == '\n') { - int rc = pdkim_bodyline_complete(ctx); /* End of line */ - if (rc != PDKIM_OK) return rc; + ctx->flags &= ~PDKIM_SEEN_CR; + if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK) + return rc; } - if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1)) + + if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1) return PDKIM_ERR_LONG_LINE; } else { /* Processing header byte */ - if (c != '\r') + if (c == '\r') + ctx->flags |= PDKIM_SEEN_CR; + else if (c == '\n') { - if (c == '\n') - { - if (ctx->flags & PDKIM_SEEN_LF) - { - int rc = pdkim_header_complete(ctx); /* Seen last header line */ - if (rc != PDKIM_OK) return rc; + if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */ + ctx->cur_header = string_catn(ctx->cur_header, &ctx->cur_header_size, + &ctx->cur_header_len, CUS "\r", 1); - ctx->flags = ctx->flags & ~PDKIM_SEEN_LF | PDKIM_PAST_HDRS; - DEBUG(D_acl) debug_printf( - "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n"); - continue; - } - else - ctx->flags |= PDKIM_SEEN_LF; - } - else if (ctx->flags & PDKIM_SEEN_LF) - { - if (!(c == '\t' || c == ' ')) - { - int rc = pdkim_header_complete(ctx); /* End of header */ - if (rc != PDKIM_OK) return rc; - } - ctx->flags &= ~PDKIM_SEEN_LF; + if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */ + { + 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"); + continue; } + else + ctx->flags = ctx->flags & ~PDKIM_SEEN_CR | PDKIM_SEEN_LF; + } + else if (ctx->flags & PDKIM_SEEN_LF) + { + if (!(c == '\t' || c == ' ')) /* End of header */ + if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK) + return rc; + ctx->flags &= ~PDKIM_SEEN_LF; } if (ctx->cur_header_len < PDKIM_MAX_HEADER_LEN) @@ -1289,7 +1303,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 */ @@ -1403,7 +1417,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"); @@ -1565,7 +1583,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; @@ -1574,7 +1592,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); @@ -1592,7 +1610,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 ) ) @@ -1622,7 +1640,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; @@ -1631,7 +1649,7 @@ while (sig) } - /* We have a winner! (if bodydhash was correct earlier) */ + /* We have a winner! (if bodyhash was correct earlier) */ if (sig->verify_status == PDKIM_VERIFY_NONE) sig->verify_status = PDKIM_VERIFY_PASS; @@ -1709,7 +1727,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) { @@ -1721,7 +1744,6 @@ DEBUG(D_acl) debug_printf("WARNING: bad dkim key in dns\n"); debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); } - return ctx; }