2 * PDKIM - a RFC4871 (DKIM) implementation
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 - 2017 Jeremy Harris <jgh@exim.org>
7 * http://duncanthrax.net/pdkim/
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #ifndef DISABLE_DKIM /* entire file */
30 # error Need SUPPORT_TLS for DKIM
33 #include "crypt_ver.h"
36 # include <openssl/rsa.h>
37 # include <openssl/ssl.h>
38 # include <openssl/err.h>
39 #elif defined(SIGN_GNUTLS)
40 # include <gnutls/gnutls.h>
41 # include <gnutls/x509.h>
47 #define PDKIM_SIGNATURE_VERSION "1"
48 #define PDKIM_PUB_RECORD_VERSION US "DKIM1"
50 #define PDKIM_MAX_HEADER_LEN 65536
51 #define PDKIM_MAX_HEADERS 512
52 #define PDKIM_MAX_BODY_LINE_LEN 16384
53 #define PDKIM_DNS_TXT_MAX_NAMELEN 1024
54 #define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\
55 "Message-ID:To:Cc:MIME-Version:Content-Type:"\
56 "Content-Transfer-Encoding:Content-ID:"\
57 "Content-Description:Resent-Date:Resent-From:"\
58 "Resent-Sender:Resent-To:Resent-Cc:"\
59 "Resent-Message-ID:In-Reply-To:References:"\
60 "List-Id:List-Help:List-Unsubscribe:"\
61 "List-Subscribe:List-Post:List-Owner:List-Archive"
63 /* -------------------------------------------------------------------------- */
64 struct pdkim_stringlist {
70 /* -------------------------------------------------------------------------- */
71 /* A bunch of list constants */
72 const uschar * pdkim_querymethods[] = {
76 const uschar * pdkim_canons[] = {
83 const uschar * dkim_hashname;
84 hashmethod exim_hashmethod;
86 static const pdkim_hashtype pdkim_hashes[] = {
87 { US"sha1", HASH_SHA1 },
88 { US"sha256", HASH_SHA2_256 },
89 { US"sha512", HASH_SHA2_512 }
92 const uschar * pdkim_keytypes[] = {
96 typedef struct pdkim_combined_canon_entry {
100 } pdkim_combined_canon_entry;
102 pdkim_combined_canon_entry pdkim_combined_canons[] = {
103 { US"simple/simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
104 { US"simple/relaxed", PDKIM_CANON_SIMPLE, PDKIM_CANON_RELAXED },
105 { US"relaxed/simple", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
106 { US"relaxed/relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_RELAXED },
107 { US"simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
108 { US"relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
113 static blob lineending = {.data = US"\r\n", .len = 2};
115 /* -------------------------------------------------------------------------- */
117 dkim_sig_to_a_tag(const pdkim_signature * sig)
119 if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes)
120 || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
122 return string_sprintf("%s-%s",
123 pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
129 pdkim_verify_status_str(int status)
133 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
134 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
135 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
136 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
137 default: return "PDKIM_VERIFY_UNKNOWN";
142 pdkim_verify_ext_status_str(int ext_status)
146 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
147 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
148 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
149 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
150 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
151 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
152 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
153 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
154 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
155 default: return "PDKIM_VERIFY_UNKNOWN";
160 pdkim_errstr(int status)
164 case PDKIM_OK: return US"OK";
165 case PDKIM_FAIL: return US"FAIL";
166 case PDKIM_ERR_RSA_PRIVKEY: return US"RSA_PRIVKEY";
167 case PDKIM_ERR_RSA_SIGNING: return US"RSA SIGNING";
168 case PDKIM_ERR_LONG_LINE: return US"RSA_LONG_LINE";
169 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
170 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
171 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
172 default: return US"(unknown)";
177 /* -------------------------------------------------------------------------- */
178 /* Print debugging functions */
180 pdkim_quoteprint(const uschar *data, int len)
183 for (i = 0; i < len; i++)
185 const int c = data[i];
188 case ' ' : debug_printf("{SP}"); break;
189 case '\t': debug_printf("{TB}"); break;
190 case '\r': debug_printf("{CR}"); break;
191 case '\n': debug_printf("{LF}"); break;
192 case '{' : debug_printf("{BO}"); break;
193 case '}' : debug_printf("{BC}"); break;
195 if ( (c < 32) || (c > 127) )
196 debug_printf("{%02x}", c);
198 debug_printf("%c", c);
206 pdkim_hexprint(const uschar *data, int len)
209 if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
210 else debug_printf("<NULL>");
216 static pdkim_stringlist *
217 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
219 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
221 memset(new_entry, 0, sizeof(pdkim_stringlist));
222 new_entry->value = string_copy(str);
223 if (base) new_entry->next = base;
229 /* Trim whitespace fore & aft */
232 pdkim_strtrim(gstring * str)
235 uschar * q = p + str->ptr;
237 while (*p == '\t' || *p == ' ') /* dump the leading whitespace */
238 { str->size--; str->ptr--; str->s++; }
241 && (q = str->s + str->ptr - 1), *q == '\t' || *q == ' '
243 str->ptr--; /* dump trailing whitespace */
245 (void) string_from_gstring(str);
250 /* -------------------------------------------------------------------------- */
253 pdkim_free_ctx(pdkim_ctx *ctx)
258 /* -------------------------------------------------------------------------- */
259 /* Matches the name of the passed raw "header" against
260 the passed colon-separated "tick", and invalidates
261 the entry in tick. Returns OK or fail-code */
262 /*XXX might be safer done using a pdkim_stringlist for "tick" */
265 header_name_match(const uschar * header, uschar * tick)
271 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
274 return PDKIM_FAIL; /* This isn't a header */
276 /* if we had strncmpic() we wouldn't need this copy */
277 hname = string_copyn(header, hcolon-header);
279 /* Copy tick-off list locally, so we can punch zeroes into it */
280 p = lcopy = string_copy(tick);
282 for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
285 if (strcmpic(p, hname) == 0)
291 if (strcmpic(p, hname) == 0)
297 /* Invalidate header name instance in tick-off list */
303 /* -------------------------------------------------------------------------- */
304 /* Performs "relaxed" canonicalization of a header. */
307 pdkim_relax_header(const uschar * header, BOOL append_crlf)
309 BOOL past_field_name = FALSE;
310 BOOL seen_wsp = FALSE;
312 uschar * relaxed = store_get(Ustrlen(header)+3);
313 uschar * q = relaxed;
315 for (p = header; *p; p++)
319 if (c == '\r' || c == '\n') /* Ignore CR & LF */
321 if (c == '\t' || c == ' ')
325 c = ' '; /* Turns WSP into SP */
329 if (!past_field_name && c == ':')
331 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
332 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
333 past_field_name = TRUE;
338 /* Lowercase header name */
339 if (!past_field_name) c = tolower(c);
343 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
345 if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
351 /* -------------------------------------------------------------------------- */
352 #define PDKIM_QP_ERROR_DECODE -1
354 static const uschar *
355 pdkim_decode_qp_char(const uschar *qp_p, int *c)
357 const uschar *initial_pos = qp_p;
359 /* Advance one char */
362 /* Check for two hex digits and decode them */
363 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
365 /* Do hex conversion */
366 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
367 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
371 /* Illegal char here */
372 *c = PDKIM_QP_ERROR_DECODE;
377 /* -------------------------------------------------------------------------- */
380 pdkim_decode_qp(const uschar * str)
384 const uschar * p = str;
385 uschar * n = store_get(Ustrlen(str)+1);
393 p = pdkim_decode_qp_char(p, &nchar);
409 /* -------------------------------------------------------------------------- */
412 pdkim_decode_base64(const uschar * str, blob * b)
415 dlen = b64decode(str, &b->data);
416 if (dlen < 0) b->data = NULL;
421 pdkim_encode_base64(blob * b)
423 return b64encode(b->data, b->len);
427 /* -------------------------------------------------------------------------- */
428 #define PDKIM_HDR_LIMBO 0
429 #define PDKIM_HDR_TAG 1
430 #define PDKIM_HDR_VALUE 2
432 static pdkim_signature *
433 pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
435 pdkim_signature * sig;
437 gstring * cur_tag = NULL;
438 gstring * cur_val = NULL;
439 BOOL past_hname = FALSE;
440 BOOL in_b_val = FALSE;
441 int where = PDKIM_HDR_LIMBO;
444 sig = store_get(sizeof(pdkim_signature));
445 memset(sig, 0, sizeof(pdkim_signature));
446 sig->bodylength = -1;
448 /* Set so invalid/missing data error display is accurate */
453 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
455 for (p = raw_hdr; ; p++)
460 if (c == '\r' || c == '\n')
463 /* Fast-forward through header name */
466 if (c == ':') past_hname = TRUE;
470 if (where == PDKIM_HDR_LIMBO)
472 /* In limbo, just wait for a tag-char to appear */
473 if (!(c >= 'a' && c <= 'z'))
476 where = PDKIM_HDR_TAG;
479 if (where == PDKIM_HDR_TAG)
481 if (c >= 'a' && c <= 'z')
482 cur_tag = string_catn(cur_tag, p, 1);
486 if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0)
491 where = PDKIM_HDR_VALUE;
496 if (where == PDKIM_HDR_VALUE)
498 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
501 if (c == ';' || c == '\0')
503 if (cur_tag && cur_val)
505 (void) string_from_gstring(cur_val);
506 pdkim_strtrim(cur_val);
508 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s);
513 pdkim_decode_base64(cur_val->s,
514 cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash);
517 /* We only support version 1, and that is currently the
518 only version there is. */
520 Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
524 uschar * s = Ustrchr(cur_val->s, '-');
526 for(i = 0; i < nelem(pdkim_keytypes); i++)
527 if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0)
528 { sig->keytype = i; break; }
529 for (++s, i = 0; i < nelem(pdkim_hashes); i++)
530 if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
531 { sig->hashtype = i; break; }
536 for (i = 0; pdkim_combined_canons[i].str; i++)
537 if (Ustrcmp(cur_val->s, pdkim_combined_canons[i].str) == 0)
539 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
540 sig->canon_body = pdkim_combined_canons[i].canon_body;
545 for (i = 0; pdkim_querymethods[i]; i++)
546 if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
548 sig->querymethod = i;
553 sig->selector = string_copyn(cur_val->s, cur_val->ptr); break;
555 sig->domain = string_copyn(cur_val->s, cur_val->ptr); break;
557 sig->identity = pdkim_decode_qp(cur_val->s); break;
559 sig->created = strtoul(CS cur_val->s, NULL, 10); break;
561 sig->expires = strtoul(CS cur_val->s, NULL, 10); break;
563 sig->bodylength = strtol(CS cur_val->s, NULL, 10); break;
565 sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break;
567 sig->copiedheaders = pdkim_decode_qp(cur_val->s); break;
569 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
573 cur_tag = cur_val = NULL;
575 where = PDKIM_HDR_LIMBO;
578 cur_val = string_catn(cur_val, p, 1);
590 /* Chomp raw header. The final newline must not be added to the signature. */
591 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
597 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
598 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
600 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
602 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
605 /*XXX hash method: extend for sha512 */
606 if (!exim_sha_init(&sig->body_hash_ctx,
607 pdkim_hashes[sig->hashtype].exim_hashmethod))
610 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
617 /* -------------------------------------------------------------------------- */
619 static pdkim_pubkey *
620 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
626 pub = store_get(sizeof(pdkim_pubkey));
627 memset(pub, 0, sizeof(pdkim_pubkey));
629 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
633 if ((val = Ustrchr(ele, '=')))
635 int taglen = val++ - ele;
637 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
640 case 'v': pub->version = val; break;
641 case 'h': pub->hashes = val; break;
643 case 'g': pub->granularity = val; break;
644 case 'n': pub->notes = pdkim_decode_qp(val); break;
645 case 'p': pdkim_decode_base64(val, &pub->key); break;
646 case 's': pub->srvtype = val; break;
647 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
648 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
650 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
655 /* Set fallback defaults */
656 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
657 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
659 DEBUG(D_acl) debug_printf(" Bad v= field\n");
663 if (!pub->granularity) pub->granularity = US"*";
665 if (!pub->keytype ) pub->keytype = US"rsa";
667 if (!pub->srvtype ) pub->srvtype = US"*";
673 DEBUG(D_acl) debug_printf(" Missing p= field\n");
678 /* -------------------------------------------------------------------------- */
680 /* Update the bodyhash for one sig, with some additional data.
681 If we have to relax the data for this sig, return our copy of it. */
683 /*XXX Currently we calculate a hash for each sig. But it is possible
684 that multi-signing will be wanted using different signing algos
685 (rsa, ec) using the same hash and canonicalization. Consider in future
686 hanging the hash+cacnon from the ctx and only referencing from the sig,
687 so that it can be calculated only once - being over the body this
688 caould be meagbytes, hence expensive. */
691 pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
693 blob * canon_data = orig_data;
694 /* Defaults to simple canon (no further treatment necessary) */
696 if (sig->canon_body == PDKIM_CANON_RELAXED)
698 /* Relax the line if not done already */
701 BOOL seen_wsp = FALSE;
705 /* We want to be able to free this else we allocate
706 for the entire message which could be many MB. Since
707 we don't know what allocations the SHA routines might
708 do, not safe to use store_get()/store_reset(). */
710 relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
711 relaxed_data->data = US (relaxed_data+1);
713 for (p = orig_data->data; *p; p++)
718 if (q > 0 && relaxed_data->data[q-1] == ' ')
721 else if (c == '\t' || c == ' ')
723 c = ' '; /* Turns WSP into SP */
730 relaxed_data->data[q++] = c;
732 relaxed_data->data[q] = '\0';
733 relaxed_data->len = q;
735 canon_data = relaxed_data;
738 /* Make sure we don't exceed the to-be-signed body length */
739 if ( sig->bodylength >= 0
740 && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
742 canon_data->len = sig->bodylength - sig->signed_body_bytes;
744 if (canon_data->len > 0)
746 exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
747 sig->signed_body_bytes += canon_data->len;
748 DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
755 /* -------------------------------------------------------------------------- */
758 pdkim_finish_bodyhash(pdkim_ctx * ctx)
760 pdkim_signature * sig;
762 /* Traverse all signatures */
763 for (sig = ctx->sig; sig; sig = sig->next)
764 { /* Finish hashes */
767 exim_sha_finish(&sig->body_hash_ctx, &bh);
771 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
772 "PDKIM [%s] Body %s computed: ",
773 sig->domain, sig->signed_body_bytes,
774 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
775 pdkim_hexprint(CUS bh.data, bh.len);
778 /* SIGNING -------------------------------------------------------------- */
779 if (ctx->flags & PDKIM_MODE_SIGN)
783 /* If bodylength limit is set, and we have received less bytes
784 than the requested amount, effectively remove the limit tag. */
785 if (sig->signed_body_bytes < sig->bodylength)
786 sig->bodylength = -1;
790 /* VERIFICATION --------------------------------------------------------- */
791 /* Be careful that the header sig included a bodyash */
793 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
795 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
801 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
802 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
803 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
805 sig->verify_status = PDKIM_VERIFY_FAIL;
806 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
814 pdkim_body_complete(pdkim_ctx * ctx)
816 pdkim_signature * sig;
818 /* In simple body mode, if any empty lines were buffered,
819 replace with one. rfc 4871 3.4.3 */
820 /*XXX checking the signed-body-bytes is a gross hack; I think
821 it indicates that all linebreaks should be buffered, including
822 the one terminating a text line */
824 for (sig = ctx->sig; sig; sig = sig->next)
825 if ( sig->canon_body == PDKIM_CANON_SIMPLE
826 && sig->signed_body_bytes == 0
827 && sig->num_buffered_blanklines > 0
829 (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
831 ctx->flags |= PDKIM_SEEN_EOD;
832 ctx->linebuf_offset = 0;
837 /* -------------------------------------------------------------------------- */
838 /* Call from pdkim_feed below for processing complete body lines */
841 pdkim_bodyline_complete(pdkim_ctx * ctx)
843 blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
844 pdkim_signature * sig;
848 /* Ignore extra data if we've seen the end-of-data marker */
849 if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
851 /* We've always got one extra byte to stuff a zero ... */
852 ctx->linebuf[line.len] = '\0';
854 /* Terminate on EOD marker */
855 if (ctx->flags & PDKIM_DOT_TERM)
857 if (memcmp(line.data, ".\r\n", 3) == 0)
858 { pdkim_body_complete(ctx); return; }
861 if (memcmp(line.data, "..", 2) == 0)
862 { line.data++; line.len--; }
865 /* Empty lines need to be buffered until we find a non-empty line */
866 if (memcmp(line.data, "\r\n", 2) == 0)
868 for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
872 /* Process line for each sig separately */
873 for (sig = ctx->sig; sig; sig = sig->next)
875 if (sig->canon_body == PDKIM_CANON_RELAXED)
877 /* Lines with just spaces need to be buffered too */
878 uschar * cp = line.data;
883 if (c == '\r' && cp[1] == '\n') break;
884 if (c != ' ' && c != '\t') goto sig_process;
888 sig->num_buffered_blanklines++;
893 /* At this point, we have a non-empty line, so release the buffered ones. */
895 while (sig->num_buffered_blanklines)
897 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
898 sig->num_buffered_blanklines--;
901 rline = pdkim_update_sig_bodyhash(sig, &line, rline);
905 if (rnl) store_free(rnl);
906 if (rline) store_free(rline);
910 ctx->linebuf_offset = 0;
915 /* -------------------------------------------------------------------------- */
916 /* Callback from pdkim_feed below for processing complete headers */
917 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
920 pdkim_header_complete(pdkim_ctx * ctx)
922 pdkim_signature * sig, * last_sig;
924 /* Special case: The last header can have an extra \r appended */
925 if ( (ctx->cur_header->ptr > 1) &&
926 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
927 --ctx->cur_header->ptr;
928 (void) string_from_gstring(ctx->cur_header);
930 if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
932 /* SIGNING -------------------------------------------------------------- */
933 if (ctx->flags & PDKIM_MODE_SIGN)
934 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
936 /* Add header to the signed headers list (in reverse order) */
937 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
939 /* VERIFICATION ----------------------------------------------------------- */
940 /* DKIM-Signature: headers are added to the verification list */
946 debug_printf("PDKIM >> raw hdr: ");
947 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
950 if (strncasecmp(CCS ctx->cur_header->s,
951 DKIM_SIGNATURE_HEADERNAME,
952 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
954 /* Create and chain new signature block. We could error-check for all
955 required tags here, but prefer to create the internal sig and expicitly
956 fail verification of it later. */
958 DEBUG(D_acl) debug_printf(
959 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
961 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
963 if (!(last_sig = ctx->sig))
967 while (last_sig->next) last_sig = last_sig->next;
968 last_sig->next = sig;
972 /* all headers are stored for signature verification */
973 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
977 ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
983 /* -------------------------------------------------------------------------- */
984 #define HEADER_BUFFER_FRAG_SIZE 256
987 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
991 /* Alternate EOD signal, used in non-dotstuffing mode */
993 pdkim_body_complete(ctx);
995 else for (p = 0; p<len; p++)
999 if (ctx->flags & PDKIM_PAST_HDRS)
1001 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1003 ctx->linebuf[ctx->linebuf_offset++] = '\r';
1004 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1005 return PDKIM_ERR_LONG_LINE;
1008 /* Processing body byte */
1009 ctx->linebuf[ctx->linebuf_offset++] = c;
1011 ctx->flags |= PDKIM_SEEN_CR;
1014 ctx->flags &= ~PDKIM_SEEN_CR;
1015 pdkim_bodyline_complete(ctx);
1018 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1019 return PDKIM_ERR_LONG_LINE;
1023 /* Processing header byte */
1025 ctx->flags |= PDKIM_SEEN_CR;
1028 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1029 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
1031 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1033 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1036 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1037 DEBUG(D_acl) debug_printf(
1038 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1042 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1044 else if (ctx->flags & PDKIM_SEEN_LF)
1046 if (!(c == '\t' || c == ' ')) /* End of header */
1047 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1049 ctx->flags &= ~PDKIM_SEEN_LF;
1052 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1053 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
1061 /* Extend a growing header with a continuation-linebreak */
1063 pdkim_hdr_cont(gstring * str, int * col)
1066 return string_catn(str, US"\r\n\t", 3);
1072 * RFC 5322 specifies that header line length SHOULD be no more than 78
1076 * returns uschar * (not nul-terminated)
1078 * col: this int holds and receives column number (octets since last '\n')
1079 * str: partial string to append to
1080 * pad: padding, split line or space after before or after eg: ";"
1081 * intro: - must join to payload eg "h=", usually the tag name
1082 * payload: eg base64 data - long data can be split arbitrarily.
1084 * this code doesn't fold the header in some of the places that RFC4871
1085 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1086 * pairs and inside long values. it also always spaces or breaks after the
1089 * no guarantees are made for output given out-of range input. like tag
1090 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1094 pdkim_headcat(int * col, gstring * str,
1095 const uschar * pad, const uschar * intro, const uschar * payload)
1103 str = pdkim_hdr_cont(str, col);
1104 str = string_catn(str, pad, l);
1108 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1111 { /*can't fit intro - start a new line to make room.*/
1112 str = pdkim_hdr_cont(str, col);
1113 l = intro?Ustrlen(intro):0;
1116 l += payload ? Ustrlen(payload):0 ;
1119 { /* this fragment will not fit on a single line */
1122 str = string_catn(str, US" ", 1);
1124 pad = NULL; /* only want this once */
1130 size_t sl = Ustrlen(intro);
1132 str = string_catn(str, intro, sl);
1135 intro = NULL; /* only want this once */
1140 size_t sl = Ustrlen(payload);
1141 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1143 str = string_catn(str, payload, chomp);
1149 /* the while precondition tells us it didn't fit. */
1150 str = pdkim_hdr_cont(str, col);
1155 str = pdkim_hdr_cont(str, col);
1161 str = string_catn(str, US" ", 1);
1168 size_t sl = Ustrlen(intro);
1170 str = string_catn(str, intro, sl);
1178 size_t sl = Ustrlen(payload);
1180 str = string_catn(str, payload, sl);
1188 /* -------------------------------------------------------------------------- */
1191 pdkim_create_header(pdkim_signature * sig, BOOL final)
1197 gstring * canon_all;
1199 canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1200 canon_all = string_catn(canon_all, US"/", 1);
1201 canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1202 (void) string_from_gstring(canon_all);
1204 hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1207 /* Required and static bits */
1208 hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1209 hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1210 hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1211 hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1212 hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
1214 /* list of header names can be split between items. */
1216 uschar * n = string_copy(sig->headernames);
1217 uschar * i = US"h=";
1222 uschar * c = Ustrchr(n, ':');
1227 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
1229 hdr = pdkim_headcat(&col, hdr, s, i, n);
1240 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1241 hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
1245 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
1247 if (sig->created > 0)
1251 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1252 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
1255 if (sig->expires > 0)
1259 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1260 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
1263 if (sig->bodylength >= 0)
1267 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1268 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
1271 /* Preliminary or final version? */
1274 base64_b = pdkim_encode_base64(&sig->sighash);
1275 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
1277 /* add trailing semicolon: I'm not sure if this is actually needed */
1278 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
1282 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1283 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1284 the headcat routine could insert a linebreak which the relaxer would reduce
1285 to a single space preceding the terminating semicolon, resulting in an
1286 incorrect header-hash. */
1287 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
1290 return string_from_gstring(hdr);
1294 /* -------------------------------------------------------------------------- */
1296 static pdkim_pubkey *
1297 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1298 const uschar ** errstr)
1300 uschar * dns_txt_name, * dns_txt_reply;
1303 /* Fetch public key for signing domain, from DNS */
1305 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1307 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1308 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1310 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1311 || dns_txt_reply[0] == '\0'
1314 sig->verify_status = PDKIM_VERIFY_INVALID;
1315 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1322 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1326 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1329 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1330 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1333 sig->verify_status = PDKIM_VERIFY_INVALID;
1334 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1339 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1341 debug_printf(" Error while parsing public key record\n");
1343 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1348 DEBUG(D_acl) debug_printf(
1349 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1351 /* Import public key */
1352 if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
1354 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1355 sig->verify_status = PDKIM_VERIFY_INVALID;
1356 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1364 /* -------------------------------------------------------------------------- */
1367 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1368 const uschar ** err)
1370 pdkim_signature * sig;
1372 /* Check if we must still flush a (partial) header. If that is the
1373 case, the message has no body, and we must compute a body hash
1374 out of '<CR><LF>' */
1375 if (ctx->cur_header && ctx->cur_header->ptr > 0)
1380 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1383 for (sig = ctx->sig; sig; sig = sig->next)
1384 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
1385 if (rnl) store_free(rnl);
1388 DEBUG(D_acl) debug_printf(
1389 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1391 /* Build (and/or evaluate) body hash */
1392 pdkim_finish_bodyhash(ctx);
1394 for (sig = ctx->sig; sig; sig = sig->next)
1397 uschar * sig_hdr = US"";
1399 gstring * hdata = NULL;
1401 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
1404 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1408 if (ctx->flags & PDKIM_MODE_SIGN)
1409 DEBUG(D_acl) debug_printf(
1410 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1414 DEBUG(D_acl) debug_printf(
1415 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1418 /* SIGNING ---------------------------------------------------------------- */
1419 /* When signing, walk through our header list and add them to the hash. As we
1420 go, construct a list of the header's names to use for the h= parameter.
1421 Then append to that list any remaining header names for which there was no
1424 if (ctx->flags & PDKIM_MODE_SIGN)
1427 pdkim_stringlist *p;
1432 sig->headernames = NULL; /* Collected signed header names */
1434 for (p = sig->headers; p; p = p->next)
1436 uschar * rh = p->value;
1438 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
1440 /* Collect header names (Note: colon presence is guaranteed here) */
1441 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
1443 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1444 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
1446 /* Feed header to the hash algorithm */
1447 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1449 /* Remember headers block for signing (when the library cannot do incremental) */
1450 hdata = exim_dkim_data_append(hdata, rh);
1452 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1456 /* Any headers we wanted to sign but were not present must also be listed */
1457 l = sig->sign_headers;
1458 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1460 g = string_append_listele(g, ':', s);
1461 sig->headernames = string_from_gstring(g);
1463 /* Create signature header with b= omitted */
1464 sig_hdr = pdkim_create_header(sig, FALSE);
1467 /* VERIFICATION ----------------------------------------------------------- */
1468 /* When verifying, walk through the header name list in the h= parameter and
1469 add the headers to the hash in that order. */
1472 uschar * p = sig->headernames;
1474 pdkim_stringlist * hdrs;
1479 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1485 if ((q = Ustrchr(p, ':')))
1488 /*XXX walk the list of headers in same order as received. */
1489 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1491 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1492 && (hdrs->value)[Ustrlen(p)] == ':'
1495 /* cook header for relaxed canon, or just copy it for simple */
1497 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1498 ? pdkim_relax_header(hdrs->value, TRUE)
1499 : string_copy(CUS hdrs->value);
1501 /* Feed header to the hash algorithm */
1502 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1504 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1513 sig_hdr = string_copy(sig->rawsig_no_b_val);
1517 DEBUG(D_acl) debug_printf(
1518 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1523 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1524 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1526 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1529 /* Relax header if necessary */
1530 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1531 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
1536 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1537 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1539 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1542 /* Finalize header hash */
1543 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1544 exim_sha_finish(&hhash_ctx, &hhash);
1548 debug_printf("PDKIM [%s] Header %s computed: ",
1549 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
1550 pdkim_hexprint(hhash.data, hhash.len);
1553 /* Remember headers block for signing (when the signing library cannot do
1555 if (ctx->flags & PDKIM_MODE_SIGN)
1556 hdata = exim_dkim_data_append(hdata, US sig_hdr);
1558 /* SIGNING ---------------------------------------------------------------- */
1559 if (ctx->flags & PDKIM_MODE_SIGN)
1563 /* Import private key, including the keytype */
1564 /*XXX extend for non-RSA algos */
1565 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
1567 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1568 return PDKIM_ERR_RSA_PRIVKEY;
1571 /* Do signing. With OpenSSL we are signing the hash of headers just
1572 calculated, with GnuTLS we have to sign an entire block of headers
1573 (due to available interfaces) and it recalculates the hash internally. */
1575 #if defined(SIGN_GNUTLS)
1576 hhash.data = hdata->s;
1577 hhash.len = hdata->ptr;
1580 /*XXX extend for non-RSA algos */
1581 if ((*err = exim_dkim_sign(&sctx,
1582 pdkim_hashes[sig->hashtype].exim_hashmethod,
1583 &hhash, &sig->sighash)))
1585 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1586 return PDKIM_ERR_RSA_SIGNING;
1591 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1592 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1595 sig->signature_header = pdkim_create_header(sig, TRUE);
1598 /* VERIFICATION ----------------------------------------------------------- */
1603 /* Make sure we have all required signature tags */
1604 if (!( sig->domain && *sig->domain
1605 && sig->selector && *sig->selector
1606 && sig->headernames && *sig->headernames
1607 && sig->bodyhash.data
1608 && sig->sighash.data
1609 && sig->keytype >= 0
1610 && sig->hashtype >= 0
1614 sig->verify_status = PDKIM_VERIFY_INVALID;
1615 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1617 DEBUG(D_acl) debug_printf(
1618 " Error in DKIM-Signature header: tags missing or invalid\n"
1619 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1623 /* Make sure sig uses supported DKIM version (only v1) */
1624 if (sig->version != 1)
1626 sig->verify_status = PDKIM_VERIFY_INVALID;
1627 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1629 DEBUG(D_acl) debug_printf(
1630 " Error in DKIM-Signature header: unsupported DKIM version\n"
1631 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1637 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1638 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1641 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1644 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1645 do not have the hash part of the sig algorithm matching */
1647 if (sig->pubkey->hashes)
1649 const uschar * list = sig->pubkey->hashes, * ele;
1651 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1652 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
1655 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1656 sig->pubkey->hashes,
1657 pdkim_keytypes[sig->keytype],
1658 pdkim_hashes[sig->hashtype].dkim_hashname);
1659 sig->verify_status = PDKIM_VERIFY_FAIL;
1660 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1665 /* Check the signature */
1666 /*XXX needs extension for non-RSA */
1667 if ((*err = exim_dkim_verify(&vctx,
1668 pdkim_hashes[sig->hashtype].exim_hashmethod,
1669 &hhash, &sig->sighash)))
1671 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1672 sig->verify_status = PDKIM_VERIFY_FAIL;
1673 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1678 /* We have a winner! (if bodyhash was correct earlier) */
1679 if (sig->verify_status == PDKIM_VERIFY_NONE)
1680 sig->verify_status = PDKIM_VERIFY_PASS;
1686 debug_printf("PDKIM [%s] signature status: %s",
1687 sig->domain, pdkim_verify_status_str(sig->verify_status));
1688 if (sig->verify_ext_status > 0)
1689 debug_printf(" (%s)\n",
1690 pdkim_verify_ext_status_str(sig->verify_ext_status));
1697 /* If requested, set return pointer to signature(s) */
1698 if (return_signatures)
1699 *return_signatures = ctx->sig;
1705 /* -------------------------------------------------------------------------- */
1707 DLLEXPORT pdkim_ctx *
1708 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1712 ctx = store_get(sizeof(pdkim_ctx));
1713 memset(ctx, 0, sizeof(pdkim_ctx));
1715 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1716 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1717 ctx->dns_txt_callback = dns_txt_callback;
1723 /* -------------------------------------------------------------------------- */
1725 /*XXX ? needs extension to cover non-RSA algo? */
1727 DLLEXPORT pdkim_signature *
1728 pdkim_init_sign(pdkim_ctx * ctx,
1729 uschar * domain, uschar * selector, uschar * privkey,
1730 uschar * hashname, const uschar ** errstr)
1733 pdkim_signature * sig;
1735 if (!domain || !selector || !privkey)
1738 /* Allocate & init one signature struct */
1740 sig = store_get(sizeof(pdkim_signature));
1741 memset(sig, 0, sizeof(pdkim_signature));
1743 sig->bodylength = -1;
1745 sig->domain = string_copy(US domain);
1746 sig->selector = string_copy(US selector);
1747 sig->privkey = string_copy(US privkey);
1748 /*XXX no keytype yet; comes from privkey */
1750 for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1751 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1752 { sig->hashtype = hashtype; break; }
1753 if (hashtype >= nelem(pdkim_hashes))
1756 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1760 if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1763 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1769 pdkim_signature s = *sig;
1772 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1773 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1774 debug_printf("WARNING: bad dkim key in dns\n");
1775 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1781 /* -------------------------------------------------------------------------- */
1784 pdkim_set_optional(pdkim_signature * sig,
1785 char * sign_headers,
1790 unsigned long created,
1791 unsigned long expires)
1794 sig->identity = string_copy(US identity);
1796 sig->sign_headers = string_copy(sign_headers
1797 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1799 sig->canon_headers = canon_headers;
1800 sig->canon_body = canon_body;
1801 sig->bodylength = bodylength;
1802 sig->created = created;
1803 sig->expires = expires;
1811 pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1812 int(*dns_txt_callback)(char *, char *))
1814 memset(ctx, 0, sizeof(pdkim_ctx));
1815 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1816 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1817 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1829 #endif /*DISABLE_DKIM*/