Hello misc@,

I'm currently working on adding ed25519 support to filter-dkimsign, but
I'm getting some mixed results with the different validators.

gmail: permfail => claims the key is missing
outlook: fail (signature syntax error)
protonmail: 2 headers
     1st: permerror (0-bit key)
     2nd: pass
yahoo: permfail
dkimvalidator.com: ed25519 not supported
rspamd: pass

I'm having some mixed feelings on how to interpret these results.
On the one hand I'm getting passes, so it appears to work in general.
But when I read RFC6373 section 3.3.4 it states:
   Other algorithms MAY be defined in the future.  Verifiers MUST ignore
   any signatures using algorithms that they do not implement.
So I wouldn't expect these fails.

Does anyone on this list know which validators are known to verify
ed25519 correctly, or which explicitly are known to fail? If someone
wants to help me test my current work, work in progress diff below. This
is to be applied on top of http://imperialat.at/dev/filter-dkimsign/
Requires openssl 1.1.1 from ports.

martijn@

Index: Makefile
===================================================================
--- Makefile    (revision 60)
+++ Makefile    (working copy)
@@ -6,6 +6,10 @@
 
 SRCS+= main.c mheader.c
 
+CRYPT_CFLAGS!=pkg-config --cflags libecrypto11
+CRYPT_LDFLAGS!=pkg-config --libs-only-L libecrypto11
+CRYPT_LDADD!=pkg-config --libs-only-l libecrypto11
+
 CFLAGS+=-I${LOCALBASE}/include
 CFLAGS+=-Wall -I${.CURDIR}
 CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes
@@ -12,8 +16,10 @@
 CFLAGS+=-Wmissing-declarations
 CFLAGS+=-Wshadow -Wpointer-arith -Wcast-qual
 CFLAGS+=-Wsign-compare
+CFLAGS+=${CRYPT_CFLAGS}
 LDFLAGS+=-L${LOCALBASE}/lib
-LDADD+=        -lcrypto -lopensmtpd
+LDFLAGS+=${CRYPT_LDFLAGS}
+LDADD+=        ${CRYPT_LDADD} -lopensmtpd
 DPADD= ${LIBCRYPTO}
 
 bindir:
Index: main.c
===================================================================
--- main.c      (revision 60)
+++ main.c      (working copy)
@@ -45,8 +45,7 @@
        int has_body;
        struct dkim_signature signature;
        int err;
-       EVP_MD_CTX *b;
-       EVP_MD_CTX *bh;
+       EVP_MD_CTX *dctx;
 };
 
 /* RFC 6376 section 5.4.1 */
@@ -92,6 +91,8 @@
 
 static EVP_PKEY *pkey;
 static const EVP_MD *hash_md;
+static int keyid = EVP_PKEY_RSA;
+static int sephash = 0;
 
 #define DKIM_SIGNATURE_LINELEN 78
 
@@ -124,9 +125,18 @@
        while ((ch = getopt(argc, argv, "a:c:d:h:k:s:tx:z")) != -1) {
                switch (ch) {
                case 'a':
-                       if (strncmp(optarg, "rsa-", 4) != 0)
-                               osmtpd_err(1, "invalid algorithm");
-                       hashalg = optarg + 4;
+                       if (strncmp(optarg, "rsa-", 4) == 0) {
+                               hashalg = optarg + 4;
+                               cryptalg = "rsa";
+                               keyid = EVP_PKEY_RSA;
+                               sephash = 0;
+                       } else if (strncmp(optarg, "ed25519-", 8) == 0) {
+                               hashalg = optarg + 8;
+                               cryptalg = "ed25519";
+                               keyid = EVP_PKEY_ED25519;
+                               sephash = 1;
+                       } else
+                               osmtpd_errx(1, "invalid algorithm");
                        break;
                case 'c':
                        if (strncmp(optarg, "simple", 6) == 0) {
@@ -166,8 +176,6 @@
                        pkey = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL);
                        if (pkey == NULL)
                                osmtpd_errx(1, "Can't read key file");
-                       if (EVP_PKEY_get0_RSA(pkey) == NULL)
-                               osmtpd_err(1, "Key is not of type rsa");
                        fclose(keyfile);
                        break;
                case 's':
@@ -190,15 +198,19 @@
        }
 
        OpenSSL_add_all_digests();
-       if ((hash_md = EVP_get_digestbyname(hashalg)) == NULL)
-               osmtpd_errx(1, "Can't find hash: %s", hashalg);
 
        if (pledge("tmppath stdio", NULL) == -1)
                osmtpd_err(1, "pledge");
 
+       if ((hash_md = EVP_get_digestbyname(hashalg)) == NULL)
+               osmtpd_errx(1, "Can't find hash: %s", hashalg);
+
        if (domain == NULL || selector == NULL || pkey == NULL)
                usage();
 
+       if (EVP_PKEY_id(pkey) != keyid)
+               osmtpd_errx(1, "Key is not of type %s", cryptalg);
+
        osmtpd_register_filter_dataline(dkim_dataline);
        osmtpd_register_filter_commit(dkim_commit);
        osmtpd_local_message(dkim_message_new, dkim_message_free);
@@ -293,13 +305,11 @@
        if (addheaders > 0 && !dkim_signature_printf(message, "z="))
                return NULL;
 
-       if ((message->b = EVP_MD_CTX_new()) == NULL ||
-           (message->bh = EVP_MD_CTX_new()) == NULL) {
+       if ((message->dctx = EVP_MD_CTX_new()) == NULL) {
                dkim_errx(message, "Can't create hash context");
                return NULL;
        }
-       if (EVP_DigestSignInit(message->b, NULL, hash_md, NULL, pkey) <= 0 ||
-           EVP_DigestInit_ex(message->bh, hash_md, NULL) == 0) {
+       if (EVP_DigestInit_ex(message->dctx, hash_md, NULL) == 0) {
                dkim_errx(message, "Failed to initialize hash context");
                return NULL;
        }
@@ -313,8 +323,7 @@
        size_t i;
 
        fclose(message->origf);
-       EVP_MD_CTX_free(message->b);
-       EVP_MD_CTX_free(message->bh);
+       EVP_MD_CTX_free(message->dctx);
        free(message->signature.signature);
        for (i = 0; message->headers[i] != NULL; i++)
                free(message->headers[i]);
@@ -514,7 +523,7 @@
        }
 
        while (message->body_whitelines--) {
-               if (EVP_DigestUpdate(message->bh, "\r\n", 2) == 0) {
+               if (EVP_DigestUpdate(message->dctx, "\r\n", 2) == 0) {
                        dkim_err(message, "Can't update hash context");
                        return;
                }
@@ -522,8 +531,8 @@
        message->body_whitelines = 0;
        message->has_body = 1;
 
-       if (EVP_DigestUpdate(message->bh, line, linelen) == 0 ||
-           EVP_DigestUpdate(message->bh, "\r\n", 2) == 0) {
+       if (EVP_DigestUpdate(message->dctx, line, linelen) == 0 ||
+           EVP_DigestUpdate(message->dctx, "\r\n", 2) == 0) {
                dkim_err(message, "Can't update hash context");
                return;
        }
@@ -534,8 +543,8 @@
 {
        struct dkim_message *message = ctx->local_message;
        /* Use largest hash size here */
-       char bbh[EVP_MAX_MD_SIZE];
-       char bh[(((sizeof(bbh) + 2) / 3) * 4) + 1];
+       char bdigest[EVP_MAX_MD_SIZE];
+       char digest[(((sizeof(bdigest) + 2) / 3) * 4) + 1];
        char *b;
        const char *sdomain = domain[0], *tsdomain;
        time_t now;
@@ -542,6 +551,7 @@
        ssize_t i;
        size_t linelen;
        char *tmp, *tmp2;
+       int ret, digestsz;
 
        if (addtime || addexpire)
                now = time(NULL);
@@ -552,26 +562,47 @@
                return;
 
        if (canonbody == CANON_SIMPLE && !message->has_body) {
-               if (EVP_DigestUpdate(message->bh, "\r\n", 2) <= 0) {
+               if (EVP_DigestUpdate(message->dctx, "\r\n", 2) <= 0) {
                        dkim_err(message, "Can't update hash context");
                        return;
                }
        }
-       if (EVP_DigestFinal_ex(message->bh, bbh, NULL) == 0) {
+       if (EVP_DigestFinal_ex(message->dctx, bdigest, NULL) == 0) {
                dkim_err(message, "Can't finalize hash context");
                return;
        }
-       EVP_EncodeBlock(bh, bbh, EVP_MD_CTX_size(message->bh));
-       if (!dkim_signature_printf(message, "bh=%s; h=", bh))
+       EVP_EncodeBlock(digest, bdigest, EVP_MD_CTX_size(message->dctx));
+       if (!dkim_signature_printf(message, "bh=%s; h=", digest))
                return;
        /* Reverse order for ease of use of RFC6367 section 5.4.2 */
        for (i = 0; message->headers[i] != NULL; i++)
                continue;
+       EVP_MD_CTX_reset(message->dctx);
+       if (sephash)
+               ret = EVP_DigestInit_ex(message->dctx, hash_md, NULL);
+       else
+               ret = EVP_DigestSignInit(message->dctx, NULL, hash_md, NULL,
+                   pkey);
+       if (ret <= 0) {
+               dkim_errx(message, "Failed to initialize hash context");
+               return;
+       }
+       ret = 1;
        for (i--; i >= 0; i--) {
-               if (EVP_DigestSignUpdate(message->b,
-                   message->headers[i],
-                   strlen(message->headers[i])) <= 0 ||
-                   EVP_DigestSignUpdate(message->b, "\r\n", 2) <= 0) {
+               if (sephash) {
+                       if (EVP_DigestUpdate(message->dctx, message->headers[i],
+                           strlen(message->headers[i])) <= 0 ||
+                           EVP_DigestUpdate(message->dctx, "\r\n", 2) <= 0) 
+                               ret = 0;
+               } else {
+                       if (EVP_DigestSignUpdate(message->dctx,
+                           message->headers[i],
+                           strlen(message->headers[i])) <= 0 ||
+                           EVP_DigestSignUpdate(message->dctx, "\r\n",
+                           2) <= 0)
+                               ret = 0;
+               }
+               if (ret == 0) {
                        dkim_errx(message, "Failed to update digest context");
                        return;
                }
@@ -597,23 +628,51 @@
                return;
        }
        dkim_parse_header(message, tmp, 1);
-       if (EVP_DigestSignUpdate(message->b, tmp, strlen(tmp)) <= 0) {
+       if (sephash)
+               ret = EVP_DigestUpdate(message->dctx, tmp, strlen(tmp));
+       else
+               ret = EVP_DigestSignUpdate(message->dctx, tmp, strlen(tmp));
+       if (ret <= 0) {
                dkim_err(message, "Failed to update digest context");
                return;
        }
        free(tmp);
-       if (EVP_DigestSignFinal(message->b, NULL, &linelen) <= 0) {
-               dkim_err(message, "Failed to finalize digest");
-               return;
+       if (sephash) {
+               if (EVP_DigestFinal_ex(message->dctx, bdigest, NULL) == 0) {
+                       dkim_err(message, "Can't finalize hash context");
+                       return;
+               }
+               digestsz = EVP_MD_CTX_size(message->dctx);
+               EVP_MD_CTX_reset(message->dctx);
+               ret = EVP_DigestSignInit(message->dctx, NULL, NULL, NULL,
+                   pkey);
+               if (EVP_DigestSign(message->dctx, NULL, &linelen, bdigest,
+                   digestsz) <= 0) {
+                       dkim_err(message, "Failed to finalize digest");
+               }
+               if ((tmp = malloc(linelen)) == NULL) {
+                       dkim_err(message, "Can't allocate space for digest");
+                       return;
+               }
+               if (EVP_DigestSign(message->dctx, tmp, &linelen, bdigest,
+                   digestsz) <= 0) {
+                       dkim_err(message, "Failed to finalize digest");
+                       return;
+               }
+       } else {
+               if (EVP_DigestSignFinal(message->dctx, NULL, &linelen) <= 0) {
+                       dkim_err(message, "Failed to finalize digest");
+                       return;
+               }
+               if ((tmp = malloc(linelen)) == NULL) {
+                       dkim_err(message, "Can't allocate space for digest");
+                       return;
+               }
+               if (EVP_DigestSignFinal(message->dctx, tmp, &linelen) <= 0) {
+                       dkim_err(message, "Failed to finalize digest");
+                       return;
+               }
        }
-       if ((tmp = malloc(linelen)) == NULL) {
-               dkim_err(message, "Can't allocate space for digest");
-               return;
-       }
-       if (EVP_DigestSignFinal(message->b, tmp, &linelen) <= 0) {
-               dkim_err(message, "Failed to finalize digest");
-               return;
-       }
        if ((b = malloc((((linelen + 2) / 3) * 4) + 1)) == NULL) {
                dkim_err(message, "Can't create DKIM signature");
                return;



Reply via email to