Validation
Validation
The chain walk
DnssecValidator is anchored on the IANA root trust anchors (the KSK DS records).
Given a zone, it walks root → TLD → zone. At each level it:
- fetches the
DNSKEYRRset (with the DO bit), - proves one key against the
DScommitted by the parent (the root uses the hard-coded anchor), - verifies the zone's DNSKEY self-signature with that key,
- only then trusts the zone's keys to authenticate the next step down.
Trust comes from the cryptography, not the transport: because every signature is
checked against an anchored key, the records may be fetched over any Resolver — a
recursive DO query, a fake — without weakening the result.
Validating a zone
use Cbox\Dns\Dns;
$dns = new Dns;
$result = $dns->dnssec()->validate('cloudflare.com');
$result->status->value; // "secure" | "insecure" | "bogus"
$result->isSecure(); // bool
$result->isInsecure();
$result->isBogus();
$result->target; // "cloudflare.com"
$result->reason; // human-readable explanation
$dns->dnssec() returns a fresh DnssecValidator bound to the facade's resolver.
validate() returns a ValidationResult.
Validating a single record set
validateRecords() fetches a specific host/type with the DO bit, learns the
signing zone from the RRSIG's signer name, validates that zone's chain, and verifies
the RRset against the zone's keys:
use Cbox\Dns\Enums\RecordType;
$dns->dnssec()->validateRecords('www.cloudflare.com', RecordType::A);
An empty answer is not a silent pass — it is validated as an authenticated
NODATA/NXDOMAIN via NSEC/NSEC3, or it is bogus.
The three outcomes
| Status | Meaning |
|---|---|
Secure |
a complete authentication chain from a trust anchor was proven |
Insecure |
an authenticated NSEC/NSEC3 proof shows the zone is genuinely unsigned (a delegation with no DS) |
Bogus |
validation was expected to succeed but failed — a missing key, a broken DS link, a bad or expired signature, or an unknown algorithm |
Bogus is the deny-by-default outcome: anything that is not provably Secure or
provably Insecure is Bogus. See the threat model for the
full matrix of what maps to bogus, and algorithms for which
signing algorithms are accepted.
What the AD bit is (and isn't)
DnsResponse::$authenticated carries the AD (authenticated-data) bit when a
transport reports it — DoH JSON exposes it directly. It only tells you that some
other validator upstream claims to have validated. It is advisory. Never treat a
bare authenticated === true as a substitute for running validate() /
validateRecords() yourself.