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