# PhoenixDKIM 3.0.0-beta13

27 May 2026

A large release. The headline is RFC 8301 enforcement: RSA-SHA1 is now completely disabled for both signing and verification, with a new `On-WeakAlgorithm` option to control what happens to messages that carry such a signature (check the man-page).

Alongside that are new features; better systemd integration; and a substantial number of bug fixes that surfaced through an audit of OpenDKIM changes (PhoenixDKIM was forked from OpenDKIM); a completed pass of `-Wconversion` / `-Wsign-conversion` remediation; and systematic testing under Clang, its sanitisers, and the extended CMake hardening flag set.

## Incompatible changes

- RSA-SHA1 verification is now refused unconditionally, in line with RFC 8301 (Cryptographic Algorithm and Key Usage Update to DomainKeys Identified Mail (DKIM)). The daemon sets `DKIM_LIBFLAGS_NOSHA1VERIFY` on every startup; any rsa-sha1 signature is permanently marked as a weak-algorithm failure before any DNS lookup or cryptographic work takes place. RSA-SHA1 signing is also disabled.

  A new `On-WeakAlgorithm` configuration option controls the milter disposition for messages carrying an rsa-sha1 signature: `neutral` (default — deliver with a neutral result), `reject`, `quarantine`, `tempfail`, or `discard`. The value `accept` is rejected at configuration load time.

## New features

- New `CheckSigningTable` configuration option and `-g` / `-G` command-line flags. When enabled, the daemon verifies that the sender address appears in the signing table before applying a signature, so a misconfigured table produces a logged diagnostic rather than a silently unsigned message.

- `opendkim-genzone` gains a `-s` flag that extends DNS zone output to cover subdomains when used with `-d`. Zone output is now reproducible: records are sorted and contain no timestamp-dependent content.

- The `KeyTable` now accepts an optional fourth field specifying the signing algorithm (e.g. `ed25519`). Different keys in the same table may use different algorithms.

- systemd integration:

  - `Type=notify` readiness signalling — the daemon calls `sd_notify(3)` after binding its socket, so service dependencies activate only once PhoenixDKIM is ready to accept connections.

  - Watchdog keep-alive — a background thread sends `WATCHDOG=1` pings on the configured `WatchdogSec` interval.

  - Service hardening directives added to the systemd unit (`PrivateTmp`, `ProtectSystem`, `CapabilityBoundingSet`, and others).

- `opendkim -V` now prints the full build configuration: enabled optional features, library versions, and compile-time flags. Development builds embed the git commit hash in the version string.

- A `DKIM_FEATURE_ED25519` capability flag has been added so callers can test for Ed25519 support at run time. New unit tests `t-test204` and `t-test205` provide multi-key signing coverage.

## Removals

- Removed K&R `__P()` portability wrappers throughout the codebase. A C89 prototype-aware compiler is now assumed.

- Removed the `smfi_insheader()` compatibility shim for sendmail < 8.13.0.

- Removed the dead `conf_singleauthres` configuration field.

## Bug fixes

- `dkim_sign()` now correctly emits the `l=` body-length tag when a length is supplied. A missing final CRLF is no longer rejected when the `l=` tag is in use.

- The header field-body character validation always returned “valid” due to a tautology in the comparison; it now correctly rejects out-of-range characters.

- Fixed an assert crash in `dkim_canon_selecthdrs` when all header fields are skipped.

- Fixed operator precedence in the `DKIM_SIG_CHECK` macro.

- `odkim.del_header()` now deletes the correct indexed instance rather than always the first occurrence.

- The milter capabilities mask is now declared correctly for `FinalPolicyScript` Lua hooks.

- `NoHeaderB` now correctly suppresses `header.b` extraction from the `Authentication-Results` output.

- `authserv-id` and job-id values are now quoted in `Authentication-Results` output as required by RFC 8601.

- `Authentication-Results` key tag fields now use comma as the separator, not semicolon.

- `Authentication-Results` headers with a no-result entry are now accepted as valid syntax.

- DNAME resource records are now skipped when parsing DNS answers for both DKIM key lookups and DKIM failure reports.

- The libunbound resolver context now loads `/etc/resolv.conf` by default, matching the behaviour of the standard system resolver.

- Fixed several memory leaks and an orphaned-list bug in key lookup code (issue #272).

- `endpwent()` is now called on all early return paths from key safety checks (issue #198).

- Fixed a stack overflow in miltertest when `REPLBODY` data exceeded the response buffer.

- `dkimf_lua_writer` is now guarded against the end-of-dump convention introduced in Lua 5.5.

- Many further fixes to key handling, DNS resolution, `Authentication-Results` formatting, miltertest, and the Lua hook interface. See the full release notes for the complete list.

## OpenDKIM upstream audit

PhoenixDKIM shares its lineage with OpenDKIM, which has recently started to receive maintenance again! We periodically review fixes made there and assess each one against our codebase. A number of those fixes were applicable here — some landed as-is, others were adapted to account for code paths that have since diverged — and are reflected in the bug fixes above.

As the two code bases continue to diverge, not every OpenDKIM fix translates directly; in those cases the underlying issue was assessed independently and addressed in a manner suited to our code. The audit nonetheless remains a valuable source of known issues and we intend to keep conducting it on a regular basis.

## Build-time analysis

A substantial portion of the fixes in this release were surfaced by building and testing under a wider set of compilers and analysis tools:

- Clang build. Compiling with Clang in addition to GCC exposes a distinct set of diagnostics. Several correctness issues — including sign-compare warnings, implicit-conversion warnings unique to Clang, and const-qualification problems — were found and fixed this way.

- Clang sanitisers. Builds with AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan) caught errors, undefined behaviour, and reads from uninitialised memory that are invisible to a normal build. Several of the bug fixes above were discovered through sanitiser runs.

- CMake hardening and warning flags. The build system carries an extended set of optional warning and hardening flags (`-Wconversion`, `-Wsign-conversion`, `-Wcast-align`, stack protectors, `_FORTIFY_SOURCE`, and others) that are off by default in most projects. Enabling these systematically revealed the conversion and sign-compare issues addressed in earlier betas, as well as several of the correctness fixes in this one.

## Compiler warning remediation

`-Wconversion` and `-Wsign-conversion` warnings have been addressed systematically across libopendkim, the daemon, miltertest, and the test suite. The work covered signed/unsigned arithmetic, implicit narrowing conversions, integer type mismatches at function call boundaries, and byte-extraction casts. No `-Wconversion` or `-Wsign-conversion` diagnostics remain in the default build configuration.

Back to announcements