X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fpdkim%2Fpdkim.c;h=30b81c4b4628fb29888bfcf33144b3f5b3af37cc;hb=b3ef41c94af9aefec7b6855cf2ce73ffeaba9d9a;hp=d875e1f89cf145b8b254bae12abb62b1a15791b1;hpb=6ab02e3ff7ada14165079ae4d2213e13d32bfad6;p=exim.git diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index d875e1f89..30b81c4b4 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -1,7 +1,7 @@ /* * PDKIM - a RFC4871 (DKIM) implementation * - * Copyright (C) 2009 Tom Kistner + * Copyright (C) 2009 - 2012 Tom Kistner * * http://duncanthrax.net/pdkim/ * @@ -20,8 +20,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* $Cambridge: exim/src/src/pdkim/pdkim.c,v 1.7 2009/11/09 14:19:48 tom Exp $ */ - #include #include #include @@ -53,6 +51,7 @@ /* -------------------------------------------------------------------------- */ struct pdkim_stringlist { char *value; + int tag; void *next; }; @@ -65,32 +64,32 @@ struct pdkim_str { /* -------------------------------------------------------------------------- */ /* A bunch of list constants */ -char *pdkim_querymethods[] = { +const char *pdkim_querymethods[] = { "dns/txt", NULL }; -char *pdkim_algos[] = { +const char *pdkim_algos[] = { "rsa-sha256", "rsa-sha1", NULL }; -char *pdkim_canons[] = { +const char *pdkim_canons[] = { "simple", "relaxed", NULL }; -char *pdkim_hashes[] = { +const char *pdkim_hashes[] = { "sha256", "sha1", NULL }; -char *pdkim_keytypes[] = { +const char *pdkim_keytypes[] = { "rsa", NULL }; typedef struct pdkim_combined_canon_entry { - char *str; + const char *str; int canon_headers; int canon_body; } pdkim_combined_canon_entry; @@ -105,15 +104,36 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = { }; +const char *pdkim_verify_status_str(int status) { + switch(status) { + case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE"; + case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID"; + case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL"; + case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS"; + default: return "PDKIM_VERIFY_UNKNOWN"; + } +} +const char *pdkim_verify_ext_status_str(int ext_status) { + switch(ext_status) { + case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY"; + case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE"; + case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE"; + case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE"; + case PDKIM_VERIFY_INVALID_PUBKEY_PARSING: return "PDKIM_VERIFY_INVALID_PUBKEY_PARSING"; + default: return "PDKIM_VERIFY_UNKNOWN"; + } +} + + /* -------------------------------------------------------------------------- */ /* Print debugging functions */ #ifdef PDKIM_DEBUG -void pdkim_quoteprint(FILE *stream, char *data, int len, int lf) { +void pdkim_quoteprint(FILE *stream, const char *data, int len, int lf) { int i; - unsigned char *p = (unsigned char *)data; + const unsigned char *p = (const unsigned char *)data; for (i=0;iallocated=(len+1); p->len=len; if (cstr) strcpy(p->str,cstr); + else p->str[p->len] = '\0'; return p; } -char *pdkim_strncat(pdkim_str *str, char *data, int len) { +char *pdkim_strncat(pdkim_str *str, const char *data, int len) { if ((str->allocated - str->len) < (len+1)) { /* Extend the buffer */ int num_frags = ((len+1)/PDKIM_STR_ALLOC_FRAG)+1; @@ -207,9 +228,10 @@ char *pdkim_strncat(pdkim_str *str, char *data, int len) { str->str[str->len] = '\0'; return str->str; } -char *pdkim_strcat(pdkim_str *str, char *cstr) { +char *pdkim_strcat(pdkim_str *str, const char *cstr) { return pdkim_strncat(str, cstr, strlen(cstr)); } + char *pdkim_numcat(pdkim_str *str, unsigned long num) { char minibuf[20]; snprintf(minibuf,20,"%lu",num); @@ -281,7 +303,6 @@ void pdkim_free_sig(pdkim_signature *sig) { if (sig->signature_header != NULL) free(sig->signature_header); if (sig->sha1_body != NULL) free(sig->sha1_body); if (sig->sha2_body != NULL) free(sig->sha2_body); - if (sig->hnames_check != NULL) free(sig->hnames_check); if (sig->pubkey != NULL) pdkim_free_pubkey(sig->pubkey); @@ -294,6 +315,13 @@ void pdkim_free_sig(pdkim_signature *sig) { /* -------------------------------------------------------------------------- */ DLLEXPORT void pdkim_free_ctx(pdkim_ctx *ctx) { if (ctx) { + pdkim_stringlist *e = ctx->headers; + while(e != NULL) { + pdkim_stringlist *c = e; + if (e->value != NULL) free(e->value); + e = e->next; + free(c); + } pdkim_free_sig(ctx->sig); pdkim_strfree(ctx->cur_header); free(ctx); @@ -306,9 +334,9 @@ DLLEXPORT void pdkim_free_ctx(pdkim_ctx *ctx) { the passed colon-separated "list", starting at entry "start". Returns the position of the header name in the list. */ -int header_name_match(char *header, - char *tick, - int do_tick) { +int header_name_match(const char *header, + char *tick, + int do_tick) { char *hname; char *lcopy; char *p; @@ -398,6 +426,7 @@ char *pdkim_relax_header (char *header, int crlf) { p++; q++; } + if ((q>relaxed) && (*(q-1) == ' ')) q--; /* Squash eventual trailing SP */ *q = '\0'; if (crlf) strcat(relaxed,"\r\n"); return relaxed; @@ -680,9 +709,6 @@ pdkim_signature *pdkim_parse_sig_header(pdkim_ctx *ctx, char *raw_hdr) { return NULL; } - /* Copy header list to 'tick-off' header list */ - sig->hnames_check = strdup(sig->headernames); - *q = '\0'; /* Chomp raw header. The final newline must not be added to the signature. */ q--; @@ -801,7 +827,7 @@ pdkim_pubkey *pdkim_parse_pubkey_record(pdkim_ctx *ctx, char *raw_record) { pub->srvtype = strdup(cur_val->str); break; case 't': - if (strchr(cur_val->str,'t') != NULL) pub->testing = 1; + if (strchr(cur_val->str,'y') != NULL) pub->testing = 1; if (strchr(cur_val->str,'s') != NULL) pub->no_subdomaining = 1; break; default: @@ -842,7 +868,7 @@ pdkim_pubkey *pdkim_parse_pubkey_record(pdkim_ctx *ctx, char *raw_record) { /* -------------------------------------------------------------------------- */ -int pdkim_update_bodyhash(pdkim_ctx *ctx, char *data, int len) { +int pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len) { pdkim_signature *sig = ctx->sig; /* Cache relaxed version of data */ char *relaxed_data = NULL; @@ -851,14 +877,14 @@ int pdkim_update_bodyhash(pdkim_ctx *ctx, char *data, int len) { /* Traverse all signatures, updating their hashes. */ while (sig != NULL) { /* Defaults to simple canon (no further treatment necessary) */ - char *canon_data = data; - int canon_len = len; + const char *canon_data = data; + int canon_len = len; if (sig->canon_body == PDKIM_CANON_RELAXED) { /* Relax the line if not done already */ if (relaxed_data == NULL) { int seen_wsp = 0; - char *p = data; + const char *p = data; int q = 0; relaxed_data = malloc(len+1); if (relaxed_data == NULL) return PDKIM_ERR_OOM; @@ -1041,65 +1067,69 @@ int pdkim_header_complete(pdkim_ctx *ctx) { ctx->num_headers++; if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL; - /* Traverse all signatures */ - while (sig != NULL) { - pdkim_stringlist *list; + /* SIGNING -------------------------------------------------------------- */ + if (ctx->mode == PDKIM_MODE_SIGN) { + /* Traverse all signatures */ + while (sig != NULL) { + pdkim_stringlist *list; - /* SIGNING -------------------------------------------------------------- */ - if (ctx->mode == PDKIM_MODE_SIGN) { if (header_name_match(ctx->cur_header->str, sig->sign_headers? sig->sign_headers: PDKIM_DEFAULT_SIGN_HEADERS, 0) != PDKIM_OK) goto NEXT_SIG; - } - /* VERIFICATION --------------------------------------------------------- */ - else { - /* Header is not included or all instances were already 'ticked off' */ - if (header_name_match(ctx->cur_header->str, - sig->hnames_check, 1) != PDKIM_OK) goto NEXT_SIG; - } - - /* Add header to the signed headers list (in reverse order) */ - list = pdkim_prepend_stringlist(sig->headers, - ctx->cur_header->str); - if (list == NULL) return PDKIM_ERR_OOM; - sig->headers = list; - NEXT_SIG: - sig = sig->next; + /* Add header to the signed headers list (in reverse order) */ + list = pdkim_prepend_stringlist(sig->headers, + ctx->cur_header->str); + if (list == NULL) return PDKIM_ERR_OOM; + sig->headers = list; + + NEXT_SIG: + sig = sig->next; + } } /* DKIM-Signature: headers are added to the verification list */ - if ( (ctx->mode == PDKIM_MODE_VERIFY) && - (strncasecmp(ctx->cur_header->str, + if (ctx->mode == PDKIM_MODE_VERIFY) { + if (strncasecmp(ctx->cur_header->str, DKIM_SIGNATURE_HEADERNAME, - strlen(DKIM_SIGNATURE_HEADERNAME)) == 0) ) { - pdkim_signature *new_sig; - /* Create and chain new signature block */ - #ifdef PDKIM_DEBUG - if (ctx->debug_stream) - fprintf(ctx->debug_stream, - "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - #endif - new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header->str); - if (new_sig != NULL) { - pdkim_signature *last_sig = ctx->sig; - if (last_sig == NULL) { - ctx->sig = new_sig; + strlen(DKIM_SIGNATURE_HEADERNAME)) == 0) { + pdkim_signature *new_sig; + /* Create and chain new signature block */ + #ifdef PDKIM_DEBUG + if (ctx->debug_stream) + fprintf(ctx->debug_stream, + "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + #endif + new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header->str); + if (new_sig != NULL) { + pdkim_signature *last_sig = ctx->sig; + if (last_sig == NULL) { + ctx->sig = new_sig; + } + else { + while (last_sig->next != NULL) { last_sig = last_sig->next; } + last_sig->next = new_sig; + } } else { - while (last_sig->next != NULL) { last_sig = last_sig->next; } - last_sig->next = new_sig; + #ifdef PDKIM_DEBUG + if (ctx->debug_stream) { + fprintf(ctx->debug_stream,"Error while parsing signature header\n"); + fprintf(ctx->debug_stream, + "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } + #endif } } + /* every other header is stored for signature verification */ else { - #ifdef PDKIM_DEBUG - if (ctx->debug_stream) { - fprintf(ctx->debug_stream,"Error while parsing signature header\n"); - fprintf(ctx->debug_stream, - "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - } - #endif + pdkim_stringlist *list; + + list = pdkim_prepend_stringlist(ctx->headers, + ctx->cur_header->str); + if (list == NULL) return PDKIM_ERR_OOM; + ctx->headers = list; } } @@ -1166,86 +1196,216 @@ DLLEXPORT int pdkim_feed (pdkim_ctx *ctx, return PDKIM_OK; } +/* + * RFC 5322 specifies that header line length SHOULD be no more than 78 + * lets make it so! + * pdkim_headcat + * returns char* + * + * col: this int holds and receives column number (octets since last '\n') + * str: partial string to append to + * pad: padding, split line or space after before or after eg: ";" + * intro: - must join to payload eg "h=", usually the tag name + * payload: eg base64 data - long data can be split arbitrarily. + * + * this code doesn't fold the header in some of the places that RFC4871 + * allows: As per RFC5322(2.2.3) it only folds before or after tag-value + * pairs and inside long values. it also always spaces or breaks after the + * "pad" + * + * no guarantees are made for output given out-of range input. like tag + * names loinger than 78, or bogus col. Input is assumed to be free of line breaks. + */ + +static char *pdkim_headcat(int *col, pdkim_str *str, const char*pad,const char *intro, const char *payload ) { + size_t l; + if( pad) + { + l = strlen(pad); + if( *col + l > 78 ) + { + pdkim_strcat(str, "\r\n\t"); + *col=1; + } + pdkim_strncat(str, pad,l); + *col +=l; + } + + l=(pad?1:0) + (intro?strlen(intro):0 ); + + if( *col + l > 78 ) + { /*can't fit intro - start a new line to make room.*/ + pdkim_strcat(str, "\r\n\t"); + *col=1; + l= intro?strlen(intro):0; + } + + l += payload ? strlen(payload):0 ; + + while(l>77) + { /* this fragment will not fit on a single line */ + if( pad ) + { + pdkim_strcat(str, " "); + *col +=1; + pad=NULL; // only want this once + l--; + } + if( intro ) + { + size_t sl=strlen(intro); + pdkim_strncat(str, intro,sl); + *col +=sl; + l-=sl; + intro=NULL; // only want this once + } + if(payload) + { + size_t sl=strlen(payload); + size_t chomp = *col+sl < 77 ? sl : 78-*col; + pdkim_strncat(str, payload,chomp); + *col +=chomp; + payload+=chomp; + l-=chomp-1; + } + // the while precondition tells us it didn't fit. + pdkim_strcat(str, "\r\n\t"); + *col=1; + } + if( *col + l > 78 ) + { + pdkim_strcat(str, "\r\n\t"); + *col=1; + pad=NULL; + } + + if( pad ) + { + pdkim_strcat(str, " "); + *col +=1; + pad=NULL; + } + + if( intro ) + { + size_t sl=strlen(intro); + pdkim_strncat(str, intro,sl); + *col +=sl; + l-=sl; + intro=NULL; + } + if(payload) + { + size_t sl=strlen(payload); + pdkim_strncat(str, payload,sl); + *col +=sl; + } + + return str->str; +} /* -------------------------------------------------------------------------- */ char *pdkim_create_header(pdkim_signature *sig, int final) { char *rc = NULL; char *base64_bh = NULL; char *base64_b = NULL; + int col=0; pdkim_str *hdr = pdkim_strnew("DKIM-Signature: v="PDKIM_SIGNATURE_VERSION); if (hdr == NULL) return NULL; + pdkim_str *canon_all = pdkim_strnew(pdkim_canons[sig->canon_headers]); + if (canon_all == NULL) goto BAIL; base64_bh = pdkim_encode_base64(sig->bodyhash, sig->bodyhash_len); if (base64_bh == NULL) goto BAIL; + col=strlen(hdr->str); + /* Required and static bits */ if ( - pdkim_strcat(hdr,"; a=") && - pdkim_strcat(hdr,pdkim_algos[sig->algo]) && - pdkim_strcat(hdr,"; q=") && - pdkim_strcat(hdr,pdkim_querymethods[sig->querymethod]) && - pdkim_strcat(hdr,"; c=") && - pdkim_strcat(hdr,pdkim_canons[sig->canon_headers]) && - pdkim_strcat(hdr,"/") && - pdkim_strcat(hdr,pdkim_canons[sig->canon_body]) && - pdkim_strcat(hdr,"; d=") && - pdkim_strcat(hdr,sig->domain) && - pdkim_strcat(hdr,"; s=") && - pdkim_strcat(hdr,sig->selector) && - pdkim_strcat(hdr,";\r\n\th=") && - pdkim_strcat(hdr,sig->headernames) && - pdkim_strcat(hdr,"; bh=") && - pdkim_strcat(hdr,base64_bh) && - pdkim_strcat(hdr,";\r\n\t") + pdkim_headcat(&col,hdr,";","a=",pdkim_algos[sig->algo]) && + pdkim_headcat(&col,hdr,";","q=",pdkim_querymethods[sig->querymethod]) && + pdkim_strcat(canon_all,"/") && + pdkim_strcat(canon_all,pdkim_canons[sig->canon_body]) && + pdkim_headcat(&col,hdr,";","c=",canon_all->str) && + pdkim_headcat(&col,hdr,";","d=",sig->domain) && + pdkim_headcat(&col,hdr,";","s=",sig->selector) ) { + /* list of eader names can be split between items. */ + { + char *n=strdup(sig->headernames); + char *f=n; + char *i="h="; + char *s=";"; + if(!n) goto BAIL; + while (*n) + { + char *c=strchr(n,':'); + if(c) *c='\0'; + if(!i) + { + if (!pdkim_headcat(&col,hdr,NULL,NULL,":")) + { + free(f); + goto BAIL; + } + } + if( !pdkim_headcat(&col,hdr,s,i,n)) + { + free(f); + goto BAIL; + } + if(c) n=c+1 ; else break; + s=NULL; + i=NULL; + } + free(f); + } + if(!pdkim_headcat(&col,hdr,";","bh=",base64_bh)) + goto BAIL; + /* Optional bits */ if (sig->identity != NULL) { - if (!( pdkim_strcat(hdr,"i=") && - pdkim_strcat(hdr,sig->identity) && - pdkim_strcat(hdr,";") ) ) { + if(!pdkim_headcat(&col,hdr,";","i=",sig->identity)){ goto BAIL; } } + if (sig->created > 0) { - if (!( pdkim_strcat(hdr,"t=") && - pdkim_numcat(hdr,sig->created) && - pdkim_strcat(hdr,";") ) ) { + char minibuf[20]; + snprintf(minibuf,20,"%lu",sig->created); + if(!pdkim_headcat(&col,hdr,";","t=",minibuf)) { goto BAIL; } } if (sig->expires > 0) { - if (!( pdkim_strcat(hdr,"x=") && - pdkim_numcat(hdr,sig->expires) && - pdkim_strcat(hdr,";") ) ) { + char minibuf[20]; + snprintf(minibuf,20,"%lu",sig->expires); + if(!pdkim_headcat(&col,hdr,";","x=",minibuf)) { goto BAIL; } } if (sig->bodylength >= 0) { - if (!( pdkim_strcat(hdr,"l=") && - pdkim_numcat(hdr,sig->bodylength) && - pdkim_strcat(hdr,";") ) ) { + char minibuf[20]; + snprintf(minibuf,20,"%lu",sig->bodylength); + if(!pdkim_headcat(&col,hdr,";","l=",minibuf)) { goto BAIL; } } - /* Extra linebreak */ - if (hdr->str[(hdr->len)-1] == ';') { - if (!pdkim_strcat(hdr," \r\n\t")) goto BAIL; - } + /* Preliminary or final version? */ if (final) { base64_b = pdkim_encode_base64(sig->sigdata, sig->sigdata_len); if (base64_b == NULL) goto BAIL; - if ( - pdkim_strcat(hdr,"b=") && - pdkim_strcat(hdr,base64_b) && - pdkim_strcat(hdr,";") - ) goto DONE; + if(!pdkim_headcat(&col,hdr,";","b=",base64_b)) goto BAIL; } else { - if (pdkim_strcat(hdr,"b=;")) goto DONE; + if(!pdkim_headcat(&col,hdr,";","b=","")) goto BAIL; } - goto BAIL; + /* add trailing semicolon: I'm not sure if this is actually needed */ + if(!pdkim_headcat(&col,hdr,NULL,";","")) goto BAIL; + + goto DONE; } DONE: @@ -1253,6 +1413,7 @@ char *pdkim_create_header(pdkim_signature *sig, int final) { BAIL: pdkim_strfree(hdr); + if (canon_all != NULL) pdkim_strfree(canon_all); if (base64_bh != NULL) free(base64_bh); if (base64_b != NULL) free(base64_b); return rc; @@ -1267,7 +1428,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu /* Check if we must still flush a (partial) header. If that is the case, the message has no body, and we must compute a body hash out of '' */ - if (ctx->cur_header->len) { + if (ctx->cur_header && ctx->cur_header->len) { int rc = pdkim_header_complete(ctx); if (rc != PDKIM_OK) return rc; pdkim_update_bodyhash(ctx,"\r\n",2); @@ -1283,7 +1444,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu #ifdef PDKIM_DEBUG if (ctx->debug_stream) fprintf(ctx->debug_stream, - "\nPDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); #endif } @@ -1354,14 +1515,23 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu char *b = strdup(sig->headernames); char *p = b; char *q = NULL; + pdkim_stringlist *hdrs = ctx->headers; + if (b == NULL) return PDKIM_ERR_OOM; + /* clear tags */ + while (hdrs != NULL) { + hdrs->tag = 0; + hdrs = hdrs->next; + } + while(1) { - pdkim_stringlist *hdrs = sig->headers; + hdrs = ctx->headers; q = strchr(p,':'); if (q != NULL) *q = '\0'; while (hdrs != NULL) { - if ( (strncasecmp(hdrs->value,p,strlen(p)) == 0) && + if ( (hdrs->tag == 0) && + (strncasecmp(hdrs->value,p,strlen(p)) == 0) && ((hdrs->value)[strlen(p)] == ':') ) { char *rh = NULL; if (sig->canon_headers == PDKIM_CANON_RELAXED) @@ -1379,7 +1549,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu pdkim_quoteprint(ctx->debug_stream, rh, strlen(rh), 1); #endif free(rh); - (hdrs->value)[0] = '_'; + hdrs->tag = 1; break; } hdrs = hdrs->next; @@ -1459,7 +1629,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu if (ctx->mode == PDKIM_MODE_SIGN) { rsa_context rsa; - rsa_init(&rsa,RSA_PKCS_V15,0,NULL,NULL); + rsa_init(&rsa,RSA_PKCS_V15,0); /* Perform private key operation */ if (rsa_parse_key(&rsa, (unsigned char *)sig->rsa_privkey, @@ -1473,7 +1643,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu if (rsa_pkcs1_sign( &rsa, RSA_PRIVATE, ((sig->algo == PDKIM_ALGO_RSA_SHA1)? - RSA_SHA1:RSA_SHA256), + SIG_RSA_SHA1:SIG_RSA_SHA256), 0, (unsigned char *)headerhash, (unsigned char *)sig->sigdata ) != 0) { @@ -1498,7 +1668,7 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu rsa_context rsa; char *dns_txt_name, *dns_txt_reply; - rsa_init(&rsa,RSA_PKCS_V15,0,NULL,NULL); + rsa_init(&rsa,RSA_PKCS_V15,0); dns_txt_name = malloc(PDKIM_DNS_TXT_MAX_NAMELEN); if (dns_txt_name == NULL) return PDKIM_ERR_OOM; @@ -1567,32 +1737,36 @@ DLLEXPORT int pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatu if (rsa_pkcs1_verify(&rsa, RSA_PUBLIC, ((sig->algo == PDKIM_ALGO_RSA_SHA1)? - RSA_SHA1:RSA_SHA256), + SIG_RSA_SHA1:SIG_RSA_SHA256), 0, (unsigned char *)headerhash, (unsigned char *)sig->sigdata) != 0) { sig->verify_status = PDKIM_VERIFY_FAIL; sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE; - #ifdef PDKIM_DEBUG - if (ctx->debug_stream) { - fprintf(ctx->debug_stream, "PDKIM [%s] signature did NOT verify OK\n", - sig->domain); - } - #endif goto NEXT_VERIFY; } - /* We have a winner! */ - sig->verify_status = PDKIM_VERIFY_PASS; + /* We have a winner! (if bodydhash was correct earlier) */ + if (sig->verify_status == PDKIM_VERIFY_NONE) { + sig->verify_status = PDKIM_VERIFY_PASS; + } + + NEXT_VERIFY: #ifdef PDKIM_DEBUG if (ctx->debug_stream) { - fprintf(ctx->debug_stream, "PDKIM [%s] signature verified OK\n", - sig->domain); + fprintf(ctx->debug_stream, "PDKIM [%s] signature status: %s", + sig->domain, pdkim_verify_status_str(sig->verify_status)); + if (sig->verify_ext_status > 0) { + fprintf(ctx->debug_stream, " (%s)\n", + pdkim_verify_ext_status_str(sig->verify_ext_status)); + } + else { + fprintf(ctx->debug_stream, "\n"); + } } #endif - NEXT_VERIFY: rsa_free(&rsa); free(dns_txt_name); free(dns_txt_reply);