38677097be4b477bd9cd10d24819f78ecd85b2ce
[exim.git] / src / src / miscmods / dkim.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge, 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
9
10 /* Code for DKIM support. Other DKIM relevant code is in
11    receive.c, transport.c and transports/smtp.c */
12
13 #include "../exim.h"
14
15 #ifndef DISABLE_DKIM
16
17 # include "pdkim.h"
18 # include "signing.h"
19
20 # ifdef MACRO_PREDEF
21 #  include "../macro_predef.h"
22
23 void
24 params_dkim(void)
25 {
26 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
27 builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
28 }
29 # else  /*!MACRO_PREDEF*/
30
31 /* Options */
32
33 uschar *dkim_verify_hashes      = US"sha256:sha512";
34 uschar *dkim_verify_keytypes    = US"ed25519:rsa";
35 uschar *dkim_verify_min_keysizes = US"rsa=1024 ed25519=250";
36 BOOL    dkim_verify_minimal     = FALSE;
37 uschar *dkim_verify_signers     = US"$dkim_signers";
38
39 /* $variables */
40
41 uschar *dkim_cur_signer         = NULL;
42 int     dkim_key_length         = 0;
43 uschar *dkim_signers            = NULL;
44 uschar *dkim_signing_domain     = NULL;
45 uschar *dkim_signing_selector   = NULL;
46 uschar *dkim_verify_reason      = NULL;
47 uschar *dkim_verify_status      = NULL;
48
49 /* Working variables */
50
51 unsigned dkim_collect_input     = 0;
52 void   *dkim_signatures         = NULL;
53 gstring *dkim_signing_record    = NULL;
54 uschar *dkim_vdom_firstpass     = NULL;
55
56
57 extern BOOL    dkim_transport_write_message(transport_ctx *,
58                   struct ob_dkim *, const uschar ** errstr);
59
60 /****************************************/
61
62 pdkim_ctx dkim_sign_ctx;
63
64 int dkim_verify_oldpool;
65 pdkim_ctx * dkim_verify_ctx = NULL;
66 pdkim_signature *dkim_cur_sig = NULL;
67 static const uschar * dkim_collect_error = NULL;
68
69 #define DKIM_MAX_SIGNATURES 20
70 static void dkim_exim_verify_pause(BOOL pause);
71
72
73 /****************************************/
74
75 /* Look up the DKIM record in DNS for the given hostname.
76 Will use the first found if there are multiple.
77 The return string is tainted, having come from off-site.
78 */
79
80 static uschar *
81 dkim_exim_query_dns_txt(const uschar * name)
82 {
83 dns_answer * dnsa = store_get_dns_answer();
84 dns_scan dnss;
85 rmark reset_point = store_mark();
86 gstring * g = string_get_tainted(256, GET_TAINTED);
87
88 lookup_dnssec_authenticated = NULL;
89 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
90   goto bad;
91
92 /* Search for TXT record */
93
94 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
95      rr;
96      rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
97   if (rr->type == T_TXT)
98     {                   /* Copy record content to the answer buffer */
99     for (int rr_offset = 0; rr_offset < rr->size; )
100       {
101       uschar len = rr->data[rr_offset++];
102
103       g = string_catn(g, US(rr->data + rr_offset), len);
104       if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN)
105         goto bad;
106
107       rr_offset += len;
108       }
109
110     /* Check if this looks like a DKIM record */
111     if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
112       {
113       store_free_dns_answer(dnsa);
114       gstring_release_unused(g);
115       return string_from_gstring(g);
116       }
117
118     gstring_reset(g);           /* overwrite previous record */
119     }
120
121 bad:
122 store_reset(reset_point);
123 store_free_dns_answer(dnsa);
124 return NULL;    /*XXX better error detail?  logging? */
125 }
126
127
128
129 /* Module API:  Lookup a DNS DKIM record and parse the pubkey.
130
131 Arguments:
132         dnsname         record to lookup in DNS
133         pubkey_p        pointer for return of pubkey
134         hashes_p        pointer for return of hashes
135
136 Return: srvtype, or NULL on error
137 */
138
139 static const uschar *
140 dkim_exim_parse_dns_pubkey(const uschar * dnsname, blob ** pubkey_p,
141   const uschar ** hashes_p)
142 {
143 const uschar * dnstxt = dkim_exim_query_dns_txt(dnsname);
144 pdkim_pubkey * p;
145
146 if (!dnstxt)
147   {
148   DEBUG(D_acl) debug_printf_indent("pubkey dns lookup fail\n");
149   return NULL;
150   }
151 if (!(p = pdkim_parse_pubkey_record(dnstxt)))
152   {
153   DEBUG(D_acl) debug_printf_indent("pubkey dns record format error\n");
154   return NULL;
155   }
156 *pubkey_p = &p->key;
157 *hashes_p = p->hashes;
158 return p->srvtype;
159 }
160
161
162
163
164 /* Return:
165         OK      verify succesful
166         FAIL    verify did not pass
167         ERROR   problem setting up the pubkey
168 */
169
170 static int
171 dkim_exim_sig_verify(const blob * sighash, const blob * data_hash,
172   hashmethod hash, const blob * pubkey, const uschar ** errstr_p)
173 {
174 ev_ctx vctx;
175 const uschar * errstr;
176 int rc = OK;
177
178 if ((errstr = exim_dkim_verify_init(pubkey, KEYFMT_DER, &vctx, NULL)))
179   rc = ERROR;
180 else if ((errstr = exim_dkim_verify(&vctx, hash, data_hash, sighash)))
181   rc = FAIL;
182
183 *errstr_p = errstr;
184 return rc;
185 }
186
187
188
189 /****************************************/
190
191 static BOOL
192 dkim_exim_init(void * dummy)
193 {
194 if (f.dkim_init_done) return TRUE;
195 f.dkim_init_done = TRUE;
196 pdkim_init();
197 return TRUE;
198 }
199
200
201
202 /* Module API: Set up for verification of a message being received.
203 Always returns OK.
204 */
205
206 static int
207 dkim_exim_verify_init(void)
208 {
209 BOOL dot_stuffing = chunking_state <= CHUNKING_OFFERED;
210
211 if (!smtp_input || smtp_batched_input || f.dkim_disable_verify)
212   return OK;
213
214 dkim_exim_init(NULL);
215
216 /* There is a store-reset between header & body reception for the main pool
217 (actually, after every header line) so cannot use that as we need the data we
218 store per-header, during header processing, at the end of body reception
219 for evaluating the signature.  Any allocs done for dkim verify
220 memory-handling must use a different pool.  We use a separate one that we
221 can reset per message. */
222
223 dkim_verify_oldpool = store_pool;
224 store_pool = POOL_MESSAGE;
225
226 /* Free previous context if there is one */
227
228 if (dkim_verify_ctx)
229   pdkim_free_ctx(dkim_verify_ctx);
230
231 /* Create new context */
232
233 dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt, dot_stuffing);
234 dkim_exim_verify_pause(FALSE);
235 dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
236 dkim_collect_error = NULL;
237
238 /* Start feed up with any cached data, but limited to message data */
239 receive_get_cache(chunking_state == CHUNKING_LAST
240                   ? chunking_data_left : GETC_BUFFER_UNLIMITED);
241
242 store_pool = dkim_verify_oldpool;
243 return OK;
244 }
245
246
247 /* Module API : Submit a chunk of data for verification input.
248 A NULL data pointer indicates end-of-message.
249 Only use the data when the feed is activated. */
250
251 static void
252 dkim_exim_verify_feed(const uschar * data, unsigned len)
253 {
254 int rc;
255
256 store_pool = POOL_MESSAGE;
257 if (  (dkim_collect_input || !data)
258    && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
259   {
260   dkim_collect_error = pdkim_errstr(rc);
261   log_write(0, LOG_MAIN,
262              "DKIM: validation error: %.100s", dkim_collect_error);
263   dkim_collect_input = 0;
264   }
265 store_pool = dkim_verify_oldpool;
266 }
267
268
269 /* Module API: pause/resume the verification data feed */
270
271 static void
272 dkim_exim_verify_pause(BOOL pause)
273 {
274 static unsigned save = 0;
275 static BOOL paused = FALSE;
276
277 if (!pause)
278   {
279   if (paused)
280     { dkim_collect_input = save; paused = FALSE; }
281   }
282 else
283   if (!paused)
284     { save = dkim_collect_input; dkim_collect_input = 0; paused = TRUE; }
285 }
286
287 /* Module API: Finish off the body hashes, calculate sigs and do compares */
288
289 static void
290 dkim_exim_verify_finish(void)
291 {
292 int rc;
293 gstring * g = NULL;
294 const uschar * errstr = NULL;
295
296 store_pool = POOL_MESSAGE;
297
298 /* Delete eventual previous signature chain */
299
300 dkim_signers = NULL;
301 dkim_signatures = NULL;
302
303 if (dkim_collect_error)
304   {
305   log_write(0, LOG_MAIN,
306       "DKIM: Error during validation, disabling signature verification: %.100s",
307       dkim_collect_error);
308   f.dkim_disable_verify = TRUE;
309   goto out;
310   }
311
312 dkim_collect_input = 0;
313
314 /* Finish DKIM operation and fetch link to signatures chain */
315
316 rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures,
317                         &errstr);
318 if (rc != PDKIM_OK && errstr)
319   log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr);
320
321 /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
322
323 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
324   {
325   if (sig->domain)   g = string_append_listele(g, ':', sig->domain);
326   if (sig->identity) g = string_append_listele(g, ':', sig->identity);
327   }
328 gstring_release_unused(g);
329 dkim_signers = string_from_gstring(g);
330
331 out:
332 store_pool = dkim_verify_oldpool;
333 }
334
335
336
337 /* Log the result for the given signature */
338 static void
339 dkim_exim_verify_log_sig(pdkim_signature * sig)
340 {
341 gstring * logmsg;
342 uschar * s;
343
344 if (!sig) return;
345
346 /* Remember the domain for the first pass result */
347
348 if (  !dkim_vdom_firstpass
349    && dkim_verify_status
350       ? Ustrcmp(dkim_verify_status, US"pass") == 0
351       : sig->verify_status == PDKIM_VERIFY_PASS
352    )
353   dkim_vdom_firstpass= string_copy(sig->domain);
354
355 /* Rewrite the sig result if the ACL overrode it.  This is only
356 needed because the DMARC code (sigh) peeks at the dkim sigs.
357 Mark the sig for this having been done. */
358
359 if (  dkim_verify_status
360    && (  dkim_verify_status != dkim_exim_expand_query(DKIM_VERIFY_STATUS)
361       || dkim_verify_reason != dkim_exim_expand_query(DKIM_VERIFY_REASON)
362    )  )
363   {                     /* overridden by ACL */
364   sig->verify_ext_status = -1;
365   if (Ustrcmp(dkim_verify_status, US"fail") == 0)
366     sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_FAIL;
367   else if (Ustrcmp(dkim_verify_status, US"invalid") == 0)
368     sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_INVALID;
369   else if (Ustrcmp(dkim_verify_status, US"none") == 0)
370     sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_NONE;
371   else if (Ustrcmp(dkim_verify_status, US"pass") == 0)
372     sig->verify_status = PDKIM_VERIFY_POLICY | PDKIM_VERIFY_PASS;
373   else
374     sig->verify_status = -1;
375   }
376
377 if (!LOGGING(dkim_verbose)) return;
378
379
380 logmsg = string_catn(NULL, US"DKIM: ", 6);
381 if (!(s = sig->domain)) s = US"<UNSET>";
382 logmsg = string_append(logmsg, 2, "d=", s);
383 if (!(s = sig->selector)) s = US"<UNSET>";
384 logmsg = string_append(logmsg, 2, " s=", s);
385 logmsg = string_fmt_append(logmsg, " c=%s/%s a=%s b=" SIZE_T_FMT,
386           sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
387           sig->canon_body    == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
388           dkim_sig_to_a_tag(sig),
389           (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : (size_t)0);
390 if ((s= sig->identity)) logmsg = string_append(logmsg, 2, " i=", s);
391 if (sig->created > 0) logmsg = string_fmt_append(logmsg, " t=%lu",
392                                     sig->created);
393 if (sig->expires > 0) logmsg = string_fmt_append(logmsg, " x=%lu",
394                                     sig->expires);
395 if (sig->bodylength > -1) logmsg = string_fmt_append(logmsg, " l=%lu",
396                                     sig->bodylength);
397
398 if (sig->verify_status & PDKIM_VERIFY_POLICY)
399   logmsg = string_append(logmsg, 5,
400             US" [", dkim_verify_status, US" - ", dkim_verify_reason, US"]");
401 else
402   switch (sig->verify_status)
403     {
404     case PDKIM_VERIFY_NONE:
405       logmsg = string_cat(logmsg, US" [not verified]");
406       break;
407
408     case PDKIM_VERIFY_INVALID:
409       logmsg = string_cat(logmsg, US" [invalid - ");
410       switch (sig->verify_ext_status)
411         {
412         case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
413           logmsg = string_cat(logmsg,
414                         US"public key record (currently?) unavailable]");
415           break;
416
417         case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
418           logmsg = string_cat(logmsg, US"overlong public key record]");
419           break;
420
421         case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
422         case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
423           logmsg = string_cat(logmsg, US"syntax error in public key record]");
424           break;
425
426         case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
427           logmsg = string_cat(logmsg, US"signature tag missing or invalid]");
428           break;
429
430         case PDKIM_VERIFY_INVALID_DKIM_VERSION:
431           logmsg = string_cat(logmsg, US"unsupported DKIM version]");
432           break;
433
434         default:
435           logmsg = string_cat(logmsg, US"unspecified problem]");
436         }
437       break;
438
439     case PDKIM_VERIFY_FAIL:
440       logmsg = string_cat(logmsg, US" [verification failed - ");
441       switch (sig->verify_ext_status)
442         {
443         case PDKIM_VERIFY_FAIL_BODY:
444           logmsg = string_cat(logmsg,
445                US"body hash mismatch (body probably modified in transit)]");
446           break;
447
448         case PDKIM_VERIFY_FAIL_MESSAGE:
449           logmsg = string_cat(logmsg,
450                 US"signature did not verify "
451                 "(headers probably modified in transit)]");
452           break;
453
454         case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
455           logmsg = string_cat(logmsg,
456                 US"signature invalid (key too short)]");
457           break;
458
459         default:
460           logmsg = string_cat(logmsg, US"unspecified reason]");
461         }
462       break;
463
464     case PDKIM_VERIFY_PASS:
465       logmsg = string_cat(logmsg, US" [verification succeeded]");
466       break;
467     }
468
469 log_write(0, LOG_MAIN, "%Y", logmsg);
470 return;
471 }
472
473
474 /* Module API:  Log a line for each signature */
475
476 void
477 dkim_exim_verify_log_all(void)
478 {
479 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
480   dkim_exim_verify_log_sig(sig);
481 }
482
483
484 /* Module API: append a log element with domain for the first passing sig */
485
486 gstring *
487 dkim_exim_vdom_firstpass(gstring * g)
488 {
489 if (dkim_vdom_firstpass)
490   g = string_append(g, 2, US" DKIM=", dkim_vdom_firstpass);
491 return g;
492 }
493
494
495 /* For one signature, run the DKIM ACL, log the sig result,
496 and append ths sig status to the status list.
497
498 Args as per dkim_exim_acl_run() below */
499
500 static int
501 dkim_acl_call(uschar * id, gstring ** res_ptr,
502   uschar ** user_msgptr, uschar ** log_msgptr)
503 {
504 int rc;
505 DEBUG(D_receive)
506   debug_printf("calling acl_smtp_dkim for identity '%s' domain '%s' sel '%s'\n",
507               id, dkim_signing_domain, dkim_signing_selector);
508
509 rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, user_msgptr, log_msgptr);
510 dkim_exim_verify_log_sig(dkim_cur_sig);
511 *res_ptr = string_append_listele(*res_ptr, ':', dkim_verify_status);
512 return rc;
513 }
514
515
516
517 /* For the given identity, run the DKIM ACL once for each matching signature.
518 If none match, run it once.
519
520 Arguments
521  id             Identity to look for in dkim signatures
522  res_ptr        ptr to growable string-list of status results,
523                 appended to per ACL run
524  user_msgptr    where to put a user error (for SMTP response)
525  log_msgptr     where to put a logging message (not for SMTP response)
526
527 Returns:       OK         access is granted by an ACCEPT verb
528                DISCARD    access is granted by a DISCARD verb
529                FAIL       access is denied
530                FAIL_DROP  access is denied; drop the connection
531                DEFER      can't tell at the moment
532                ERROR      disaster
533 */
534
535 static int
536 dkim_exim_acl_run(uschar * id, gstring ** res_ptr,
537   uschar ** user_msgptr, uschar ** log_msgptr)
538 {
539 uschar * cmp_val;
540 int rc = -1;
541
542 dkim_verify_status = US"none";
543 dkim_verify_reason = US"";
544 dkim_cur_signer = id;
545
546 if (f.dkim_disable_verify || !id || !dkim_verify_ctx)
547   return OK;
548
549 /* Find signatures to run ACL on */
550
551 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
552   if (  (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
553      && strcmpic(cmp_val, id) == 0
554      )
555     {
556     /* The "dkim_domain" and "dkim_selector" expansion variables have
557     related globals, since they are used in the signing code too.
558     Instead of inventing separate names for verification, we set
559     them here. This is easy since a domain and selector is guaranteed
560     to be in a signature. The other dkim_* expansion items are
561     dynamically fetched from dkim_cur_sig at expansion time (see
562     dkim_exim_expand_query() below). */
563
564     dkim_cur_sig = sig;
565     dkim_signing_domain = US sig->domain;
566     dkim_signing_selector = US sig->selector;
567     dkim_key_length = sig->keybits;
568
569     /* These two return static strings, so we can compare the addr
570     later to see if the ACL overwrote them.  Check that when logging */
571
572     dkim_verify_status = dkim_exim_expand_query(DKIM_VERIFY_STATUS);
573     dkim_verify_reason = dkim_exim_expand_query(DKIM_VERIFY_REASON);
574
575     if (  (rc = dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr)) != OK
576        || dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
577       return rc;
578     }
579
580 if (rc != -1)
581   return rc;
582
583 /* No matching sig found.  Call ACL once anyway. */
584
585 dkim_cur_sig = NULL;
586 return dkim_acl_call(id, res_ptr, user_msgptr, log_msgptr);
587 }
588
589
590 /* Module API:
591 Loop over dkim_verify_signers option doing ACL calls.  If one return any
592 non-OK value stop and return that, else return OK.
593 */
594
595 int
596     /*XXX need a user_msgptr */
597 dkim_exim_acl_entry(uschar ** user_msgptr, uschar ** log_msgptr)
598 {
599 int rc = OK;
600
601 GET_OPTION("dkim_verify_signers");
602 if (dkim_verify_signers && *dkim_verify_signers)
603   {
604   const uschar * dkim_verify_signers_expanded =
605                       expand_cstring(dkim_verify_signers);
606   gstring * results = NULL, * seen_items = NULL;
607   int signer_sep = 0, old_pool = store_pool;
608
609   if (!dkim_verify_signers_expanded)
610     {
611     log_write(0, LOG_MAIN|LOG_PANIC,
612       "expansion of dkim_verify_signers option failed: %s",
613       expand_string_message);
614     return DEFER;
615     }
616
617   store_pool = POOL_PERM;   /* Allow created variables to live to data ACL */
618
619   /* Loop over signers we want to verify, calling ACL.  Default to OK
620   when no signers are present.  Each call from here expands to an ACL
621   call per matching sig in the message. */
622
623   for (uschar * item;
624       item = string_nextinlist(&dkim_verify_signers_expanded,
625                                     &signer_sep, NULL, 0); )
626     {
627     /* Prevent running ACL for an empty item */
628     if (!item || !*item) continue;
629
630     /* Only run ACL once for each domain or identity,
631     no matter how often it appears in the expanded list. */
632     if (seen_items)
633       {
634       uschar * seen_item;
635       const uschar * seen_items_list = string_from_gstring(seen_items);
636       int seen_sep = ':';
637       BOOL seen_this_item = FALSE;
638
639       while ((seen_item = string_nextinlist(&seen_items_list, &seen_sep,
640                                             NULL, 0)))
641         if (Ustrcmp(seen_item, item) == 0)
642           {
643           seen_this_item = TRUE;
644           break;
645           }
646
647       if (seen_this_item)
648         {
649         DEBUG(D_receive)
650           debug_printf("acl_smtp_dkim: skipping signer %s, "
651             "already seen\n", item);
652         continue;
653         }
654
655       seen_items = string_catn(seen_items, US":", 1);
656       }
657     seen_items = string_cat(seen_items, item);
658
659     if ((rc = dkim_exim_acl_run(item, &results, user_msgptr, log_msgptr)) != OK)
660       {
661       DEBUG(D_receive)
662         debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
663           "skipping remaining items\n", rc, item);
664       break;
665       }
666     if (dkim_verify_minimal && Ustrcmp(dkim_verify_status, "pass") == 0)
667       break;
668     }                   /* signers loop */
669
670   dkim_verify_status = string_from_gstring(results);
671   store_pool = old_pool;
672   }
673 else
674   dkim_exim_verify_log_all();
675
676 return rc;
677 }
678
679 /******************************************************************************/
680
681 /* Module API */
682
683 static int
684 dkim_exim_signer_isinlist(const uschar * l)
685 {
686 return dkim_cur_signer
687   ? match_isinlist(dkim_cur_signer, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL)
688   : FAIL;
689 }
690
691 /* Module API */
692
693 static int
694 dkim_exim_status_listmatch(const uschar * l)
695 {                                               /* return good for any match */
696 const uschar * s = dkim_verify_status ? dkim_verify_status : US"none";
697 int sep = 0, rc = FAIL;
698 for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); )
699   if (   (rc = match_isinlist(ss, &l, 0, NULL, NULL, MCL_STRING, TRUE, NULL))
700       == OK) break;
701 return rc;
702 }
703
704 /* Module API: Overwriteable dkim result variables */
705
706 static void
707 dkim_exim_setvar(const uschar * name, void * val)
708 {
709 if (Ustrcmp(name, "dkim_verify_status") == 0)
710   dkim_verify_status = val;
711 else if (Ustrcmp(name, "dkim_verify_reason") == 0)
712   dkim_verify_reason = val;
713 }
714
715 /******************************************************************************/
716
717 static void
718 dkim_smtp_reset(void)
719 {
720 dkim_cur_signer = dkim_signers =
721 dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL;
722 f.dkim_disable_verify = FALSE;
723 dkim_collect_input = 0;
724 dkim_vdom_firstpass = dkim_verify_status = dkim_verify_reason = NULL;
725 dkim_key_length = 0;
726 }
727
728 /******************************************************************************/
729
730 static uschar *
731 dkim_exim_expand_defaults(int what)
732 {
733 switch (what)
734   {
735   case DKIM_ALGO:               return US"";
736   case DKIM_BODYLENGTH:         return US"9999999999999";
737   case DKIM_CANON_BODY:         return US"";
738   case DKIM_CANON_HEADERS:      return US"";
739   case DKIM_COPIEDHEADERS:      return US"";
740   case DKIM_CREATED:            return US"0";
741   case DKIM_EXPIRES:            return US"9999999999999";
742   case DKIM_HEADERNAMES:        return US"";
743   case DKIM_IDENTITY:           return US"";
744   case DKIM_KEY_GRANULARITY:    return US"*";
745   case DKIM_KEY_SRVTYPE:        return US"*";
746   case DKIM_KEY_NOTES:          return US"";
747   case DKIM_KEY_TESTING:        return US"0";
748   case DKIM_NOSUBDOMAINS:       return US"0";
749   case DKIM_VERIFY_STATUS:      return US"none";
750   case DKIM_VERIFY_REASON:      return US"";
751   default:                      return US"";
752   }
753 }
754
755
756 /* Module API: return a computed value for a variable expansion */
757
758 uschar *
759 dkim_exim_expand_query(int what)
760 {
761 if (!dkim_verify_ctx || f.dkim_disable_verify || !dkim_cur_sig)
762   return dkim_exim_expand_defaults(what);
763
764 switch (what)
765   {
766   case DKIM_ALGO:
767     return dkim_sig_to_a_tag(dkim_cur_sig);
768
769   case DKIM_BODYLENGTH:
770     return dkim_cur_sig->bodylength >= 0
771       ? string_sprintf("%ld", dkim_cur_sig->bodylength)
772       : dkim_exim_expand_defaults(what);
773
774   case DKIM_CANON_BODY:
775     switch (dkim_cur_sig->canon_body)
776       {
777       case PDKIM_CANON_RELAXED: return US"relaxed";
778       case PDKIM_CANON_SIMPLE:
779       default:                  return US"simple";
780       }
781
782   case DKIM_CANON_HEADERS:
783     switch (dkim_cur_sig->canon_headers)
784       {
785       case PDKIM_CANON_RELAXED: return US"relaxed";
786       case PDKIM_CANON_SIMPLE:
787       default:                  return US"simple";
788       }
789
790   case DKIM_COPIEDHEADERS:
791     return dkim_cur_sig->copiedheaders
792       ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
793
794   case DKIM_CREATED:
795     return dkim_cur_sig->created > 0
796       ? string_sprintf("%lu", dkim_cur_sig->created)
797       : dkim_exim_expand_defaults(what);
798
799   case DKIM_EXPIRES:
800     return dkim_cur_sig->expires > 0
801       ? string_sprintf("%lu", dkim_cur_sig->expires)
802       : dkim_exim_expand_defaults(what);
803
804   case DKIM_HEADERNAMES:
805     return dkim_cur_sig->headernames
806       ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
807
808   case DKIM_IDENTITY:
809     return dkim_cur_sig->identity
810       ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
811
812   case DKIM_KEY_GRANULARITY:
813     return dkim_cur_sig->pubkey
814       ? dkim_cur_sig->pubkey->granularity
815       ? US dkim_cur_sig->pubkey->granularity
816       : dkim_exim_expand_defaults(what)
817       : dkim_exim_expand_defaults(what);
818
819   case DKIM_KEY_SRVTYPE:
820     return dkim_cur_sig->pubkey
821       ? dkim_cur_sig->pubkey->srvtype
822       ? US dkim_cur_sig->pubkey->srvtype
823       : dkim_exim_expand_defaults(what)
824       : dkim_exim_expand_defaults(what);
825
826   case DKIM_KEY_NOTES:
827     return dkim_cur_sig->pubkey
828       ? dkim_cur_sig->pubkey->notes
829       ? US dkim_cur_sig->pubkey->notes
830       : dkim_exim_expand_defaults(what)
831       : dkim_exim_expand_defaults(what);
832
833   case DKIM_KEY_TESTING:
834     return dkim_cur_sig->pubkey
835       ? dkim_cur_sig->pubkey->testing
836       ? US"1"
837       : dkim_exim_expand_defaults(what)
838       : dkim_exim_expand_defaults(what);
839
840   case DKIM_NOSUBDOMAINS:
841     return dkim_cur_sig->pubkey
842       ? dkim_cur_sig->pubkey->no_subdomaining
843       ? US"1"
844       : dkim_exim_expand_defaults(what)
845       : dkim_exim_expand_defaults(what);
846
847   case DKIM_VERIFY_STATUS:
848     switch (dkim_cur_sig->verify_status)
849       {
850       case PDKIM_VERIFY_INVALID:        return US"invalid";
851       case PDKIM_VERIFY_FAIL:           return US"fail";
852       case PDKIM_VERIFY_PASS:           return US"pass";
853       case PDKIM_VERIFY_NONE:
854       default:                          return US"none";
855       }
856
857   case DKIM_VERIFY_REASON:
858     switch (dkim_cur_sig->verify_ext_status)
859       {
860       case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
861                                                 return US"pubkey_unavailable";
862       case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
863       case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:  return US"pubkey_der_syntax";
864       case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE: return US"pubkey_too_short";
865       case PDKIM_VERIFY_FAIL_BODY:              return US"bodyhash_mismatch";
866       case PDKIM_VERIFY_FAIL_MESSAGE:           return US"signature_incorrect";
867       }
868
869   default:
870     return US"";
871   }
872 }
873
874
875 /* Module API */
876
877 static void
878 dkim_exim_sign_init(void)
879 {
880 int old_pool = store_pool;
881
882 dkim_exim_init(NULL);
883 store_pool = POOL_MAIN;
884 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
885 store_pool = old_pool;
886 }
887
888
889 /* Generate signatures for the given file.
890 If a prefix is given, prepend it to the file for the calculations.
891
892 Return:
893   NULL:         error; error string written
894   string:       signature header(s), or a zero-length string (not an error)
895 */
896
897 gstring *
898 dkim_exim_sign(int fd, off_t off, uschar * prefix,
899   struct ob_dkim * dkim, const uschar ** errstr)
900 {
901 const uschar * dkim_domain = NULL;
902 int sep = 0;
903 gstring * seen_doms = NULL;
904 pdkim_signature * sig;
905 gstring * sigbuf;
906 int pdkim_rc;
907 int sread;
908 uschar buf[4096];
909 int save_errno = 0;
910 int old_pool = store_pool;
911 uschar * errwhen;
912 const uschar * s;
913
914 if (dkim->dot_stuffed)
915   dkim_sign_ctx.flags |= PDKIM_DOT_TERM;
916
917 store_pool = POOL_MAIN;
918
919 GET_OPTION("dkim_domain");
920 if ((s = dkim->dkim_domain) && !(dkim_domain = expand_cstring(s)))
921   /* expansion error, do not send message. */
922   { errwhen = US"dkim_domain"; goto expand_bad; }
923
924 /* Set $dkim_domain expansion variable to each unique domain in list. */
925
926 if (dkim_domain)
927   while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
928   {
929   const uschar * dkim_sel;
930   int sel_sep = 0;
931
932   if (dkim_signing_domain[0] == '\0')
933     continue;
934
935   /* Only sign once for each domain, no matter how often it
936   appears in the expanded list. */
937
938   dkim_signing_domain = string_copylc(dkim_signing_domain);
939   if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
940       0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
941     continue;
942
943   seen_doms = string_append_listele(seen_doms, ':', dkim_signing_domain);
944
945   /* Set $dkim_selector expansion variable to each selector in list,
946   for this domain. */
947
948   GET_OPTION("dkim_selector");
949   if (!(dkim_sel = expand_string(dkim->dkim_selector)))
950     { errwhen = US"dkim_selector"; goto expand_bad; }
951
952   while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
953           NULL, 0)))
954     {
955     uschar * dkim_canon_expanded;
956     int pdkim_canon;
957     uschar * dkim_sign_headers_expanded = NULL;
958     uschar * dkim_private_key_expanded;
959     uschar * dkim_hash_expanded;
960     uschar * dkim_identity_expanded = NULL;
961     uschar * dkim_timestamps_expanded = NULL;
962     unsigned long tval = 0, xval = 0;
963
964     /* Get canonicalization to use */
965
966     GET_OPTION("dkim_canon");
967     dkim_canon_expanded = dkim->dkim_canon
968       ? expand_string(dkim->dkim_canon) : US"relaxed";
969     if (!dkim_canon_expanded)   /* expansion error, do not send message. */
970       { errwhen = US"dkim_canon"; goto expand_bad; }
971
972     if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
973       pdkim_canon = PDKIM_CANON_RELAXED;
974     else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
975       pdkim_canon = PDKIM_CANON_SIMPLE;
976     else
977       {
978       log_write(0, LOG_MAIN,
979                  "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
980                  dkim_canon_expanded);
981       pdkim_canon = PDKIM_CANON_RELAXED;
982       }
983
984     GET_OPTION("dkim_sign_headers");
985     if (  dkim->dkim_sign_headers
986        && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
987       { errwhen = US"dkim_sign_header"; goto expand_bad; }
988     /* else pass NULL, which means default header list */
989
990     /* Get private key to use. */
991
992     GET_OPTION("dkim_private_key");
993     if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
994       { errwhen = US"dkim_private_key"; goto expand_bad; }
995
996     if (  Ustrlen(dkim_private_key_expanded) == 0
997        || Ustrcmp(dkim_private_key_expanded, "0") == 0
998        || Ustrcmp(dkim_private_key_expanded, "false") == 0
999        )
1000       continue;         /* don't sign, but no error */
1001
1002     if (  dkim_private_key_expanded[0] == '/'
1003        && !(dkim_private_key_expanded =
1004              expand_file_big_buffer(dkim_private_key_expanded)))
1005       goto bad;
1006
1007     GET_OPTION("dkim_hash");
1008     if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
1009       { errwhen = US"dkim_hash"; goto expand_bad; }
1010
1011     GET_OPTION("dkim_identity");
1012     if (dkim->dkim_identity)
1013       if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
1014         { errwhen = US"dkim_identity"; goto expand_bad; }
1015       else if (!*dkim_identity_expanded)
1016         dkim_identity_expanded = NULL;
1017
1018     GET_OPTION("dkim_timestamps");
1019     if (dkim->dkim_timestamps)
1020       if (!(dkim_timestamps_expanded = expand_string(dkim->dkim_timestamps)))
1021         { errwhen = US"dkim_timestamps"; goto expand_bad; }
1022       else
1023         {
1024         tval = (unsigned long) time(NULL);
1025         xval = strtoul(CCS dkim_timestamps_expanded, NULL, 10);
1026         if (xval > 0)
1027           xval += tval;
1028         }
1029
1030     if (!(sig = pdkim_init_sign(&dkim_sign_ctx, dkim_signing_domain,
1031                           dkim_signing_selector,
1032                           dkim_private_key_expanded,
1033                           dkim_hash_expanded,
1034                           errstr
1035                           )))
1036       goto bad;
1037     dkim_private_key_expanded[0] = '\0';
1038
1039     pdkim_set_optional(sig,
1040                         CS dkim_sign_headers_expanded,
1041                         CS dkim_identity_expanded,
1042                         pdkim_canon,
1043                         pdkim_canon, -1, tval, xval);
1044
1045     if (!pdkim_set_sig_bodyhash(&dkim_sign_ctx, sig))
1046       goto bad;
1047
1048     dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_domain);
1049     dkim_signing_record = string_append_listele(dkim_signing_record, ':', dkim_signing_selector);
1050
1051     if (!dkim_sign_ctx.sig)             /* link sig to context chain */
1052       dkim_sign_ctx.sig = sig;
1053     else
1054       {
1055       pdkim_signature * n = dkim_sign_ctx.sig;
1056       while (n->next) n = n->next;
1057       n->next = sig;
1058       }
1059     }
1060   }
1061
1062 /* We may need to carry on with the data-feed even if there are no DKIM sigs to
1063 produce, if some other package (eg. ARC) is signing. */
1064
1065 if (!dkim_sign_ctx.sig && !dkim->force_bodyhash)
1066   {
1067   DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n");
1068   sigbuf = string_get(1);       /* return a zero-len string */
1069   }
1070 else
1071   {
1072   if (prefix && (pdkim_rc = pdkim_feed(&dkim_sign_ctx, prefix, Ustrlen(prefix))) != PDKIM_OK)
1073     goto pk_bad;
1074
1075   if (lseek(fd, off, SEEK_SET) < 0)
1076     sread = -1;
1077   else
1078     while ((sread = read(fd, &buf, sizeof(buf))) > 0)
1079       if ((pdkim_rc = pdkim_feed(&dkim_sign_ctx, buf, sread)) != PDKIM_OK)
1080         goto pk_bad;
1081
1082   /* Handle failed read above. */
1083   if (sread == -1)
1084     {
1085     debug_printf("DKIM: Error reading -K file.\n");
1086     save_errno = errno;
1087     goto bad;
1088     }
1089
1090   /* Build string of headers, one per signature */
1091
1092   if ((pdkim_rc = pdkim_feed_finish(&dkim_sign_ctx, &sig, errstr)) != PDKIM_OK)
1093     goto pk_bad;
1094
1095   if (!sig)
1096     {
1097     DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n");
1098     sigbuf = string_get(1);     /* return a zero-len string */
1099     }
1100   else for (sigbuf = NULL; sig; sig = sig->next)
1101     sigbuf = string_append(sigbuf, 2, US sig->signature_header, US"\r\n");
1102   }
1103
1104 CLEANUP:
1105   (void) string_from_gstring(sigbuf);
1106   store_pool = old_pool;
1107   errno = save_errno;
1108   return sigbuf;
1109
1110 pk_bad:
1111   log_write(0, LOG_MAIN|LOG_PANIC,
1112                 "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
1113 bad:
1114   sigbuf = NULL;
1115   goto CLEANUP;
1116
1117 expand_bad:
1118   *errstr = string_sprintf("failed to expand %s: %s",
1119               errwhen, expand_string_message);
1120   log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr);
1121   goto bad;
1122 }
1123
1124
1125
1126 #ifdef SUPPORT_DMARC
1127
1128 /* Module API */
1129
1130 static const pdkim_signature *
1131 dkim_sigs_list(void)
1132 {
1133 return dkim_signatures;
1134 }
1135 #endif
1136
1137 #ifdef EXPERIMENTAL_ARC
1138
1139 /* Module API */
1140 static int
1141 dkim_hashname_to_type(const blob * name)
1142 {
1143 return pdkim_hashname_to_hashtype(name->data, name->len);
1144 }
1145
1146 /* Module API */
1147 hashmethod
1148 dkim_hashtype_to_method(int hashtype)
1149 {
1150 return hashtype >= 0 ? pdkim_hashes[hashtype].exim_hashmethod : -1;
1151 }
1152
1153 /* Module API */
1154 hashmethod
1155 dkim_hashname_to_method(const blob * name)
1156 {
1157 return dkim_hashtype_to_method(dkim_hashname_to_type(name));
1158 }
1159
1160 /*  Module API: Set up a body hashing method on the given signature-context
1161 (creates a new one if needed, or uses an already-present one).
1162
1163 Arguments:
1164         signing         TRUE to use dkim's signing context, else dkim_verify_ctx
1165         canon           canonicalization spec, text form
1166         hash            hash spec, text form
1167         bodylen         byte count for message body
1168
1169 Return: pointer to hashing method struct
1170 */
1171
1172 static pdkim_bodyhash *
1173 dkim_set_bodyhash(BOOL signing,
1174   const blob * canon, const blob * hashname, long bodylen)
1175 {
1176 int canon_head = -1, canon_body = -1;
1177
1178 pdkim_cstring_to_canons(canon->data, canon->len, &canon_head, &canon_body);
1179 return pdkim_set_bodyhash(signing ? &dkim_sign_ctx: dkim_verify_ctx,
1180         dkim_hashname_to_type(hashname),
1181         canon_body,
1182         bodylen);
1183 }
1184
1185 /* Module API: Sign a blob of data (which might already be a hash, if
1186 Ed25519 or GCrypt signing).
1187
1188 Arguments:
1189         data            to be signed
1190         hm              hash to be applied to the data
1191         privkey         private key for siging, PEM format
1192         signature       pointer for result blob
1193
1194 Return: NULL, or error string on failure
1195 */
1196
1197 static const uschar *
1198 dkim_sign_blob(const blob * data, hashmethod hm, const uschar * privkey,
1199   blob * signature)
1200 {
1201 es_ctx sctx;
1202 const uschar * errstr;
1203
1204 if ((errstr = exim_dkim_signing_init(privkey, &sctx)))
1205   { DEBUG(D_transport) debug_printf("signing key setup: %s\n", errstr); }
1206 else errstr = exim_dkim_sign(&sctx, hm, data, signature);
1207
1208 return errstr;
1209 }
1210
1211 #endif  /*EXPERIMENTAL_ARC*/
1212
1213
1214 /* Module API */
1215
1216 gstring *
1217 authres_dkim(gstring * g)
1218 {
1219 int start = 0;          /* compiler quietening */
1220
1221 DEBUG(D_acl) start = gstring_length(g);
1222
1223 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
1224   {
1225   g = string_catn(g, US";\n\tdkim=", 8);
1226
1227   if (sig->verify_status & PDKIM_VERIFY_POLICY)
1228     g = string_append(g, 5,
1229       US"policy (", dkim_verify_status, US" - ", dkim_verify_reason, US")");
1230   else switch(sig->verify_status)
1231     {
1232     case PDKIM_VERIFY_NONE:    g = string_cat(g, US"none"); break;
1233     case PDKIM_VERIFY_INVALID:
1234       switch (sig->verify_ext_status)
1235         {
1236         case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
1237           g = string_cat(g, US"tmperror (pubkey unavailable)\n\t\t"); break;
1238         case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
1239           g = string_cat(g, US"permerror (overlong public key record)\n\t\t"); break;
1240         case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
1241         case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
1242           g = string_cat(g, US"neutral (public key record import problem)\n\t\t");
1243           break;
1244         case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
1245           g = string_cat(g, US"neutral (signature tag missing or invalid)\n\t\t");
1246           break;
1247         case PDKIM_VERIFY_INVALID_DKIM_VERSION:
1248           g = string_cat(g, US"neutral (unsupported DKIM version)\n\t\t");
1249           break;
1250         default:
1251           g = string_cat(g, US"permerror (unspecified problem)\n\t\t"); break;
1252         }
1253       break;
1254     case PDKIM_VERIFY_FAIL:
1255       switch (sig->verify_ext_status)
1256         {
1257         case PDKIM_VERIFY_FAIL_BODY:
1258           g = string_cat(g,
1259             US"fail (body hash mismatch; body probably modified in transit)\n\t\t");
1260           break;
1261         case PDKIM_VERIFY_FAIL_MESSAGE:
1262           g = string_cat(g,
1263             US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
1264           break;
1265         case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:       /* should this really be "polcy"? */
1266           g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
1267           break;
1268         default:
1269           g = string_cat(g, US"fail (unspecified reason)\n\t\t");
1270           break;
1271         }
1272       break;
1273     case PDKIM_VERIFY_PASS:    g = string_cat(g, US"pass"); break;
1274     default:                   g = string_cat(g, US"permerror"); break;
1275     }
1276   if (sig->domain)   g = string_append(g, 2, US" header.d=", sig->domain);
1277   if (sig->identity) g = string_append(g, 2, US" header.i=", sig->identity);
1278   if (sig->selector) g = string_append(g, 2, US" header.s=", sig->selector);
1279   g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig));
1280   }
1281
1282 DEBUG(D_acl)
1283   if (gstring_length(g) == start)
1284     debug_printf("DKIM:\tno authres\n");
1285   else
1286     debug_printf("DKIM:\tauthres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
1287 return g;
1288 }
1289
1290 /******************************************************************************/
1291 /* Module API */
1292
1293 static optionlist dkim_options[] = {
1294   { "acl_smtp_dkim",            opt_stringptr,   {&acl_smtp_dkim} },
1295   { "dkim_verify_hashes",       opt_stringptr,   {&dkim_verify_hashes} },
1296   { "dkim_verify_keytypes",     opt_stringptr,   {&dkim_verify_keytypes} },
1297   { "dkim_verify_min_keysizes", opt_stringptr,   {&dkim_verify_min_keysizes} },
1298   { "dkim_verify_minimal",      opt_bool,        {&dkim_verify_minimal} },
1299   { "dkim_verify_signers",      opt_stringptr,   {&dkim_verify_signers} },
1300 };
1301
1302 static void * dkim_functions[] = {
1303   [DKIM_VERIFY_FEED] =          dkim_exim_verify_feed,
1304   [DKIM_VERIFY_PAUSE] =         dkim_exim_verify_pause,
1305   [DKIM_VERIFY_FINISH] =        dkim_exim_verify_finish,
1306   [DKIM_ACL_ENTRY] =            dkim_exim_acl_entry,
1307   [DKIM_VERIFY_LOG_ALL] =       dkim_exim_verify_log_all,
1308   [DKIM_VDOM_FIRSTPASS] =       dkim_exim_vdom_firstpass,
1309
1310   [DKIM_SIGNER_ISINLIST] =      dkim_exim_signer_isinlist,
1311   [DKIM_STATUS_LISTMATCH] =     dkim_exim_status_listmatch,
1312
1313   [DKIM_SETVAR] =               dkim_exim_setvar,
1314   [DKIM_EXPAND_QUERY] =         dkim_exim_expand_query,
1315
1316   [DKIM_TRANSPORT_INIT] =       dkim_exim_sign_init,
1317   [DKIM_TRANSPORT_WRITE] =      dkim_transport_write_message,
1318
1319 #ifdef SUPPORT_DMARC
1320   [DKIM_SIGS_LIST] =            dkim_sigs_list,
1321 #endif
1322 #ifdef EXPERIMENTAL_ARC
1323   [DKIM_HASHNAME_TO_TYPE] =     dkim_hashname_to_type,
1324   [DKIM_HASHTYPE_TO_METHOD] =   dkim_hashtype_to_method,
1325   [DKIM_HASHNAME_TO_METHOD] =   dkim_hashname_to_method,
1326   [DKIM_SET_BODYHASH] =         dkim_set_bodyhash,
1327   [DKIM_DNS_PUBKEY] =           dkim_exim_parse_dns_pubkey,
1328   [DKIM_SIG_VERIFY] =           dkim_exim_sig_verify,
1329   [DKIM_HEADER_RELAX] =         pdkim_relax_header_n,
1330   [DKIM_SIGN_DATA] =            dkim_sign_blob,
1331 #endif
1332 };
1333
1334 static var_entry dkim_variables[] = {
1335   { "dkim_algo",           vtype_dkim,        (void *)DKIM_ALGO },
1336   { "dkim_bodylength",     vtype_dkim,        (void *)DKIM_BODYLENGTH },
1337   { "dkim_canon_body",     vtype_dkim,        (void *)DKIM_CANON_BODY },
1338   { "dkim_canon_headers",  vtype_dkim,        (void *)DKIM_CANON_HEADERS },
1339   { "dkim_copiedheaders",  vtype_dkim,        (void *)DKIM_COPIEDHEADERS },
1340   { "dkim_created",        vtype_dkim,        (void *)DKIM_CREATED },
1341   { "dkim_cur_signer",     vtype_stringptr,   &dkim_cur_signer },
1342   { "dkim_domain",         vtype_stringptr,   &dkim_signing_domain },
1343   { "dkim_expires",        vtype_dkim,        (void *)DKIM_EXPIRES },
1344   { "dkim_headernames",    vtype_dkim,        (void *)DKIM_HEADERNAMES },
1345   { "dkim_identity",       vtype_dkim,        (void *)DKIM_IDENTITY },
1346   { "dkim_key_granularity",vtype_dkim,        (void *)DKIM_KEY_GRANULARITY },
1347   { "dkim_key_length",     vtype_int,         &dkim_key_length },
1348   { "dkim_key_nosubdomains",vtype_dkim,       (void *)DKIM_NOSUBDOMAINS },
1349   { "dkim_key_notes",      vtype_dkim,        (void *)DKIM_KEY_NOTES },
1350   { "dkim_key_srvtype",    vtype_dkim,        (void *)DKIM_KEY_SRVTYPE },
1351   { "dkim_key_testing",    vtype_dkim,        (void *)DKIM_KEY_TESTING },
1352   { "dkim_selector",       vtype_stringptr,   &dkim_signing_selector },
1353   { "dkim_signers",        vtype_stringptr,   &dkim_signers },
1354   { "dkim_verify_reason",  vtype_stringptr,   &dkim_verify_reason },
1355   { "dkim_verify_status",  vtype_stringptr,   &dkim_verify_status },
1356 };
1357
1358 misc_module_info dkim_module_info = {
1359   .name =               US"dkim",
1360 # if SUPPORT_DKIM==2
1361   .dyn_magic =          MISC_MODULE_MAGIC,
1362 # endif
1363   .init =               dkim_exim_init,
1364   .msg_init =           dkim_exim_verify_init,
1365   .authres =            authres_dkim,
1366   .smtp_reset =         dkim_smtp_reset,
1367
1368   .options =            dkim_options,
1369   .options_count =      nelem(dkim_options),
1370
1371   .functions =          dkim_functions,
1372   .functions_count =    nelem(dkim_functions),
1373
1374   .variables =          dkim_variables,
1375   .variables_count =    nelem(dkim_variables),
1376 };
1377
1378 # endif /*!MACRO_PREDEF*/
1379 #endif  /*!DISABLE_DKIM*/