Skip to content

fix: DANE downgrade resistance#545

Open
wez wants to merge 8 commits into
mainfrom
dane
Open

fix: DANE downgrade resistance#545
wez wants to merge 8 commits into
mainfrom
dane

Conversation

@wez

@wez wez commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

We weren't checking the DNSSEC status for A/AAAA when considering DANE, and were overly permissive in a couple of related cases.

This diff ended up fairly large because the bulk of it is to facilitate testing.

refs: #543
refs: #517

@wez

wez commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

@vdukhovni could I trouble you for a review? Thank you!

wez added 2 commits June 25, 2026 06:18
We weren't checking the DNSSEC status for A/AAAA when considering
DANE, and were overly permissive in a couple of related cases.

This diff ended up fairly large because the bulk of it is to
facilitate testing.

refs: #543
refs: #517
This surfaces aggregate dane results
Comment thread crates/dns-resolver/src/lib.rs Outdated
Comment on lines +229 to +235
/// The caller is responsible for only invoking this when the chain to the MX
/// host was securely (DNSSEC) resolved: both the MX RRset (see
/// [`MailExchanger::is_secure`]) and the MX host's address records (see
/// [`ResolvedAddress::is_secure`](kumo_log_types::ResolvedAddress)) must be
/// secure. RFC 7672 section 2.2 requires the address records to be secure
/// before it is safe to rely on TLSA records; we satisfy that by gating on the
/// secure status of the very address we are about to connect to.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in less common (roughly 1%) of cases where the MX hostname is a CNAME into an unsigned zone, but the MX hostname's zone is signed, it is still possible for the TLSA records to be signed, so a check for that can be made by validating the security status of a second explicit CNAME query. There are very few domains for which this is applicable, but some do exist (and even mostly have certificates that match the TLSA records):

braindeath.be. IN MX 10 mail.braindeath.be. ; NoError AD=1
mail.anoebis.be. IN A 144.21.32.133 ; NoError AD=0
mail.anoebis.be. IN AAAA ? ; NODATA AD=0
mail.braindeath.be. IN CNAME mail.anoebis.be. ; NOERROR AD=1
_25._tcp.mail.braindeath.be. IN TLSA 3 1 1 2f92...9ed3 ; NoError AD=1

If you feel this is not worth supporting, I'd understand, but if the CNAME fallback is not too painful, that would be nice to have.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still considering this bit; it might end up in a separate PR

Comment thread crates/dns-resolver/src/lib.rs Outdated
Comment thread crates/dns-resolver/src/lib.rs Outdated
Comment thread docs/reference/kumo/make_egress_path/enable_dane.md Outdated
Comment thread docs/reference/kumo/make_egress_path/enable_dane.md Outdated
wez added 5 commits June 27, 2026 07:44
This is technically a breaking change, but in a good way.
We will no longer send SMTP AUTH PLAIN creds when we didn't
validate the peer certificate.  This is what you want in
all production deployments.  The new option facilitates
test setups or other unusual configurations where the certs
cannot be verified but you have contrived to trust the
remote system through some other means.
When we first built out DANE, the hickory implementation was
all or nothing when DNSSEC validation was enabled, making it unsuitable
for use in an MTA.

Since that time hickory has matured; this commit wires up the
DNSSEC signals and that enables its use with DANE.

We do still require openssl for establishing the connection when
DANE is enabled; that's a different constraint.
trust_anchor_file now accepts `{ managed = "<path>" }` for an RFC 5011
auto-maintained anchor file (unbound only; hickory errors). Unbound seeds
the file from the bundled root anchors when the file is absent.
Address most of the easy points from the review, others will land
separately.
This allows you to explicit indicate that an mx_list should
be treated as DNSSEC secure.

We cannot simply assume that lua code setting mx_list be treated
as secure, because the lua code may be simply passing through
the result of some other DNS lookup--we need an explicit way
to thread through the overall secure flag in order for the
secure property to be correctly upheld.
@wez

wez commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

One of the commits in this stack makes the trust-anchor situation more explicit. Previously, the embedded unbound resolver implicitly enabled its built in trust anchors and didn't discuss or directly reference this concern. The state here in this commit now also enables DNSSEC in hickory (it was previously blocked by limitations in hickory's implementation) and discusses how to explicitly configure external trust anchors. At the present time, hickory doesn't support RFC 5011, but unbound does.

At the present time, supporting this is tricky because hickory and
unbound work quite differently and we'd need to implement it twice
two different ways, and it's currently not worth the effort based
on the the number of domains that fall into this category.

Document the limitation, how to recognize it, and what you might
consider configuring if you need to ensure authentication and/or
privacy to such a domain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants