Fix l= label / Fix missing string terminator
[users/jgh/exim.git] / src / src / dkim.c
index fb846beb4e0fa8dc792f6c8c9d3e63db2f607d2b..dd8334b634423d221014cbeb5b2a914ccc4d5ee7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.2 2009/02/24 18:43:59 tom Exp $ */
+/* $Cambridge: exim/src/src/dkim.c,v 1.1.2.11 2009/05/19 09:49:14 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 #include "pdkim/pdkim.h"
 
+pdkim_ctx       *dkim_verify_ctx = NULL;
+pdkim_signature *dkim_signatures = NULL;
 
-void dkim_exim_verify_init(void) {
+int dkim_exim_query_dns_txt(char *name, char *answer) {
+  dns_answer dnsa;
+  dns_scan   dnss;
+  dns_record *rr;
+
+  if (dns_lookup(&dnsa, (uschar *)name, T_TXT, NULL) != DNS_SUCCEED) return 1;
+
+  /* Search for TXT record */
+  for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+       rr != NULL;
+       rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+    if (rr->type == T_TXT) break;
+
+  /* Copy record content to the answer buffer */
+  if (rr != NULL) {
+    int rr_offset = 0;
+    int answer_offset = 0;
+    while (rr_offset < rr->size) {
+      uschar len = (rr->data)[rr_offset++];
+      snprintf(answer+(answer_offset),
+               PDKIM_DNS_TXT_MAX_RECLEN-(answer_offset),
+               "%.*s", (int)len, (char *)((rr->data)+rr_offset));
+      rr_offset+=len;
+      answer_offset+=len;
+    }
+  }
+  else return 1;
+
+  return PDKIM_OK;
+}
+
+
+int dkim_exim_verify_init(void) {
+
+  /* Free previous context if there is one */
+  if (dkim_verify_ctx) pdkim_free_ctx(dkim_verify_ctx);
+
+  /* Create new context */
+  dkim_verify_ctx = pdkim_init_verify(PDKIM_INPUT_SMTP,
+                                      &dkim_exim_query_dns_txt
+                                     );
+
+  if (dkim_verify_ctx != NULL) {
+    dkim_collect_input = 1;
+    pdkim_set_debug_stream(dkim_verify_ctx,debug_file);
+    return 1;
+  }
+  else {
+    dkim_collect_input = 0;
+    return 0;
+  }
 }
 
-void dkim_exim_verify_finish(void) {
+
+int dkim_exim_verify_feed(uschar *data, int len) {
+  if (pdkim_feed(dkim_verify_ctx,
+                 (char *)data,
+                 len) != PDKIM_OK) return 0;
+  return 1;
 }
 
+
+int dkim_exim_verify_finish(void) {
+  dkim_signatures = NULL;
+  dkim_collect_input = 0;
+  if (pdkim_feed_finish(dkim_verify_ctx,&dkim_signatures) != PDKIM_OK) return 0;
+
+  while (dkim_signatures != NULL) {
+    int size = 0;
+    int ptr = 0;
+    uschar *logmsg = string_append(NULL, &size, &ptr, 5,
+
+      string_sprintf( "DKIM: v=%u d=%s s=%s c=%s/%s a=%s ",
+                      dkim_signatures->version,
+                      dkim_signatures->domain,
+                      dkim_signatures->selector,
+                      (dkim_signatures->canon_headers == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
+                      (dkim_signatures->canon_body    == PDKIM_CANON_SIMPLE)?"simple":"relaxed",
+                      (dkim_signatures->algo          == PDKIM_ALGO_RSA_SHA256)?"rsa-sha256":"rsa-sha1"
+                    ),
+
+      ((dkim_signatures->identity != NULL)?
+        string_sprintf("i=%s ", dkim_signatures->identity)
+        :
+        US""
+      ),
+      ((dkim_signatures->created > 0)?
+        string_sprintf("t=%lu ", dkim_signatures->created)
+        :
+        US""
+      ),
+      ((dkim_signatures->expires > 0)?
+        string_sprintf("x=%lu ", dkim_signatures->expires)
+        :
+        US""
+      ),
+      ((dkim_signatures->bodylength > -1)?
+        string_sprintf("l=%lu ", dkim_signatures->bodylength)
+        :
+        US""
+      )
+    );
+
+    switch(dkim_signatures->verify_status) {
+      case PDKIM_VERIFY_NONE:
+        logmsg = string_append(logmsg, &size, &ptr, 1, "[not verified]");
+      break;
+      case PDKIM_VERIFY_INVALID:
+        logmsg = string_append(logmsg, &size, &ptr, 1, "[invalid - ");
+        switch (dkim_signatures->verify_ext_status) {
+          case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "public key record (currently?) unavailable]");
+          break;
+          case PDKIM_VERIFY_INVALID_BUFFER_SIZE:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "overlong public key record]");
+          break;
+          case PDKIM_VERIFY_INVALID_PUBKEY_PARSING:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "syntax error in public key record]");
+          break;
+          default:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified problem]");
+        }
+      break;
+      case PDKIM_VERIFY_FAIL:
+        logmsg = string_append(logmsg, &size, &ptr, 1, "[verification failed - ");
+        switch (dkim_signatures->verify_ext_status) {
+          case PDKIM_VERIFY_FAIL_BODY:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "body hash mismatch (body probably modified in transit)]");
+          break;
+          case PDKIM_VERIFY_FAIL_MESSAGE:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "signature did not verify (headers probably modified in transit)]");
+          break;
+          default:
+            logmsg = string_append(logmsg, &size, &ptr, 1, "unspecified reason]");
+        }
+      break;
+      case PDKIM_VERIFY_PASS:
+        logmsg = string_append(logmsg, &size, &ptr, 1, "[verification succeeded]");
+      break;
+    }
+
+    logmsg[ptr] = '\0';
+    log_write(0, LOG_MAIN, (char *)logmsg);
+
+    /* Try next signature */
+    dkim_signatures = dkim_signatures->next;
+  }
+
+  return dkim_signatures?1:0;
+}
+
+
 int dkim_exim_verify_result(uschar *domain, uschar **result, uschar **error) {
+
+  if (dkim_verify_ctx) {
+
+  }
+
   return OK;
 }
 
+
 uschar *dkim_exim_sign(int dkim_fd,
                        uschar *dkim_private_key,
                        uschar *dkim_domain,
@@ -35,7 +189,7 @@ uschar *dkim_exim_sign(int dkim_fd,
                        uschar *dkim_sign_headers) {
   pdkim_ctx *ctx = NULL;
   uschar *rc = NULL;
-  char *signature;
+  pdkim_signature *signature;
   int pdkim_canon;
   int sread;
   char buf[4096];
@@ -119,21 +273,21 @@ uschar *dkim_exim_sign(int dkim_fd,
     dkim_private_key = big_buffer;
   }
 
-  ctx = pdkim_init_sign((char *)dkim_signing_domain,
+  ctx = pdkim_init_sign(PDKIM_INPUT_SMTP,
+                        (char *)dkim_signing_domain,
                         (char *)dkim_signing_selector,
-                        dkim_private_key
+                        (char *)dkim_private_key
                        );
 
   pdkim_set_debug_stream(ctx,debug_file);
 
   pdkim_set_optional(ctx,
-                     PDKIM_INPUT_SMTP,
                      (char *)dkim_sign_headers,
                      NULL,
                      pdkim_canon,
                      pdkim_canon,
-                     0,
-                     PDKIM_ALGO_RSA_SHA1,
+                     -1,
+                     PDKIM_ALGO_RSA_SHA256,
                      0,
                      0);
 
@@ -154,8 +308,8 @@ uschar *dkim_exim_sign(int dkim_fd,
   if (pdkim_feed_finish(ctx,&signature) != PDKIM_OK)
     goto CLEANUP;
 
-  rc = store_get(strlen(signature)+3);
-  Ustrcpy(rc,US signature);
+  rc = store_get(strlen(signature->signature_header)+3);
+  Ustrcpy(rc,US signature->signature_header);
   Ustrcat(rc,US"\r\n");
 
   CLEANUP: