]> code.citadel.org Git - citadel.git/commitdiff
more work on alerting
authorArt Cancro <ajc@citadel.org>
Wed, 15 May 2024 13:50:46 +0000 (13:50 +0000)
committerArt Cancro <ajc@citadel.org>
Wed, 15 May 2024 13:50:46 +0000 (13:50 +0000)
citadel/server/modules/inetcfg/serv_inetcfg.c
citadel/server/modules/smtp/dkim.c
citadel/server/modules/smtp/serv_smtpclient.c
citadel/server/modules/smtp/smtp_util.h
citadel/tests/dkimtester/Makefile

index e7e9ebdb559118e10d92db2153e9f7f5d5d4deab..1691f0f107a4587ec97961974bcfbd56129f6922 100644 (file)
@@ -52,7 +52,7 @@ void inetcfg_setTo(struct CtdlMessage *msg) {
 
                if (inetcfg != NULL) free(inetcfg);
                inetcfg = conf;
-               dkim_check_advisory();                  // this will check to see if we have to advise the admin about dkim
+               dkim_check_advisory(inetcfg);           // this will check to see if we have to advise the admin about dkim
        }
 }
 
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
index 3332cf4a5ce6555d43d923ca824a644be1e32096..03f54b108b0725c794e0fb2f6c5b8dcbf4bdd5ca 100644 (file)
@@ -244,17 +244,12 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from, char *sou
                && !IsEmptyStr(dkim_private_key)                // Do we have a private signing key?
                && !IsEmptyStr(dkim_selector)                   // and a selector to go with it?
        ) {
-               char *pkey = strdup(dkim_private_key);          // If you answered "yes" to all of the above questions,
-               if (pkey) {                                     // congratulations!  We get to DKIM-sign the message!
-                       char *sp;
-                       while (sp = strchr(pkey, '_')) {        // The dkim_private_key record contains our RSA private key,
-                               *sp = '\n';                     // but we have to convert all the newlines back to underscores.
-                       }
-                       syslog(LOG_DEBUG, "smtpclient: dkim-signing with private key for selector <%s> domain <%s>",
-                               dkim_selector, dkim_from_domain);
-                       dkim_sign(s.TheMessage, pkey, dkim_from_domain, dkim_selector);
-                       free(pkey);
-               }
+               // If you answered "yes" to all of the above questions, congratulations!  We get to sign the message!
+               syslog(LOG_DEBUG, "smtpclient: dkim-signing for selector <%s> in domain <%s>", dkim_selector, dkim_from_domain);
+
+               // Remember, the dkim_sign() function is capable of handling a PEM-encoded PKCS#7 private key that
+               // has had all of its newlines replaced by underscores -- which is exactly how we store it.
+               dkim_sign(s.TheMessage,dkim_private_key, dkim_from_domain, dkim_selector);
        }
 
        // Prepare the buffer for transmittal
index 8f30226435abb1c98e9bcde774835a23ca5a3c33..041fa4dacc580f729b7ff19d452fff7e78295a68 100644 (file)
@@ -31,4 +31,4 @@ void smtp_do_bounce(const char *instr, int is_final);
 char *smtpstatus(int code);
 void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector);
 void dkim_init(void);
-void dkim_check_advisory(void);
+void dkim_check_advisory(char *inetcfg_in);
index d308ec2fcc086015112aecc8020f992af9935aba..0ab4467da4cb3e513c37040d8a24250fd67d3d83 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile
 
 dkimtester: dkimtester.c ../../server/modules/smtp/dkim.c
-       cc -DDKIM_VERIFY_SIGNATURE -g dkimtester.c ../../server/modules/smtp/dkim.c -lcrypto -lcitadel -o dkimtester
+       cc -DCTDLDIR=/tmp -DDKIM_VERIFY_SIGNATURE -g dkimtester.c ../../server/modules/smtp/dkim.c -lcrypto -lcitadel -o dkimtester
 
 clean:
        rm -f dkimtester