1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // ***************************************************************************
19 // nsec.c: This file contains support functions to validate NSEC records for
20 // NODATA and NXDOMAIN error.
21 // ***************************************************************************
23 #include "mDNSEmbeddedAPI.h"
24 #include "DNSCommon.h"
28 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
29 // and use the stub functions implemented later in this file.
31 #ifndef DNSSEC_DISABLED
33 // Implementation Notes
35 // NSEC records in DNSSEC are used for authenticated denial of existence i.e., if the response to a query
36 // results in NXDOMAIN or NODATA error, the response also contains NSEC records in the additional section
37 // to prove the non-existence of the original name. In most of the cases, NSEC records don't have any
38 // relationship to the original name queried i.e, if they are cached based on the name like other records,
39 // it can't be located to prove the non-existence of the original name. Hence, we create a negative cache
40 // record like we do for the NXDOMAIN/NODATA error and then cache the NSEC records as part of that. Sometimes,
41 // NSEC records are also used for wildcard expanded answer in which case they are cached with the cache record
42 // that is created for the original name. NSEC records are freed when the parent cache (the record that they
43 // are attached to is expired).
45 // NSEC records also can be queried like any other record and hence can exist independent of the negative
46 // cache record. It exists as part of negative cache record only when we get a NXDOMAIN/NODATA error with
47 // NSEC records. When a query results in NXDOMAIN/NODATA error and needs to be validated, the NSEC
48 // records (and its RRSIGS) are cached as part of the negative cache record. The NSEC records that
49 // exist separately from the negative cache record should not be used to answer ValidationRequired/
50 // ValidatingResponse questions as it may not be sufficient to prove the non-existence of the name.
51 // The exception is when the NSEC record is looked up explicitly. See DNSSECRecordAnswersQuestion
55 mDNSlocal CacheRecord
*NSECParentForQuestion(mDNS
*const m
, DNSQuestion
*q
)
62 slot
= HashSlot(&q
->qname
);
63 namehash
= DomainNameHashValue(&q
->qname
);
64 cg
= CacheGroupForName(m
, slot
, namehash
, &q
->qname
);
67 LogDNSSEC("NSECParentForQuestion: Cannot find cg for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
70 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
71 if (SameNameRecordAnswersQuestion(&cr
->resrec
, q
))
76 mDNSlocal
void UpdateParent(DNSSECVerifier
*dv
)
78 AuthChainLink(dv
->parent
, dv
->ac
);
80 dv
->parent
->NumPackets
+= dv
->NumPackets
;
83 // Note: This should just call the parent callback which will free the DNSSECVerifier.
84 mDNSlocal
void VerifyNSECCallback(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
88 LogMsg("VerifyNSECCCallback: ERROR!! no parent DV\n");
89 FreeDNSSECVerifier(m
, dv
);
94 // Before we free the "dv", we need to update the
95 // parent with our AuthChain information
98 // "status" indicates whether we are able to successfully verify
99 // the NSEC/NSEC3 signatures. For NSEC3, the OptOut flag may be set
100 // for which we need to deliver insecure result.
101 if ((dv
->parent
->flags
& NSEC3_OPT_OUT
) && (status
== DNSSEC_Secure
))
103 dv
->parent
->DVCallback(m
, dv
->parent
, DNSSEC_Insecure
);
107 dv
->parent
->DVCallback(m
, dv
->parent
, status
);
109 // The callback we called in the previous line should recursively
110 // free all the DNSSECVerifiers starting from dv->parent and above.
111 // So, set that to NULL and free the "dv" itself here.
112 dv
->parent
= mDNSNULL
;
113 FreeDNSSECVerifier(m
, dv
);
116 // If the caller provides a callback, it takes the responsibility of calling the original callback
117 // in "pdv" when it is done.
121 // rr: The NSEC record that should be verified
122 // rv: The NSEC record can also be provided like this
123 // pdv: Parent DNSSECVerifier which will be called when the verification is done.
124 // callback: As part of the proof, we need multiple NSEC verifications before we call the "pdv" callback in
125 // which case a intermediate "callback" is provided which can be used to do multiple verifications.
126 // ncr: The cache record where the RRSIGS are cached
128 // NSEC records and signatures are cached along with the cache record so that we can expire them all together. We can't cache
129 // them based on the name hash like other records as in most cases the returned NSECs has a different name than we asked for
130 // (except for NODATA error where the name exists but type does not exist).
132 mDNSexport
void VerifyNSEC(mDNS
*const m
, ResourceRecord
*rr
, RRVerifier
*rv
, DNSSECVerifier
*pdv
, CacheRecord
*ncr
, DNSSECVerifierCallback callback
)
134 DNSSECVerifier
*dv
= mDNSNULL
;
136 const domainname
*name
;
141 LogDNSSEC("VerifyNSEC: Both rr and rv are NULL");
146 LogDNSSEC("VerifyNSEC: ERROR!! pdv is NULL");
149 // Remember the name and type for which we are verifying, so that when we are done processing all
150 // the verifications, we can trace it back.
152 // Note: Currently it is not used because when the verification completes as we just
153 // call the "pdv" callback which has its origName and origType.
165 dv
= AllocateDNSSECVerifier(m
, name
, rrtype
, pdv
->q
.InterfaceID
, DNSSEC_VALIDATION_SECURE
,
166 (callback
? callback
: VerifyNSECCallback
), mDNSNULL
);
169 LogMsg("VerifyNSEC: mDNSPlatformMemAlloc failed");
175 if (AddRRSetToVerifier(dv
, rr
, rv
, RRVS_rr
) != mStatus_NoError
)
177 LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier failed to add NSEC");
181 // Add the signatures after validating them
185 if ((*rp
)->resrec
.rrtype
== kDNSType_RRSIG
)
187 ValidateRRSIG(dv
, RRVS_rrsig
, &(*rp
)->resrec
);
194 LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier missing rrset");
197 // Expired signatures.
201 // Next step is to fetch the keys
204 StartDNSSECVerification(m
, dv
);
207 pdv
->DVCallback(m
, pdv
, DNSSEC_Bogus
);
210 dv
->parent
= mDNSNULL
;
211 FreeDNSSECVerifier(m
, dv
);
216 mDNSlocal
void DeleteCachedNSECS(mDNS
*const m
, CacheRecord
*cr
)
218 CacheRecord
*rp
, *next
;
220 if (cr
->nsec
) LogDNSSEC("DeleteCachedNSECS: Deleting NSEC Records\n");
221 for (rp
= cr
->nsec
; rp
; rp
= next
)
224 ReleaseCacheRecord(m
, rp
);
229 // Returns success if it adds the nsecs and the rrsigs to the cache record. Otherwise, it returns
230 // failure (mDNSfalse)
231 mDNSexport mDNSBool
AddNSECSForCacheRecord(mDNS
*const m
, CacheRecord
*crlist
, CacheRecord
*negcr
, mDNSu8 rcode
)
234 mDNSBool nsecs_seen
= mDNSfalse
;
235 mDNSBool nsec3s_seen
= mDNSfalse
;
237 if (rcode
!= kDNSFlag1_RC_NoErr
&& rcode
!= kDNSFlag1_RC_NXDomain
)
239 LogMsg("AddNSECSForCacheRecord: Addings nsecs for rcode %d", rcode
);
243 // Sanity check the list to see if we have anything else other than
244 // NSECs and its RRSIGs
245 for (cr
= crlist
; cr
; cr
= cr
->next
)
247 if (cr
->resrec
.rrtype
!= kDNSType_NSEC
&& cr
->resrec
.rrtype
!= kDNSType_NSEC3
&&
248 cr
->resrec
.rrtype
!= kDNSType_SOA
&& cr
->resrec
.rrtype
!= kDNSType_RRSIG
)
250 LogMsg("AddNSECSForCacheRecord: ERROR!! Adding Wrong record %s", CRDisplayString(m
, cr
));
253 if (cr
->resrec
.rrtype
== kDNSType_RRSIG
)
255 RDataBody2
*const rdb
= (RDataBody2
*)cr
->smallrdatastorage
.data
;
256 rdataRRSig
*rrsig
= &rdb
->rrsig
;
257 mDNSu16 tc
= swap16(rrsig
->typeCovered
);
258 if (tc
!= kDNSType_NSEC
&& tc
!= kDNSType_NSEC3
&& tc
!= kDNSType_SOA
)
260 LogMsg("AddNSECSForCacheRecord:ERROR!! Adding RRSIG with Wrong type %s", CRDisplayString(m
, cr
));
264 else if (cr
->resrec
.rrtype
== kDNSType_NSEC
)
266 nsecs_seen
= mDNStrue
;
268 else if (cr
->resrec
.rrtype
== kDNSType_NSEC3
)
270 nsec3s_seen
= mDNStrue
;
272 LogDNSSEC("AddNSECSForCacheRecord: Found a valid record %s", CRDisplayString(m
, cr
));
274 if ((nsecs_seen
&& nsec3s_seen
) || (!nsecs_seen
&& !nsec3s_seen
))
276 LogDNSSEC("AddNSECSForCacheRecord:ERROR nsecs_seen %d, nsec3s_seen %d", nsecs_seen
, nsec3s_seen
);
279 DeleteCachedNSECS(m
, negcr
);
280 LogDNSSEC("AddNSECSForCacheRecord: Adding NSEC Records for %s", CRDisplayString(m
, negcr
));
281 negcr
->nsec
= crlist
;
285 // Return the number of labels that matches starting from the right (excluding the
287 mDNSexport
int CountLabelsMatch(const domainname
*const d1
, const domainname
*const d2
)
290 int match
, i
, skip1
, skip2
;
292 c1
= CountLabels(d1
);
294 c2
= CountLabels(d2
);
297 // Root label always matches. And we don't include it here to
301 // Compare as many labels as possible starting from the rightmost
302 count
= c1
< c2
? c1
: c2
;
303 for (i
= count
; i
> 0; i
--)
305 const domainname
*da
, *db
;
307 da
= SkipLeadingLabels(d1
, skip1
);
308 db
= SkipLeadingLabels(d2
, skip2
);
309 if (!SameDomainName(da
, db
)) return match
;
317 // Empty Non-Terminal (ENT): if the qname is bigger than nsec owner's name and a
318 // subdomain of the nsec's nxt field, then the qname is a empty non-terminal. For
319 // example, if you are looking for (in RFC 4035 example zone) "y.w.example A"
320 // record, if it is a ENT, then it would return
322 // x.w.example. 3600 NSEC x.y.w.example. MX RRSIG NSEC
324 // This function is normally called before checking for wildcard matches. If you
325 // find this NSEC, there is no need to look for a wildcard record
326 // that could possibly answer the question.
327 mDNSlocal mDNSBool
NSECAnswersENT(const ResourceRecord
*const rr
, domainname
*qname
)
329 const domainname
*oname
= rr
->name
;
330 const RDataBody2
*const rdb
= (RDataBody2
*)rr
->rdata
->u
.data
;
331 const domainname
*nxt
= (const domainname
*)&rdb
->data
;
335 // Is the owner name smaller than qname?
336 ret
= DNSSECCanonicalOrder(oname
, qname
, mDNSNULL
);
339 // Is the next domain field a subdomain of qname ?
340 ret
= DNSSECCanonicalOrder(nxt
, qname
, &subdomain
);
345 LogMsg("NSECAnswersENT: ERROR!! DNSSECCanonicalOrder subdomain set "
346 " qname %##s, NSEC %##s", qname
->c
, rr
->name
->c
);
354 mDNSlocal
const domainname
*NSECClosestEncloser(ResourceRecord
*rr
, domainname
*qname
)
356 const domainname
*oname
= rr
->name
;
357 const RDataBody2
*const rdb
= (RDataBody2
*)rr
->rdata
->u
.data
;
358 const domainname
*nxt
= (const domainname
*)&rdb
->data
;
361 match1
= CountLabelsMatch(oname
, qname
);
362 match2
= CountLabelsMatch(nxt
, qname
);
363 // Return the closest i.e the one that matches more labels
365 return SkipLeadingLabels(oname
, CountLabels(oname
) - match1
);
367 return SkipLeadingLabels(nxt
, CountLabels(nxt
) - match2
);
370 // Assumption: NSEC has been validated outside of this function
372 // Does the name exist given the name and NSEC rr ?
374 // Returns -1 if it is an inappropriate nsec
375 // Returns 1 if the name exists
376 // Returns 0 if the name does not exist
378 mDNSlocal
int NSECNameExists(mDNS
*const m
, ResourceRecord
*rr
, domainname
*name
, mDNSu16 qtype
)
380 const RDataBody2
*const rdb
= (RDataBody2
*)rr
->rdata
->u
.data
;
381 const domainname
*nxt
= (const domainname
*)&rdb
->data
;
382 const domainname
*oname
= rr
->name
; // owner name
383 int ret1
, subdomain1
;
384 int ret2
, subdomain2
;
385 int ret3
, subdomain3
;
387 ret1
= DNSSECCanonicalOrder(oname
, name
, &subdomain1
);
390 LogDNSSEC("NSECNameExists: owner name %##s is bigger than name %##s", oname
->c
, name
->c
);
394 // Section 4.1 of draft-ietf-dnsext-dnssec-bis-updates-14:
396 // Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume non-
397 // existence of any RRs below that zone cut, which include all RRs at
398 // that (original) owner name other than DS RRs, and all RRs below that
399 // owner name regardless of type.
401 // This also implies that we can't use the child side NSEC for DS question.
405 mDNSBool soa
= RRAssertsExistence(rr
, kDNSType_SOA
);
406 mDNSBool ns
= RRAssertsExistence(rr
, kDNSType_NS
);
408 // We are here because the owner name is the same as "name". Make sure the
409 // NSEC has the right NS and SOA bits set.
410 if (qtype
!= kDNSType_DS
&& ns
&& !soa
)
412 LogDNSSEC("NSECNameExists: Parent side NSEC %s can't be used for question %##s (%s)",
413 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
416 else if (qtype
== kDNSType_DS
&& soa
)
418 LogDNSSEC("NSECNameExists: Child side NSEC %s can't be used for question %##s (%s)",
419 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
422 LogDNSSEC("NSECNameExists: owner name %##s is same as name %##s", oname
->c
, name
->c
);
426 // If the name is a.b.com and NSEC's owner name is b.com i.e., a subdomain
427 // and nsec comes from the parent (NS is set and SOA is not set), then this
428 // NSEC can't be used for names below the owner name.
430 // Similarly if DNAME is set, we can't use it here. See RFC2672-bis-dname
432 if (subdomain1
&& (RRAssertsExistence(rr
, kDNSType_DNAME
) ||
433 (RRAssertsNonexistence(rr
, kDNSType_SOA
) && RRAssertsExistence(rr
, kDNSType_NS
))))
435 LogDNSSEC("NSECNameExists: NSEC %s comes from the parent, can't use it here",
436 RRDisplayString(m
, rr
));
440 // At this stage, we know that name is greater than the owner name and
441 // the nsec is not from the parent side.
443 // Compare with the next field in the nsec.
445 ret2
= DNSSECCanonicalOrder(name
, nxt
, &subdomain2
);
447 // Exact match with the nsec next name
450 LogDNSSEC("NSECNameExists: name %##s is same as nxt name %##s", name
->c
, nxt
->c
);
454 ret3
= DNSSECCanonicalOrder(oname
, nxt
, &subdomain3
);
458 // Pathological case of a single name in the domain. This means only the
459 // apex of the zone itself exists. Nothing below it. "subdomain2" indicates
460 // that name is a subdmain of "next" and hence below the zone.
463 LogDNSSEC("NSECNameExists: owner name %##s subdomain of nxt name %##s", oname
->c
, nxt
->c
);
468 LogDNSSEC("NSECNameExists: Single name in zone, owner name %##s is same as nxt name %##s", oname
->c
, nxt
->c
);
475 // Regular NSEC in the zone. Make sure that the "name" lies within
476 // oname and next. oname < name and name < next
477 if (ret1
< 0 && ret2
< 0)
479 LogDNSSEC("NSECNameExists: Normal NSEC name %##s lies within owner %##s and nxt name %##s",
480 name
->c
, oname
->c
, nxt
->c
);
485 LogDNSSEC("NSECNameExists: Normal NSEC name %##s does not lie within owner %##s and nxt name %##s",
486 name
->c
, oname
->c
, nxt
->c
);
492 // Last NSEC in the zone. The "next" is pointing to the apex. All names
493 // should be a subdomain of that and the name should be bigger than
495 if (ret1
< 0 && subdomain2
)
497 LogDNSSEC("NSECNameExists: Last NSEC name %##s lies within owner %##s and nxt name %##s",
498 name
->c
, oname
->c
, nxt
->c
);
503 LogDNSSEC("NSECNameExists: Last NSEC name %##s does not lie within owner %##s and nxt name %##s",
504 name
->c
, oname
->c
, nxt
->c
);
509 LogDNSSEC("NSECNameExists: NSEC %s did not match any case", RRDisplayString(m
, rr
));
513 // If the answer was result of a wildcard match, then this function proves
514 // that a proper wildcard was used to answer the question and that the
515 // original name does not exist
516 mDNSexport
void WildcardAnswerProof(mDNS
*const m
, DNSSECVerifier
*dv
)
520 const domainname
*ce
;
522 CacheRecord
**nsec3
= mDNSNULL
;
524 LogDNSSEC("WildcardAnswerProof: Question %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
526 // RFC 4035: Section 3.1.3.3
528 // 1) We used a wildcard because the qname does not exist, so verify
529 // that the qname does not exist
531 // 2) Is the wildcard the right one ?
533 // Unfortunately, this is not well explained in that section. Refer to
534 // RFC 5155 section 7.2.6.
536 // Walk the list of nsecs we received and see if they prove that
537 // the name does not exist
539 mDNSPlatformMemZero(&q
, sizeof(DNSQuestion
));
540 q
.ThisQInterval
= -1;
541 InitializeQuestion(m
, &q
, dv
->InterfaceID
, &dv
->origName
, dv
->origType
, mDNSNULL
, mDNSNULL
);
543 ncr
= NSECParentForQuestion(m
, &q
);
546 LogMsg("WildcardAnswerProof: Can't find NSEC Parent for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
551 LogDNSSEC("WildcardAnswerProof: found %s", CRDisplayString(m
, ncr
));
556 if ((*rp
)->resrec
.rrtype
== kDNSType_NSEC
)
558 CacheRecord
*cr
= *rp
;
559 if (!NSECNameExists(m
, &cr
->resrec
, &dv
->origName
, dv
->origType
))
562 else if ((*rp
)->resrec
.rrtype
== kDNSType_NSEC3
)
570 mDNSBool ret
= mDNSfalse
;
573 ret
= NSEC3WildcardAnswerProof(m
, ncr
, dv
);
577 LogDNSSEC("WildcardAnswerProof: NSEC3 wildcard proof failed for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
584 ce
= NSECClosestEncloser(&((*rp
)->resrec
), &dv
->origName
);
587 LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser NULL for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
590 if (!SameDomainName(ce
, dv
->wildcardName
))
592 LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser %##s does not match wildcard name %##s", q
.qname
.c
, dv
->wildcardName
->c
);
597 VerifyNSEC(m
, &((*rp
)->resrec
), mDNSNULL
, dv
, ncr
, mDNSNULL
);
600 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
603 // We have a NSEC. Need to see if it proves that NODATA exists for the given name. Note that this
604 // function does not prove anything as proof may require more than one NSEC and this function
605 // processes only one NSEC at a time.
607 // Returns mDNSfalse if the NSEC does not prove the NODATA error
608 // Returns mDNStrue if the NSEC proves the NODATA error
610 mDNSlocal mDNSBool
NSECNoDataError(mDNS
*const m
, ResourceRecord
*rr
, domainname
*name
, mDNSu16 qtype
, domainname
**wildcard
)
612 const domainname
*oname
= rr
->name
; // owner name
614 if (wildcard
) *wildcard
= mDNSNULL
;
617 // section 3.1.3.1 : Name matches. Prove that the type does not exist and also CNAME is
618 // not set as in that case CNAME should have been returned ( CNAME part is mentioned in
619 // section 4.3 of dnssec-bis-updates.) Without the CNAME check, a positive response can
620 // be converted to a NODATA/NOERROR response.
622 // section 3.1.3.4 : No exact match for the name but there is a wildcard that could match
623 // the name but not the type. There are two NSECs in this case. One of them is a wildcard
624 // NSEC and another NSEC proving that the qname does not exist. We are called with one
625 // NSEC at a time. We return what we matched and the caller should decide whether all
626 // conditions are met for the proof.
627 if (SameDomainName(oname
, name
))
629 mDNSBool soa
= RRAssertsExistence(rr
, kDNSType_SOA
);
630 mDNSBool ns
= RRAssertsExistence(rr
, kDNSType_NS
);
631 if (qtype
!= kDNSType_DS
)
633 // For non-DS type questions, we don't want to use the parent side records to
637 LogDNSSEC("NSECNoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)",
638 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
646 LogDNSSEC("NSECNoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)",
647 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
651 if (RRAssertsExistence(rr
, qtype
) || RRAssertsExistence(rr
, kDNSType_CNAME
))
653 LogMsg("NSECNoDataError: ERROR!! qtype %s exists in %s", DNSTypeName(qtype
), RRDisplayString(m
, rr
));
656 LogDNSSEC("NSECNoDataError: qype %s does not exist in %s", DNSTypeName(qtype
), RRDisplayString(m
, rr
));
661 // Name does not exist. Before we check for a wildcard match, make sure that
662 // this is not an ENT.
663 if (NSECAnswersENT(rr
, name
))
665 LogDNSSEC("NSECNoDataError: name %##s exists %s", name
->c
, RRDisplayString(m
, rr
));
669 // Wildcard check. If this is a wildcard NSEC, then check to see if we could
670 // have answered the question using this wildcard and it should not have the
671 // "qtype" passed in with its bitmap.
673 // See RFC 4592, on how wildcards are used to synthesize answers. Find the
674 // closest encloser and the qname should be a subdomain i.e if the wildcard
675 // is *.x.example, x.example is the closest encloser and the qname should be
676 // a subdomain e.g., y.x.example or z.y.x.example and so on.
677 if (oname
->c
[0] == 1 && oname
->c
[1] == '*')
680 const domainname
*ce
= SkipLeadingLabels(oname
, 1);
682 r
= DNSSECCanonicalOrder(name
, ce
, &s
);
685 if (RRAssertsExistence(rr
, qtype
) || RRAssertsExistence(rr
, kDNSType_CNAME
))
687 LogMsg("NSECNoDataError: ERROR!! qtype %s exists in wildcard %s", DNSTypeName(qtype
), RRDisplayString(m
, rr
));
690 if (qtype
== kDNSType_DS
&& RRAssertsExistence(rr
, kDNSType_SOA
))
692 LogDNSSEC("NSECNoDataError: Child side wildcard NSEC %s, can't use for parent qname %##s (%s)",
693 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
696 else if (qtype
!= kDNSType_DS
&& RRAssertsNonexistence(rr
, kDNSType_SOA
) &&
697 RRAssertsExistence(rr
, kDNSType_NS
))
699 // Don't use the parent side record for this
700 LogDNSSEC("NSECNoDataError: Parent side wildcard NSEC %s, can't use for child qname %##s (%s)",
701 RRDisplayString(m
, rr
), name
->c
, DNSTypeName(qtype
));
704 *wildcard
= (domainname
*)ce
;
705 LogDNSSEC("NSECNoDataError: qtype %s does not exist in wildcard %s", DNSTypeName(qtype
), RRDisplayString(m
, rr
));
713 mDNSexport
void NoDataNSECCallback(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
719 LogDNSSEC("NoDataNSECCallback: called");
722 LogMsg("NoDataNSECCCallback: no parent DV");
723 FreeDNSSECVerifier(m
, dv
);
729 // Before we free the "dv", we need to update the
730 // parent with our AuthChain information
736 // We don't care about the "dv" that was allocated in VerifyNSEC
737 // as it just verifies one of the nsecs. Get the original verifier and
738 // verify the other NSEC like we did the first time.
739 dv
->parent
= mDNSNULL
;
740 FreeDNSSECVerifier(m
, dv
);
742 if (status
!= DNSSEC_Secure
)
747 ncr
= NSECParentForQuestion(m
, &pdv
->q
);
750 LogMsg("NoDataNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv
->q
.qname
.c
, DNSTypeName(pdv
->q
.qtype
));
753 rv
= pdv
->pendingNSEC
;
754 pdv
->pendingNSEC
= rv
->next
;
755 // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one,
756 // we don't need to come back here; let the regular NSECCallback call the original callback.
758 LogDNSSEC("NoDataNSECCallback: Verifying %##s (%s)", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
759 if (!pdv
->pendingNSEC
)
760 VerifyNSEC(m
, mDNSNULL
, rv
, pdv
, ncr
, mDNSNULL
);
762 VerifyNSEC(m
, mDNSNULL
, rv
, pdv
, ncr
, NoDataNSECCallback
);
766 pdv
->DVCallback(m
, pdv
, status
);
769 mDNSexport
void NameErrorNSECCallback(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
775 LogDNSSEC("NameErrorNSECCallback: called");
778 LogMsg("NameErrorNSECCCallback: no parent DV");
779 FreeDNSSECVerifier(m
, dv
);
785 // Before we free the "dv", we need to update the
786 // parent with our AuthChain information
791 // We don't care about the "dv" that was allocated in VerifyNSEC
792 // as it just verifies one of the nsecs. Get the original verifier and
793 // verify the other NSEC like we did the first time.
794 dv
->parent
= mDNSNULL
;
795 FreeDNSSECVerifier(m
, dv
);
797 if (status
!= DNSSEC_Secure
)
802 ncr
= NSECParentForQuestion(m
, &pdv
->q
);
805 LogMsg("NameErrorNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv
->q
.qname
.c
, DNSTypeName(pdv
->q
.qtype
));
808 rv
= pdv
->pendingNSEC
;
809 pdv
->pendingNSEC
= rv
->next
;
810 // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one,
811 // we don't need to come back here; let the regular NSECCallback call the original callback.
813 LogDNSSEC("NameErrorNSECCallback: Verifying %##s (%s)", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
814 if (!pdv
->pendingNSEC
)
815 VerifyNSEC(m
, mDNSNULL
, rv
, pdv
, ncr
, mDNSNULL
);
817 VerifyNSEC(m
, mDNSNULL
, rv
, pdv
, ncr
, NameErrorNSECCallback
);
822 pdv
->DVCallback(m
, pdv
, status
);
825 // We get a NODATA error with no records in answer section. This proves
826 // that qname does not exist.
827 mDNSlocal
void NoDataProof(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*ncr
)
830 domainname
*wildcard
= mDNSNULL
;
831 const domainname
*ce
= mDNSNULL
;
832 ResourceRecord
*nsec_wild
= mDNSNULL
;
833 ResourceRecord
*nsec_noname
= mDNSNULL
;
835 // NODATA Error could mean two things. The name exists with no type or there is a
836 // wildcard that matches the name but no type. This is done by NSECNoDataError.
838 // If it is the case of wildcard, there are two NSECs. One is the wildcard NSEC and
839 // the other NSEC to prove that there is no other closer match.
845 if ((*rp
)->resrec
.rrtype
== kDNSType_NSEC
)
847 CacheRecord
*cr
= *rp
;
848 if (NSECNoDataError(m
, &cr
->resrec
, &dv
->q
.qname
, dv
->q
.qtype
, &wildcard
))
852 dv
->flags
|= WILDCARD_PROVES_NONAME_EXISTS
;
853 LogDNSSEC("NoDataProof: NSEC %s proves NODATA error for %##s (%s)",
854 RRDisplayString(m
, &(*rp
)->resrec
), dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
858 dv
->flags
|= NSEC_PROVES_NOTYPE_EXISTS
;
859 LogDNSSEC("NoDataProof: NSEC %s proves NOTYPE error for %##s (%s)",
860 RRDisplayString(m
, &(*rp
)->resrec
), dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
862 nsec_wild
= &cr
->resrec
;
864 if (!NSECNameExists(m
, &cr
->resrec
, &dv
->q
.qname
, dv
->q
.qtype
))
866 LogDNSSEC("NoDataProof: NSEC %s proves that name %##s (%s) does not exist",
867 RRDisplayString(m
, &(*rp
)->resrec
), dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
868 // If we have a wildcard, then we should check to see if the closest
869 // encloser is the same as the wildcard.
870 ce
= NSECClosestEncloser(&cr
->resrec
, &dv
->q
.qname
);
871 dv
->flags
|= NSEC_PROVES_NONAME_EXISTS
;
872 nsec_noname
= &cr
->resrec
;
877 if (!nsec_noname
&& !nsec_wild
)
879 LogDNSSEC("NoDataProof: No valid NSECs for %##s (%s)", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
882 // If the type exists, then we have to verify just that NSEC
883 if (!(dv
->flags
& NSEC_PROVES_NOTYPE_EXISTS
))
885 // If we have a wildcard, then we should have a "ce" which matches the wildcard
886 // If we don't have a wildcard, then we should have proven that the name does not
887 // exist which means we would have set the "ce".
890 LogMsg("NoDataProof: Cannot prove that the name %##s (%s) does not exist", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
893 if (wildcard
&& !SameDomainName(wildcard
, ce
))
895 LogMsg("NoDataProof: wildcard %##s does not match closest encloser %##s", wildcard
->c
, ce
->c
);
898 // If a single NSEC can prove both, then we just have validate that one NSEC.
899 if (nsec_wild
== nsec_noname
)
901 nsec_noname
= mDNSNULL
;
902 dv
->flags
&= ~NSEC_PROVES_NONAME_EXISTS
;
906 if ((dv
->flags
& (WILDCARD_PROVES_NONAME_EXISTS
|NSEC_PROVES_NONAME_EXISTS
)) ==
907 (WILDCARD_PROVES_NONAME_EXISTS
|NSEC_PROVES_NONAME_EXISTS
))
910 RRVerifier
*r
= AllocateRRVerifier(nsec_noname
, &status
);
912 // First verify wildcard NSEC and then when we are done, we
913 // will verify the noname nsec
915 LogDNSSEC("NoDataProof: Verifying wild and noname %s", RRDisplayString(m
, nsec_wild
));
916 VerifyNSEC(m
, nsec_wild
, mDNSNULL
, dv
, ncr
, NoDataNSECCallback
);
918 else if ((dv
->flags
& WILDCARD_PROVES_NONAME_EXISTS
) ||
919 (dv
->flags
& NSEC_PROVES_NOTYPE_EXISTS
))
921 LogDNSSEC("NoDataProof: Verifying wild %s", RRDisplayString(m
, nsec_wild
));
922 VerifyNSEC(m
, nsec_wild
, mDNSNULL
, dv
, ncr
, mDNSNULL
);
924 else if (dv
->flags
& NSEC_PROVES_NONAME_EXISTS
)
926 LogDNSSEC("NoDataProof: Verifying noname %s", RRDisplayString(m
, nsec_noname
));
927 VerifyNSEC(m
, nsec_noname
, mDNSNULL
, dv
, ncr
, mDNSNULL
);
931 LogDNSSEC("NoDataProof: Error return");
932 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
935 mDNSlocal mDNSBool
NSECNoWildcard(mDNS
*const m
, ResourceRecord
*rr
, domainname
*qname
, mDNSu16 qtype
)
937 const domainname
*ce
;
940 // If the query name is c.x.w.example and if the name does not exist, we should get
941 // get a nsec back that looks something like this:
943 // w.example NSEC a.w.example
945 // First, we need to get the closest encloser which in this case is w.example. Wild
946 // card synthesis works by finding the closest encloser first and then look for
947 // a "*" label (assuming * label does not appear in the question). If it does not
948 // exists, it would return the NSEC at that name. And the wildcard name at the
949 // closest encloser "*.w.example" would be covered by such an NSEC. (Appending "*"
950 // makes it bigger than w.example and "* is smaller than "a" for the above NSEC)
952 ce
= NSECClosestEncloser(rr
, qname
);
953 if (!ce
) { LogMsg("NSECNoWildcard: No closest encloser for rr %s, qname %##s (%s)", qname
->c
, DNSTypeName(qtype
)); return mDNSfalse
; }
958 if (!AppendDomainName(&wild
, ce
))
960 LogMsg("NSECNoWildcard: ERROR!! Can't append domainname closest encloser name %##s, qname %##s (%s)", ce
->c
, qname
->c
, DNSTypeName(qtype
));
963 if (NSECNameExists(m
, rr
, &wild
, qtype
) != 0)
965 LogDNSSEC("NSECNoWildcard: Wildcard name %##s exists or not valid qname %##s (%s)", wild
.c
, qname
->c
, DNSTypeName(qtype
));
968 LogDNSSEC("NSECNoWildcard: Wildcard name %##s does not exist for record %s, qname %##s (%s)", wild
.c
,
969 RRDisplayString(m
, rr
), qname
->c
, DNSTypeName(qtype
));
973 // We get a NXDOMAIN error with no records in answer section. This proves
974 // that qname does not exist.
975 mDNSlocal
void NameErrorProof(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*ncr
)
978 ResourceRecord
*nsec_wild
= mDNSNULL
;
979 ResourceRecord
*nsec_noname
= mDNSNULL
;
982 // NXDOMAIN Error. We need to prove that the qname does not exist and there
983 // is no wildcard that can be used to answer the question.
988 if ((*rp
)->resrec
.rrtype
== kDNSType_NSEC
)
990 CacheRecord
*cr
= *rp
;
991 if (!NSECNameExists(m
, &cr
->resrec
, &dv
->q
.qname
, dv
->q
.qtype
))
993 LogDNSSEC("NameErrorProof: NSEC %s proves name does not exist for %##s (%s)",
994 RRDisplayString(m
, &(*rp
)->resrec
), dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
995 // If we have a wildcard, then we should check to see if the closest
996 // encloser is the same as the wildcard.
997 dv
->flags
|= NSEC_PROVES_NONAME_EXISTS
;
998 nsec_noname
= &cr
->resrec
;
1000 if (NSECNoWildcard(m
, &cr
->resrec
, &dv
->q
.qname
, dv
->q
.qtype
))
1002 dv
->flags
|= WILDCARD_PROVES_NONAME_EXISTS
;
1003 nsec_wild
= &cr
->resrec
;
1004 LogDNSSEC("NameErrorProof: NSEC %s proves wildcard cannot answer question for %##s (%s)",
1005 RRDisplayString(m
, &(*rp
)->resrec
), dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
1010 if (!nsec_noname
|| !nsec_wild
)
1012 LogMsg("NameErrorProof: Proof failed for %##s (%s) noname %p, wild %p", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
), nsec_noname
, nsec_wild
);
1016 // First verify wildcard NSEC and then when we are done, we will verify the noname nsec.
1017 // Sometimes a single NSEC can prove both that the "qname" does not exist and a wildcard
1018 // could not have produced qname. These are a few examples where this can happen.
1020 // 1. If the zone is example.com and you look up *.example.com and if there are no wildcards,
1021 // you will get a NSEC back "example.com NSEC a.example.com". This proves that both the
1022 // name does not exist and *.example.com also does not exist
1024 // 2. If the zone is example.com and it has a record like this:
1026 // example.com NSEC d.example.com
1028 // any name you lookup in between like a.example.com,b.example.com etc. you will get a single
1029 // NSEC back. In that case we just have to verify only once.
1031 if (nsec_wild
!= nsec_noname
)
1033 RRVerifier
*r
= AllocateRRVerifier(nsec_noname
, &status
);
1035 dv
->pendingNSEC
= r
;
1036 LogDNSSEC("NoDataProof: Verifying wild %s", RRDisplayString(m
, nsec_wild
));
1037 VerifyNSEC(m
, nsec_wild
, mDNSNULL
, dv
, ncr
, NameErrorNSECCallback
);
1041 LogDNSSEC("NoDataProof: Verifying only one %s", RRDisplayString(m
, nsec_wild
));
1042 VerifyNSEC(m
, nsec_wild
, mDNSNULL
, dv
, ncr
, mDNSNULL
);
1046 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1049 mDNSexport CacheRecord
*NSECRecordIsDelegation(mDNS
*const m
, domainname
*name
, mDNSu16 qtype
)
1053 mDNSu32 slot
, namehash
;
1055 slot
= HashSlot(name
);
1056 namehash
= DomainNameHashValue(name
);
1058 cg
= CacheGroupForName(m
, (const mDNSu32
)slot
, namehash
, name
);
1061 LogDNSSEC("NSECRecordForName: cg NULL for %##s", name
);
1064 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
1066 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& cr
->resrec
.rrtype
== qtype
)
1069 for (ncr
= cr
->nsec
; ncr
; ncr
= ncr
->next
)
1071 if (ncr
->resrec
.rrtype
== kDNSType_NSEC
&&
1072 SameDomainName(ncr
->resrec
.name
, name
))
1074 // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit
1076 if (RRAssertsExistence(&ncr
->resrec
, kDNSType_SOA
) ||
1077 RRAssertsExistence(&ncr
->resrec
, kDNSType_DS
))
1079 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but DS or SOA bit set", CRDisplayString(m
, ncr
), name
,
1080 DNSTypeName(qtype
));
1083 // Section 2.3 of RFC 4035 states that:
1085 // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST
1086 // have an NSEC resource record.
1088 // So, if we have an NSEC record matching the question name with the NS bit set,
1089 // then this is a delegation.
1091 if (RRAssertsExistence(&ncr
->resrec
, kDNSType_NS
))
1093 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s)", CRDisplayString(m
, ncr
), name
, DNSTypeName(qtype
));
1098 LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but NS bit is not set", CRDisplayString(m
, ncr
), name
,
1099 DNSTypeName(qtype
));
1109 mDNSlocal
void StartInsecureProof(mDNS
* const m
, DNSSECVerifier
*dv
)
1112 DNSSECVerifier
*prevdv
= mDNSNULL
;
1114 // Remember the name that triggered the insecure proof
1115 AssignDomainName(&trigger
, &dv
->q
.qname
);
1123 prevdv
->parent
= mDNSNULL
;
1124 FreeDNSSECVerifier(m
, prevdv
);
1126 // For Optional DNSSEC, we are opportunistically verifying dnssec. We don't care
1127 // if something results in bogus as we still want to deliver results to the
1128 // application e.g., CNAME processing results in bogus because the path is broken,
1129 // but we still want to follow CNAMEs so that we can deliver the final results to
1131 if (dv
->ValidationRequired
== DNSSEC_VALIDATION_SECURE_OPTIONAL
)
1133 LogDNSSEC("StartInsecureProof: Aborting insecure proof for %##s (%s)", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
1134 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1138 LogDNSSEC("StartInsecureProof for %##s (%s)", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
1139 // Don't start the insecure proof again after we finish the one that we start here by
1140 // setting InsecureProofDone.
1141 dv
->InsecureProofDone
= 1;
1142 ProveInsecure(m
, dv
, mDNSNULL
, &trigger
);
1146 mDNSexport
void ValidateWithNSECS(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*cr
)
1148 LogDNSSEC("ValidateWithNSECS: called for %s", CRDisplayString(m
, cr
));
1150 // If we are encountering a break in the chain of trust i.e., NSEC/NSEC3s for
1151 // DS query, then do the insecure proof. This is important because if we
1152 // validate these NSECs normally and prove that they are "secure", we will
1153 // end up delivering the secure result to the original question where as
1154 // these NSEC/NSEC3s actually prove that DS does not exist and hence insecure.
1156 // This break in the chain can happen after we have partially validated the
1157 // path (dv->ac is non-NULL) or the first time (dv->ac is NULL) after we
1158 // fetched the DNSKEY (dv->key is non-NULL). We don't want to do this
1159 // if we have just started the non-existence proof (dv->key is NULL) as
1160 // it does not indicate a break in the chain of trust.
1162 // If we are already doing a insecurity proof, don't start another one. In
1163 // the case of NSECs, it is possible that insecurity proof starts and it
1164 // gets NSECs and as part of validating that we receive more NSECS in which
1165 // case we don't want to start another insecurity proof.
1166 if (dv
->ValidationRequired
!= DNSSEC_VALIDATION_INSECURE
&&
1167 (!dv
->parent
|| dv
->parent
->ValidationRequired
!= DNSSEC_VALIDATION_INSECURE
))
1169 if ((dv
->ac
&& dv
->q
.qtype
== kDNSType_DS
) ||
1170 (!dv
->ac
&& dv
->key
&& dv
->q
.qtype
== kDNSType_DS
))
1172 LogDNSSEC("ValidateWithNSECS: Starting insecure proof: name %##s ac %p, key %p, parent %p", dv
->q
.qname
.c
,
1173 dv
->ac
, dv
->key
, dv
->parent
);
1174 StartInsecureProof(m
, dv
);
1178 // "parent" is set when we are validating a NSEC and we should not be here in
1179 // the normal case when parent is set. For example, we are looking up the A
1180 // record for www.example.com and following can happen.
1182 // a) Record does not exist and we get a NSEC
1183 // b) While validating (a), we get an NSEC for the first DS record that we look up
1184 // c) Record exists but we get NSECs for the first DS record
1185 // d) We are able to partially validate (a) or (b), but we get NSECs somewhere in
1188 // For (a), parent is not set as we are not validating the NSEC yet. Hence we would
1189 // start the validation now.
1191 // For (b), the parent is set, but should be caught by the above "if" block because we
1192 // should have gotten the DNSKEY at least. In the case of nested insecurity proof,
1193 // we would end up here and fail with bogus.
1195 // For (c), the parent is not set and should be caught by the above "if" block because we
1196 // should have gotten the DNSKEY at least.
1198 // For (d), the above "if" block would catch it as "dv->ac" is non-NULL.
1200 // Hence, we should not come here in the normal case. Possible pathological cases are:
1201 // Insecure proof getting NSECs while validating NSECs, getting NSECs for DNSKEY for (c)
1205 LogDNSSEC("ValidateWithNSECS: dv parent set for %##s (%s)", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
1206 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1209 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
1212 CacheRecord
*neg
= cr
->nsec
;
1213 mDNSBool nsecs_seen
= mDNSfalse
;
1217 // The list can only have NSEC or NSEC3s. This was checked when we added the
1218 // NSECs to the cache record.
1219 if (neg
->resrec
.rrtype
== kDNSType_NSEC
)
1220 nsecs_seen
= mDNStrue
;
1221 LogDNSSEC("ValidateWithNSECS: NSECCached Record %s", CRDisplayString(m
, neg
));
1225 rcode
= (mDNSu8
)(cr
->responseFlags
.b
[1] & kDNSFlag1_RC_Mask
);
1226 if (rcode
== kDNSFlag1_RC_NoErr
)
1229 NoDataProof(m
, dv
, cr
);
1231 NSEC3NoDataProof(m
, dv
, cr
);
1233 else if (rcode
== kDNSFlag1_RC_NXDomain
)
1236 NameErrorProof(m
, dv
, cr
);
1238 NSEC3NameErrorProof(m
, dv
, cr
);
1242 LogDNSSEC("ValidateWithNSECS: Rcode %d invalid", rcode
);
1243 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1248 LogMsg("ValidateWithNSECS: Not a valid cache record %s for NSEC proofs", CRDisplayString(m
, cr
));
1249 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1254 #else // !DNSSEC_DISABLED
1256 mDNSexport mDNSBool
AddNSECSForCacheRecord(mDNS
*const m
, CacheRecord
*crlist
, CacheRecord
*negcr
, mDNSu8 rcode
)
1266 #endif // !DNSSEC_DISABLED