Skip to content

feat(eudi): optional DNSSEC check for did:web verifier domains - #621

Open
dobby-coder[bot] wants to merge 5 commits into
masterfrom
feat/didweb-dnssec-check-619
Open

feat(eudi): optional DNSSEC check for did:web verifier domains#621
dobby-coder[bot] wants to merge 5 commits into
masterfrom
feat/didweb-dnssec-check-619

Conversation

@dobby-coder

@dobby-coder dobby-coder Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Closes #619

Adds an optional DNSSEC check to did:web validation in the OpenID4VP flow. Off by default; when off or unavailable, existing did:web validation is unchanged.

How it works

The new eudi/dnssec package validates the DNSSEC chain of trust for a host's address records. It queries a recursive resolver with the DO and CD bits set and verifies every RRSIG, DS and DNSKEY itself, anchored at the IANA root trust anchors. The resolver's AD bit is deliberately not trusted: on a hostile network the path to the resolver is exactly what the attacker controls, and with local validation a spoofed resolver can cause a warning but can never forge a "secure" verdict.

Four outcomes: secure, insecure (domain is not signed), bogus (validation failed, the spoofing signal), indeterminate (check unavailable, e.g. no resolver or a resolver that strips DNSSEC records).

didweb.DocumentResolver and DidVerifierValidator take an optional dnssec.Verifier. In the OpenID4VP flow the outcome maps to typed warnings on the requestor (TrustedParty.Warnings) that reach the app through the session state:

  • bogus becomes did_web_dnssec_invalid
  • insecure becomes did_web_dnssec_missing
  • secure and indeterminate produce no warning

Validation itself is never blocked by the check. Enable it with client.SetDidWebDnssecCheck(true).

The warning codes are for irmamobile to translate into user-friendly text (the wallet owns the wording, so no DNSSEC jargon needs to reach users). Note that did_web_dnssec_missing will fire for most domains on the internet; showing it prominently is a product decision.

Limitations

  • No NSEC/NSEC3 denial-of-existence validation: an on-path attacker can downgrade secure to insecure, but cannot forge secure. Documented in the package.
  • The default configuration uses the system resolvers from /etc/resolv.conf. No fallback to a public resolver, on purpose: sending verifier domains to a third-party DNS service would leak user activity. Deployments can set ChainVerifier.Servers explicitly.

Testing

  • eudi/dnssec is tested against an in-process fake resolver serving a fully signed root, TLD and leaf zone hierarchy: tampered records, stripped signatures, expired signatures, forged DS, self-signed DS (a zone forging its own chain), CNAME into an unsigned zone, completely unsigned zones and IPv6-only hosts.
  • eudi/didweb and eudi/openid4vp tests cover the plumbing: the check runs against the DID's domain, each status maps to the right warning, and a nil verifier changes nothing.
  • Live check from this branch: internet.nl and yivi.app validate as secure, dnssec-failed.org as bogus, google.com as insecure.
  • go test ./... passes except for pre-existing failures that need postgres/mail services (keyshare and sessiontest keyshare subtests, identical on master).

dobby-coder Bot and others added 4 commits July 17, 2026 00:40
Validates the DNSSEC chain of trust for a host's address records, from
the IANA root trust anchors down to the leaf zone, using a recursive
resolver only as transport (DO+CD; the AD bit is not trusted). Outcomes
distinguish a failed validation (bogus) from an unsigned domain
(insecure) and an unavailable check (indeterminate), so callers can
warn without blocking.

Part of #619

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The did:web document resolver and DID verifier validator accept an
optional dnssec.Verifier. When configured, a bogus or missing DNSSEC
chain for the verifier's domain surfaces as a typed warning on the
requestor handed to the app (did_web_dnssec_invalid /
did_web_dnssec_missing); it never blocks the session. Off by default,
opt-in via client.SetDidWebDnssecCheck(true).

Part of #619

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dobby-coder
dobby-coder Bot requested a review from kamphuisem July 17, 2026 00:45

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

VERDICT: approve

Rules Dobby 2 sign-off, merged with the code review.

Code review (Review Dobby 2): production code is correct. Built and ran the dnssec tests (12/12) and didweb tests green; gofmt and go vet clean. The openid4vp package was skipped locally because SQLCipher cgo is unavailable in the review container, but the CI test job (which installs libsqlcipher-dev) passes. One non-blocking nit, left inline: a test-only data race in the fake resolver, visible only under go test -race.

Rule check: no violations. Reviewer assigned, PR body closes #619, conventional commit title, changelog entry present, 19 new test functions across 4 test files, prose clean. All 18 CI checks pass.

Non-blocking; safe to merge once a maintainer agrees.

Comment thread eudi/dnssec/dnssec_test.go
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.

Add optional DNSSEC check to did:web validation

1 participant