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
55 /* -------------------------------------------------------------------------- */
56 struct pdkim_stringlist {
62 /* -------------------------------------------------------------------------- */
63 /* A bunch of list constants */
64 const uschar * pdkim_querymethods[] = {
68 const uschar * pdkim_canons[] = {
75 const uschar * dkim_hashname;
76 hashmethod exim_hashmethod;
78 static const pdkim_hashtype pdkim_hashes[] = {
79 { US"sha1", HASH_SHA1 },
80 { US"sha256", HASH_SHA2_256 },
81 { US"sha512", HASH_SHA2_512 }
84 const uschar * pdkim_keytypes[] = {
88 typedef struct pdkim_combined_canon_entry {
92 } pdkim_combined_canon_entry;
94 pdkim_combined_canon_entry pdkim_combined_canons[] = {
95 { US"simple/simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
96 { US"simple/relaxed", PDKIM_CANON_SIMPLE, PDKIM_CANON_RELAXED },
97 { US"relaxed/simple", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
98 { US"relaxed/relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_RELAXED },
99 { US"simple", PDKIM_CANON_SIMPLE, PDKIM_CANON_SIMPLE },
100 { US"relaxed", PDKIM_CANON_RELAXED, PDKIM_CANON_SIMPLE },
105 static blob lineending = {.data = US"\r\n", .len = 2};
107 /* -------------------------------------------------------------------------- */
109 dkim_sig_to_a_tag(const pdkim_signature * sig)
111 if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes)
112 || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
114 return string_sprintf("%s-%s",
115 pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
121 pdkim_verify_status_str(int status)
125 case PDKIM_VERIFY_NONE: return "PDKIM_VERIFY_NONE";
126 case PDKIM_VERIFY_INVALID: return "PDKIM_VERIFY_INVALID";
127 case PDKIM_VERIFY_FAIL: return "PDKIM_VERIFY_FAIL";
128 case PDKIM_VERIFY_PASS: return "PDKIM_VERIFY_PASS";
129 default: return "PDKIM_VERIFY_UNKNOWN";
134 pdkim_verify_ext_status_str(int ext_status)
138 case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
139 case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
140 case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
141 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
142 case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
143 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
144 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
145 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
146 case PDKIM_VERIFY_INVALID_DKIM_VERSION: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
147 default: return "PDKIM_VERIFY_UNKNOWN";
152 pdkim_errstr(int status)
156 case PDKIM_OK: return US"OK";
157 case PDKIM_FAIL: return US"FAIL";
158 case PDKIM_ERR_RSA_PRIVKEY: return US"RSA_PRIVKEY";
159 case PDKIM_ERR_RSA_SIGNING: return US"RSA SIGNING";
160 case PDKIM_ERR_LONG_LINE: return US"RSA_LONG_LINE";
161 case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
162 case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
163 case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
164 default: return US"(unknown)";
169 /* -------------------------------------------------------------------------- */
170 /* Print debugging functions */
172 pdkim_quoteprint(const uschar *data, int len)
175 for (i = 0; i < len; i++)
177 const int c = data[i];
180 case ' ' : debug_printf("{SP}"); break;
181 case '\t': debug_printf("{TB}"); break;
182 case '\r': debug_printf("{CR}"); break;
183 case '\n': debug_printf("{LF}"); break;
184 case '{' : debug_printf("{BO}"); break;
185 case '}' : debug_printf("{BC}"); break;
187 if ( (c < 32) || (c > 127) )
188 debug_printf("{%02x}", c);
190 debug_printf("%c", c);
198 pdkim_hexprint(const uschar *data, int len)
201 if (data) for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
202 else debug_printf("<NULL>");
208 static pdkim_stringlist *
209 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
211 pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist));
213 memset(new_entry, 0, sizeof(pdkim_stringlist));
214 new_entry->value = string_copy(str);
215 if (base) new_entry->next = base;
221 /* Trim whitespace fore & aft */
224 pdkim_strtrim(gstring * str)
227 uschar * q = p + str->ptr;
229 while (*p == '\t' || *p == ' ') /* dump the leading whitespace */
230 { str->size--; str->ptr--; str->s++; }
233 && (q = str->s + str->ptr - 1), *q == '\t' || *q == ' '
235 str->ptr--; /* dump trailing whitespace */
237 (void) string_from_gstring(str);
242 /* -------------------------------------------------------------------------- */
245 pdkim_free_ctx(pdkim_ctx *ctx)
250 /* -------------------------------------------------------------------------- */
251 /* Matches the name of the passed raw "header" against
252 the passed colon-separated "tick", and invalidates
253 the entry in tick. Entries can be prefixed for multi- or over-signing,
254 in which case do not invalidate.
256 Returns OK for a match, or fail-code
260 header_name_match(const uschar * header, uschar * tick)
262 const uschar * ticklist = tick;
265 uschar * hname, * p, * ele;
266 uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
269 return PDKIM_FAIL; /* This isn't a header */
271 /* if we had strncmpic() we wouldn't need this copy */
272 hname = string_copyn(header, hcolon-header);
274 while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0))
278 case '=': case '+': multisign = TRUE; ele++; break;
279 default: multisign = FALSE; break;
282 if (strcmpic(ele, hname) == 0)
285 *p = '_'; /* Invalidate this header name instance in tick-off list */
293 /* -------------------------------------------------------------------------- */
294 /* Performs "relaxed" canonicalization of a header. */
297 pdkim_relax_header(const uschar * header, BOOL append_crlf)
299 BOOL past_field_name = FALSE;
300 BOOL seen_wsp = FALSE;
302 uschar * relaxed = store_get(Ustrlen(header)+3);
303 uschar * q = relaxed;
305 for (p = header; *p; p++)
309 if (c == '\r' || c == '\n') /* Ignore CR & LF */
311 if (c == '\t' || c == ' ')
315 c = ' '; /* Turns WSP into SP */
319 if (!past_field_name && c == ':')
321 if (seen_wsp) q--; /* This removes WSP immediately before the colon */
322 seen_wsp = TRUE; /* This removes WSP immediately after the colon */
323 past_field_name = TRUE;
328 /* Lowercase header name */
329 if (!past_field_name) c = tolower(c);
333 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
335 if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
341 /* -------------------------------------------------------------------------- */
342 #define PDKIM_QP_ERROR_DECODE -1
344 static const uschar *
345 pdkim_decode_qp_char(const uschar *qp_p, int *c)
347 const uschar *initial_pos = qp_p;
349 /* Advance one char */
352 /* Check for two hex digits and decode them */
353 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
355 /* Do hex conversion */
356 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
357 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
361 /* Illegal char here */
362 *c = PDKIM_QP_ERROR_DECODE;
367 /* -------------------------------------------------------------------------- */
370 pdkim_decode_qp(const uschar * str)
374 const uschar * p = str;
375 uschar * n = store_get(Ustrlen(str)+1);
383 p = pdkim_decode_qp_char(p, &nchar);
399 /* -------------------------------------------------------------------------- */
402 pdkim_decode_base64(const uschar * str, blob * b)
405 dlen = b64decode(str, &b->data);
406 if (dlen < 0) b->data = NULL;
411 pdkim_encode_base64(blob * b)
413 return b64encode(b->data, b->len);
417 /* -------------------------------------------------------------------------- */
418 #define PDKIM_HDR_LIMBO 0
419 #define PDKIM_HDR_TAG 1
420 #define PDKIM_HDR_VALUE 2
422 static pdkim_signature *
423 pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
425 pdkim_signature * sig;
427 gstring * cur_tag = NULL;
428 gstring * cur_val = NULL;
429 BOOL past_hname = FALSE;
430 BOOL in_b_val = FALSE;
431 int where = PDKIM_HDR_LIMBO;
434 sig = store_get(sizeof(pdkim_signature));
435 memset(sig, 0, sizeof(pdkim_signature));
436 sig->bodylength = -1;
438 /* Set so invalid/missing data error display is accurate */
443 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
445 for (p = raw_hdr; ; p++)
450 if (c == '\r' || c == '\n')
453 /* Fast-forward through header name */
456 if (c == ':') past_hname = TRUE;
460 if (where == PDKIM_HDR_LIMBO)
462 /* In limbo, just wait for a tag-char to appear */
463 if (!(c >= 'a' && c <= 'z'))
466 where = PDKIM_HDR_TAG;
469 if (where == PDKIM_HDR_TAG)
471 if (c >= 'a' && c <= 'z')
472 cur_tag = string_catn(cur_tag, p, 1);
476 if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0)
481 where = PDKIM_HDR_VALUE;
486 if (where == PDKIM_HDR_VALUE)
488 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
491 if (c == ';' || c == '\0')
493 if (cur_tag && cur_val)
495 (void) string_from_gstring(cur_val);
496 pdkim_strtrim(cur_val);
498 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s);
503 pdkim_decode_base64(cur_val->s,
504 cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash);
507 /* We only support version 1, and that is currently the
508 only version there is. */
510 Ustrcmp(cur_val->s, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
514 uschar * s = Ustrchr(cur_val->s, '-');
516 for(i = 0; i < nelem(pdkim_keytypes); i++)
517 if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0)
518 { sig->keytype = i; break; }
519 for (++s, i = 0; i < nelem(pdkim_hashes); i++)
520 if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
521 { sig->hashtype = i; break; }
526 for (i = 0; pdkim_combined_canons[i].str; i++)
527 if (Ustrcmp(cur_val->s, pdkim_combined_canons[i].str) == 0)
529 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
530 sig->canon_body = pdkim_combined_canons[i].canon_body;
535 for (i = 0; pdkim_querymethods[i]; i++)
536 if (Ustrcmp(cur_val->s, pdkim_querymethods[i]) == 0)
538 sig->querymethod = i;
543 sig->selector = string_copyn(cur_val->s, cur_val->ptr); break;
545 sig->domain = string_copyn(cur_val->s, cur_val->ptr); break;
547 sig->identity = pdkim_decode_qp(cur_val->s); break;
549 sig->created = strtoul(CS cur_val->s, NULL, 10); break;
551 sig->expires = strtoul(CS cur_val->s, NULL, 10); break;
553 sig->bodylength = strtol(CS cur_val->s, NULL, 10); break;
555 sig->headernames = string_copyn(cur_val->s, cur_val->ptr); break;
557 sig->copiedheaders = pdkim_decode_qp(cur_val->s); break;
559 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
563 cur_tag = cur_val = NULL;
565 where = PDKIM_HDR_LIMBO;
568 cur_val = string_catn(cur_val, p, 1);
580 /* Chomp raw header. The final newline must not be added to the signature. */
581 while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
587 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
588 pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
590 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sighash.len*8);
592 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
595 /*XXX hash method: extend for sha512 */
596 if (!exim_sha_init(&sig->body_hash_ctx,
597 pdkim_hashes[sig->hashtype].exim_hashmethod))
600 debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
607 /* -------------------------------------------------------------------------- */
609 static pdkim_pubkey *
610 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
616 pub = store_get(sizeof(pdkim_pubkey));
617 memset(pub, 0, sizeof(pdkim_pubkey));
619 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
623 if ((val = Ustrchr(ele, '=')))
625 int taglen = val++ - ele;
627 DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
630 case 'v': pub->version = val; break;
631 case 'h': pub->hashes = val; break;
633 case 'g': pub->granularity = val; break;
634 case 'n': pub->notes = pdkim_decode_qp(val); break;
635 case 'p': pdkim_decode_base64(val, &pub->key); break;
636 case 's': pub->srvtype = val; break;
637 case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
638 if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
640 default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
645 /* Set fallback defaults */
646 if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
647 else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
649 DEBUG(D_acl) debug_printf(" Bad v= field\n");
653 if (!pub->granularity) pub->granularity = US"*";
655 if (!pub->keytype ) pub->keytype = US"rsa";
657 if (!pub->srvtype ) pub->srvtype = US"*";
663 DEBUG(D_acl) debug_printf(" Missing p= field\n");
668 /* -------------------------------------------------------------------------- */
670 /* Update the bodyhash for one sig, with some additional data.
671 If we have to relax the data for this sig, return our copy of it. */
673 /*XXX Currently we calculate a hash for each sig. But it is possible
674 that multi-signing will be wanted using different signing algos
675 (rsa, ec) using the same hash and canonicalization. Consider in future
676 hanging the hash+cacnon from the ctx and only referencing from the sig,
677 so that it can be calculated only once - being over the body this
678 caould be meagbytes, hence expensive. */
681 pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
683 blob * canon_data = orig_data;
684 /* Defaults to simple canon (no further treatment necessary) */
686 if (sig->canon_body == PDKIM_CANON_RELAXED)
688 /* Relax the line if not done already */
691 BOOL seen_wsp = FALSE;
695 /* We want to be able to free this else we allocate
696 for the entire message which could be many MB. Since
697 we don't know what allocations the SHA routines might
698 do, not safe to use store_get()/store_reset(). */
700 relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
701 relaxed_data->data = US (relaxed_data+1);
703 for (p = orig_data->data; *p; p++)
708 if (q > 0 && relaxed_data->data[q-1] == ' ')
711 else if (c == '\t' || c == ' ')
713 c = ' '; /* Turns WSP into SP */
720 relaxed_data->data[q++] = c;
722 relaxed_data->data[q] = '\0';
723 relaxed_data->len = q;
725 canon_data = relaxed_data;
728 /* Make sure we don't exceed the to-be-signed body length */
729 if ( sig->bodylength >= 0
730 && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
732 canon_data->len = sig->bodylength - sig->signed_body_bytes;
734 if (canon_data->len > 0)
736 exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
737 sig->signed_body_bytes += canon_data->len;
738 DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
745 /* -------------------------------------------------------------------------- */
748 pdkim_finish_bodyhash(pdkim_ctx * ctx)
750 pdkim_signature * sig;
752 /* Traverse all signatures */
753 for (sig = ctx->sig; sig; sig = sig->next)
754 { /* Finish hashes */
757 exim_sha_finish(&sig->body_hash_ctx, &bh);
761 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
762 "PDKIM [%s] Body %s computed: ",
763 sig->domain, sig->signed_body_bytes,
764 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
765 pdkim_hexprint(CUS bh.data, bh.len);
768 /* SIGNING -------------------------------------------------------------- */
769 if (ctx->flags & PDKIM_MODE_SIGN)
773 /* If bodylength limit is set, and we have received less bytes
774 than the requested amount, effectively remove the limit tag. */
775 if (sig->signed_body_bytes < sig->bodylength)
776 sig->bodylength = -1;
780 /* VERIFICATION --------------------------------------------------------- */
781 /* Be careful that the header sig included a bodyash */
783 if (sig->bodyhash.data && memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
785 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
791 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
792 pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
793 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
795 sig->verify_status = PDKIM_VERIFY_FAIL;
796 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
804 pdkim_body_complete(pdkim_ctx * ctx)
806 pdkim_signature * sig;
808 /* In simple body mode, if any empty lines were buffered,
809 replace with one. rfc 4871 3.4.3 */
810 /*XXX checking the signed-body-bytes is a gross hack; I think
811 it indicates that all linebreaks should be buffered, including
812 the one terminating a text line */
814 for (sig = ctx->sig; sig; sig = sig->next)
815 if ( sig->canon_body == PDKIM_CANON_SIMPLE
816 && sig->signed_body_bytes == 0
817 && sig->num_buffered_blanklines > 0
819 (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
821 ctx->flags |= PDKIM_SEEN_EOD;
822 ctx->linebuf_offset = 0;
827 /* -------------------------------------------------------------------------- */
828 /* Call from pdkim_feed below for processing complete body lines */
831 pdkim_bodyline_complete(pdkim_ctx * ctx)
833 blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
834 pdkim_signature * sig;
838 /* Ignore extra data if we've seen the end-of-data marker */
839 if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
841 /* We've always got one extra byte to stuff a zero ... */
842 ctx->linebuf[line.len] = '\0';
844 /* Terminate on EOD marker */
845 if (ctx->flags & PDKIM_DOT_TERM)
847 if (memcmp(line.data, ".\r\n", 3) == 0)
848 { pdkim_body_complete(ctx); return; }
851 if (memcmp(line.data, "..", 2) == 0)
852 { line.data++; line.len--; }
855 /* Empty lines need to be buffered until we find a non-empty line */
856 if (memcmp(line.data, "\r\n", 2) == 0)
858 for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
862 /* Process line for each sig separately */
863 for (sig = ctx->sig; sig; sig = sig->next)
865 if (sig->canon_body == PDKIM_CANON_RELAXED)
867 /* Lines with just spaces need to be buffered too */
868 uschar * cp = line.data;
873 if (c == '\r' && cp[1] == '\n') break;
874 if (c != ' ' && c != '\t') goto sig_process;
878 sig->num_buffered_blanklines++;
883 /* At this point, we have a non-empty line, so release the buffered ones. */
885 while (sig->num_buffered_blanklines)
887 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
888 sig->num_buffered_blanklines--;
891 rline = pdkim_update_sig_bodyhash(sig, &line, rline);
895 if (rnl) store_free(rnl);
896 if (rline) store_free(rline);
900 ctx->linebuf_offset = 0;
905 /* -------------------------------------------------------------------------- */
906 /* Callback from pdkim_feed below for processing complete headers */
907 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
910 pdkim_header_complete(pdkim_ctx * ctx)
912 pdkim_signature * sig, * last_sig;
914 /* Special case: The last header can have an extra \r appended */
915 if ( (ctx->cur_header->ptr > 1) &&
916 (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
917 --ctx->cur_header->ptr;
918 (void) string_from_gstring(ctx->cur_header);
920 if (++ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
922 /* SIGNING -------------------------------------------------------------- */
923 if (ctx->flags & PDKIM_MODE_SIGN)
924 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
926 /* Add header to the signed headers list (in reverse order) */
927 sig->headers = pdkim_prepend_stringlist(sig->headers, ctx->cur_header->s);
929 /* VERIFICATION ----------------------------------------------------------- */
930 /* DKIM-Signature: headers are added to the verification list */
936 debug_printf("PDKIM >> raw hdr: ");
937 pdkim_quoteprint(CUS ctx->cur_header->s, ctx->cur_header->ptr);
940 if (strncasecmp(CCS ctx->cur_header->s,
941 DKIM_SIGNATURE_HEADERNAME,
942 Ustrlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
944 /* Create and chain new signature block. We could error-check for all
945 required tags here, but prefer to create the internal sig and expicitly
946 fail verification of it later. */
948 DEBUG(D_acl) debug_printf(
949 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
951 sig = pdkim_parse_sig_header(ctx, ctx->cur_header->s);
953 if (!(last_sig = ctx->sig))
957 while (last_sig->next) last_sig = last_sig->next;
958 last_sig->next = sig;
962 /* all headers are stored for signature verification */
963 ctx->headers = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->s);
967 ctx->cur_header->s[ctx->cur_header->ptr = 0] = '\0'; /* leave buffer for reuse */
973 /* -------------------------------------------------------------------------- */
974 #define HEADER_BUFFER_FRAG_SIZE 256
977 pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
981 /* Alternate EOD signal, used in non-dotstuffing mode */
983 pdkim_body_complete(ctx);
985 else for (p = 0; p<len; p++)
989 if (ctx->flags & PDKIM_PAST_HDRS)
991 if (c == '\n' && !(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
993 ctx->linebuf[ctx->linebuf_offset++] = '\r';
994 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
995 return PDKIM_ERR_LONG_LINE;
998 /* Processing body byte */
999 ctx->linebuf[ctx->linebuf_offset++] = c;
1001 ctx->flags |= PDKIM_SEEN_CR;
1004 ctx->flags &= ~PDKIM_SEEN_CR;
1005 pdkim_bodyline_complete(ctx);
1008 if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
1009 return PDKIM_ERR_LONG_LINE;
1013 /* Processing header byte */
1015 ctx->flags |= PDKIM_SEEN_CR;
1018 if (!(ctx->flags & PDKIM_SEEN_CR)) /* emulate the CR */
1019 ctx->cur_header = string_catn(ctx->cur_header, CUS "\r", 1);
1021 if (ctx->flags & PDKIM_SEEN_LF) /* Seen last header line */
1023 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1026 ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS;
1027 DEBUG(D_acl) debug_printf(
1028 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1032 ctx->flags = (ctx->flags & ~PDKIM_SEEN_CR) | PDKIM_SEEN_LF;
1034 else if (ctx->flags & PDKIM_SEEN_LF)
1036 if (!(c == '\t' || c == ' ')) /* End of header */
1037 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1039 ctx->flags &= ~PDKIM_SEEN_LF;
1042 if (!ctx->cur_header || ctx->cur_header->ptr < PDKIM_MAX_HEADER_LEN)
1043 ctx->cur_header = string_catn(ctx->cur_header, CUS &data[p], 1);
1051 /* Extend a growing header with a continuation-linebreak */
1053 pdkim_hdr_cont(gstring * str, int * col)
1056 return string_catn(str, US"\r\n\t", 3);
1062 * RFC 5322 specifies that header line length SHOULD be no more than 78
1066 * returns uschar * (not nul-terminated)
1068 * col: this int holds and receives column number (octets since last '\n')
1069 * str: partial string to append to
1070 * pad: padding, split line or space after before or after eg: ";"
1071 * intro: - must join to payload eg "h=", usually the tag name
1072 * payload: eg base64 data - long data can be split arbitrarily.
1074 * this code doesn't fold the header in some of the places that RFC4871
1075 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1076 * pairs and inside long values. it also always spaces or breaks after the
1079 * no guarantees are made for output given out-of range input. like tag
1080 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1084 pdkim_headcat(int * col, gstring * str,
1085 const uschar * pad, const uschar * intro, const uschar * payload)
1093 str = pdkim_hdr_cont(str, col);
1094 str = string_catn(str, pad, l);
1098 l = (pad?1:0) + (intro?Ustrlen(intro):0);
1101 { /*can't fit intro - start a new line to make room.*/
1102 str = pdkim_hdr_cont(str, col);
1103 l = intro?Ustrlen(intro):0;
1106 l += payload ? Ustrlen(payload):0 ;
1109 { /* this fragment will not fit on a single line */
1112 str = string_catn(str, US" ", 1);
1114 pad = NULL; /* only want this once */
1120 size_t sl = Ustrlen(intro);
1122 str = string_catn(str, intro, sl);
1125 intro = NULL; /* only want this once */
1130 size_t sl = Ustrlen(payload);
1131 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1133 str = string_catn(str, payload, chomp);
1139 /* the while precondition tells us it didn't fit. */
1140 str = pdkim_hdr_cont(str, col);
1145 str = pdkim_hdr_cont(str, col);
1151 str = string_catn(str, US" ", 1);
1158 size_t sl = Ustrlen(intro);
1160 str = string_catn(str, intro, sl);
1168 size_t sl = Ustrlen(payload);
1170 str = string_catn(str, payload, sl);
1178 /* -------------------------------------------------------------------------- */
1181 pdkim_create_header(pdkim_signature * sig, BOOL final)
1187 gstring * canon_all;
1189 canon_all = string_cat (NULL, pdkim_canons[sig->canon_headers]);
1190 canon_all = string_catn(canon_all, US"/", 1);
1191 canon_all = string_cat (canon_all, pdkim_canons[sig->canon_body]);
1192 (void) string_from_gstring(canon_all);
1194 hdr = string_cat(NULL, US"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION);
1197 /* Required and static bits */
1198 hdr = pdkim_headcat(&col, hdr, US";", US"a=", dkim_sig_to_a_tag(sig));
1199 hdr = pdkim_headcat(&col, hdr, US";", US"q=", pdkim_querymethods[sig->querymethod]);
1200 hdr = pdkim_headcat(&col, hdr, US";", US"c=", canon_all->s);
1201 hdr = pdkim_headcat(&col, hdr, US";", US"d=", sig->domain);
1202 hdr = pdkim_headcat(&col, hdr, US";", US"s=", sig->selector);
1204 /* list of header names can be split between items. */
1206 uschar * n = string_copy(sig->headernames);
1207 uschar * i = US"h=";
1212 uschar * c = Ustrchr(n, ':');
1217 hdr = pdkim_headcat(&col, hdr, NULL, NULL, US":");
1219 hdr = pdkim_headcat(&col, hdr, s, i, n);
1230 base64_bh = pdkim_encode_base64(&sig->bodyhash);
1231 hdr = pdkim_headcat(&col, hdr, US";", US"bh=", base64_bh);
1235 hdr = pdkim_headcat(&col, hdr, US";", US"i=", sig->identity);
1237 if (sig->created > 0)
1241 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1242 hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
1245 if (sig->expires > 0)
1249 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1250 hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
1253 if (sig->bodylength >= 0)
1257 snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1258 hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
1261 /* Preliminary or final version? */
1264 base64_b = pdkim_encode_base64(&sig->sighash);
1265 hdr = pdkim_headcat(&col, hdr, US";", US"b=", base64_b);
1267 /* add trailing semicolon: I'm not sure if this is actually needed */
1268 hdr = pdkim_headcat(&col, hdr, NULL, US";", US"");
1272 /* To satisfy the rule "all surrounding whitespace [...] deleted"
1273 ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
1274 the headcat routine could insert a linebreak which the relaxer would reduce
1275 to a single space preceding the terminating semicolon, resulting in an
1276 incorrect header-hash. */
1277 hdr = pdkim_headcat(&col, hdr, US";", US"b=;", US"");
1280 return string_from_gstring(hdr);
1284 /* -------------------------------------------------------------------------- */
1286 static pdkim_pubkey *
1287 pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
1288 const uschar ** errstr)
1290 uschar * dns_txt_name, * dns_txt_reply;
1293 /* Fetch public key for signing domain, from DNS */
1295 dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
1297 dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
1298 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1300 if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
1301 || dns_txt_reply[0] == '\0'
1304 sig->verify_status = PDKIM_VERIFY_INVALID;
1305 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1312 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1316 pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
1319 if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply))
1320 || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0)
1323 sig->verify_status = PDKIM_VERIFY_INVALID;
1324 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1329 debug_printf(" Invalid public key service type '%s'\n", p->srvtype);
1331 debug_printf(" Error while parsing public key record\n");
1333 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1338 DEBUG(D_acl) debug_printf(
1339 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1341 /* Import public key */
1342 if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
1344 DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
1345 sig->verify_status = PDKIM_VERIFY_INVALID;
1346 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1354 /* -------------------------------------------------------------------------- */
1357 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
1358 const uschar ** err)
1360 pdkim_signature * sig;
1362 /* Check if we must still flush a (partial) header. If that is the
1363 case, the message has no body, and we must compute a body hash
1364 out of '<CR><LF>' */
1365 if (ctx->cur_header && ctx->cur_header->ptr > 0)
1370 if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
1373 for (sig = ctx->sig; sig; sig = sig->next)
1374 rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
1375 if (rnl) store_free(rnl);
1378 DEBUG(D_acl) debug_printf(
1379 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1381 /* Build (and/or evaluate) body hash */
1382 pdkim_finish_bodyhash(ctx);
1384 for (sig = ctx->sig; sig; sig = sig->next)
1387 uschar * sig_hdr = US"";
1389 gstring * hdata = NULL;
1391 if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
1394 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1398 if (ctx->flags & PDKIM_MODE_SIGN)
1399 DEBUG(D_acl) debug_printf(
1400 "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
1404 DEBUG(D_acl) debug_printf(
1405 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
1408 /* SIGNING ---------------------------------------------------------------- */
1409 /* When signing, walk through our header list and add them to the hash. As we
1410 go, construct a list of the header's names to use for the h= parameter.
1411 Then append to that list any remaining header names for which there was no
1414 if (ctx->flags & PDKIM_MODE_SIGN)
1417 pdkim_stringlist *p;
1422 sig->headernames = NULL; /* Collected signed header names */
1424 for (p = sig->headers; p; p = p->next)
1426 uschar * rh = p->value;
1428 if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
1430 /* Collect header names (Note: colon presence is guaranteed here) */
1431 g = string_append_listele_n(g, ':', rh, Ustrchr(rh, ':') - rh);
1433 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1434 rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
1436 /* Feed header to the hash algorithm */
1437 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1439 /* Remember headers block for signing (when the library cannot do incremental) */
1440 hdata = exim_dkim_data_append(hdata, rh);
1442 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1446 /* Any headers we wanted to sign but were not present must also be listed.
1447 Ignore elements that have been ticked-off or are marked as never-oversign. */
1449 l = sig->sign_headers;
1450 while((s = string_nextinlist(&l, &sep, NULL, 0)))
1452 if (*s == '+') /* skip oversigning marker */
1454 if (*s != '_' && *s != '=')
1455 g = string_append_listele(g, ':', s);
1457 sig->headernames = string_from_gstring(g);
1459 /* Create signature header with b= omitted */
1460 sig_hdr = pdkim_create_header(sig, FALSE);
1463 /* VERIFICATION ----------------------------------------------------------- */
1464 /* When verifying, walk through the header name list in the h= parameter and
1465 add the headers to the hash in that order. */
1468 uschar * p = sig->headernames;
1470 pdkim_stringlist * hdrs;
1475 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1481 if ((q = Ustrchr(p, ':')))
1484 /*XXX walk the list of headers in same order as received. */
1485 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1487 && strncasecmp(CCS hdrs->value, CCS p, Ustrlen(p)) == 0
1488 && (hdrs->value)[Ustrlen(p)] == ':'
1491 /* cook header for relaxed canon, or just copy it for simple */
1493 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1494 ? pdkim_relax_header(hdrs->value, TRUE)
1495 : string_copy(CUS hdrs->value);
1497 /* Feed header to the hash algorithm */
1498 exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1500 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1509 sig_hdr = string_copy(sig->rawsig_no_b_val);
1513 DEBUG(D_acl) debug_printf(
1514 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1519 "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
1520 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1522 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1525 /* Relax header if necessary */
1526 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1527 sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
1532 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1533 pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
1535 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1538 /* Finalize header hash */
1539 exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1540 exim_sha_finish(&hhash_ctx, &hhash);
1544 debug_printf("PDKIM [%s] Header %s computed: ",
1545 sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
1546 pdkim_hexprint(hhash.data, hhash.len);
1549 /* Remember headers block for signing (when the signing library cannot do
1551 if (ctx->flags & PDKIM_MODE_SIGN)
1552 hdata = exim_dkim_data_append(hdata, US sig_hdr);
1554 /* SIGNING ---------------------------------------------------------------- */
1555 if (ctx->flags & PDKIM_MODE_SIGN)
1559 /* Import private key, including the keytype */
1560 /*XXX extend for non-RSA algos */
1561 if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
1563 DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
1564 return PDKIM_ERR_RSA_PRIVKEY;
1567 /* Do signing. With OpenSSL we are signing the hash of headers just
1568 calculated, with GnuTLS we have to sign an entire block of headers
1569 (due to available interfaces) and it recalculates the hash internally. */
1571 #if defined(SIGN_GNUTLS)
1572 hhash.data = hdata->s;
1573 hhash.len = hdata->ptr;
1576 /*XXX extend for non-RSA algos */
1577 if ((*err = exim_dkim_sign(&sctx,
1578 pdkim_hashes[sig->hashtype].exim_hashmethod,
1579 &hhash, &sig->sighash)))
1581 DEBUG(D_acl) debug_printf("signing: %s\n", *err);
1582 return PDKIM_ERR_RSA_SIGNING;
1587 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1588 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1591 sig->signature_header = pdkim_create_header(sig, TRUE);
1594 /* VERIFICATION ----------------------------------------------------------- */
1599 /* Make sure we have all required signature tags */
1600 if (!( sig->domain && *sig->domain
1601 && sig->selector && *sig->selector
1602 && sig->headernames && *sig->headernames
1603 && sig->bodyhash.data
1604 && sig->sighash.data
1605 && sig->keytype >= 0
1606 && sig->hashtype >= 0
1610 sig->verify_status = PDKIM_VERIFY_INVALID;
1611 sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR;
1613 DEBUG(D_acl) debug_printf(
1614 " Error in DKIM-Signature header: tags missing or invalid\n"
1615 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1619 /* Make sure sig uses supported DKIM version (only v1) */
1620 if (sig->version != 1)
1622 sig->verify_status = PDKIM_VERIFY_INVALID;
1623 sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION;
1625 DEBUG(D_acl) debug_printf(
1626 " Error in DKIM-Signature header: unsupported DKIM version\n"
1627 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1633 debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
1634 pdkim_hexprint(sig->sighash.data, sig->sighash.len);
1637 if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
1640 /* If the pubkey limits to a list of specific hashes, ignore sigs that
1641 do not have the hash part of the sig algorithm matching */
1643 if (sig->pubkey->hashes)
1645 const uschar * list = sig->pubkey->hashes, * ele;
1647 while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
1648 if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
1651 DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
1652 sig->pubkey->hashes,
1653 pdkim_keytypes[sig->keytype],
1654 pdkim_hashes[sig->hashtype].dkim_hashname);
1655 sig->verify_status = PDKIM_VERIFY_FAIL;
1656 sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
1661 /* Check the signature */
1662 /*XXX needs extension for non-RSA */
1663 if ((*err = exim_dkim_verify(&vctx,
1664 pdkim_hashes[sig->hashtype].exim_hashmethod,
1665 &hhash, &sig->sighash)))
1667 DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
1668 sig->verify_status = PDKIM_VERIFY_FAIL;
1669 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1674 /* We have a winner! (if bodyhash was correct earlier) */
1675 if (sig->verify_status == PDKIM_VERIFY_NONE)
1676 sig->verify_status = PDKIM_VERIFY_PASS;
1682 debug_printf("PDKIM [%s] signature status: %s",
1683 sig->domain, pdkim_verify_status_str(sig->verify_status));
1684 if (sig->verify_ext_status > 0)
1685 debug_printf(" (%s)\n",
1686 pdkim_verify_ext_status_str(sig->verify_ext_status));
1693 /* If requested, set return pointer to signature(s) */
1694 if (return_signatures)
1695 *return_signatures = ctx->sig;
1701 /* -------------------------------------------------------------------------- */
1703 DLLEXPORT pdkim_ctx *
1704 pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
1708 ctx = store_get(sizeof(pdkim_ctx));
1709 memset(ctx, 0, sizeof(pdkim_ctx));
1711 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1712 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1713 ctx->dns_txt_callback = dns_txt_callback;
1719 /* -------------------------------------------------------------------------- */
1721 /*XXX ? needs extension to cover non-RSA algo? */
1723 DLLEXPORT pdkim_signature *
1724 pdkim_init_sign(pdkim_ctx * ctx,
1725 uschar * domain, uschar * selector, uschar * privkey,
1726 uschar * hashname, const uschar ** errstr)
1729 pdkim_signature * sig;
1731 if (!domain || !selector || !privkey)
1734 /* Allocate & init one signature struct */
1736 sig = store_get(sizeof(pdkim_signature));
1737 memset(sig, 0, sizeof(pdkim_signature));
1739 sig->bodylength = -1;
1741 sig->domain = string_copy(US domain);
1742 sig->selector = string_copy(US selector);
1743 sig->privkey = string_copy(US privkey);
1744 /*XXX no keytype yet; comes from privkey */
1746 for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
1747 if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
1748 { sig->hashtype = hashtype; break; }
1749 if (hashtype >= nelem(pdkim_hashes))
1752 debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
1756 if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
1759 debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
1765 pdkim_signature s = *sig;
1768 debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1769 if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
1770 debug_printf("WARNING: bad dkim key in dns\n");
1771 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1777 /* -------------------------------------------------------------------------- */
1780 pdkim_set_optional(pdkim_signature * sig,
1781 char * sign_headers,
1786 unsigned long created,
1787 unsigned long expires)
1790 sig->identity = string_copy(US identity);
1792 sig->sign_headers = string_copy(sign_headers
1793 ? US sign_headers : US PDKIM_DEFAULT_SIGN_HEADERS);
1795 sig->canon_headers = canon_headers;
1796 sig->canon_body = canon_body;
1797 sig->bodylength = bodylength;
1798 sig->created = created;
1799 sig->expires = expires;
1807 pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
1808 int(*dns_txt_callback)(char *, char *))
1810 memset(ctx, 0, sizeof(pdkim_ctx));
1811 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
1812 ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
1813 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
1825 #endif /*DISABLE_DKIM*/