]> code.citadel.org Git - citadel.git/blobdiff - citadel/server/modules/smtp/dkim.c
more work on alerting
[citadel.git] / citadel / server / modules / smtp / dkim.c
index beb1681e2f4276bc770ce37124b739c45a459c75..b8835d36f931282e65a99330a052f1cb32fcf596 100644 (file)
@@ -30,8 +30,6 @@
 #include <openssl/evp.h>
 #include <libcitadel.h>
 #include "../../config.h"
-#include "../../internet_addressing.h"
-
 
 // This utility function is used by the body canonicalizer
 char *dkim_rtrim(char *str) {
@@ -362,6 +360,53 @@ void dkim_final_header_list(char *header_list, size_t header_list_size, StrBuf *
 }
 
 
+// Supplied with a PEM-encoded PKCS#7 private key, that might also have newlines replaced with underscores, return an EVP_PKEY.
+// Caller is responsible for freeing it.
+EVP_PKEY *dkim_import_key(char *pkey_in) {
+
+       if (!pkey_in) {
+               return(NULL);
+       }
+
+       // Citadel Server stores the private key in PEM-encoded PKCS#7 format, but with all newlines replaced by underscores.
+       // Fix that before we try to decode it.
+       char *pkey_with_newlines = strdup(pkey_in);
+       if (!pkey_with_newlines) {
+               return(NULL);
+       }
+       char *sp;
+       while (sp = strchr(pkey_with_newlines, '_')) {
+               *sp = '\n';
+       }
+
+       // Load the private key into an OpenSSL "BIO" structure
+       BIO *bufio = BIO_new_mem_buf((void*)pkey_with_newlines, strlen(pkey_with_newlines));
+       if (bufio == NULL) {
+               syslog(LOG_ERR, "dkim: BIO_new_mem_buf() failed");
+               free(pkey_with_newlines);
+               return(NULL);
+       }
+
+       // Now import the private key
+       EVP_PKEY *pkey = NULL;                  // Don't combine this line with the next one.  It will barf.
+       pkey = PEM_read_bio_PrivateKey(
+               bufio,                          // BIO to read the private key from
+               &pkey,                          // pointer to EVP_PKEY structure
+               NULL,                           // password callback - can be NULL
+               NULL                            // parameter passed to callback or password if callback is NULL
+       );
+
+       free(pkey_with_newlines);
+       BIO_free(bufio);
+
+       if (pkey == NULL) {
+               syslog(LOG_ERR, "dkim: PEM_read_bio_PrivateKey() failed");
+       }
+
+       return(pkey);
+}
+
+
 // DKIM-sign an email, supplied as a full RFC2822-compliant message stored in a StrBuf
 void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        int i = 0;
@@ -370,6 +415,12 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
                return;
        }
 
+       // Import the private key
+       EVP_PKEY *pkey = dkim_import_key(pkey_in);
+       if (pkey == NULL) {
+               return;
+       }
+
        // find the break between headers and body
        size_t msglen = StrLength(email);                                       // total length of message (headers + body)
 
@@ -436,27 +487,6 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        // Compute a hash of the canonicalized headers, and then sign that hash with our private key.
        // RFC6376 says that we hash and sign everything up to the "b=" and then we'll add the rest at the end.
 
-       // Load the private key into an OpenSSL "BIO" structure
-       BIO *bufio = BIO_new_mem_buf((void*)pkey_in, strlen(pkey_in));
-       if (bufio == NULL) {
-               syslog(LOG_ERR, "dkim: BIO_new_mem_buf() failed");
-               abort();
-       }
-
-       // Now import the private key
-       EVP_PKEY *pkey = NULL;                  // Don't combine this line with the next one.  It will barf.
-       pkey = PEM_read_bio_PrivateKey(
-               bufio,                          // BIO to read the private key from
-               &pkey,                          // pointer to EVP_PKEY structure
-               NULL,                           // password callback - can be NULL
-               NULL                            // parameter passed to callback or password if callback is NULL
-       );
-       if (pkey == NULL) {
-               syslog(LOG_ERR, "dkim: PEM_read_bio_PrivateKey() failed");
-               abort();
-       }
-       BIO_free(bufio);                        // Don't need this anymore, we have `pkey` now
-
        // The hashing/signing library calls are documented at https://wiki.openssl.org/index.php/EVP_Signing_and_Verifying
        // NOTE: EVP_DigestSign*() functions are supplied with the actual data to be hashed and signed.
        // That means we don't hash it first, otherwise we would be signing double-hashed (and therefore wrong) data.
@@ -549,11 +579,12 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
 }
 
 
+#ifndef DKIM_VERIFY_SIGNATURE
 // Generate a private key and selector for DKIM if needed.  This is called during server startup.
 void dkim_init(void) {
 
        char *dkim_private_key = CtdlGetConfigStr("dkim_private_key");
-       if (dkim_private_key) {
+       if (!IsEmptyStr(dkim_private_key)) {
                syslog(LOG_DEBUG, "dkim: private key exists and will continue to be used.");
        }
        else {
@@ -609,7 +640,7 @@ void dkim_init(void) {
 
 
 // If the DKIM key, DKIM selector, or set of signing domains has changed, we need to tell the administrator about it.
-void dkim_check_advisory(void) {
+void dkim_check_advisory(char *inetcfg_in) {
 
        // If there is no DKIM ... there is nothing to discuss
        if (IsEmptyStr(CtdlGetConfigStr("dkim_private_key"))) return;
@@ -627,7 +658,7 @@ void dkim_check_advisory(void) {
        StrBufAppendBufPlain(hashsrc, CtdlGetConfigStr("dkim_private_key"), strlen(CtdlGetConfigStr("dkim_private_key")), 0);
        StrBufAppendBufPlain(hashsrc, CtdlGetConfigStr("dkim_selector"), strlen(CtdlGetConfigStr("dkim_selector")), 0);
 
-       char *ptr = inetcfg;
+       char *ptr = inetcfg_in;
        while (ptr && *ptr) {
                char *sep = strchr(ptr, '|');
                if (sep && !strncasecmp(sep+1, HKEY("localhost"))) {
@@ -661,23 +692,27 @@ void dkim_check_advisory(void) {
                        " \n"
                );
 
-               ptr = inetcfg;
+               ptr = inetcfg_in;
                while (ptr && *ptr) {
                        char *sep = strchr(ptr, '|');
                        if (sep && !strncasecmp(sep+1, HKEY("localhost"))) {
-                               StrBufAppendPrintf(message, " Record name : %s._domainkey.%s\n",
-                                       CtdlGetConfigStr("dkim_selector"),
-                                       "fixme.FIXME.com"
-                               );
-                               StrBufAppendPrintf(message, " Record type : TXT\n");
-                               StrBufAppendPrintf(message, " Record value: c=dkim1 etc. etc. etc.\n");
-                               StrBufAppendPrintf(message, " \n");
+                               StrBufAppendPrintf(message, " Host name  : %s._domainkey.", CtdlGetConfigStr("dkim_selector"));
+                               StrBufAppendBufPlain(message, ptr, sep-ptr, 0);
+                               StrBufAppendBufPlain(message, HKEY("\r\n"), 0);
+                               StrBufAppendPrintf(message, " Record type: TXT\n");
+                               StrBufAppendBufPlain(message, HKEY(" Value      : v=DKIM1;k=rsa;p="), 0);
+
+                               // figure out the public key and get it
+
+                               StrBufAppendPrintf(message, "\n \n");
                        }
                        ptr = strchr(ptr, '\n');
                        if (ptr) ++ptr;
                }
 
+#if 0
                CtdlAideMessage(ChrPtr(message), "DKIM records");
+#endif
                FreeStrBuf(&message);
        }
 
@@ -685,3 +720,4 @@ void dkim_check_advisory(void) {
        CtdlSetConfigStr("dkim_config_hash", encoded_config_hash);
        free(encoded_config_hash);
 }
+#endif