GithubHelp home page GithubHelp logo

trusteddomainproject / opendkim Goto Github PK

View Code? Open in Web Editor NEW
91.0 21.0 50.0 5.26 MB

License: Other

Makefile 1.36% Roff 1.47% C 72.35% Shell 1.27% M4 2.64% Lua 4.43% Python 0.20% Perl 3.15% HTML 12.16% Objective-C 0.33% PHP 0.20% CSS 0.04% C++ 0.40%
dkim phishing

opendkim's Introduction

OPENDKIM README
===============

This directory has the latest open source DKIM filter software from The
OpenDKIM Project.

There is a web site at http://www.opendkim.org that is home for the latest
updates.


+--------------+
| INTRODUCTION |
+--------------+

The Trusted Domain Project is a community effort to develop and maintain an open
source library for producing DKIM-aware applications, and a "milter"-based
filter for providing DKIM service.

The DKIM sender authentication system was originally created by the E-mail
Signing Technology Group (ESTG) and is now a draft standard of the
IETF (RFC6376).  DKIM is an amalgamation of the DomainKeys (DK) proposal by
Yahoo!, Inc. and the Internet Identified Mail (IIM) proposal by Cisco.

"milter" is a portmanteau of "mail filter" and refers to a protocol and API
for communicating mail traffic information between MTAs and mail filtering
plug-in applications.  It was originally invented at Sendmail, Inc. but
has also been adapted to other MTAs.

The OpenDKIM project started as a code fork of version 2.8.3 of the open source
"dkim-milter" package developed and maintained by Sendmail, Inc.  The license
used by The OpenDKIM project is found in the LICENSE file.  Portions of this
project are also covered by the Sendmail Open Source License, available in
this distribution in the file "LICENSE.Sendmail".  See the copyright notice(s)
in each source file to determine whether or not it is covered by both licenses.

This package consists of a library that implements the DKIM service and a
milter-based filter application that can plug in to any milter-aware MTA to
provide that service to sufficiently recent sendmail, Postfix or other MTAs
that support the milter protocol.

An optional asynchronous resolver library is also provided to work around
limitations of the basic BIND resolver which comes installed on most
systems.


+--------------+
| DEPENDENCIES |
+--------------+

To compile and operate, this package requires the following:

o OpenSSL (http://www.openssl.org, or ask your software vendor for a package).
  Any version will get you started, however v0.9.8 or later is required if
  you want to be able to sign or verify messages using the SHA256 message
  digest algorithm which is generally required for current DKIM applications.

o sendmail v8.13.0 (or later), or Postfix 2.3, (or later) and libmilter.
  (These are only required if you are building the filter.)

o Access to a working nameserver (required only for signature verification).

o On Linux systems, either libbsd (BSD compatibility library) or some other
  library that provides strlcat() and strlcpy().

o If you wish to interface the filter with SQL databases, or store statistical
  information in a database, OpenDBX v1.3.7 or later is required.

o If you wish to use the Lua interpreter hooks for filter policy control, or
  statistical extensions (--enable-statsext), Lua v5.1 or later is required.

o If you wish to interface the filter with LDAP servers, OpenLDAP v2.1.3
  or later is required.

o For local hash or btree database support in either the filter or the
  library, Oracle's BerkeleyDB is required.  All versions are supported.

o If you are interested in tinkering with the build and packaging structure,
  you may need to upgrade to these versions of GNU's "autotools" components:
	autoconf (GNU Autoconf) 2.61
	automake (GNU automake) 1.7 (or 1.9 to avoid warnings)
	ltmain.sh (GNU libtool) 2.2.6 (or 1.5.26 after make maintainer-clean)


+-----------------------+
| RELATED DOCUMENTATION |
+-----------------------+

The man page for opendkim (the actual filter program) is present in the
opendkim directory of this source distribution.  There is additional
information in the INSTALL and FEATURES files, and in the README file in the
opendkim directory.  Changes are documented in the RELEASE_NOTES file.

HTML-style documentation for libopendkim is available in libopendkim/docs in
this source distribution.

General information about DKIM can be found at http://www.dkim.org

Mailing lists discussing and supporting the DKIM software found in this
package are maintained via a list server at opendkim.org.  Visit
http://www.opendkim.org to subscribe or browse archives.  The available
lists are:

	opendkim-announce	(moderated) Release announcements.

	opendkim-users		General OpenDKIM user questions and answers.

	opendkim-dev		Chatter among OpenDKIM developers.

	opendkim-cvs		Automated source code change announcements.
				May be renamed soon to something more general
				since we're moving away from CVS.

Bug tracking is done via the trackers on SourceForge at
http://sourceforge.net/projects/opendkim.  You can enter new bug
reports there, but please check first for older bugs already open,
or even already closed, before opening a new issue.


+---------+
| WARNING |
+---------+

Since OpenDKIM uses cryptography, the following information from OpenSSL
applies to this package as well.

PLEASE REMEMBER THAT EXPORT/IMPORT AND/OR USE OF STRONG CRYPTOGRAPHY
SOFTWARE, PROVIDING CRYPTOGRAPHY HOOKS OR EVEN JUST COMMUNICATING
TECHNICAL DETAILS ABOUT CRYPTOGRAPHY SOFTWARE IS ILLEGAL IN SOME
PARTS OF THE WORLD.  SO, WHEN YOU IMPORT THIS PACKAGE TO YOUR
COUNTRY, RE-DISTRIBUTE IT FROM THERE OR EVEN JUST EMAIL TECHNICAL
SUGGESTIONS OR EVEN SOURCE PATCHES TO THE AUTHOR OR OTHER PEOPLE
YOU ARE STRONGLY ADVISED TO PAY CLOSE ATTENTION TO ANY EXPORT/IMPORT
AND/OR USE LAWS WHICH APPLY TO YOU.  THE AUTHORS ARE NOT LIABLE FOR
ANY VIOLATIONS YOU MAKE HERE.  SO BE CAREFUL, IT IS YOUR RESPONSIBILITY.

If you use OpenSSL then make sure you read their README file which
contains information about patents etc.


+---------------------+
| DIRECTORY STRUCTURE |
+---------------------+

contrib		A collection of user contributed scripts that may be useful.

docs		A collection of RFCs and drafts related to opendkim.

libar		An optional thread-safe asynchronous resolver library.

libopendkim	A library that implements the proposed DKIM standard.

libopendkim/docs HTML documentation describing the API provided by libopendkim.

libvbr		An optional library that implements Vouch By Reference
		(VBR, RFC5518).

opendkim	A milter-based filter application which uses libopenkim (and
		optionally libar) to provide DKIM service via an MTA using
		the milter protocol.


+----------------+
| RUNTIME ISSUES |
+----------------+

WARNING: symbol 'X' not available

 The filter attempted to get some information from the MTA that the MTA
 did not provide.

 At various points in the interaction between the MTA and the filter, certain
 macros containing information about the job in progress or the connection
 being handled are passed from the MTA to the filter.

 In the case of sendmail, the names of the macros the MTA should pass to the
 filter are defined by the "Milter.macros" settings in sendmail.cf, e.g.
 "Milter.macros.connect", "Milter.macros.envfrom", etc.  This message
 indicates that the filter needed the contents of macro X, but that macro
 was not passed down from the MTA.

 Typically the values needed by this filter are passed from the MTA if the
 sendmail.cf was generated by the usual m4 method.  If you do not have
 those options defined in your sendmail.cf, make sure your M4 configuration
 files are current and rebuild your sendmail.cf to get appropriate lines
 added to your sendmail.cf, and then restart sendmail.

MTA timeouts

 By default, the MTA is configured to wait up to ten seconds for a response
 from a filter before giving up.  When querying remote nameservers
 for key and policy data, the DKIM filter may not get a response from the
 resolver within that time frame, and thus this MTA timeout will occur.
 This can cause messages to be rejected, temp-failed or delivered without
 verification, depending on the failure mode selected for the filter.

 When using the standard resolver library provided with your system, the
 DNS timeout cannot be adjusted.  If you encounter this problem, you must
 increase the time the MTA waits for replies.  See the documentation in
 the sendmail open source distribution (libmilter/README in particular)
 for instructions on changing these timeouts.

 When using the provided asynchronous resolver library, you can use the
 "-T" command line option to change the timeout so that it is shorter than
 the MTA timeout.

d2i_PUBKEY_bio() failed

 After retrieving and decoding a public key to perform a message verification,
 the OpenSSL library attempted to make use of that key but failed.  The
 known possible causes are:

  (a) Memory exhaustion

  (b) Key corruption

 If you're set to temp-fail messages in these cases, the remote end will
 probably retry the message.  If the same message fails again later,
 the key is probably corrupted or otherwise invalid.

 You can try compiling with _FFR_LOG_SSL_ERRORS to have the filter extract
 OpenSSL library errors and include them in the system log when such
 conditions occur for further diagnostics.  In one observed case, a corrupt
 key also caused the following to be logged:

  error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag;
  error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error

Other OpenDKIM issues:

 Report any bugs to the email address [email protected] or to
 the sourceforge issue trackers accessible at:
 
 https://sourceforge.net/p/opendkim/_list/tickets


+-----------------------------+
| Sendmail REWRITING FEATURES |
+-----------------------------+

There are two features of the sendmail MTA which, if activated, can interfere
with successful use of the DKIM service.  The two features are MASQUERADE_AS
and FEATURE(genericstable).  See cf/README in the open source sendmail
source code distribution for more information.

Due to the way the milter protocol is incorporated into the MTA, opendkim
sees the headers before they are modified as required by those two features.
This means the DKIM signature is generated based on the headers originally
injected by the mail client and not on the headers which are actually sent
out by the MTA.  As a result, the verifying agent at the receiver's side
will be unable to verify the signature as the signed data and the received
data don't match.

The suggested solutions to this problem are:

(1) Send mail with the headers already written as needed, obviating the
    need for these features (or just turn them off).

(2) Have two MTAs set up, either on separate boxes or on the same box.
    The first MTA should do all of the rewriting (i.e. use these two
    features) and the second one should use opendkim to add the signature
    and do no rewriting at all.

(3) Have multiple DaemonPortOptions lines in your configuration file.  The
    first daemon port (port 25) does the header rewriting and then routes
    the message to the second port; the latter does no rewriting but does the
    signing and then sends the message on its way.

There is also a feature of Sendmail that will cause it to alter addresses
after signing but before they are transmitted.  The feature, which is on
by default, passes addresses in header fields to the resolver functions
to ensure they are canonical.  This can result in the replacement of those
strings in the sent message with their canonical forms only after the message
is signed, which will invalidate the signatures.  To suppress this feature,
add the following line to your sendmail.mc and submit.mc configuration files,
re-generate your configuration and restart the filter:

	FEATURE(`nocanonify')

--
Copyright (c) 2010-2012, 2014, The Trusted Domain Project.
  All rights reserved.

opendkim's People

Contributors

grooverdan avatar jablko avatar mskucherawy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

opendkim's Issues

opendkim/opendkim.c:dkimf_securefile: protect by mutex reading output of getpwuid

pw->pw_name can be changed by a concurrent call of getpwuid(), so reading pw->pw_name it must be protected by the same lock, that protects getpwuid().

Copy of https://sourceforge.net/p/opendkim/patches/39/.

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -4724,10 +4724,9 @@ dkimf_securefile(const char *path, ino_t *ino, uid_t myuid, char *err,
        if (myuid == (uid_t) -1)
                myuid = pw->pw_uid;
 
-       pthread_mutex_unlock(&pwdb_lock);
-
 #ifdef HAVE_REALPATH
        strlcpy(myname, pw->pw_name, sizeof myname);
+       pthread_mutex_unlock(&pwdb_lock);
 
        p = realpath(path, real);
        if (p == NULL)
@@ -4766,6 +4765,7 @@ dkimf_securefile(const char *path, ino_t *ino, uid_t myuid, char *err,
 
        return 1;
 #else /* HAVE_REALPATH */
+       pthread_mutex_unlock(&pwdb_lock);
        struct stat s;
 
        status = stat(path, &s);

libopendkim/dkim.c: adjustments for GnuTLS 3.4

Includes https://sourceforge.net/p/opendkim/patches/36/: gnutls_pubkey_verify_hash() was removed in v3.4 and gnutls_pubkey_verify_hash2() was added in version 3.0.20.

Compilation fixes after the introduction of ED25519.

diff --git a/RELEASE_NOTES b/RELEASE_NOTES
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -6,7 +6,7 @@ release, and a summary of the changes in that release.
 2.11.0         2018/05/31
        README: Clarify for the send+verify mode how to tweak sendmail not
                to break signatures.
-       Add support for ED25519 keys.
+       Add support for ED25519 keys with OpenSSL.
        Add "header.s" and "header.a" in generated Authentication-Results
                header fields.
        Add _FFR_CONDITIONAL, experimental support for conditional DKIM
diff --git a/libopendkim/dkim.c b/libopendkim/dkim.c
--- a/libopendkim/dkim.c
+++ b/libopendkim/dkim.c
@@ -1172,7 +1172,7 @@ dkim_privkey_load(DKIM *dkim)
 #endif /* USE_GNUTLS */
 
 #ifdef USE_GNUTLS 
-       status = gnutls_x509_privkey_init(&crypto->rsa_key);
+       status = gnutls_x509_privkey_init(&crypto->crypto_key);
        if (status != GNUTLS_E_SUCCESS)
        {
                dkim_load_ssl_errors(dkim, status);
@@ -1182,14 +1182,14 @@ dkim_privkey_load(DKIM *dkim)
 
        if (strncmp((char *) dkim->dkim_key, "-----", 5) == 0)
        {                                               /* PEM */
-               status = gnutls_x509_privkey_import(crypto->rsa_key,
-                                                   &crypto->rsa_keydata,
+               status = gnutls_x509_privkey_import(crypto->crypto_key,
+                                                   &crypto->crypto_keydata,
                                                    GNUTLS_X509_FMT_PEM);
        }
        else
        {
-               status = gnutls_x509_privkey_import(crypto->rsa_key,
-                                                   &crypto->rsa_keydata,
+               status = gnutls_x509_privkey_import(crypto->crypto_key,
+                                                   &crypto->crypto_keydata,
                                                    GNUTLS_X509_FMT_DER);
        }
 
@@ -1200,7 +1200,7 @@ dkim_privkey_load(DKIM *dkim)
                return DKIM_STAT_NORESOURCE;
        }
 
-       status = gnutls_privkey_init(&crypto->rsa_privkey);
+       status = gnutls_privkey_init(&crypto->crypto_privkey);
        if (status != GNUTLS_E_SUCCESS)
        {
                dkim_load_ssl_errors(dkim, status);
@@ -1208,18 +1208,18 @@ dkim_privkey_load(DKIM *dkim)
                return DKIM_STAT_NORESOURCE;
        }
 
-       status = gnutls_privkey_import_x509(crypto->rsa_privkey,
-                                           crypto->rsa_key, 0);
+       status = gnutls_privkey_import_x509(crypto->crypto_privkey,
+                                           crypto->crypto_key, 0);
        if (status != GNUTLS_E_SUCCESS)
        {
                dkim_load_ssl_errors(dkim, status);
                dkim_error(dkim, "gnutls_privkey_import_x509() failed");
-               (void) gnutls_privkey_deinit(rsa->rsa_privkey);
+               (void) gnutls_privkey_deinit(crypto->crypto_privkey);
                return DKIM_STAT_NORESOURCE;
        }
 
-       (void) gnutls_privkey_get_pk_algorithm(rsa->rsa_privkey,
-                                              &rsa->rsa_keysize);
+       (void) gnutls_privkey_get_pk_algorithm(crypto->crypto_privkey,
+                                              &crypto->crypto_keysize);
 
 #else /* USE_GNUTLS */
 
@@ -5533,6 +5533,11 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
        size_t diglen = 0;
 #ifdef USE_GNUTLS
        gnutls_datum_t key;
+#if GNUTLS_VERSION_MAJOR==3
+       gnutls_digest_algorithm_t hash;
+       gnutls_sign_algorithm_t sign_algo;
+#endif
+
 #else /* USE_GNUTLS */
        BIO *key;
 #endif /* USE_GNUTLS */
@@ -5685,11 +5690,26 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
                        return DKIM_STAT_OK;
                }
 
+#if GNUTLS_VERSION_MAJOR==2
                vstat = gnutls_pubkey_verify_hash(crypto->crypto_pubkey, 0,
+#else
+               hash = dkim_libfeature(dkim->dkim_libhandle, DKIM_FEATURE_SHA256) &&
+                       sig->sig_hashtype == DKIM_HASHTYPE_SHA256 ? GNUTLS_DIG_SHA256 : GNUTLS_DIG_SHA1;
+
+               sign_algo = gnutls_pk_to_sign(GNUTLS_PK_RSA, hash);
+               if (sign_algo == GNUTLS_SIGN_UNKNOWN)
+               {
+                       assert(0);
+                       /* NOTREACHED */
+               }
+
+               vstat = gnutls_pubkey_verify_hash2(crypto->crypto_pubkey,
+                                                   sign_algo, 0,
+#endif
                                                  &crypto->crypto_digest,
                                                  &crypto->crypto_sig);
                if (vstat < 0)
-                       dkim_sig_load_ssl_errors(dkim, sig, rsastat);
+                       dkim_sig_load_ssl_errors(dkim, sig, vstat);
 
                (void) gnutls_pubkey_get_pk_algorithm(crypto->crypto_pubkey,
                                                      &crypto->crypto_keysize);

Latest tarballs cannot be built using ./configure && make

The tarballs published at https://github.com/trusteddomainproject/OpenDKIM/releases cannot be built and installed using the classic procedure ./configure make make install. This used to work in the past, and it should work according to the INSTALL file.

$ curl -LO https://github.com/trusteddomainproject/OpenDKIM/archive/rel-opendkim-2-11-0-Beta2.tar.gz
$ tar xvf rel-opendkim-2-11-0-Beta2.tar.gz
$ cd OpenDKIM-rel-opendkim-2-11-0-Beta2
$ ./configure
configure: error: cannot find install-sh, install.sh, or shtool in build-aux "."/build-aux

On a system that has Autotools, autoreconf -i can of course generate the missing files, but this additional step shouldn’t be necessary.

Fix tests for GnuTLS

diff --git a/libopendkim/dkim.c b/libopendkim/dkim.c
--- a/libopendkim/dkim.c
+++ b/libopendkim/dkim.c
@@ -5693,8 +5693,6 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
                vstat = gnutls_pubkey_verify_hash(crypto->crypto_pubkey, 0,
                                                  &crypto->crypto_digest,
                                                  &crypto->crypto_sig);
-               if (vstat < 0)
-                       dkim_sig_load_ssl_errors(dkim, sig, vstat);
 # else /* GNUTLS_VERSION_MAJOR == 2 */
                hash = dkim_libfeature(dkim->dkim_libhandle,
                                       DKIM_FEATURE_SHA256);
@@ -5709,9 +5707,12 @@ dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
                                                   signalg, 0,
                                                   &crypto->crypto_digest,
                                                   &crypto->crypto_sig);
+# endif /* GNUTLS_VERSION_MAJOR == 2 */
                if (vstat < 0)
                        dkim_sig_load_ssl_errors(dkim, sig, vstat);
-# endif /* GNUTLS_VERSION_MAJOR == 2 */
+               else
+                       /* OpenSSL’s RSA_verify returns 1 on success, so we normalize vstat here */
+                       vstat = 1;
 
                (void) gnutls_pubkey_get_pk_algorithm(crypto->crypto_pubkey,
                                                      &crypto->crypto_keysize);

Odd release file naming

The most recent beta release file is named:

rel-opendkim-2-11-0-Beta0.tar.gz

This is novel. Is it on purpose?

I would have expected opendkim-2.11.0-Beta0.tar.gz.

It would be nice to have a more normal dot separated version number in the tarball name as some of the Debian tools are more difficult to use the way it is now.

Thanks for considering,

Scott K

Squash some code

diff --git a/opendkim/opendkim-db.c b/opendkim/opendkim-db.c
--- a/opendkim/opendkim-db.c
+++ b/opendkim/opendkim-db.c
@@ -20,7 +20,6 @@
 #ifdef HAVE_STDBOOL_H
 # include <stdbool.h>
 #endif /* HAVE_STDBOOL_H */
-#include <syslog.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
diff --git a/opendkim/opendkim-lua.c b/opendkim/opendkim-lua.c
--- a/opendkim/opendkim-lua.c
+++ b/opendkim/opendkim-lua.c
@@ -600,7 +600,7 @@ dkimf_lua_setup_hook(void *ctx, const char *script, size_t scriptlen,
 **     -1 -- memory allocation failure
 **
 **  Notes:
-**     Called by mlfi_eom() so it can decide whether or not the message
+**     Called by mlfi_eoh() so it can decide whether or not the message
 **     is acceptable.
 */
 
diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -750,7 +750,6 @@ _Bool querycache;                           /* local query cache */
 #endif /* QUERY_CACHE */
 _Bool die;                                     /* global "die" flag */
 int diesig;                                    /* signal to distribute */
-int thread_count;                              /* thread count */
 #ifdef QUERY_CACHE
 time_t cache_lastlog;                          /* last cache stats logged */
 #endif /* QUERY_CACHE */
@@ -5233,7 +5232,7 @@ dkimf_msr_body(struct signreq *sr, DKIM **last, u_char *body, size_t bodylen)
 
 /*
 **  DKIMF_MSR_MINBODY -- determine minimum body required to satisfy all
-**                       all open canonicalizations
+**                       open canonicalizations
 **
 **  Parameters:
 **     srh -- head of the signature request list
@@ -11213,7 +11212,6 @@ mlfi_envrcpt(SMFICTX *ctx, char **envrcpt)
                                       "message requeueing (internal error)");
                        }
 
-                       free(copy);
                        dkimf_cleanup(ctx);
                        return SMFIS_TEMPFAIL;
                }
@@ -16595,11 +16593,11 @@ main(int argc, char **argv)
        {
                if (curconf->conf_dolog)
                {
-                       syslog(LOG_ERR, "pthread_sigprocmask(): %s",
+                       syslog(LOG_ERR, "pthread_sigmask(): %s",
                               strerror(status));
                }
 
-               fprintf(stderr, "%s: pthread_sigprocmask(): %s\n", progname,
+               fprintf(stderr, "%s: pthread_sigmask(): %s\n", progname,
                        strerror(status));
 
                dkimf_zapkey(curconf);

diff --git a/opendkim/stats.c b/opendkim/stats.c
--- a/opendkim/stats.c
+++ b/opendkim/stats.c
@@ -56,11 +56,6 @@
 #include "opendkim.h"
 #include "opendkim-db.h"
 
-/* macros, defaults */
-#define        DEFCT                   "text/plain"
-#define        DEFCTE                  "7bit"
-#define        DKIMF_STATS_MAXCOST     10
-
 /* globals */
 static pthread_mutex_t stats_lock;
 

RFC 8616 and a configure issue

RFC 8616 allows UTF-8 characters in domain and selector (and the i= tag). That doesn't seem to disturb signing. However, verification is hampered by a couple of ASCII checks in dkim.c. In addition, looking up the key requires IDNA encoding.

The configure issue should go in a separate bug, but I report it here to avoid having to manually edit the diff. It is res_ninit, which is not detected it it is a macro (similar to bug #23).

The patch attached is a diff against the trunk at revision 5013. It makes verification work.
patch.txt

/usr/lib/tmpfiles.d/opendkim.conf path points to /var/run/ instead of /run

System:
Debian buster/sid via Raspbian

OpenDKIM:
opendkim: OpenDKIM Filter v2.11.0
Compiled with OpenSSL 1.1.1b 26 Feb 2019
SMFI_VERSION 0x1000001
libmilter version 1.0.1
Supported signing algorithms:
rsa-sha1
rsa-sha256
Supported canonicalization algorithms:
relaxed
simple
Active code options:
POLL
QUERY_CACHE
USE_DB
USE_LDAP
USE_LUA
USE_ODBX
USE_UNBOUND
_FFR_ATPS
_FFR_RBL
_FFR_REPLACE_RULES
_FFR_SENDER_MACRO
_FFR_STATS
_FFR_VBR
libopendkim 2.11.0: atps query_cache

Issue:
The following line is logged in syslog on startup:
[/usr/lib/tmpfiles.d/opendkim.conf:1] Line references path below legacy directory /var/run/, updating /var/run/opendkim → /run/opendkim; please update the tmpfiles.d/ drop-in file accordingly.

Looking at the tmpfiles.d config file, the content is:
rpi# cat /usr/lib/tmpfiles.d/opendkim.conf
d /var/run/opendkim 0750 opendkim opendkim - -

Path has been moved from /var/run to /run and systemd tmpfiles.d has been updated to warn when SW component still uses the old path.

OpenDKIM needs to be updated to use /run instead of /var/run for PID file.

"unprotected header field"

Hello,

e-mails are being rejected as follows:

Jul  4 11:27:52 [servername] opendkim[37482]: F2BCE7E971: o4.hv30n.shared.sendgrid.net [167.89.100.125] not internal
Jul  4 11:27:52 [servername] opendkim[37482]: F2BCE7E971: not authenticated
Jul  4 11:27:53 [servername] opendkim[37482]: F2BCE7E971: signature=2pq1mzDc domain=example.com selector=s1 result="unprotected header field"
Jul  4 11:27:53 [servername] postfix/cleanup[87943]: F2BCE7E971: milter-reject: END-OF-MESSAGE from o4.hv30n.shared.sendgrid.net[167.89.100.125]: 4.7.0 DKIM signature processing failed; from=<bounces+16072861-25fe-[recipient]=[servername]@em285.example.com> to=<[recipient]@[servername]> proto=ESMTP helo=<o4.hv30n.shared.sendgrid.net>

To avoid the upfront rejection, I modified opendkim.conf from

On-BadSignature reject
On-SignatureError reject

to

On-BadSignature tempfail
On-SignatureError tempfail

and restarted the moving parts. As a result, the emails are still being rejected with the above message type.

Searching for "unprotected header field" here in github, I could only find one line of code, namely a definition of "DKIM_SIGERROR_MBSFAILED" in libopendkim/dkim-tables.c.

I then looked into the specification (rfc6541, rfc6376, rfc5672, rfc5518, rfc4871, rfc4870) and could not find any reference to "unprotected header field" and "DKIM_SIGERROR_MBSFAILED".

According to libopendkim/dkim.h, DKIM_SIGERROR_MBSFAILED means "must be signed" failure, that is "a header on the "must be signed" list was present but not covered by this signature".

# MustBeSigned (dataset)
#    Specifies a set of header fields that, if present, must be cov-
#    ered by the DKIM signature  when  verifying  a  message.   If  a
#    header  field  in  this set is present in the message and is not
#    signed, the filter will treat even an otherwise valid  signature
#    as invalid.  The default is an empty list.

ADDED TO CLARIFY

This scenario is about my opendkim server (example.com) verifying some one else's e-mail.

My understanding of the issue is that my opendkim server rejected an e-mail because its DKIM signature did not cover a header that had to be signed according to the sender's DKIM policy.

What I need from my opendkim server is to add a dkim=tempfail in the Authentication header and deliver the e-mail. I do not want it to reject the e-mail. I want to see the e-mail to inspect it myself.

opendkim: incompatible SSL versions

Hello,

Today i have installed opendkim on ubuntu 16.04.4 and got error when i tryed to start it:

May 31 11:06:02 mail opendkim[59911]: opendkim: incompatible SSL versions (library = 0x0100020bf, filter = 01000204f)

OpenDKIM version - opendkim 2.10.3-3build1
Openssl version - 1.0.2.g-1ubuntu4.12

After that i tryed to download source of openssl from openssl.org and compile it and there is the same error with:

openssl version
OpenSSL 1.1.0.h 27 Mar 2018

ares_parse() fails on outlook.com/alum.mit.edu added header

opendkim 2.11.0-Beta2 reports in maillog:
failed to parse Authentication-Results: header field

I patched it to include the offending header content in the syslog to find it:

Authentication-Results: spf=pass (sender IP is 209.85.219.172)#12 smtp.mailfrom=example.org; alum.mit.edu; dkim=pass (signature was verified)#12 header.d=example.org;alum.mit.edu; dmarc=pass action=none#012 header.from=example.org;compauth=pass reason=100

This header is being added by MX alum-mit-edu.mail.protection.outlook.com which receives mail on behalf of the MIT alum.mit.edu email forwarding service, before forwarding on to the true destination address. At that true destination, opendkim reports its inability to parse this header.

When mail is sent directly from example.org to the true destination address (not going through the alum.mit.edu forwarder), the above header is not added, and opendkim works as expected.

opendkim: in test mode always verify

Even if the configuration file delegates to a Lua script whether opendkim should verify or sign.

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
index 6938e21b..ab56ac22 100644
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -12299,7 +12299,7 @@ mlfi_eoh(SMFICTX *ctx)
        */
 
        /* signing requests with signing mode disabled */
-       if (dfc->mctx_srhead != NULL && 
+       if (!testmode && dfc->mctx_srhead != NULL &&
            (conf->conf_mode & DKIMF_MODE_SIGNER) == 0)
                return SMFIS_ACCEPT;

miltertest: Buffer overflow when replacing the message body

miltertest crashes when a milter replaces the message body with a message body larger than 1 kilobyte or so. It looks like the cause is a buffer overflow in miltertest. To reproduce:

overflow.c:

#include <assert.h>
#include <string.h>
#include "libmilter/mfapi.h"

// Crashes with size 1033, works when decreased:
#define BODYSIZE 1033

static sfsistat overflow_eom(SMFICTX *ctx) {
    unsigned char body[BODYSIZE];
    memset(body, '.', BODYSIZE);

    int status = smfi_replacebody(ctx, body, BODYSIZE);
    assert(status == MI_SUCCESS);

    return SMFIS_CONTINUE;
}

int main(void) {
    int status = smfi_setconn("inet:3000@localhost");
    assert(status == MI_SUCCESS);

    status = smfi_register((struct smfiDesc) {
        .xxfi_version = SMFI_VERSION,
        .xxfi_flags = SMFIF_CHGBODY,
        .xxfi_eom = overflow_eom,
    });
    assert(status == MI_SUCCESS);

    return smfi_main();
}

overflow.lua:

conn = mt.connect("inet:3000@localhost")
assert(conn)

local err = mt.eom(conn)
assert(err == nil, err)
assert(mt.getreply(conn) == SMFIR_CONTINUE)

Compile the milter with something like c99 -Wall overflow.c -lmilter -o overflow, then start the milter with ./overflow and run the test:

$ miltertest -s overflow.lua
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

Daemon not running with all groups when "UserID usr:grp" is used

We're currently making several changes to the Gentoo Linux ebuild of OpenDKIM to address security issues. While doing so, we came across a problem which is bugging us. We have a user opendkim which is member of groups opendkim and dkimsocket. Group opendkim is meant to regulate read access to the private key file:

$ ls -l /var/lib/opendkim/
total 8.2M
-r--r----- 1 root     opendkim 1.7K Feb  3  2019 mumble.key
-r--r--r-- 1 root     opendkim  451 Feb  3  2019 mumble.pub
...

Group dkimsocket is meant to regulate write access to a local socket file via the following settings:

$ cat /etc/opendkim/opendkim.conf
Socket local:/run/opendkim/socket
UserID opendkim:dkimsocket
UMask 0117
...

$ ls -l /run/opendkim/
total 0
srw-rw---- 1 opendkim dkimsocket 0 Apr  1 19:38 socket=

Unfortunately the resulting process runs as only one group, namely dkimsocket, instead of running as both opendkim and dkimsocket:

$ cat /proc/26389/status
Name:    opendkim
...
Uid:    108   108   108   108
Gid:    1007  1007  1007  1007
FDSize: 64
Groups: 1007

When using only UserID opendkim (no group), and when dkimsocket is that user's primary group, the process picks up both groups, dkimsocket and opendkim:

$ cat /proc/26778/status
Name:    opendkim
...
Uid:    108   108   108   108
Gid:    1007  1007  1007  1007
FDSize: 64
Groups: 108 1007

The combined result is that we cannot enforce access to the private key and the local socket using distinct groups. This matters because the MTA needs to write to the socket but should not have access to the key file, while OpenDKIM should not be able to access any of the MTA's files.

I can set the owner of mumble.key to opendkim:opendkim instead of root:opendkim, but from a security standpoint this means that if some adversary manages to run code as opendkim he can overwrite the key material.

libunbound: Protect calls to ub_ctx_config() by mutex

libunbound:ub_ctx_config() uses internally a flex generated non-reentrant lexer and bison generated non-pure paprser. Calling simultaneously two non-reentrant lexers or parsers is a bad idea, and two threads can alter the state of the lexer/parser without synchronization.

The calls to ub_ctx_config in opendkim/opendkim-dns.c:dkimf_ub_config need to be protected by mutex.
The documentation of libunbound:ub_ctx_config() says the function is thread-safe, but this is only true when only one instance of libunbound:ub_ctx * is used in the application, which is not the case with opendkim. See also https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=1913.

Copy of https://sourceforge.net/p/opendkim/bugs/265/.

diff --git a/opendkim/opendkim-dns.c b/opendkim/opendkim-dns.c
--- a/opendkim/opendkim-dns.c
+++ b/opendkim/opendkim-dns.c
@@ -75,6 +75,7 @@ struct dkimf_unbound
        pthread_cond_t          ub_ready;
 };
 
+pthread_mutex_t                ub_config_mutex;
 /* struct dkimf_unbound_cb_data -- libunbound callback data */
 struct dkimf_unbound_cb_data
 {
@@ -440,7 +441,9 @@ dkimf_ub_config(void *srv, const char *file)
 
        ub = srv;
 
+       pthread_mutex_lock(&ub_config_mutex);
        status = ub_ctx_config(ub->ub_ub, (char *) file);
+       pthread_mutex_unlock(&ub_config_mutex);
 
        return (status == 0 ? 0 : -1);
 }
diff --git a/opendkim/opendkim-dns.h b/opendkim/opendkim-dns.h
--- a/opendkim/opendkim-dns.h
+++ b/opendkim/opendkim-dns.h
@@ -33,6 +33,7 @@ struct dkimf_filedns;
 /* libunbound includes */
 # include <unbound.h>
 
+extern pthread_mutex_t         ub_config_mutex;
 /* prototypes */
 extern int dkimf_unbound_setup __P((DKIM_LIB *));
 # ifdef _FFR_RBL
diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -15555,6 +15555,9 @@ main(int argc, char **argv)
        no_i_whine = TRUE;
        conffile = NULL;
 
+#ifdef USE_UNBOUND
+       pthread_mutex_init(&ub_config_mutex, NULL);
+#endif
        memset(myhostname, '\0', sizeof myhostname);
        (void) gethostname(myhostname, sizeof myhostname);
 

Clarify how not to break signatures in sendmail when relaying emails

This is an updated copy of https://sourceforge.net/p/opendkim/patches/40/.

diff --git a/RELEASE_NOTES b/RELEASE_NOTES
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -4,6 +4,8 @@ This listing shows the versions of the OpenDKIM package, the date of
 release, and a summary of the changes in that release.
 
 2.11.0         2018/05/31
+       opendkim/README: Clarify for the send+verify mode how to tweak
+               sendmail not to break signatures.
        Add support for ED25519 keys.
        Add "header.s" and "header.a" in generated Authentication-Results
                header fields.
diff --git a/opendkim/README b/opendkim/README
--- a/opendkim/README
+++ b/opendkim/README
@@ -160,7 +160,38 @@ start at step (5).
         socket specification:
            INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost')
 
-    (c) Rebuild your sendmail.cf in the usual way
+    (c) When the MTA will be used for relaying emails, e.g. delivering to other
+        hosts using the aliases mechanism, it is important not to break
+        signatures inserted by the original sender, in particular when the
+        sending domain published p=reject; DMARC policy.  By default, sendmail
+        adds quotes to address headers, when there are no quotes and the
+        display-part of the address contains fullstop or apostrophe,
+        invalidating any DKIM signatures contained in the message.  To tell
+        sendmail not to modify the headers insert in sendmail.mc:
+           conf(`confMUST_QUOTE_CHARS', `')
+
+    (d) As stated in sendmail's KNOWNBUGS file, sendmail truncates
+        header-values longer than 256 characters, which could mean truncating
+        the domain of a long From:-header-value and invaldating the signature.
+        Consider increasing MAXNAME in sendmail/conf.h to mitigate changing
+        the messages and invalidating their signatures.  This change requires
+        recompiling sendmail.
+
+    (e) Beware that when sendmail receives the header:
+
+To: Aaaaaaaaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaaaaa <[email protected]>,Bbbbbbbbbbbbbbbbbb b <[email protected]>
+Message-ID: <[email protected]>
+
+        it will send it unmodified to the milter and later rewrite it to:
+
+To: Aaaaaaaaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaaaaa <[email protected]>,
+        Bbbbbbbbbbbbbbbbbb b <[email protected]>
+
+        After the comma a new line and eight spaces were inserted.  The
+       insertion of white space characters (during folding) breaks the DKIM
+       signature.
+
+    (f) Rebuild your sendmail.cf in the usual way
 
     For Postfix:
 
@@ -272,6 +303,17 @@ your sendmail.mc file:
 
        define(`confSEVEN_BIT_INPUT',true)dnl
 
+However, the aforementioned tweak changes the byte sequence C2 A0 (NO BREAK
+SPACE) into "B ", altering what is displayed to the final user. In practice,
+when the server running OpenDKIM is used just for relaying email in terms of
+aliases, having mailboxes hosted somewhere else, relayed messages are
+displayed correctly to the final user only when the tweak is not made.
+
+The further, when openDKIM is used both to sign and verify signatures, a set
+confSEVER_BIT_INPUT invalidates the signature added by the original sender.
+If the MTA connected to OpenDKIM is used to relay messages, e.g. as aliases,
+and the origianl sender set p=reject; DMARC policy, then the adjustment is
+counterproductive.
 
 TESTING
 =======

Parsing of RSAPublicKey format from DNS

see #51

If I haven't missed any important update to the DKIM spec, the current spec says:

RFC6376, Section 3.6.1:

The "rsa" key type
indicates that an ASN.1 DER-encoded [ITU-X660-1997] RSAPublicKey
(see [RFC3447], Sections 3.1 and A.1.1) is being used in the "p="
tag. (Note: the "p=" tag further encodes the value using the
base64 algorithm.) Unrecognized key types MUST be ignored.

Errata exist (https://www.rfc-editor.org/errata/eid3017) that extend this to

The "rsa" key type
indicates that an ASN.1 DER-encoded [ITU-X660-1997] RSAPublicKey
(see [RFC3447], Sections 3.1 and A.1.1), which MAY be contained in
a SubjectPublicKeyInfo (see [RFC5280], Section A.1), is being used
in the "p=" tag.

The errata is set to "Held for Document Update":

The erratum is not a necessary update to the RFC. However, any future update of the document might consider this erratum, and determine whether it is correct and merits including in the update.

To my understanding, this may mean anything with regard to a future version of the spec.

I'm aware that appearantly the whole world uses SubjectPublicKeyInfo in published DNS records and I also noticed that, e.g. dkimpy is in its current state is also not able to parse a RSAPublicKey which is not contained in a SubjectPublicKeyInfo from the 'p=' tag in a TXT record. But still, the RFC defines the RSAPublicKey-represenation definitely as valid and therefore I think it would be somehow correct to support it.

Libbsd dependency on linux

Hi,
On linux opendkim is dependent on libbsd because of strlcpy and strlcat functions. I found a way how to remove this dependency with simple wrapper which uses strncpy and strncat functions which are included in glibc. Would you be open to a change which would add configuration argument to configure.ac, some conditionals to makefiles and conditionals to source files which are using strl* functions?

NXDOMAIN handling in stub resolver

Hi everyone,

I noticed that with the default resolver active, libopendkim reports DKIM_SIGERROR_KEYFAIL if it receives a NXDOMAIN reply. This is not distinguishable from a SRVFAIL "reply", which would translate into a TEMPFAIL according to RFC 6376.
To my understanding, a DKIM_SIGERROR_NOKEY would be the more appropriate reaction, which then should be translated into a PERMFAIL in terms of DKIM results.

The default resolver in dkim-dns.c uses res_(n)query, which returns a failure and sets h_errno to HOST_NOT_FOUND in case of a NXDOMAIN reply. This is never checked however, so the evaluation of results in dkim-key.c justs sees a DKIM_DNS_ERROR and reports DKIM_STAT_KEYFAIL (which translates to DKIM_SIGERROR_KEYFAIL), which indicates a temporary failure (retry again later), which does not really make sense for NXDOMAIN.

Main problem is that the res_(n)query documentation does not cleary state what happens with the passed buffer in case of a NXDOMAIN response and that libopendkim does not define a explicit DKIM_DNS_ERROR_NOTFOUND.

The implementations I've seen all return -1 but still fill the buf with the actual DNS response packet. This could be used by copying the header data (maybe even setting hdr->rcode = NXDOMAIN for good measure) and returning DKIM_DNS_SUCCESS, as well as checking for NXDOMAIN earlier in dkim_get_key_dns (see workaround)

If someone with the capability to merge agrees to that solution or has ideas for improvement I'm happy to provide a PR.

AR: set header.a=ed25519-sha256 even when dkim_libfeature(lib, DKIM_FEATURE_ED25519) fails

When an email with DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/simple; … arrives and opendkim is not compiled to support ed25519-sha256, in libopendkim/dkim.c:2106 sigalg is set to 2. dkim_libfeature(lib, DKIM_FEATURE_ED25519) on line 2134 returns false. On line 2141 continue is executed. In turm on line 2150 dkim→dkim_siglist[c]→sig_signalg is not set. It stays 0, as set on line 1963 with memset. signalg 0 corresponds in dkim-tables.c:table algorithms to DKIM_SIGN_RSASHA1.

When adding the Authentication-Results’ header in opendkim.c:dkimf_ar_all_sigs(), first algorithm = dkim_sig_getalgorithm(sigs[c]); is called, which returns rsa-sha1, and then header.a=rsa-sha1 is added to AR. But it should add ed25519-sha256.

Proposed fix, setting sig_signalg to 2 even when dkim_libfeature(lib, DKIM_FEATURE_ED25519) fails:

diff --git a/libopendkim/dkim.c b/libopendkim/dkim.c
--- a/libopendkim/dkim.c
+++ b/libopendkim/dkim.c
@@ -2103,7 +2103,7 @@ dkim_siglist_setup(DKIM *dkim)
                }
                else
                {
-                       signalg = dkim_name_to_code(algorithms,
+                       dkim->dkim_siglist[c]->sig_signalg = signalg = dkim_name_to_code(algorithms,
                                                    (char *) param);
 
                        if (signalg == -1)
@@ -2147,7 +2147,6 @@ dkim_siglist_setup(DKIM *dkim)
                                /* NOTREACHED */
                        }
 
-                       dkim->dkim_siglist[c]->sig_signalg = signalg;
                        dkim->dkim_siglist[c]->sig_hashtype = hashtype;
                }
 

Patch for LibreSSL 2.8.2

The attached patch allows the OpenDKIM-rel-opendkim-2-11-0-Beta2.tar.gz release to build against LibreSSL 2.8.2 (portable) on CentOS 7.

What I suspect is there is a better way, to check for OPENSSL_thread_stop() support via autoconf - so that if future versions of LibreSSL add it, it will just be picked up. But this works for now if you are interested in it.
OpenDKIM-rel-opendkim-2-11-0-Beta2-thread_stop.patch.txt

dead project - alternatives?

Since this project is dead...

What are some alternative milters that support DKIM? Preferably something that works in RHEL 8/CentOS 8.

Thank you.

If RequiredHeaders conditions are not met, tell over SMTP the exact reason and log it

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
index 0c5132aa..db24b925 100644
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -12741,63 +12741,62 @@ mlfi_eoh(SMFICTX *ctx)
        /* if requested, verify RFC5322-required headers (RFC5322 3.6) */
        if (conf->conf_reqhdrs)
        {
-               _Bool ok = TRUE;
+               char *msg = NULL;
 
                /* exactly one From: */
                if (dkimf_findheader(dfc, "From", 0) == NULL ||
                    dkimf_findheader(dfc, "From", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message does not have exactly one From header";
 
                /* exactly one Date: */
                if (dkimf_findheader(dfc, "Date", 0) == NULL ||
                    dkimf_findheader(dfc, "Date", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message does not have exactly one Date header";
 
                /* no more than one Reply-To: */
                if (dkimf_findheader(dfc, "Reply-To", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one Reply-To headers";
 
                /* no more than one To: */
                if (dkimf_findheader(dfc, "To", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one To headers";
 
                /* no more than one Cc: */
                if (dkimf_findheader(dfc, "Cc", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one Cc headers";
 
                /* no more than one Bcc: */
                if (dkimf_findheader(dfc, "Bcc", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one Bcc headers";
 
                /* no more than one Message-Id: */
                if (dkimf_findheader(dfc, "Message-Id", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one Message-Id headers";
 
                /* no more than one In-Reply-To: */
                if (dkimf_findheader(dfc, "In-Reply-To", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one In-Reply-To headers";
 
                /* no more than one References: */
                if (dkimf_findheader(dfc, "References", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one References headers";
 
                /* no more than one Subject: */
                if (dkimf_findheader(dfc, "Subject", 1) != NULL)
-                       ok = FALSE;
+                       msg = "Message has more than one Subject headers";
 
-               if (!ok)
+               if (msg)
                {
                        if (conf->conf_dolog)
                        {
                                syslog(LOG_INFO,
-                                      "%s: RFC5322 header requirement error",
-                                      dfc->mctx_jobid);
+                                      "%s: RFC5322 header requirement error %s",
+                                      dfc->mctx_jobid, msg);
                        }
-
-                       dfc->mctx_addheader = TRUE;
-                       dfc->mctx_headeronly = TRUE;
-                       dfc->mctx_status = DKIMF_STATUS_BADFORMAT;
-                       return SMFIS_CONTINUE;
+                       if (dkimf_setreply(ctx, "550", "5.7.1", msg) != MI_SUCCESS &&
+                           conf->conf_dolog)
+                               syslog(LOG_NOTICE, "%s: smfi_setreply() failed", dfc->mctx_jobid);
+                       return SMFIS_REJECT;
                }
        }
 

feedback on configuring OpenDKIM-2.11.0-Beta2

>pwd
/opt/src/OpenDKIM-rel-opendkim-2-11-0-Beta2

>autoconf                                                                                                                                                                         
configure.ac:37: error: possibly undefined macro: AM_INIT_AUTOMAKE
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
configure.ac:65: error: possibly undefined macro: AM_PROG_CC_C_O
configure.ac:66: error: possibly undefined macro: AC_PROG_LIBTOOL
configure.ac:103: error: possibly undefined macro: AC_DEFINE
configure.ac:360: error: possibly undefined macro: AM_CONDITIONAL
configure.ac:629: error: possibly undefined macro: AC_MSG_WARN

>autoreconf                                                                                                                                                                       
configure.ac:64: error: required file 'build-aux/compile' not found
configure.ac:64:   'automake --add-missing' can install 'compile'
configure.ac:67: error: required file 'build-aux/config.guess' not found
configure.ac:67:   'automake --add-missing' can install 'config.guess'
configure.ac:67: error: required file 'build-aux/config.sub' not found
configure.ac:67:   'automake --add-missing' can install 'config.sub'
configure.ac:44: error: required file 'build-aux/install-sh' not found
configure.ac:44:   'automake --add-missing' can install 'install-sh'
configure.ac:67: error: required file 'build-aux/ltmain.sh' not found
configure.ac:44: error: required file 'build-aux/missing' not found
configure.ac:44:   'automake --add-missing' can install 'missing'
autobuild/Makefile.am: error: required file 'build-aux/depcomp' not found
autobuild/Makefile.am:   'automake --add-missing' can install 'depcomp'
parallel-tests: error: required file 'build-aux/test-driver' not found
parallel-tests:   'automake --add-missing' can install 'test-driver'
./conf	autoreconf: automake failed with exit status: 1

>./configure                                                                                                                                                                      
configure: error: cannot find install-sh, install.sh, or shtool in build-aux "."/build-aux

>ls -l ./build-aux/                                                                                                                                                               
total 8
-rw-rw-r--@ 1 me  staff  96 Nov 15 01:47 README

>cat ./build-aux/README                                                                                                                                                           

This directory is a placeholder for scripts generated during or required
by the build process.

Crash on DNS lookup with Unbound during verification

The OpenDKIM milter crashes when it does a DNS lookup during verification. I can reproduce this crash reliably (always); configuration and repro follow.

/etc/opendkim-debug.conf:

Background            false
Syslog                yes
UserID                opendkim
UMask                 007
PidFile               /var/run/opendkim/opendkim.pid
Socket                local:/var/spool/postfix/opendkim/opendkim.sock
Domain                example.com
KeyFile               /etc/dkimkeys/2018.private
Selector              2018
InternalHosts         /dev/null
ResolverConfiguration /etc/unbound/unbound-debug.conf

/etc/unbound/unbound-debug.conf:

server:
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

GDB session:

~/tmp$ sudo gdb usr/local/sbin/opendkim
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
...
Reading symbols from usr/local/sbin/opendkim...done.
(gdb) br opendkim-dns.c:554
Breakpoint 1 at 0x20168: file opendkim-dns.c, line 554.
(gdb) run -x /etc/opendkim-debug.conf
Starting program: /home/ubuntu/tmp/usr/local/sbin/opendkim -x /etc/opendkim-debug.conf
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff4d92700 (LWP 8979)]
[New Thread 0x7ffff4591700 (LWP 8980)]
[New Thread 0x7ffff3d90700 (LWP 8981)]
[New Thread 0x7ffff358f700 (LWP 8982)]
[New Thread 0x7ffff2d8e700 (LWP 8983)]
[New Thread 0x7ffff258d700 (LWP 9009)]
[Switching to Thread 0x7ffff2d8e700 (LWP 8983)]

Thread 6 "opendkim" hit Breakpoint 1, dkimf_ub_waitreply (srv=0x7fffe4000d90, qh=0x7fffe4048050, to=0x7ffff2d8a960, bytes=0x7ffff2d8a8f0, error=0x7ffff2d8a8c8,
    dnssec=0x7ffff2d8a8cc) at opendkim-dns.c:554
554             status = dkimf_unbound_wait(ub, ubdata, to);
(gdb) bt
#0  dkimf_ub_waitreply (srv=0x7fffe4000d90, qh=0x7fffe4048050, to=0x7ffff2d8a960, bytes=0x7ffff2d8a8f0, error=0x7ffff2d8a8c8, dnssec=0x7ffff2d8a8cc)
    at opendkim-dns.c:554
#1  0x00007ffff7bb7ea3 in dkim_get_key_dns (dkim=0x7fffe4044e70, sig=0x7fffe40457c0, buf=0x7ffff2d8cb30 "", buflen=1025) at dkim-keys.c:189
#2  0x00007ffff7bc1bf0 in dkim_get_key (dkim=0x7fffe4044e70, sig=0x7fffe40457c0, test=false) at dkim.c:2975
#3  0x00007ffff7bc6a38 in dkim_sig_process (dkim=0x7fffe4044e70, sig=0x7fffe40457c0) at dkim.c:5582
#4  0x00007ffff7bc304e in dkim_eoh_verify (dkim=0x7fffe4044e70) at dkim.c:3575
#5  0x00007ffff7bc838c in dkim_eoh (dkim=0x7fffe4044e70) at dkim.c:6631
#6  0x0000555555569027 in mlfi_eoh (ctx=0x5555557d9dd0) at opendkim.c:13219
#7  0x00007ffff79a36c2 in mi_engine () from /usr/lib/x86_64-linux-gnu/libmilter.so.1.0.1
#8  0x00007ffff79a610a in ?? () from /usr/lib/x86_64-linux-gnu/libmilter.so.1.0.1
#9  0x00007ffff69546db in start_thread (arg=0x7ffff2d8e700) at pthread_create.c:463
#10 0x00007ffff667d88f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) c
Continuing.
[Thread 0x7ffff2d8e700 (LWP 8983) exited]
[Thread 0x7ffff358f700 (LWP 8982) exited]
[Thread 0x7ffff3d90700 (LWP 8981) exited]
[Thread 0x7ffff4591700 (LWP 8980) exited]
[Thread 0x7ffff4d92700 (LWP 8979) exited]
[Thread 0x7ffff7fe8500 (LWP 8975) exited]
[Inferior 1 (process 8975) exited with code 01]
(gdb) bt
No stack.

dkim_get_key_dns never returns.

The crash is triggered on incoming mail containing a DKIM-Signature header. I use this command on the server to trigger the crash:

sed "s/@NOW@/$(date +'%s')/" <<'EOF' | sendmail -t [email protected]
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=example.com; s=selector;
        t=1573641096; bh=J7OfRAYFSdE62gucKQqRxN+C9lxwvN1kvGUkuM/t0O8=;
        h=Date:From:To;
        b=KneGz9SzBtGsAovEbzC4HC45/GyFABSwutje0JNre/iV0dnNt6pNVr91qOUJ0tOrA
         wtdiif5agrf4j45sSSbQgCfYqMZrw/oGxi7Bz6iUuluq45Yx+ozxAuYZSt9n9Yy5zR
         37DSMyH1nYUGiG7shF82VFhYo7mI0LHIBSm+6ygM=
Date: Wed, 13 Nov 2019 11:31:20 +0100
From: <[email protected]>
To: <[email protected]>
Message-Id: <@NOW@@localhost>
Subject: test

Test message.
EOF

In syslog the crash appears only as a Postfix error message:

Dec 25 16:59:33 kes postfix/cleanup[13981]: warning: milter unix:/opendkim/opendkim.sock: can't read SMFIC_EOH reply packet header: Success

When I use TrustAnchorFile /usr/share/dns/root.key instead of the ResolverConfiguration setting the crash does not happen. So it looks like it is related to DNS resolution with Unbound. This is on an Ubuntu 18.04 Server, /usr/share/dns/root.key is provided by the package dns-root-data, and /var/lib/unbound/root.key is managed by the unbound package.

I'm using the current tarball, version 2.11.0-beta2 to reproduce, but it is an old problem that occurs in earlier versions as well. I compiled opendkim using these options:

./configure --enable-debug --with-unbound
make
make install DESTDIR=$HOME/tmp

Need help debugging: first, can anyone confirm this reproduction? It should be reproducible on a stock opendkim install (2.11.0~alpha-11build1 from APT) on Ubuntu 18.04 Server. Just seeing the crash would be enough to rule out that it is something on my side. Replace example.com above with your domain. If you need further information, please let me know.

Real Opendkim Status?

Could one of the board or someone responsible at the TrustedDomainProject please clearly comment on the website where users can see & find it about the real status of OpenDKIMs many open bugs, at https://sourceforge.net/p/opendkim/bugs/?

Most recent is the OpenSSL 111 non-support on FreeBSD? Looks like for other OSs too.

There's been no response from the author for a very long time.

If the project's been abandoned that's cool. Can you just finally say so devs can stop spinning their wheels and figure out a different solution?

cc:
@mskucherawy
@pmidge
@davecrocker
@AntiFreeze

contrib/repute/repute.py: compress

if len(x) > 0: is equivalent to if len(x): and the latter is equivalent to if x: for all internal types.

diff --git a/contrib/repute/repute.py b/contrib/repute/repute.py
--- a/contrib/repute/repute.py
+++ b/contrib/repute/repute.py
@@ -47,13 +47,13 @@ class DKIM(object):
                 "identity": "dkim",
             }
 
-            if res1[0] and len(res1[1]) > 0:
+            if res1[0] and res1[1]:
                 res1 = res1[1][0]
                 reputons["rating"] = res1[0]
                 reputons["sample-size"] = res1[2]
                 reputons["generated"] = res1[1]
 
-            if res2[0] and len(res2[1]) > 0:
+            if res2[0] and res2[1]:
                 res2 = res2[1][0]
                 reputons['rate'] = res2[0]
 
@@ -79,7 +79,7 @@ class DKIM(object):
             
             rows = yield self.cp.runQuery(query, {'domain': domain, 'reporter': reporter})
 
-            if len(rows) > 0:
+            if rows:
                 ret = dict(itertools.izip(fields, rows[0]))
             else:
                 ret = 0
@@ -103,7 +103,7 @@ class DKIM(object):
             fields = ['domain'] +  fields
 
             rows = yield self.cp.runQuery(query, { 'reporter' : reporter } )
-            if len(rows) > 0:
+            if rows:
                 ret = dict(itertools.izip(fields, rows[0]))
                 request.setHeader('Last-modified', rows[0][3].strftime("%A, %d, %B %Y %H:%M GMT"))
             else:

Headers with leading CRLF canonicalized incorrectly

If a header is wrapped immediately after the field name then it's (relaxed) canonicalized form will have a space between the field name and field value.

e.g.

List-Unsubscribe:
   =?us-ascii?q?long_meaningless_value...

will canonicalize to

list-unsubscribe: =?us-ascii?q?long_meaningless_value...

instead of

list-unsubscribe:=?us-ascii?q?long_meaningless_value...

which causes validation to fail.

The RFC says that any whitespace after the colon should be deleted.

opendkim/opendkim.c:dkimf_config_free(): don't assert conf->refcnt == 0

xxfi_close() is not necessary called, when SIGINT, SIGHUP or SIGTERM are sent to the signal handler thread established by smfi_main(), before smfi_main() returns. For this to happen the underlaying select/poll calls need to return. On some UNIX the poll/select calls exist, when libmilter closes the connection with the MTA, on Linux select/poll exit, when the timeout set by smfi_settimeout() expires.

In turn, when SIGTERM is sent to opendkim, the opened connections are not xxfi_closed() for each previously established xxfi_negotiate(), the reference counter is not decreased to zero and the assert fails.

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -5905,7 +5905,6 @@ static void
 dkimf_config_free(struct dkimf_config *conf)
 {
        assert(conf != NULL);
-       assert(conf->conf_refcnt == 0);
 
        dkimf_zapkey(conf);
 

Remove preference for poll() vs select() after libar removal

Currently nothing uses poll() within opendkim. libunbound and libmilter can use select() or poll(), but this is completely different stuff.

diff --git a/INSTALL b/INSTALL
--- a/INSTALL
+++ b/INSTALL
@@ -158,9 +158,6 @@ filter              Compile the opendkim filter.  Requires libmilter (see
 live-testing   Enables unit tests that require live access to the Internet
                to succeed.
 
-poll           Compile to use poll() instead of select() for asynchronous
-               I/O.
-
 popauth                Enables support for POP-before-SMTP checks.
 
 query_cache    Compile the opendkim library to support local caching of
diff --git a/autobuild/autobuild.conf.sample b/autobuild/autobuild.conf.sample
--- a/autobuild/autobuild.conf.sample
+++ b/autobuild/autobuild.conf.sample
@@ -17,7 +17,6 @@
                "--enable-diffheaders",
                "--enable-vbr",
                "--enable-atps",
-               "--enable-poll",
                "--with-unbound",
                "--enable-replace_rules",
                "--with-libmemcached",
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -353,8 +353,6 @@ AC_DEFUN([LIB_FFR_FEATURE],
 #
 FEATURE([popauth], [enable POP-before-SMTP support])
 
-FEATURE([poll], [use poll() instead of select()])
-
 FFR_FEATURE([atps], [experimental Authorized Third Party Signers checks])
 LIB_FFR_FEATURE([atps], [experimental Authorized Third Party Signers checks])
 AM_CONDITIONAL([ATPS], [test x"$enable_atps" = x"yes"])
diff --git a/opendkim/util.c b/opendkim/util.c
--- a/opendkim/util.c
+++ b/opendkim/util.c
@@ -80,10 +80,6 @@ static char *optlist[] =
        "DEBUG",
 #endif /* DEBUG */
 
-#if POLL
-       "POLL",
-#endif /* POLL */
-
 #if POPAUTH
        "POPAUTH",
 #endif /* POPAUTH */
(END)

Fedora 33 deprecating libdb, which opendkim uses for its cache

Fedora 33 (release due Fall 2020) is expected to deprecate libdb 5.3.x, and cannot move forward to libdb 6.x due to license change to AGPL. Upstream projects such as opendkim should be advised that in a future Fedora release (as early as F35 Fall 2021), libdb 5.3.x will not be available, and they should consider other methods of storage than libdb.

OpenDKIM uses libdb for it's cache.

https://fedoraproject.org/wiki/Changes/Libdb_deprecated

Body with specified length doesn't end with CRLF will trigger 'CRLF at end of body missing'

OpenDKIM will only receive message body with length specified in DKIM signature (l=), and reply SMFIS_SKIP to MTA. Thus, the body does not have to be ended with CRLF and should not trigger CRLF at end of body missing if CRLF is not exist.

According to the section 3.7 of RFC6376,

the Signer/Verifier MUST hash the message body,
   canonicalized using the body canonicalization algorithm specified in
   the "c=" tag and then truncated to the length specified in the "l="
   tag.

In addition to that, the "simple" and "relaxed" body canonicalization algorithm both suggest that if body is not empty and have no trailing CRLF, a CRLF is added. So, OpenDKIM should just append a CRLF to the body if body doesn't end with CRLF.

I suggest that this if-else block should be replaced by the if block.

wrong pkg-config check for lua

In confgure.ac we have among other things...

PKG_CHECK_MODULES([LIBLUA], [lua5.1],
    [
	lua_found="yes"
	LIBLUA_INCDIRS="$LIBLUA_CFLAGS"
    ],
    [AC_MSG_WARN([pkg-config for Lua not found, trying manual search...])])

The upstream pkg-config file is named lua.pc, so lua5.1 is the wrong name unless some distros have renamed it. Either way we should check for lua, but maybe we should also check for lua5.1 if someone knows why lua5.1 is there in the first place.

When the pkg-config check fails, the manual search looks first to /usr/lib which can detect 32-bit libs on a 64-bit system (Gentoo bug 704556).

opendkim/opendkim.conf.5.in: update

The description says Boolean values default to "false". It is redundant to state that the defaults for DomainKeyCompat and ResignAll are false.

MinimumKeysBits states "The default is 1024, which accepts all signatures. A value of 0 causes the default to be used." There are 768bit signatures today, so that 0 means indeed all signatures are checked, but 1024 -the default - does not mean that all signatures are checked.

ReplaceRule states 'This can be used to accommodate expected changes such as are made to From: fields by MTA "masquerade" features.' -- needs rephrasing.

ScreenPolicyScript states "The script has access to all of the header fields and connection information and can that certain signatures be ignored based on that information." This needs rephrasing.

TemporaryDirectory speaks about libdkim but means libopendkim.

Copy of https://sourceforge.net/p/opendkim/bugs/263/.

diff --git a/opendkim/opendkim.conf.5.in b/opendkim/opendkim.conf.5.in
index 9046a1cd..127c5e69 100644
--- a/opendkim/opendkim.conf.5.in
+++ b/opendkim/opendkim.conf.5.in
@@ -233,7 +233,6 @@ is defined.
 .I DomainKeysCompat (boolean)
 If set, backward compatibility with DomainKeys (RFC4870) key records is
 enabled.  When not set, such keys are considered to be syntactically invalid.
-The default is "false".
 
 .TP
 .I DontSignMailTo (dataset)
@@ -507,7 +506,7 @@ for all addresses.
 .TP
 .I MilterDebug (integer)
 Sets the debug level to be requested from the milter library.  The
-default is 0.
+highest useful value is six.
 
 .TP
 .I Minimum (string)
@@ -533,8 +532,7 @@ valid.
 .I MinimumKeyBits (integer)
 Establishes a minimum key size for acceptable signatures.  Signatures with
 smaller key sizes, even if they otherwise pass DKIM validation, will me marked
-as invalid.  The default is 1024, which accepts all signatures.  A value of
-0 causes the default to be used.
+as invalid.  The default is 1024.  A value of 0 accepts all signatures.
 
 .TP
 .I Mode (string)
.I Mode (string)
@@ -789,7 +787,7 @@ setting.  By default, all header fields are included.
 Specifies a file containing a list of text replacement rules that are
 applied to the message header fields to replace certain content expected to be
 changed as the message passes through local MTAs.  This can be used to
-accommodate expected changes such as are made to From: fields by MTA
+accommodate expected changes such as those made to From: fields by MTA
 "masquerade" features.  Each entry in the file consists of a POSIX regular
 expression, followed by a tab (ASCII 9), followed by the text that should
 be used to replace the text matching the expression.  The '#' character
@@ -836,7 +834,6 @@ Where
 .I ResignMailTo
 triggers a re-signing action, this flag indicates whether or not all mail
 should be signed (if set) versus only verified mail being signed (if not set).
-The default is "false".
 @RESIGN_MANNOTICE@
 
 .TP
@@ -871,7 +868,7 @@ Gives the name of a Lua script that should be run after all of the header
 fields have been processed for a message; in particular, this is useful
 after all DKIM signatures have been detected and initial evaluation has
 been done.  The script has access to all of the header fields and connection
-information and can that certain signatures be ignored based on that
+information and can determine that certain signatures be ignored based on that
 information.  See
 .I opendkim-lua(3)
 for details. @LUA_MANNOTICE@
@@ -1080,6 +1077,10 @@ data from a single repoter.
 If set, instructs the DKIM library to refuse processing of a message if the
 header field count does not conform to RFC5322 Section 3.6.
 
+.TP
+.I StatisticsPolicyScript (string)
+The statistics script is run after all of the DKIM verification and signing work has been completed but before any final message handling is done. The main purpose of this script is to give the user an opportunity to examine the message or its signatures and make arbitrary additional statistical observations that should be recorded by the statistics module.
+
 .TP
 .I StrictTestMode (Boolean)
 Selects strict CRLF mode during testing (see the
@@ -1121,7 +1122,7 @@ messages.
 .I TemporaryDirectory (string)
 Specifies the directory in which temporary canonicalization files should
 be written.  The default is to use the
-.I libdkim
+.I libopendkim
 default location, currently
 .I /tmp.
 

key data is not secure: <user> is in group <group> which has multiple users ...

Hi,

I'm running OpenDKIM 2.11.0-Beta2 in a Docker container based on Alpine. After migrating the setup from my physical machine into the Docker container, I got the following error:

mail._domainkey.domain1.net: key data is not secure: opendkim is in group 0 which has multiple users (e.g., "sync")

Checking the key permissions, everything seems fine for me:

/etc/opendkim # ls -l
total 36
-rw-r--r--    1 opendkim opendkim       369 Jun  4 09:34 KeyTable
-rw-r--r--    1 opendkim opendkim       177 Jun  4 09:34 SigningTable
-rw-r--r--    1 opendkim opendkim        86 Jun  4 09:34 TrustedHosts
drwx------    6 opendkim opendkim        86 Jun  4 09:34 keys
-rw-r--r--    1 opendkim opendkim     21919 Jun 25 22:38 opendkim.conf

/etc/opendkim/keys # ls -l
total 0
drwx------    2 opendkim opendkim        42 Jun  4 09:34 domain1.net

/etc/opendkim/keys/domain1.net # ls -la
total 8
drwx------    2 opendkim opendkim        42 Jun  4 09:34 .
drwx------    6 opendkim opendkim        86 Jun  4 09:34 ..
-rw-------    1 opendkim opendkim       887 Jun  4 09:34 mail.private
-rw-------    1 opendkim opendkim       309 Jun  4 09:34 mail.txt

OpenDKIM runs under the user opendkim. Here the relevant parts of passwd and group:

/ # cat /etc/passwd
root:x:0:0:root:/root:/bin/ash
...
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
...
operator:x:11:0:operator:/root:/sbin/nologin
...
opendkim:x:101:102:opendkim:/run/opendkim:/sbin/nologin
/ # cat /etc/group
root:x:0:root
...
opendkim:x:102:opendkim
e6d59cba7235:~$ whoami
opendkim
e6d59cba7235:~$ groups
opendkim

Any ideas what could be wrong here? The strangest thing for me is that the safe key check says my user is in group 0, which it clearly isn't. I checked that all key files are owned by opendkim as well. Maybe the safe key check has a problem? I noticed that in Alpine Linux several users have group 0 assigned which seems to be not the case for other distros.

Any idea what I could miss?

For others having similar issues: I mitigated the problem by setting RequireSafeKeys No in the config for now. However, this should not be used carelessly - key permissions should be correctly set.

Thanks for your support!

Cheers,
Chris

librbl: fix memory leaks

detected by the clang static analyzer

diff --git a/librbl/rbl.c b/librbl/rbl.c
--- a/librbl/rbl.c
+++ b/librbl/rbl.c
@@ -965,8 +965,13 @@ rbl_query_start(RBL *rbl, u_char *query, void **qh)
 
        if (rbl->rbl_dns_service == NULL &&
            rbl->rbl_dns_init != NULL &&
-           rbl->rbl_dns_init(&rbl->rbl_dns_service) != 0)
+           rbl->rbl_dns_init(&rbl->rbl_dns_service) != 0) {
+               if (rbl->rbl_free)
+                       rbl->rbl_free(rbl->rbl_closure, rq);
+               else
+                       free(rq);
                return RBL_STAT_DNSERROR;
+       }
 
        status = rbl->rbl_dns_start(rbl->rbl_dns_service, T_A, rblquery,
                                    rq->rq_buf, sizeof rq->rq_buf, &rq->rq_qh);
diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -11404,6 +11404,8 @@ mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
                        if (conf->conf_dolog)
                                syslog(LOG_ERR, "dkimf_db_get() failed");
 
+                       TRYFREE(newhdr->hdr_hdr);
+                       free(newhdr);
                        return SMFIS_TEMPFAIL;
                }
  
diff --git a/opendkim/util.c b/opendkim/util.c
--- a/opendkim/util.c
+++ b/opendkim/util.c
@@ -812,8 +812,10 @@ dkimf_load_replist(FILE *in, struct replace **list)
                }
 
                p = strrchr(rule, '\t');
-               if (p == NULL)
+               if (p == NULL) {
+                       free(newrep);
                        return FALSE;
+               }
 
                *p = '\0';
 
@@ -821,6 +823,7 @@ dkimf_load_replist(FILE *in, struct replace **list)
                if (status != 0)
                {
                        fprintf(stderr, "%s: regcomp() failed\n", progname);
+                       free(newrep);
                        return FALSE;
                }
 
@@ -829,6 +832,7 @@ dkimf_load_replist(FILE *in, struct replace **list)
                {
                        fprintf(stderr, "%s: strdup(): %s\n", progname,
                                strerror(errno));
+                       free(newrep);
                        return FALSE;
                }

opendkim/opendkim.c:mlfi_body: don't SMFIS_SKIP a big message, that doesn't need verification, but needs signing

sendmail sends bodies to libmilter in chunks of 64k.

When opendkim is supposed simulateneously to verify the signature of an email and to sign the message, the body is >64k, and the email has no signature yet, that can be verified, opendkim shall not send SMFIS_SKIP, hence ingoring the remaining chunks of the message, as opendkim needs the remaining chunks for correct signing of the message.

Copy of https://sourceforge.net/p/opendkim/patches/42/.

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -13394,13 +13394,10 @@ mlfi_body(SMFICTX *ctx, u_char *bodyp, size_t bodylen)
                return dkimf_libstatus(ctx, last, "dkim_body()", status);
 
 #ifdef SMFIS_SKIP
-       if (dfc->mctx_srhead != NULL && cc->cctx_milterv2 &&
-           dkimf_msr_minbody(dfc->mctx_srhead) == 0)
-                       return SMFIS_SKIP;
-
-       if (dfc->mctx_dkimv != NULL && cc->cctx_milterv2 &&
-           dkim_minbody(dfc->mctx_dkimv) == 0)
-                       return SMFIS_SKIP;
+       if (cc->cctx_milterv2 &&
+           (dfc->mctx_srhead == NULL || dkimf_msr_minbody(dfc->mctx_srhead) == 0) &&
+           (dfc->mctx_dkimv == NULL || dkim_minbody(dfc->mctx_dkimv) == 0))
+               return SMFIS_SKIP;
 #endif /* SMFIS_SKIP */
 
        return SMFIS_CONTINUE;

Really prepend Authentication-Results and DKIM-Signature headers

as these are trace headers:

diff --git a/opendkim/opendkim.c b/opendkim/opendkim.c
--- a/opendkim/opendkim.c
+++ b/opendkim/opendkim.c
@@ -4250,7 +4250,7 @@ dkimf_add_ar_fields(struct msgctx *dfc, struct dkimf_config *conf,
        assert(conf != NULL);
        assert(ctx != NULL);
 
-       if (dkimf_insheader(ctx, 1, AUTHRESULTSHDR,
+       if (dkimf_insheader(ctx, 0, AUTHRESULTSHDR,
                            (char *) dfc->mctx_dkimar) == MI_FAILURE)
        {
                if (conf->conf_dolog)
@@ -13511,7 +13511,7 @@ mlfi_eom(SMFICTX *ctx)
                         dkimf_lookup_inttostr(dfc->mctx_status,
                                               dkimf_statusstrings));
 
-               if (dkimf_insheader(ctx, 1, AUTHRESULTSHDR,
+               if (dkimf_insheader(ctx, 0, AUTHRESULTSHDR,
                                    (char *) header) == MI_FAILURE)
                {
                        if (conf->conf_dolog)
@@ -14956,7 +14956,7 @@ mlfi_eom(SMFICTX *ctx)
                                                        sizeof header);
                                        }
                
-                                       if (dkimf_insheader(ctx, 1,
+                                       if (dkimf_insheader(ctx, 0,
                                                            AUTHRESULTSHDR,
                                                            (char *) header) == MI_FAILURE)
                                        {
@@ -15159,7 +15159,7 @@ mlfi_eom(SMFICTX *ctx)
                        dkimf_stripcr((char *) start);
                        dkimf_dstring_cat(dfc->mctx_tmpstr, start);
 
-                       if (dkimf_insheader(ctx, 1, DKIM_SIGNHEADER,
+                       if (dkimf_insheader(ctx, 0, DKIM_SIGNHEADER,
                                            (char *) dkimf_dstring_get(dfc->mctx_tmpstr)) == MI_FAILURE)
                        {
                                if (conf->conf_dolog)
@@ -15195,7 +15195,7 @@ mlfi_eom(SMFICTX *ctx)
                /* add VBR-Info header if generated */
                if (dfc->mctx_vbrinfo != NULL)
                {
-                       if (dkimf_insheader(ctx, 1, VBR_INFOHEADER,
+                       if (dkimf_insheader(ctx, 0, VBR_INFOHEADER,
                                            dfc->mctx_vbrinfo) == MI_FAILURE)
                        {
                                if (conf->conf_dolog)

Need to be able to specify both RSA and Ed25519 keys/selectors in opendkim

It looks like the libopendkim.c changes in Beta0 only use a single parameter for the key file/selector. In order to produce a double rsa-sha256/ed25519-sha256 signed message (which is operationally what we'll need for quite some time), I believe that would mean passing a message through the library twice for signing. This seems inefficient.

Regardless of the library implementation, opendkim will need to know both rsa and ed25519 keys for dual signing. This will require some additional paraters for ed25519. I'd suggest something like:

.TP
.I KeyFileEd25519 (string)
Gives the location of a Ed25519 private key to be used for Ed25519 signing
all messages. File is the Base64 encoded output of RFC 8032 Ed25519 private Key
generation (as used in dkimpy). Ignored if a
.I KeyTableEd25519
is defined.

TP
.I SelectorEd25519 (string)
Defines the name of the selector to be used when signing messages using Ed25519.
See the
.B DKIM
specification for details. Used only when signing with a single key;
see the
.I SigningTable
parameter below for more information.

This parameter is ignored if a
.I KeyTableEd25519
is defined.

opendkim/README add notes when Postfix modifies messages

As per discussion at https://marc.info/?t=152682982800002&r=1&w=2.

diff --git a/opendkim/README b/opendkim/README
--- a/opendkim/README
+++ b/opendkim/README
@@ -273,8 +273,8 @@ You could put "file:" in front of the filename for the KeyTable just to be
 precise, but "file:" is assumed if the value starts with a "/".
 
 
-HANDLING 8-BIT MESSAGES
-=======================
+HANDLING 8-BIT MESSAGES (Sendmail)
+==================================
 
 SMTP was not designed for handling of other than 7-bit ASCII, and the
 mechanisms to do so were added later.  There is considerable flexibility in
@@ -301,6 +301,37 @@ If the MTA connected to OpenDKIM is used to relay messages, e.g. as aliases,
 and the origianl sender set p=reject; DMARC policy, then the adjustment is
 counterproductive.
 
+NOTES ON POSTFIX  REWRITING OF MESSAGES
+=====================================
+Like other MIME-aware MTAs, Postfix downgrades 8bit body content to 7bit when
+a remote SMTP server does not announce 8BITMIME support.  If DKIM signatures
+must survive transmission to servers that don't announce 8BITMIME, Wietse
+recommends to downgrade before signing (for example, specify "-o
+smtp_discard_ehlo_keywords=8bitmime,silent-discard" for an SMTP client that
+delivers to a null filter or to amavisd).
+
+You could specify "disable_mime_output_conversion = no" locally, but that won't
+prevent remote MTAs from doing the 8bit to 7bit downgrade and breaking DKIM
+signatures.
+
+You prevent Postfix from adding From/Date/Message-ID headers, and from rewriting
+addresses in headers, by setting the -G flag for the sendmail command, and by
+setting local_header_rewrite_clients to empty (by default these modifications
+are enabled only for submissions by local processes and from clients in local
+networks).
+
+Otherwise, Postfix should not modify a well-formed email message.  For example,
+if the address in a from/to/etc. header is not modified, then the header is
+passed through unchanged regardless of the content of mailbox display names,
+comments, etc.
+
+However, there are no guarantees for out-of-spec email and for some obsolete
+forms. For example, Postfix will fold lines > 998 (not including the <CR><LF>) by
+inserting <CR><LF><SPACE> to minimize damage to MIME-formatted messages, will
+truncate (multiline) headers that contain >102400 bytes or >10240 tokens, and
+will replace the obsolete form "headername :" with the normal form "headername:"
+because many things in Postfix expect the normal form..
+
 TESTING
 =======
 

key retrieval failed ... reply truncated

I'm using opendkim 2.10.3, seeing lots of these kinds of messages in the log:

opendkim[107]: 69C74D511E4: key retrieval failed (s=aweber_key_a, d=aweber.com): \
'aweber_key_a._domainkey.aweber.com' reply truncated
opendkim[107]: BBFC7D4F68B: key retrieval failed (s=20161025, d=gmail.com): \
'20161025._domainkey.gmail.com' reply truncated

According to https://stackoverflow.com/a/54893405/202311 it may be due to missing UDPSize option in DNS lookup query.

from Sourceforge: #273 v2.11.1 coredump, 'signal 6', BT provided

On,

    lsb_release -rd
        Description:    openSUSE Leap 15.0
        Release:        15.0
    uname -rm
        4.18.12-lp150.3.ga880bd8-default x86_64

I've built & run,

    /usr/local/opendkim/sbin/opendkim -V
        opendkim: OpenDKIM Filter v2.11.0
                Compiled with OpenSSL 1.1.1  11 Sep 2018
                SMFI_VERSION 0x1000001
                libmilter version 1.0.1
                Supported signing algorithms:
                        rsa-sha1
                        rsa-sha256
                        ed25519-sha256
                Supported canonicalization algorithms:
                        relaxed
                        simple
                Active code options:
                        USE_MDB
                        USE_UNBOUND
                        _FFR_DIFFHEADERS
                        _FFR_STATS
                        _FFR_VBR
                libopendkim 2.11.0: diffheaders debug

Once launched, it runs for a fair while, accepting/verifying submitted msgs, then intermittenly terminates with signal 6,

    journalctl -f | grep -i opendkim
        ...
        Oct 08 11:54:03 mail.loc systemd[1]: Starting OpenDKIM...
        Oct 08 11:54:03 mail.loc systemd[1]: Started OpenDKIM.
        Oct 08 11:54:03 mail.loc opendkim[44544]: OpenDKIM Filter: Opening listen socket on conn local:/var/run/opendkim/opendkim.sock
        Oct 08 11:54:03 mail.loc opendkim[44544]: OpenDKIM Filter v2.11.0 starting (args: -l -x /usr/local/etc/opendkim/opendkim.conf -u opendkim)
        ...
        Oct 08 13:39:16 mail.loc opendkim[44576]: 42TXK023bYz10hm: DKIM-Signature field added (s=dkim-7f99436557929e03, d=example.com)
        Oct 08 13:39:16 mail.loc opendkim[44543]: terminated with signal 6, restarting
        Oct 08 13:39:16 mail.loc opendkim[49996]: OpenDKIM Filter: Opening listen socket on conn local:/var/run/opendkim/opendkim.sock
        Oct 08 13:39:16 mail.loc opendkim[49996]: OpenDKIM Filter v2.11.0 starting (args: -l -x /usr/local/etc/opendkim/opendkim.conf -u opendkim)
        ...

Core dumps

    ls -al /var/lib/systemd/coredump/core*
        -rw------- 1 opendkim postfix-milter 39M Oct  8 13:39 /var/lib/systemd/coredump/core.44576

and a backtrace reports,

    gdb /usr/local/opendkim/sbin/opendkim /var/lib/systemd/coredump/core.44576
        GNU gdb (GDB; openSUSE Leap 15.0) 8.1
        Copyright (C) 2018 Free Software Foundation, Inc.
        License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
        This is free software: you are free to change and redistribute it.
        There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
        and "show warranty" for details.
        This GDB was configured as "x86_64-suse-linux".
        Type "show configuration" for configuration details.
        For bug reporting instructions, please see:
        <http://bugs.opensuse.org/>.
        Find the GDB manual and other documentation resources online at:
        <http://www.gnu.org/software/gdb/documentation/>.
        For help, type "help".
        Type "apropos word" to search for commands related to "word"...
        Reading symbols from /usr/local/opendkim/sbin/opendkim...done.
        [New LWP 49990]
        [New LWP 44576]
        [New LWP 44577]
        [New LWP 48292]
        [New LWP 44578]
        [Thread debugging using libthread_db enabled]
        Using host libthread_db library "/lib64/libthread_db.so.1".
        Core was generated by `/usr/local/opendkim/sbin/opendkim -l -x /usr/local/etc/opendkim/opendkim.conf -'.
        Program terminated with signal SIGABRT, Aborted.
        #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
        51      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
        [Current thread is 1 (Thread 0x7f6c460a3700 (LWP 49990))]
        (gdb) print p
        No symbol "p" in current context.
        (gdb) bt
            #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
            #1  0x00007f6c492336c1 in __GI_abort () at abort.c:79
            #2  0x00007f6c49275427 in __libc_message (action=action@entry=(do_abort | do_backtrace),
                fmt=fmt@entry=0x7f6c4937e230 "*** Error in `%s': %s: 0x%s ***\n")
                at ../sysdeps/posix/libc_fatal.c:181
            #3  0x00007f6c4927bc43 in malloc_printerr (action=<optimized out>,
                str=0x7f6c4937e5b8 "double free or corruption (out)", ptr=<optimized out>,
                ar_ptr=<optimized out>) at malloc.c:5428
            #4  0x00007f6c4927d549 in _int_free (av=0x7f6c495b0c20 <main_arena>, p=<optimized out>,
                have_lock=<optimized out>) at malloc.c:4170
            #5  0x00007f6c4936260b in tcache_thread_freeres () at malloc.c:2999
            #6  0x00007f6c49362662 in __libc_thread_freeres () at thread-freeres.c:29
            #7  0x00007f6c495bd57e in start_thread (arg=0x7f6c460a3700) at pthread_create.c:478
            #8  0x00007f6c492f482f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

failed to parse Authentication-Results on valid headers

Some emails show above error and when accompanied by a DMARC reject policy the email is subsequently rejected.

The email in this case was from american airlines customer relations - they use exchange servers. After changing the email to be used to gmail, and re-sending, the reply went through to gmail just fine.

I examined the email sent to google and the DKIM-signature looks fine to me and google is fine with it as well - showing dkim and dmarc both pass:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aa.com; s=selector2;
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
bh...

So seems to be a bug with OpenDKIM.

Is there any chance that a fix is in the works for opendkim?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.