DKIM: fix non-debug build. Bug 1713
[exim.git] / src / src / dkim.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge, 1995 - 2015 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* Code for DKIM support. Other DKIM relevant code is in
9    receive.c, transport.c and transports/smtp.c */
10
11 #include "exim.h"
12
13 #ifndef DISABLE_DKIM
14
15 #include "pdkim/pdkim.h"
16
17 pdkim_ctx *dkim_verify_ctx = NULL;
18 pdkim_signature *dkim_signatures = NULL;
19 pdkim_signature *dkim_cur_sig = NULL;
20
21 static int
22 dkim_exim_query_dns_txt(char *name, char *answer)
23 {
24 dns_answer dnsa;
25 dns_scan dnss;
26 dns_record *rr;
27
28 lookup_dnssec_authenticated = NULL;
29 if (dns_lookup(&dnsa, US name, T_TXT, NULL) != DNS_SUCCEED)
30   return PDKIM_FAIL;
31
32 /* Search for TXT record */
33
34 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
35      rr;
36      rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
37   if (rr->type == T_TXT)
38     {
39     int rr_offset = 0;
40     int answer_offset = 0;
41
42     /* Copy record content to the answer buffer */
43
44     while (rr_offset < rr->size)
45       {
46       uschar len = rr->data[rr_offset++];
47       snprintf(answer + answer_offset,
48                 PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
49                 "%.*s", (int)len, (char *) (rr->data + rr_offset));
50       rr_offset += len;
51       answer_offset += len;
52       if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
53         return PDKIM_FAIL;
54       }
55     return PDKIM_OK;
56     }
57
58 return PDKIM_FAIL;
59 }
60
61
62 void
63 dkim_exim_verify_init(void)
64 {
65 /* Free previous context if there is one */
66
67 if (dkim_verify_ctx)
68   pdkim_free_ctx(dkim_verify_ctx);
69
70 /* Create new context */
71
72 dkim_verify_ctx = pdkim_init_verify(PDKIM_INPUT_SMTP, &dkim_exim_query_dns_txt);
73 dkim_collect_input = !!dkim_verify_ctx;
74 #ifdef PDKIM_DEBUG
75 if (dkim_collect_input)
76   pdkim_set_debug_stream(dkim_verify_ctx, debug_file);
77 #endif
78 }
79
80
81 void
82 dkim_exim_verify_feed(uschar * data, int len)
83 {
84 if (  dkim_collect_input
85    && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
86   dkim_collect_input = FALSE;
87 }
88
89
90 void
91 dkim_exim_verify_finish(void)
92 {
93 pdkim_signature *sig = NULL;
94 int dkim_signers_size = 0;
95 int dkim_signers_ptr = 0;
96 dkim_signers = NULL;
97
98 /* Delete eventual previous signature chain */
99
100 dkim_signatures = NULL;
101
102 /* If we have arrived here with dkim_collect_input == FALSE, it
103 means there was a processing error somewhere along the way.
104 Log the incident and disable futher verification. */
105
106 if (!dkim_collect_input)
107   {
108   log_write(0, LOG_MAIN,
109              "DKIM: Error while running this message through validation,"
110              " disabling signature verification.");
111   dkim_disable_verify = TRUE;
112   return;
113   }
114
115 dkim_collect_input = FALSE;
116
117 /* Finish DKIM operation and fetch link to signatures chain */
118
119 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
120   return;
121
122 for (sig = dkim_signatures; sig; sig = sig->next)
123   {
124   int size = 0;
125   int ptr = 0;
126
127   /* Log a line for each signature */
128
129   uschar *logmsg = string_append(NULL, &size, &ptr, 5,
130         string_sprintf("d=%s s=%s c=%s/%s a=%s ",
131               sig->domain,
132               sig->selector,
133               sig->canon_headers == PDKIM_CANON_SIMPLE ?  "simple" : "relaxed",
134               sig->canon_body == PDKIM_CANON_SIMPLE ?  "simple" : "relaxed",
135               sig->algo == PDKIM_ALGO_RSA_SHA256 ?  "rsa-sha256" : "rsa-sha1"),
136
137         sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
138         sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
139         sig->expires > 0 ? string_sprintf("x=%lu ", sig->expires) : US"",
140         sig->bodylength > -1 ? string_sprintf("l=%lu ", sig->bodylength) : US""
141         );
142
143   switch (sig->verify_status)
144     {
145     case PDKIM_VERIFY_NONE:
146       logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
147       break;
148
149     case PDKIM_VERIFY_INVALID:
150       logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
151       switch (sig->verify_ext_status)
152         {
153         case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
154           logmsg = string_append(logmsg, &size, &ptr, 1,
155                         "public key record (currently?) unavailable]");
156           break;
157
158         case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
159           logmsg = string_append(logmsg, &size, &ptr, 1,
160                         "overlong public key record]");
161           break;
162
163         case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
164           logmsg = string_append(logmsg, &size, &ptr, 1,
165                        "syntax error in public key record]");
166           break;
167
168         default:
169           logmsg = string_append(logmsg, &size, &ptr, 1,
170                         "unspecified problem]");
171         }
172       break;
173
174     case PDKIM_VERIFY_FAIL:
175       logmsg =
176         string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
177       switch (sig->verify_ext_status)
178         {
179         case PDKIM_VERIFY_FAIL_BODY:
180           logmsg = string_append(logmsg, &size, &ptr, 1,
181                        "body hash mismatch (body probably modified in transit)]");
182           break;
183
184         case PDKIM_VERIFY_FAIL_MESSAGE:
185           logmsg = string_append(logmsg, &size, &ptr, 1,
186                        "signature did not verify (headers probably modified in transit)]");
187         break;
188
189         default:
190           logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
191         }
192       break;
193
194     case PDKIM_VERIFY_PASS:
195       logmsg =
196         string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
197       break;
198     }
199
200   logmsg[ptr] = '\0';
201   log_write(0, LOG_MAIN, "DKIM: %s", logmsg);
202
203   /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
204
205   dkim_signers = string_append(dkim_signers,
206                                 &dkim_signers_size,
207                                 &dkim_signers_ptr, 2, sig->domain, ":");
208
209   if (sig->identity)
210     dkim_signers = string_append(dkim_signers,
211                                   &dkim_signers_size,
212                                   &dkim_signers_ptr, 2, sig->identity, ":");
213
214   /* Process next signature */
215   }
216
217 /* NULL-terminate and chop the last colon from the domain list */
218
219 if (dkim_signers)
220   {
221   dkim_signers[dkim_signers_ptr] = '\0';
222   if (Ustrlen(dkim_signers) > 0)
223   dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
224   }
225 }
226
227
228 void
229 dkim_exim_acl_setup(uschar * id)
230 {
231 pdkim_signature * sig;
232 uschar * cmp_val;
233
234
235 dkim_cur_sig = NULL;
236 dkim_cur_signer = id;
237
238 if (dkim_disable_verify || !id || !dkim_verify_ctx)
239   return;
240
241 /* Find signature to run ACL on */
242
243 for (sig = dkim_signatures; sig; sig = sig->next)
244   if (  (cmp_val = Ustrchr(id, '@') != NULL ? US sig->identity : US sig->domain)
245      && strcmpic(cmp_val, id) == 0
246      )
247     {
248     dkim_cur_sig = sig;
249
250     /* The "dkim_domain" and "dkim_selector" expansion variables have
251        related globals, since they are used in the signing code too.
252        Instead of inventing separate names for verification, we set
253        them here. This is easy since a domain and selector is guaranteed
254        to be in a signature. The other dkim_* expansion items are
255        dynamically fetched from dkim_cur_sig at expansion time (see
256        function below). */
257
258     dkim_signing_domain = US sig->domain;
259     dkim_signing_selector = US sig->selector;
260     return;
261     }
262 }
263
264
265 static uschar *
266 dkim_exim_expand_defaults(int what)
267 {
268 switch (what)
269   {
270   case DKIM_ALGO:               return US"";
271   case DKIM_BODYLENGTH:         return US"9999999999999";
272   case DKIM_CANON_BODY:         return US"";
273   case DKIM_CANON_HEADERS:      return US"";
274   case DKIM_COPIEDHEADERS:      return US"";
275   case DKIM_CREATED:            return US"0";
276   case DKIM_EXPIRES:            return US"9999999999999";
277   case DKIM_HEADERNAMES:        return US"";
278   case DKIM_IDENTITY:           return US"";
279   case DKIM_KEY_GRANULARITY:    return US"*";
280   case DKIM_KEY_SRVTYPE:        return US"*";
281   case DKIM_KEY_NOTES:          return US"";
282   case DKIM_KEY_TESTING:        return US"0";
283   case DKIM_NOSUBDOMAINS:       return US"0";
284   case DKIM_VERIFY_STATUS:      return US"none";
285   case DKIM_VERIFY_REASON:      return US"";
286   default:                      return US"";
287   }
288 }
289
290
291 uschar *
292 dkim_exim_expand_query(int what)
293 {
294 if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
295   return dkim_exim_expand_defaults(what);
296
297 switch (what)
298   {
299   case DKIM_ALGO:
300     switch (dkim_cur_sig->algo)
301       {
302       case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
303       case PDKIM_ALGO_RSA_SHA256:
304       default:                  return US"rsa-sha256";
305       }
306
307   case DKIM_BODYLENGTH:
308     return dkim_cur_sig->bodylength >= 0
309       ? string_sprintf(OFF_T_FMT, (LONGLONG_T) dkim_cur_sig->bodylength)
310       : dkim_exim_expand_defaults(what);
311
312   case DKIM_CANON_BODY:
313     switch (dkim_cur_sig->canon_body)
314       {
315       case PDKIM_CANON_RELAXED: return US"relaxed";
316       case PDKIM_CANON_SIMPLE:
317       default:                  return US"simple";
318       }
319
320   case DKIM_CANON_HEADERS:
321   switch (dkim_cur_sig->canon_headers)
322     {
323     case PDKIM_CANON_RELAXED:   return US"relaxed";
324     case PDKIM_CANON_SIMPLE:
325     default:                    return US"simple";
326     }
327
328   case DKIM_COPIEDHEADERS:
329     return dkim_cur_sig->copiedheaders
330       ? US dkim_cur_sig->copiedheaders : dkim_exim_expand_defaults(what);
331
332   case DKIM_CREATED:
333     return dkim_cur_sig->created > 0
334       ? string_sprintf("%llu", dkim_cur_sig->created)
335       : dkim_exim_expand_defaults(what);
336
337   case DKIM_EXPIRES:
338     return dkim_cur_sig->expires > 0
339       ? string_sprintf("%llu", dkim_cur_sig->expires)
340       : dkim_exim_expand_defaults(what);
341
342   case DKIM_HEADERNAMES:
343     return dkim_cur_sig->headernames
344       ?  US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
345
346   case DKIM_IDENTITY:
347     return dkim_cur_sig->identity
348       ? US dkim_cur_sig->identity : dkim_exim_expand_defaults(what);
349
350   case DKIM_KEY_GRANULARITY:
351     return dkim_cur_sig->pubkey
352       ? dkim_cur_sig->pubkey->granularity
353       ? US dkim_cur_sig->pubkey->granularity
354       : dkim_exim_expand_defaults(what)
355       : dkim_exim_expand_defaults(what);
356
357   case DKIM_KEY_SRVTYPE:
358     return dkim_cur_sig->pubkey
359       ? dkim_cur_sig->pubkey->srvtype
360       ? US dkim_cur_sig->pubkey->srvtype
361       : dkim_exim_expand_defaults(what)
362       : dkim_exim_expand_defaults(what);
363
364   case DKIM_KEY_NOTES:
365     return dkim_cur_sig->pubkey
366       ? dkim_cur_sig->pubkey->notes
367       ? US dkim_cur_sig->pubkey->notes
368       : dkim_exim_expand_defaults(what)
369       : dkim_exim_expand_defaults(what);
370
371   case DKIM_KEY_TESTING:
372     return dkim_cur_sig->pubkey
373       ? dkim_cur_sig->pubkey->testing
374       ? US"1"
375       : dkim_exim_expand_defaults(what)
376       : dkim_exim_expand_defaults(what);
377
378   case DKIM_NOSUBDOMAINS:
379     return dkim_cur_sig->pubkey
380       ? dkim_cur_sig->pubkey->no_subdomaining
381       ? US"1"
382       : dkim_exim_expand_defaults(what)
383       : dkim_exim_expand_defaults(what);
384
385   case DKIM_VERIFY_STATUS:
386     switch (dkim_cur_sig->verify_status)
387       {
388       case PDKIM_VERIFY_INVALID:        return US"invalid";
389       case PDKIM_VERIFY_FAIL:           return US"fail";
390       case PDKIM_VERIFY_PASS:           return US"pass";
391       case PDKIM_VERIFY_NONE:
392       default:                          return US"none";
393       }
394
395   case DKIM_VERIFY_REASON:
396     switch (dkim_cur_sig->verify_ext_status)
397       {
398       case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
399                                                 return US"pubkey_unavailable";
400       case PDKIM_VERIFY_INVALID_PUBKEY_PARSING: return US"pubkey_syntax";
401       case PDKIM_VERIFY_FAIL_BODY:              return US"bodyhash_mismatch";
402       case PDKIM_VERIFY_FAIL_MESSAGE:           return US"signature_incorrect";
403       }
404
405   default:
406     return US"";
407   }
408 }
409
410
411 uschar *
412 dkim_exim_sign(int dkim_fd, uschar * dkim_private_key,
413                 const uschar * dkim_domain, uschar * dkim_selector,
414                 uschar * dkim_canon, uschar * dkim_sign_headers)
415 {
416 int sep = 0;
417 uschar *seen_items = NULL;
418 int seen_items_size = 0;
419 int seen_items_offset = 0;
420 uschar itembuf[256];
421 uschar *dkim_canon_expanded;
422 uschar *dkim_sign_headers_expanded;
423 uschar *dkim_private_key_expanded;
424 pdkim_ctx *ctx = NULL;
425 uschar *rc = NULL;
426 uschar *sigbuf = NULL;
427 int sigsize = 0;
428 int sigptr = 0;
429 pdkim_signature *signature;
430 int pdkim_canon;
431 int pdkim_rc;
432 int sread;
433 char buf[4096];
434 int save_errno = 0;
435 int old_pool = store_pool;
436
437 store_pool = POOL_MAIN;
438
439 if (!(dkim_domain = expand_cstring(dkim_domain)))
440   {
441   /* expansion error, do not send message. */
442   log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
443              "dkim_domain: %s", expand_string_message);
444   rc = NULL;
445   goto CLEANUP;
446   }
447
448 /* Set $dkim_domain expansion variable to each unique domain in list. */
449
450 while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
451                                    itembuf, sizeof(itembuf))))
452   {
453   if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
454     continue;
455
456   /* Only sign once for each domain, no matter how often it
457   appears in the expanded list. */
458
459   if (seen_items)
460     {
461     const uschar *seen_items_list = seen_items;
462     if (match_isinlist(dkim_signing_domain,
463                         &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
464                         NULL) == OK)
465       continue;
466
467     seen_items =
468       string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
469     }
470
471   seen_items =
472     string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
473                  dkim_signing_domain);
474   seen_items[seen_items_offset] = '\0';
475
476   /* Set up $dkim_selector expansion variable. */
477
478   if (!(dkim_signing_selector = expand_string(dkim_selector)))
479     {
480     log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
481                "dkim_selector: %s", expand_string_message);
482     rc = NULL;
483     goto CLEANUP;
484     }
485
486   /* Get canonicalization to use */
487
488   dkim_canon_expanded = dkim_canon ? expand_string(dkim_canon) : US"relaxed";
489   if (!dkim_canon_expanded)
490     {
491     /* expansion error, do not send message. */
492     log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
493                "dkim_canon: %s", expand_string_message);
494     rc = NULL;
495     goto CLEANUP;
496     }
497
498   if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
499     pdkim_canon = PDKIM_CANON_RELAXED;
500   else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
501     pdkim_canon = PDKIM_CANON_SIMPLE;
502   else
503     {
504     log_write(0, LOG_MAIN,
505                "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
506                dkim_canon_expanded);
507     pdkim_canon = PDKIM_CANON_RELAXED;
508     }
509
510   dkim_sign_headers_expanded = NULL;
511   if (dkim_sign_headers)
512     if (!(dkim_sign_headers_expanded = expand_string(dkim_sign_headers)))
513       {
514       log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
515                  "dkim_sign_headers: %s", expand_string_message);
516       rc = NULL;
517       goto CLEANUP;
518       }
519                         /* else pass NULL, which means default header list */
520
521   /* Get private key to use. */
522
523   if (!(dkim_private_key_expanded = expand_string(dkim_private_key)))
524     {
525     log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
526                "dkim_private_key: %s", expand_string_message);
527     rc = NULL;
528     goto CLEANUP;
529     }
530
531   if (  Ustrlen(dkim_private_key_expanded) == 0
532      || Ustrcmp(dkim_private_key_expanded, "0") == 0
533      || Ustrcmp(dkim_private_key_expanded, "false") == 0
534      )
535     continue;           /* don't sign, but no error */
536
537   if (dkim_private_key_expanded[0] == '/')
538     {
539     int privkey_fd = 0;
540
541     /* Looks like a filename, load the private key. */
542
543     memset(big_buffer, 0, big_buffer_size);
544     privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY);
545     if (privkey_fd < 0)
546       {
547       log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
548                  "private key file for reading: %s",
549                  dkim_private_key_expanded);
550       rc = NULL;
551       goto CLEANUP;
552       }
553
554     if (read(privkey_fd, big_buffer, big_buffer_size - 2) < 0)
555       {
556       log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
557                  dkim_private_key_expanded);
558       rc = NULL;
559       goto CLEANUP;
560       }
561
562     (void) close(privkey_fd);
563     dkim_private_key_expanded = big_buffer;
564     }
565
566   ctx = pdkim_init_sign(PDKIM_INPUT_SMTP,
567                          (char *) dkim_signing_domain,
568                          (char *) dkim_signing_selector,
569                          (char *) dkim_private_key_expanded);
570 #ifdef PDKIM_DEBUG
571   pdkim_set_debug_stream(ctx, debug_file);
572 #endif
573   pdkim_set_optional(ctx,
574                       (char *) dkim_sign_headers_expanded,
575                       NULL,
576                       pdkim_canon,
577                       pdkim_canon, -1, PDKIM_ALGO_RSA_SHA256, 0, 0);
578
579   lseek(dkim_fd, 0, SEEK_SET);
580
581   while ((sread = read(dkim_fd, &buf, 4096)) > 0)
582     if (pdkim_feed(ctx, buf, sread) != PDKIM_OK)
583       {
584       rc = NULL;
585       goto CLEANUP;
586       }
587
588   /* Handle failed read above. */
589   if (sread == -1)
590     {
591     debug_printf("DKIM: Error reading -K file.\n");
592     save_errno = errno;
593     rc = NULL;
594     goto CLEANUP;
595     }
596
597   if ((pdkim_rc = pdkim_feed_finish(ctx, &signature)) != PDKIM_OK)
598     {
599     log_write(0, LOG_MAIN|LOG_PANIC, "DKIM: signing failed (RC %d)", pdkim_rc);
600     rc = NULL;
601     goto CLEANUP;
602     }
603
604   sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
605                           US signature->signature_header, US"\r\n");
606
607   pdkim_free_ctx(ctx);
608   ctx = NULL;
609   }
610
611 if (sigbuf)
612   {
613   sigbuf[sigptr] = '\0';
614   rc = sigbuf;
615   }
616 else
617   rc = US"";
618
619 CLEANUP:
620 if (ctx)
621   pdkim_free_ctx(ctx);
622 store_pool = old_pool;
623 errno = save_errno;
624 return rc;
625 }
626
627 #endif