Copyright updates:
[exim.git] / src / src / dkim.c
index 8bb2efbf059a29c56b0a8878d86c0338e7765d53..92adb35897665f650653de3622c639f72800361f 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge, 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for DKIM support. Other DKIM relevant code is in
@@ -21,6 +22,7 @@ void
 params_dkim(void)
 {
 builtin_macro_create_var(US"_DKIM_SIGN_HEADERS", US PDKIM_DEFAULT_SIGN_HEADERS);
+builtin_macro_create_var(US"_DKIM_OVERSIGN_HEADERS", US PDKIM_OVERSIGN_HEADERS);
 }
 # else /*!MACRO_PREDEF*/
 
@@ -37,29 +39,28 @@ static const uschar * dkim_collect_error = NULL;
 
 
 
-/*XXX the caller only uses the first record if we return multiple.
+/* Look up the DKIM record in DNS for the given hostname.
+Will use the first found if there are multiple.
+The return string is tainted, having come from off-site.
 */
 
 uschar *
 dkim_exim_query_dns_txt(const uschar * name)
 {
-/*XXX need to always alloc the dnsa, from tainted mem.
-Then, we hope, the answers will be tainted */
-
-dns_answer dnsa;
+dns_answer * dnsa = store_get_dns_answer();
 dns_scan dnss;
 rmark reset_point = store_mark();
 gstring * g = NULL;
 
 lookup_dnssec_authenticated = NULL;
-if (dns_lookup(&dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
+if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
   return NULL; /*XXX better error detail?  logging? */
 
 /* Search for TXT record */
 
-for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
      rr;
-     rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
   if (rr->type == T_TXT)
     {
     int rr_offset = 0;
@@ -96,6 +97,8 @@ return NULL;  /*XXX better error detail?  logging? */
 void
 dkim_exim_init(void)
 {
+if (f.dkim_init_done) return;
+f.dkim_init_done = TRUE;
 pdkim_init();
 }
 
@@ -104,6 +107,8 @@ pdkim_init();
 void
 dkim_exim_verify_init(BOOL dot_stuffing)
 {
+dkim_exim_init();
+
 /* There is a store-reset between header & body reception
 so cannot use the main pool. Any allocs done by Exim
 memory-handling must use the perm pool. */
@@ -264,6 +269,11 @@ else
                "(headers probably modified in transit)]");
          break;
 
+       case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:
+         logmsg = string_cat(logmsg,
+               US"signature invalid (key too short)]");
+         break;
+
        default:
          logmsg = string_cat(logmsg, US"unspecified reason]");
        }
@@ -402,7 +412,7 @@ for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
     dkim_cur_sig = sig;
     dkim_signing_domain = US sig->domain;
     dkim_signing_selector = US sig->selector;
-    dkim_key_length = sig->sighash.len * 8;
+    dkim_key_length = sig->keybits;
 
     /* These two return static strings, so we can compare the addr
     later to see if the ACL overwrote them.  Check that when logging */
@@ -556,6 +566,7 @@ switch (what)
                                                return US"pubkey_unavailable";
       case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:return US"pubkey_dns_syntax";
       case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT: return US"pubkey_der_syntax";
+      case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:        return US"pubkey_too_short";
       case PDKIM_VERIFY_FAIL_BODY:             return US"bodyhash_mismatch";
       case PDKIM_VERIFY_FAIL_MESSAGE:          return US"signature_incorrect";
       }
@@ -570,6 +581,8 @@ void
 dkim_exim_sign_init(void)
 {
 int old_pool = store_pool;
+
+dkim_exim_init();
 store_pool = POOL_MAIN;
 pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
 store_pool = old_pool;
@@ -848,6 +861,9 @@ for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
           g = string_cat(g,
            US"fail (signature did not verify; headers probably modified in transit)\n\t\t");
          break;
+        case PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE:      /* should this really be "polcy"? */
+          g = string_fmt_append(g, "fail (public key too short: %u bits)\n\t\t", sig->keybits);
+          break;
         default:
           g = string_cat(g, US"fail (unspecified reason)\n\t\t");
          break;