]> code.citadel.org Git - citadel.git/commitdiff
Moved dkimtester into the main repo
authorArt Cancro <ajc@citadel.org>
Sat, 11 May 2024 02:10:22 +0000 (02:10 +0000)
committerArt Cancro <ajc@citadel.org>
Sat, 11 May 2024 02:10:22 +0000 (02:10 +0000)
citadel/server/modules/smtp/dkim.c
citadel/tests/dkimtester/.gitignore [new file with mode: 0644]
citadel/tests/dkimtester/Makefile [new file with mode: 0644]
citadel/tests/dkimtester/README.md [new file with mode: 0644]
citadel/tests/dkimtester/dkimtester.c [new file with mode: 0644]
citadel/tests/dkimtester/tester.pl [new file with mode: 0755]

index 589332ea44f85b59659b75b76db420b3e5b7f571..248a89564182c8a0fb81fdd6a7b7debbbf032c2d 100644 (file)
@@ -469,7 +469,9 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        }
        EVP_MD_CTX_free(mdctx);
 
-       // THIS IS OPTIONAL.  Do it a second time, but verify the signature instead of signing.
+       // This is an optional routine to verify our own signature.
+       // The test program in tests/dkimtester enables it.  It is not enabled during server operation.
+#ifdef DKIM_VERIFY_SIGNATURE
        mdctx = EVP_MD_CTX_new();
        if (mdctx) {
                assert(EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) == 1);
@@ -477,7 +479,7 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
                assert(EVP_DigestVerifyFinal(mdctx, sig, signature_len) == 1);
                EVP_MD_CTX_free(mdctx);
        }
-       // End verify
+#endif
 
        // With the signature complete, we no longer need the private key or the unfolded headers.
        EVP_PKEY_free(pkey);
diff --git a/citadel/tests/dkimtester/.gitignore b/citadel/tests/dkimtester/.gitignore
new file mode 100644 (file)
index 0000000..c9a9405
--- /dev/null
@@ -0,0 +1 @@
+dkimtester
diff --git a/citadel/tests/dkimtester/Makefile b/citadel/tests/dkimtester/Makefile
new file mode 100644 (file)
index 0000000..d308ec2
--- /dev/null
@@ -0,0 +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
+
+clean:
+       rm -f dkimtester
diff --git a/citadel/tests/dkimtester/README.md b/citadel/tests/dkimtester/README.md
new file mode 100644 (file)
index 0000000..4d46b69
--- /dev/null
@@ -0,0 +1,13 @@
+# dkimtester
+
+This was originally where we developed the DKIM code for Citadel
+but it is properly merged into Citadel now.  What's left is just
+a test harness.
+
+You must have the `Mail::DKIM::Verifier` perl module installed,
+which can be found on CPAN.
+
+Also it depends on a DKIM record for `dev.citadel.org` which is
+correct at the time I am writing this.  Good luck keeping that in
+place.
+
diff --git a/citadel/tests/dkimtester/dkimtester.c b/citadel/tests/dkimtester/dkimtester.c
new file mode 100644 (file)
index 0000000..c923bd5
--- /dev/null
@@ -0,0 +1,96 @@
+// ***** TEST HARNESS *****
+// This contains a private key that, at the time of writing, matches the DKIM public key for dev.citadel.org
+// We can use the attached test message to validate a signature against that.
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <syslog.h>
+#include <libcitadel.h>
+
+// oof, a prototype where one does not belong hehe
+void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector);
+
+int main(int argc, char *argv[]) {
+
+       openlog("dkim", LOG_PERROR, LOG_USER);
+
+       char *private_key =
+               "-----BEGIN PRIVATE KEY-----\n"
+               "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfuefcepokRrnp\n"
+               "SSDsxu+QDqeD8GL9QnZz/N6IxTdBv6Wc10ExBe2IjS5dKI7AvhSSEK0zGE8Hkpmw\n"
+               "eccbiepQqeueteWzAMZ1uT43bD3k7eye7vWobiOP9QtoYGR6sG25h2W5Tbc91W4f\n"
+               "dvYnxYVJjx8wIVF0f3o25v+rQueoo0HlvGyA9/xi9GAaJL05OmK1xnMJgSvW/Q8Q\n"
+               "zq7apf1D6XPXHuhv5tevElkZ5jlvM2w0cTVyAzMrUh6Rkcn9xM4/NPWYghBc3jO4\n"
+               "TrPnSrobQGrX0fcizE/FN6I0in0Ke8Z+gMM8NeFcsjvLZe9MpY9i0pw/ygLIh5t3\n"
+               "O4qpwC1JAgMBAAECggEAIwiTCMEAGzciDKhhagJ66BWLYMtHTP5X2zDZThSH4xlW\n"
+               "HznL4RfbCtuEy5y6we7h/L90x8ACPB7WRz7CkYrmsMvy9A7q0b2I1k10MyyVgqBJ\n"
+               "QdgMitv4YKYQK7+QbG/tNrS/lqVXUOz3iiDQSgkRpqOtUBWfkj0WD7vbhF99NDhV\n"
+               "dxaehFkKv3yNy0bXJlHJBJ6KtOUnDwub8TExh8dyj3kB8Qzj4I98shaXPNUSSaOw\n"
+               "zG6QG72yrxlMs495jkIPbF2JDidmLrX+oVISwKyaBWx+BkFV/KFAEKgaB5/nCw7+\n"
+               "qq/jxsmXim3HuQ3MIAjq1yw9aGRH1HMi8Gn7tYlNGwKBgQDy6EEKpuEiW9wwlI2+\n"
+               "GVuSkhSTTX1h6qK/ay8Jtyb8yJM/BxogAQlfjdgFixiZHy5MaomTbfeT2GDji553\n"
+               "+RsnZ60+g7FI9nHwabSxtuCQ+vjbFqCsdMPAiSeG0bEzo0zf5TjASdUtuZL0vXjl\n"
+               "yMZWDEuESoVNlYlvCOVkw2nvIwKBgQDryPuSq6PNVHRWsKRRs5ju4wKs/1ucBOg5\n"
+               "gCcN8lE03mFCWAlZhypE4/fAhTQ/a5KQoAzc0QZcXRueDyNsnc+QWw3/QWf8/fkV\n"
+               "HPfTWS3Dcuj+4RnWUucaZ/mKFlTC3+eNSlpyaPIMlCjXGsJ9GlPrsaAi9KPbD2v/\n"
+               "XcMq/PMOowKBgHVf7S3sfZVQthFzdxqIvksQ84hKRW/vJT1B2bTkH56+fQhTsjgM\n"
+               "yC64J85l7DjxbDnYsSngVWXHhOnvKV/nq0tbOcefcydCjsQREBNfvxvPajjTskgj\n"
+               "FAQRQlxPL0U4f4khBk9EXhJ+PZithaHjZpNl1YfTSp62x3Yz4kTSeHnpAoGAGn5m\n"
+               "5kArE7NdrzACBrwrfww7DL1Uyd8zSOLBgKutvEcQnqfNxSWO9la3TAarrESmH2Ic\n"
+               "j+Nc15wOsl/5FwdUf1/73qa2zJKtHlY28qSeo8uRqrIYeSCvnyP3wjBoLc2C8zlb\n"
+               "mGd6azdqr2DuYahHrcAzwjnC/6Zn+DXM7FOn7AkCgYBp1xxY88cCoF24yffkD3MC\n"
+               "ACUury4qRSDTGx6/qCCkIyWxg1vuiDrlPWhSwQznxHvovcfpdjdbWcFY87IK6mpG\n"
+               "aJHwMJ7Kw+baoxGPZWHwdg6BgvUCihe3xlcaq6rOBoLviD6FOzbogg++Tvi0LemG\n"
+               "y/wEs/mZkaRzW4n41ir0Xw==\n"
+               "-----END PRIVATE KEY-----\n"
+       ;
+
+       // These elements are identical to the ones from previous revisions.  Don't change them; we need to compare.
+       char *domain = "dev.citadel.org";
+       char *selector = "foo";
+
+       // Sample message
+       StrBuf *email = NewStrBufPlain(HKEY(
+               "From: Fred Bloggs <bloggs@dev.citadel.org>\r\n"
+               "X-irrelevant-header: wow mom 303\r\n"
+               "To: Bread Floggs <bf@example.com>\r\n"
+               "Subject: The ultimate test message!\r\n"
+               "Message-ID: <73294856-8726543-473298@dev.citadel.org>\r\n"
+               "\r\n"
+               "Hi.\r\n"
+               "\r\n"
+               "Bhille Disassemble.  Highly recommend.\r\n"
+               "\r\n"
+               "--Fred\r\n"
+       ));
+
+       // create signature
+       dkim_sign(email, private_key, domain, selector);
+
+       // Show the user what we did
+       printf("%s", (char *)ChrPtr(email));
+
+       FILE *fp;
+       printf("\033[34m-----\033[0m\n");
+       printf("Piping original version to test program...\n");
+       fp = popen("./tester.pl | sed s/pass/\033[32mpass\033[0m/g | sed s/fail/\033[31mfail\033[0m/g", "w");
+       fwrite((char *)ChrPtr(email), StrLength(email), 1, fp);
+       pclose(fp);
+       printf("\033[34m-----\033[0m\n");
+       printf("Piping altered version to test program...\n");
+       fp = popen("sed s/oggs/argh/g | ./tester.pl | sed s/pass/\033[32mpass\033[0m/g | sed s/fail/\033[31mfail\033[0m/g", "w");
+       fwrite((char *)ChrPtr(email), StrLength(email), 1, fp);
+       pclose(fp);
+       printf("\033[34m-----\033[0m\n");
+
+       // free some memory
+       FreeStrBuf(&email);
+
+       // exit the test program
+       return(0);
+}
diff --git a/citadel/tests/dkimtester/tester.pl b/citadel/tests/dkimtester/tester.pl
new file mode 100755 (executable)
index 0000000..1f23339
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+use Mail::DKIM::Verifier;
+# create a verifier object
+my $dkim = Mail::DKIM::Verifier->new();
+# read an email from a file handle
+while (<STDIN>)
+{
+    # remove local line terminators
+    chomp;
+    s/\015$//;
+    # use SMTP line terminators
+    $dkim->PRINT("$_\015\012");
+}
+$dkim->CLOSE;
+# what is the result of the verify?
+my $result = $dkim->result;
+
+# there might be multiple signatures, what is the result per signature?
+foreach my $signature ($dkim->signatures)
+{
+    print 'signature identity: ' . $signature->identity . "\n";
+    print '     verify result: ' . $signature->result_detail . "\n";
+}
+# the alleged author of the email may specify how to handle email
+foreach my $policy ($dkim->policies)
+{
+    die 'fraudulent message' if ($policy->apply($dkim) eq 'reject');
+}