DKIM: error verification on missing tags. Bug 1853
[exim.git] / src / src / dkim.c
index db2eb4948cd587f56f1a5f8a29a11fc1f39a7b12..24de2bc332f090d317ed9a5f66bf20f510cef232 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge, 1995 - 2015 */
+/* Copyright (c) University of Cambridge, 1995 - 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for DKIM support. Other DKIM relevant code is in
@@ -14,6 +14,7 @@
 
 #include "pdkim/pdkim.h"
 
+int dkim_verify_oldpool;
 pdkim_ctx *dkim_verify_ctx = NULL;
 pdkim_signature *dkim_signatures = NULL;
 pdkim_signature *dkim_cur_sig = NULL;
@@ -59,9 +60,24 @@ return PDKIM_FAIL;
 }
 
 
+void
+dkim_exim_init(void)
+{
+pdkim_init();
+}
+
+
+
 void
 dkim_exim_verify_init(void)
 {
+/* 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. */
+
+dkim_verify_oldpool = store_pool;
+store_pool = POOL_PERM;
+
 /* Free previous context if there is one */
 
 if (dkim_verify_ctx)
@@ -69,19 +85,21 @@ if (dkim_verify_ctx)
 
 /* Create new context */
 
-dkim_verify_ctx = pdkim_init_verify(PDKIM_INPUT_SMTP, &dkim_exim_query_dns_txt);
+dkim_verify_ctx = pdkim_init_verify(&dkim_exim_query_dns_txt);
+dkim_collect_input = !!dkim_verify_ctx;
 
-if ((dkim_collect_input = !!dkim_verify_ctx))
-  pdkim_set_debug_stream(dkim_verify_ctx, debug_file);
+store_pool = dkim_verify_oldpool;
 }
 
 
 void
 dkim_exim_verify_feed(uschar * data, int len)
 {
+store_pool = POOL_PERM;
 if (  dkim_collect_input
    && pdkim_feed(dkim_verify_ctx, (char *)data, len) != PDKIM_OK)
   dkim_collect_input = FALSE;
+store_pool = dkim_verify_oldpool;
 }
 
 
@@ -93,6 +111,8 @@ int dkim_signers_size = 0;
 int dkim_signers_ptr = 0;
 dkim_signers = NULL;
 
+store_pool = POOL_PERM;
+
 /* Delete eventual previous signature chain */
 
 dkim_signatures = NULL;
@@ -107,7 +127,7 @@ if (!dkim_collect_input)
             "DKIM: Error while running this message through validation,"
             " disabling signature verification.");
   dkim_disable_verify = TRUE;
-  return;
+  goto out;
   }
 
 dkim_collect_input = FALSE;
@@ -115,7 +135,7 @@ dkim_collect_input = FALSE;
 /* Finish DKIM operation and fetch link to signatures chain */
 
 if (pdkim_feed_finish(dkim_verify_ctx, &dkim_signatures) != PDKIM_OK)
-  return;
+  goto out;
 
 for (sig = dkim_signatures; sig; sig = sig->next)
   {
@@ -125,12 +145,16 @@ for (sig = dkim_signatures; sig; sig = sig->next)
   /* Log a line for each signature */
 
   uschar *logmsg = string_append(NULL, &size, &ptr, 5,
-       string_sprintf("d=%s s=%s c=%s/%s a=%s ",
+       string_sprintf("d=%s s=%s c=%s/%s a=%s b=%d ",
              sig->domain,
              sig->selector,
-             sig->canon_headers == PDKIM_CANON_SIMPLE ?  "simple" : "relaxed",
-             sig->canon_body == PDKIM_CANON_SIMPLE ?  "simple" : "relaxed",
-             sig->algo == PDKIM_ALGO_RSA_SHA256 ?  "rsa-sha256" : "rsa-sha1"),
+             sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
+             sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
+             sig->algo == PDKIM_ALGO_RSA_SHA256
+             ? "rsa-sha256"
+             : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
+             (int)sig->sigdata.len > -1 ? sig->sigdata.len * 8 : 0
+             ),
 
        sig->identity ? string_sprintf("i=%s ", sig->identity) : US"",
        sig->created > 0 ? string_sprintf("t=%lu ", sig->created) : US"",
@@ -158,11 +182,22 @@ for (sig = dkim_signatures; sig; sig = sig->next)
                        "overlong public key record]");
          break;
 
-       case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
+       case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD:
+       case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT:
          logmsg = string_append(logmsg, &size, &ptr, 1,
                       "syntax error in public key record]");
          break;
 
+        case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR:
+          logmsg = string_append(logmsg, &size, &ptr, 1,
+                       "signature tag missing or invalid]");
+          break;
+
+        case PDKIM_VERIFY_INVALID_DKIM_VERSION:
+          logmsg = string_append(logmsg, &size, &ptr, 1,
+                       "unsupported DKIM version]");
+          break;
+
        default:
          logmsg = string_append(logmsg, &size, &ptr, 1,
                        "unspecified problem]");
@@ -220,6 +255,9 @@ if (dkim_signers)
   if (Ustrlen(dkim_signers) > 0)
   dkim_signers[Ustrlen(dkim_signers) - 1] = '\0';
   }
+
+out:
+store_pool = dkim_verify_oldpool;
 }
 
 
@@ -229,7 +267,6 @@ dkim_exim_acl_setup(uschar * id)
 pdkim_signature * sig;
 uschar * cmp_val;
 
-
 dkim_cur_sig = NULL;
 dkim_cur_signer = id;
 
@@ -255,6 +292,7 @@ for (sig = dkim_signatures; sig; sig = sig->next)
 
     dkim_signing_domain = US sig->domain;
     dkim_signing_selector = US sig->selector;
+    dkim_key_length = sig->sigdata.len * 8;
     return;
     }
 }
@@ -339,7 +377,7 @@ switch (what)
 
   case DKIM_HEADERNAMES:
     return dkim_cur_sig->headernames
-      ?  US dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
+      ? dkim_cur_sig->headernames : dkim_exim_expand_defaults(what);
 
   case DKIM_IDENTITY:
     return dkim_cur_sig->identity
@@ -395,7 +433,8 @@ switch (what)
       {
       case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
                                                return US"pubkey_unavailable";
-      case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:        return US"pubkey_syntax";
+      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_FAIL_BODY:             return US"bodyhash_mismatch";
       case PDKIM_VERIFY_FAIL_MESSAGE:          return US"signature_incorrect";
       }
@@ -561,16 +600,15 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
     dkim_private_key_expanded = big_buffer;
     }
 
-  ctx = pdkim_init_sign(PDKIM_INPUT_SMTP,
-                        (char *) dkim_signing_domain,
+  ctx = pdkim_init_sign( (char *) dkim_signing_domain,
                         (char *) dkim_signing_selector,
-                        (char *) dkim_private_key_expanded);
-  pdkim_set_debug_stream(ctx, debug_file);
+                        (char *) dkim_private_key_expanded,
+                        PDKIM_ALGO_RSA_SHA256);
   pdkim_set_optional(ctx,
                      (char *) dkim_sign_headers_expanded,
                      NULL,
                      pdkim_canon,
-                     pdkim_canon, -1, PDKIM_ALGO_RSA_SHA256, 0, 0);
+                     pdkim_canon, -1, 0, 0);
 
   lseek(dkim_fd, 0, SEEK_SET);