OpenDKIM-provided tools do not provide a usable key-pair for DKIM

I use opendkim-genkey -b 2048 -t -s default -d mydomain.com, resulting in files default.private and default.txt. Yes, default.private begins (correctly, SFAIK) with -----BEGIN RSA PRIVATE KEY----- and default.txt does not exceed 256 chars per segment (does not violate DNS coding requirements.) Also, opendkim-testkey returns nothing (without -v) and with -v -v -v it says Key not secure (but I'm not using DNSSEC) and also Key OK, so the key is at least minimally correct according to opendkim per se.

I get the errors

Sep 26 22:41:49 mydomain opendkim[1793958]: 18R2fhko1843765: SSL error:0909006C:PEM routines:get_name:no start line
Sep 26 22:41:49 mydomain opendkim[1793958]: 18R2fhko1843765: dkim_eom(): resource unavailable: PEM_read_bio_PrivateKey() failed
Sep 26 22:41:49 mydomain sm-mta[1843765]: 18R2fhko1843765: milter=opendkim, reject=451 4.7.0 resource unavailable
Sep 26 22:41:49 mydomain sm-mta[1843765]: 18R2fhko1843765: Milter: data, reject=451 4.7.0 resource unavailable
Sep 26 22:41:49 mydomain sm-mta[1843765]: 18R2fhko1843765: to=<[email protected]>, delay=00:00:00, pri=30408, stat=resource unavailable

I've seen a lot of web search references to both errors SSL error:0909006C:PEM routines:get_name:no start line and dkim_eom(): resource unavailable: PEM_read_bio_PrivateKey() failed, but nothing that helps. When I've seen "case closed", it was because of user implementation errors such as bad permissions, bad file location specs or bad key/txt formatting, and the submitters usually said "sorry for the noise", but none of those are the case. I am doing EXACTLY as the documentation specifies, with the failures I logged above.

For those who'd like to know, I'm using Ubuntu 20.04 LTS and sendmail 8.15.2. The complaint originates from the opendkim milter vs. SSL routines, so the external context shouldn't matter.

I would ask on the opendkim mailing list, but "lists.opendkim.org" is down. I need to make OpenDKIM running, to obey Master Goo (besides it being best practice, o well.) I will be grateful if anyone else has run into this, specifically, and can give a working answer.

The output I'm using is precisely what "opendkim-genkey" outputs, there are no formatting errors as described elsewhere, and opendkim-testkey is happy, so please excuse that I haven't included that actual data.

p.s.: opendkim installed with apt install opendkim:

opendkim -p /var/run/opendkim.sock -V opendkim:
OpenDKIM Filter v2.11.0 Compiled with OpenSSL 1.1.1f 31 Mar 2020  
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: 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

Neither opendkim-tool-generated keys nor manually generated (per OpenDKIM documentation) keys get past the errors.


Solution 1:

I have verified that the key is correct (private<==>public) and accessible by two different means. I am not using KeyTable. My /etc/opendkim.conf (actual domain disguised) is:

Syslog          yes
UMask           007
Domain          mydomain.sometld
KeyFile         /etc/dkimkeys/10191.private
Selector        10191
Mode            v
Socket          inet:8892@localhost
#@Socket        local:/run/opendkim/opendkim.sock
PidFile         /run/opendkim/opendkim.pid
OversignHeaders From
TrustAnchorFile /usr/share/dns/root.key
UserID          opendkim

I keep the filter in mode "v", since "sv" fails as indicated and I only have to restart the milter with "sv" to test. Using opendkim-2.10.3 obtained from opendkim.org: I have hacked libopendkim/dkim.c, used by the milter, to show me the first 96 chars(*) of the key being attempted, when it next fails (in the early morning hours when nobody cares.) (*) 96 = header line + first 'row' of key data.

1135         if (strncmp((char *) dkim->dkim_key, "-----", 5) == 0)
1136         {                                               /* PEM */
1137                 rsa->rsa_pkey = PEM_read_bio_PrivateKey(rsa->rsa_keydata, NULL,
1138                                                         NULL, NULL);
1139 
1140                 if (rsa->rsa_pkey == NULL)
1141                 {
1142                         dkim_load_ssl_errors(dkim, 0);
1143                         dkim_error(dkim, "PEM_read_bio_PrivateKey() failed");
1144                         // ecsd: we want to see what failed:
1145                         char dbuf[128]; sprintf(dbuf,"dkim_key %96.96s\n",dkim->dkim_key);
1146                         dkim_error(dkim, dbuf);
1147                         // end extra debug
1148                         BIO_free(rsa->rsa_keydata);
1149                         rsa->rsa_keydata = NULL;
1150                         return DKIM_STAT_NORESOURCE;
1151                 }
1152         }

I should be debugging PEM_read_bio_PrivateKey (to find out what it's bitching about), but bear too much trepidation at recompiling that whole subsystem, besides, the complaint is of a bad header, so I only need to understand what is being tried "instead", since the private key's contents are correct. Meanwhile, what's with opendkim.org that their mailing list is down, and listed contacts at opendkim.org and dkim.org don't work? Like everyone got bored and went home. Not cool for a protocol you want universally adopted. At least the code tries, but e.g. I had to hack "configure" to stop it requiring a library containing SSL_library_init(), which the (outer world) doc says is obviated (thus the opendkim code would seem not to be being maintained properly.)

configure:
16846 fi
16847 rm conftest.$ac_ext
16848 LIBS=$ac_func_search_save_LIBS
16849 fi
16850 #ecsd
16851 $as_echo "for libssl, LIBS:$LIBS"
16852 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_library_init" >&5
16853 $as_echo "$ac_cv_search_SSL_library_init" >&6; }
16854 ac_res=$ac_cv_search_SSL_library_init
16855 #ecsd:
16856 #if test "$ac_res" != no; then :
16857 #  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
16858 #else
16859 #  as_fn_error $? "libssl not found" "$LINENO" 5
16860 #fi
16861 
16862 
16863 
16864 fi

Solution 2:

This is an answer, hopefully: I tried to compile OpenDKIM from source, but that got nowhere: the PEM error went away, but the filter failed in other ways fatal to its use. So I got "dk-filter", which latest version is obsolete, since it uses SHA1 only, calls "relaxed" "nofws", only handles one canonicalization (relaxed or simple, versus two as in 'relaxed/simple', and uses 'dns' but not 'dns/txt'. I hacked it per RFC8301 (which no-one cites) and it may be working; it handles inbound mail, and finally gave me a DKIM signature:

DomainKey-Signature: a=rsa-sha256; s=10191; d=mydarneddomain.com; c=relaxed/simple; q=dns/txt;
    h=to:from:subject:message-id:date:user-agent:mime-version:
    content-type:content-transfer-encoding:content-language:x-uctc:x-sdmilter-detected;
    b=kldIuC9j/EIB7ouhRrhxmZBkC7xAazd8RiWHUA/1R0FZK265yeFgf+TPqbfTjErps
    CrkoCn1I2gdMpq8k9ZrdF8RsQk8FeZBVLGE9iY3D2Rkj/ozjdOyHgNaNDCHKfdnpiNp
    4uV/w7ZG8fAEdDwfSoQ3IBvCmxoszV2bzGvzKz+DuT17G8ES3aJcKsdm9+MEHz0VxrB
    EHdOd9ij/EBZFHTMwcLqBWVi+kTvUvzjFK1ssPEO9CHXIWqjBE1gKtfiIDkeJ7kx0w4
    ft8TiPvMb5Z1WyOPWoI6a+tNNz2at1URSYvxMcDi77m93GH5Tcda1fNN/shx9ze9Igw
    DwPHc6mFA==

Since I hacked the thing into compliance and workingness (yet to be confirmed in practice, but way soon), and since it may work for all those for whom OpenDKIM doesn't work, it's worth sharing, on github, say. I don't yet know how to do that; if someone would like to help with that, let me know.

The thing is really raw, there is not even a "dk-filter.conf" file, rather one has to use the command line; I use

dk-filter -p inet:8892@localhost -b sv -c relaxed -d mydarneddomain.com -D -h -H -l -S 10191 -s /etc/dkimkeys/10191.private

although -d can refer to a file listing hosts to be signed (not yet tested.) Nor is it a "service". If someone can cite a book which explains how to wrap it up for e.g. Ubuntu as a service, let me know.

p.s.: RFC8301 mandates specific values and prohibits the use of SHA1. Sites that check DKIM keys may have a stale comment saying that either sha1 or sha256 can be used. Nothing less than sha256 can be used now, and those comments are out of date.