Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSCore / nsec.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 // ***************************************************************************
19 // nsec.c: This file contains support functions to validate NSEC records for
20 // NODATA and NXDOMAIN error.
21 // ***************************************************************************
22
23 #include "mDNSEmbeddedAPI.h"
24 #include "DNSCommon.h"
25 #include "nsec.h"
26 #include "nsec3.h"
27
28 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
29 // and use the stub functions implemented later in this file.
30
31 #ifndef DNSSEC_DISABLED
32
33 // Implementation Notes
34 //
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).
44 //
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
52 // for more details.
53 //
54
55 mDNSlocal CacheRecord *NSECParentForQuestion(mDNS *const m, DNSQuestion *q)
56 {
57     CacheGroup *cg;
58     CacheRecord *cr;
59     mDNSu32 namehash;
60
61     namehash = DomainNameHashValue(&q->qname);
62     cg = CacheGroupForName(m, namehash, &q->qname);
63     if (!cg)
64     {
65         LogDNSSEC("NSECParentForQuestion: Cannot find cg for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
66         return mDNSNULL;
67     }
68     for (cr = cg->members; cr; cr = cr->next)
69         if (SameNameRecordAnswersQuestion(&cr->resrec, q))
70             return cr;
71     return mDNSNULL;
72 }
73
74 mDNSlocal void UpdateParent(DNSSECVerifier *dv)
75 {
76     AuthChainLink(dv->parent, dv->ac);
77     ResetAuthChain(dv);
78     dv->parent->NumPackets += dv->NumPackets;
79 }
80
81 // Note: This should just call the parent callback which will free the DNSSECVerifier.
82 mDNSlocal void VerifyNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
83 {
84     if (!dv->parent)
85     {
86         LogMsg("VerifyNSECCCallback: ERROR!! no parent DV\n");
87         FreeDNSSECVerifier(m, dv);
88         return;
89     }
90     if (dv->ac)
91     {
92         // Before we free the "dv", we need to update the
93         // parent with our AuthChain information
94         UpdateParent(dv);
95     }
96     // "status" indicates whether we are able to successfully verify
97     // the NSEC/NSEC3 signatures. For NSEC3, the OptOut flag may be set
98     // for which we need to deliver insecure result.
99     if ((dv->parent->flags & NSEC3_OPT_OUT) && (status == DNSSEC_Secure))
100     {
101         dv->parent->DVCallback(m, dv->parent, DNSSEC_Insecure);
102     }
103     else
104     {
105         dv->parent->DVCallback(m, dv->parent, status);
106     }
107     // The callback we called in the previous line should recursively
108     // free all the DNSSECVerifiers starting from dv->parent and above.
109     // So, set that to NULL and free the "dv" itself here.
110     dv->parent = mDNSNULL;
111     FreeDNSSECVerifier(m, dv);
112 }
113
114 // If the caller provides a callback, it takes the responsibility of calling the original callback
115 // in "pdv" when it is done.
116 //
117 // INPUT:
118 //
119 // rr: The NSEC record that should be verified
120 // rv: The NSEC record can also be provided like this
121 // pdv: Parent DNSSECVerifier which will be called when the verification is done.
122 // callback:  As part of the proof, we need multiple NSEC verifications before we call the "pdv" callback in
123 // which case a intermediate "callback" is provided which can be used to do multiple verifications.
124 // ncr: The cache record where the RRSIGS are cached
125 //
126 // NSEC records and signatures are cached along with the cache record so that we can expire them all together. We can't cache
127 // them based on the name hash like other records as in most cases the returned NSECs has a different name than we asked for
128 // (except for NODATA error where the name exists but type does not exist).
129 //
130 mDNSexport void VerifyNSEC(mDNS *const m, ResourceRecord *rr, RRVerifier *rv, DNSSECVerifier *pdv, CacheRecord *ncr, DNSSECVerifierCallback callback)
131 {
132     DNSSECVerifier *dv = mDNSNULL;
133     CacheRecord **rp;
134     const domainname *name;
135     mDNSu16 rrtype;
136
137     if (!rv && !rr)
138     {
139         LogDNSSEC("VerifyNSEC: Both rr and rv are NULL");
140         goto error;
141     }
142     if (!pdv)
143     {
144         LogDNSSEC("VerifyNSEC: ERROR!! pdv is NULL");
145         return;
146     }
147     // Remember the name and type for which we are verifying, so that when we are done processing all
148     // the verifications, we can trace it back.
149     //
150     // Note: Currently it is not used because when the verification completes as we just
151     // call the "pdv" callback which has its origName and origType.
152     if (rr)
153     {
154         name = rr->name;
155         rrtype = rr->rrtype;
156     }
157     else
158     {
159         name = &rv->name;
160         rrtype = rv->rrtype;
161     }
162
163     dv = AllocateDNSSECVerifier(m, name, rrtype, pdv->q.InterfaceID, DNSSEC_VALIDATION_SECURE,
164         (callback ? callback : VerifyNSECCallback), mDNSNULL);
165     if (!dv)
166     {
167         LogMsg("VerifyNSEC: mDNSPlatformMemAlloc failed");
168         return;
169     }
170
171     dv->parent = pdv;
172
173     if (AddRRSetToVerifier(dv, rr, rv, RRVS_rr) != mStatus_NoError)
174     {
175         LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier failed to add NSEC");
176         goto error;
177     }
178
179     // Add the signatures after validating them
180     rp = &(ncr->nsec);
181     while (*rp)
182     {
183         if ((*rp)->resrec.rrtype == kDNSType_RRSIG)
184         {
185             ValidateRRSIG(dv, RRVS_rrsig, &(*rp)->resrec);
186         }
187         rp=&(*rp)->next;
188     }
189
190     if (!dv->rrset)
191     {
192         LogMsg("VerifyNSEC: ERROR!! AddRRSetToVerifier missing rrset");
193         goto error;
194     }
195     // Expired signatures.
196     if (!dv->rrsig)
197         goto error;
198
199     // Next step is to fetch the keys
200     dv->next = RRVS_key;
201
202     StartDNSSECVerification(m, dv);
203     return;
204 error:
205     pdv->DVCallback(m, pdv, DNSSEC_Bogus);
206     if (dv)
207     {
208         dv->parent = mDNSNULL;
209         FreeDNSSECVerifier(m, dv);
210     }
211     return;
212 }
213
214 mDNSlocal void DeleteCachedNSECS(mDNS *const m, CacheRecord *cr)
215 {
216     CacheRecord *rp, *next;
217
218     if (cr->nsec) LogDNSSEC("DeleteCachedNSECS: Deleting NSEC Records\n");
219     for (rp = cr->nsec; rp; rp = next)
220     {
221         next  = rp->next;
222         ReleaseCacheRecord(m, rp);
223     }
224     cr->nsec = mDNSNULL;
225 }
226
227 // Returns success if it adds the nsecs and the rrsigs to the cache record. Otherwise, it returns
228 // failure (mDNSfalse)
229 mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
230 {
231     CacheRecord *cr;
232     mDNSBool nsecs_seen = mDNSfalse;
233     mDNSBool nsec3s_seen = mDNSfalse;
234
235     if (rcode != kDNSFlag1_RC_NoErr && rcode != kDNSFlag1_RC_NXDomain)
236     {
237         LogMsg("AddNSECSForCacheRecord: Addings nsecs for rcode %d", rcode);
238         return mDNSfalse;
239     }
240
241     // Sanity check the list to see if we have anything else other than
242     // NSECs and its RRSIGs
243     for (cr = crlist; cr; cr = cr->next)
244     {
245         if (cr->resrec.rrtype != kDNSType_NSEC && cr->resrec.rrtype != kDNSType_NSEC3 &&
246             cr->resrec.rrtype != kDNSType_SOA && cr->resrec.rrtype != kDNSType_RRSIG)
247         {
248             LogMsg("AddNSECSForCacheRecord: ERROR!! Adding Wrong record %s", CRDisplayString(m, cr));
249             return mDNSfalse;
250         }
251         if (cr->resrec.rrtype == kDNSType_RRSIG)
252         {
253             RDataBody2 *const rdb = (RDataBody2 *)cr->smallrdatastorage.data;
254             rdataRRSig *rrsig = &rdb->rrsig;
255             mDNSu16 tc = swap16(rrsig->typeCovered);
256             if (tc != kDNSType_NSEC && tc != kDNSType_NSEC3 && tc != kDNSType_SOA)
257             {
258                 LogMsg("AddNSECSForCacheRecord:ERROR!! Adding RRSIG with Wrong type %s", CRDisplayString(m, cr));
259                 return mDNSfalse;
260             }
261         }
262         else if (cr->resrec.rrtype == kDNSType_NSEC)
263         {
264             nsecs_seen = mDNStrue;
265         }
266         else if (cr->resrec.rrtype == kDNSType_NSEC3)
267         {
268             nsec3s_seen = mDNStrue;
269         }
270         LogDNSSEC("AddNSECSForCacheRecord: Found a valid record %s", CRDisplayString(m, cr));
271     }
272     if ((nsecs_seen && nsec3s_seen) || (!nsecs_seen && !nsec3s_seen))
273     {
274         LogDNSSEC("AddNSECSForCacheRecord:ERROR  nsecs_seen %d, nsec3s_seen %d", nsecs_seen, nsec3s_seen);
275         return mDNSfalse;
276     }
277     DeleteCachedNSECS(m, negcr);
278     LogDNSSEC("AddNSECSForCacheRecord: Adding NSEC Records for %s", CRDisplayString(m, negcr));
279     negcr->nsec = crlist;
280     return mDNStrue;
281 }
282
283 // Return the number of labels that matches starting from the right (excluding the
284 // root label)
285 mDNSexport int CountLabelsMatch(const domainname *const d1, const domainname *const d2)
286 {
287     int count, c1, c2;
288     int match, i, skip1, skip2;
289
290     c1 = CountLabels(d1);
291     skip1 = c1 - 1;
292     c2 = CountLabels(d2);
293     skip2 = c2 - 1;
294
295     // Root label always matches. And we don't include it here to
296     // match CountLabels
297     match = 0;
298
299     // Compare as many labels as possible starting from the rightmost
300     count = c1 < c2 ? c1 : c2;
301     for (i = count; i > 0; i--)
302     {
303         const domainname *da, *db;
304
305         da = SkipLeadingLabels(d1, skip1);
306         db = SkipLeadingLabels(d2, skip2);
307         if (!SameDomainName(da, db)) return match;
308         skip1--;
309         skip2--;
310         match++;
311     }
312     return match;
313 }
314
315 // Empty Non-Terminal (ENT): if the qname is bigger than nsec owner's name and a
316 // subdomain of the nsec's nxt field, then the qname is a empty non-terminal. For
317 // example, if you are looking for (in RFC 4035 example zone) "y.w.example  A"
318 // record, if it is a ENT, then it would return
319 //
320 // x.w.example. 3600 NSEC x.y.w.example. MX RRSIG NSEC
321 //
322 // This function is normally called before checking for wildcard matches. If you
323 // find this NSEC, there is no need to look for a wildcard record
324 // that could possibly answer the question.
325 mDNSlocal mDNSBool NSECAnswersENT(const ResourceRecord *const rr, domainname *qname)
326 {
327     const domainname *oname = rr->name;
328     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
329     const domainname *nxt = (const domainname *)&rdb->data;
330     int ret;
331     int subdomain;
332
333     // Is the owner name smaller than qname?
334     ret = DNSSECCanonicalOrder(oname, qname, mDNSNULL);
335     if (ret < 0)
336     {
337         // Is the next domain field a subdomain of qname ?
338         ret = DNSSECCanonicalOrder(nxt, qname, &subdomain);
339         if (subdomain)
340         {
341             if (ret <= 0)
342             {
343                 LogMsg("NSECAnswersENT: ERROR!! DNSSECCanonicalOrder subdomain set "
344                        " qname %##s, NSEC %##s", qname->c, rr->name->c);
345             }
346             return mDNStrue;
347         }
348     }
349     return mDNSfalse;
350 }
351
352 mDNSlocal const domainname *NSECClosestEncloser(ResourceRecord *rr, domainname *qname)
353 {
354     const domainname *oname = rr->name;
355     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
356     const domainname *nxt = (const domainname *)&rdb->data;
357     int match1, match2;
358
359     match1 = CountLabelsMatch(oname, qname);
360     match2 = CountLabelsMatch(nxt, qname);
361     // Return the closest i.e the one that matches more labels
362     if (match1 > match2)
363         return SkipLeadingLabels(oname, CountLabels(oname) - match1);
364     else
365         return SkipLeadingLabels(nxt, CountLabels(nxt) - match2);
366 }
367
368 // Assumption: NSEC has been validated outside of this function
369 //
370 // Does the name exist given the name and NSEC rr ?
371 //
372 // Returns -1 if it is an inappropriate nsec
373 // Returns 1 if the name exists
374 // Returns 0 if the name does not exist
375 //
376 mDNSlocal int NSECNameExists(mDNS *const m, ResourceRecord *rr, domainname *name, mDNSu16 qtype)
377 {
378     const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
379     const domainname *nxt = (const domainname *)&rdb->data;
380     const domainname *oname = rr->name; // owner name
381     int ret1, subdomain1;
382     int ret2, subdomain2;
383     int ret3, subdomain3;
384
385     ret1 = DNSSECCanonicalOrder(oname, name, &subdomain1);
386     if (ret1 > 0)
387     {
388         LogDNSSEC("NSECNameExists: owner name %##s is bigger than name %##s", oname->c, name->c);
389         return -1;
390     }
391
392     // Section 4.1 of draft-ietf-dnsext-dnssec-bis-updates-14:
393     //
394     //   Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume non-
395     //   existence of any RRs below that zone cut, which include all RRs at
396     //   that (original) owner name other than DS RRs, and all RRs below that
397     //   owner name regardless of type.
398     //
399     // This also implies that we can't use the child side NSEC for DS question.
400
401     if (!ret1)
402     {
403         mDNSBool soa = RRAssertsExistence(rr, kDNSType_SOA);
404         mDNSBool ns = RRAssertsExistence(rr, kDNSType_NS);
405
406         // We are here because the owner name is the same as "name". Make sure the
407         // NSEC has the right NS and SOA bits set.
408         if (qtype != kDNSType_DS && ns && !soa)
409         {
410             LogDNSSEC("NSECNameExists: Parent side NSEC %s can't be used for question %##s (%s)",
411                       RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
412             return -1;
413         }
414         else if (qtype == kDNSType_DS && soa)
415         {
416             LogDNSSEC("NSECNameExists: Child side NSEC %s can't be used for question %##s (%s)",
417                       RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
418             return -1;
419         }
420         LogDNSSEC("NSECNameExists: owner name %##s is same as name %##s", oname->c, name->c);
421         return 1;
422     }
423
424     // If the name is a.b.com and NSEC's owner name is b.com i.e., a subdomain
425     // and nsec comes from the parent (NS is set and SOA is not set), then this
426     // NSEC can't be used for names below the owner name.
427     //
428     // Similarly if DNAME is set, we can't use it here. See RFC2672-bis-dname
429     // appendix.
430     if (subdomain1 && (RRAssertsExistence(rr, kDNSType_DNAME) ||
431                        (RRAssertsNonexistence(rr, kDNSType_SOA) && RRAssertsExistence(rr, kDNSType_NS))))
432     {
433         LogDNSSEC("NSECNameExists: NSEC %s comes from the parent, can't use it here",
434                   RRDisplayString(m, rr));
435         return -1;
436     }
437
438     // At this stage, we know that name is greater than the owner name and
439     // the nsec is not from the parent side.
440     //
441     // Compare with the next field in the nsec.
442     //
443     ret2 = DNSSECCanonicalOrder(name, nxt, &subdomain2);
444
445     // Exact match with the nsec next name
446     if (!ret2)
447     {
448         LogDNSSEC("NSECNameExists: name %##s is same as nxt name %##s", name->c, nxt->c);
449         return 1;
450     }
451
452     ret3 = DNSSECCanonicalOrder(oname, nxt, &subdomain3);
453
454     if (!ret3)
455     {
456         // Pathological case of a single name in the domain. This means only the
457         // apex of the zone itself exists. Nothing below it. "subdomain2" indicates
458         // that name is a subdmain of "next" and hence below the zone.
459         if (subdomain2)
460         {
461             LogDNSSEC("NSECNameExists: owner name %##s subdomain of nxt name %##s", oname->c, nxt->c);
462             return 0;
463         }
464         else
465         {
466             LogDNSSEC("NSECNameExists: Single name in zone, owner name %##s is same as nxt name %##s", oname->c, nxt->c);
467             return -1;
468         }
469     }
470
471     if (ret3 < 0)
472     {
473         // Regular NSEC in the zone. Make sure that the "name" lies within
474         // oname and next. oname < name and name < next
475         if (ret1 < 0 && ret2 < 0)
476         {
477             LogDNSSEC("NSECNameExists: Normal NSEC name %##s lies within owner %##s and nxt name %##s",
478                       name->c, oname->c, nxt->c);
479             return 0;
480         }
481         else
482         {
483             LogDNSSEC("NSECNameExists: Normal NSEC name %##s does not lie within owner %##s and nxt name %##s",
484                       name->c, oname->c, nxt->c);
485             return -1;
486         }
487     }
488     else
489     {
490         // Last NSEC in the zone. The "next" is pointing to the apex. All names
491         // should be a subdomain of that and the name should be bigger than
492         // oname
493         if (ret1 < 0 && subdomain2)
494         {
495             LogDNSSEC("NSECNameExists: Last NSEC name %##s lies within owner %##s and nxt name %##s",
496                       name->c, oname->c, nxt->c);
497             return 0;
498         }
499         else
500         {
501             LogDNSSEC("NSECNameExists: Last NSEC name %##s does not lie within owner %##s and nxt name %##s",
502                       name->c, oname->c, nxt->c);
503             return -1;
504         }
505     }
506
507     LogDNSSEC("NSECNameExists: NSEC %s did not match any case", RRDisplayString(m, rr));
508     return -1;
509 }
510
511 // If the answer was result of a wildcard match, then this function proves
512 // that a proper wildcard was used to answer the question and that the
513 // original name does not exist
514 mDNSexport void WildcardAnswerProof(mDNS *const m, DNSSECVerifier *dv)
515 {
516     CacheRecord *ncr;
517     CacheRecord **rp;
518     const domainname *ce;
519     DNSQuestion q;
520     CacheRecord **nsec3 = mDNSNULL;
521
522     LogDNSSEC("WildcardAnswerProof: Question %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
523     //
524     // RFC 4035: Section 3.1.3.3
525     //
526     // 1) We used a wildcard because the qname does not exist, so verify
527     //    that the qname does not exist
528     //
529     // 2) Is the wildcard the right one ?
530     //
531     // Unfortunately, this is not well explained in that section. Refer to
532     // RFC 5155 section 7.2.6.
533
534     // Walk the list of nsecs we received and see if they prove that
535     // the name does not exist
536
537     mDNSPlatformMemZero(&q, sizeof(DNSQuestion));
538     q.ThisQInterval = -1;
539     InitializeQuestion(m, &q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL);
540
541     ncr = NSECParentForQuestion(m, &q);
542     if (!ncr)
543     {
544         LogMsg("WildcardAnswerProof: Can't find NSEC Parent for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
545         goto error;
546     }
547     else
548     {
549         LogDNSSEC("WildcardAnswerProof: found %s", CRDisplayString(m, ncr));
550     }
551     rp = &(ncr->nsec);
552     while (*rp)
553     {
554         if ((*rp)->resrec.rrtype == kDNSType_NSEC)
555         {
556             CacheRecord *cr = *rp;
557             if (!NSECNameExists(m, &cr->resrec, &dv->origName, dv->origType))
558                 break;
559         }
560         else if ((*rp)->resrec.rrtype == kDNSType_NSEC3)
561         {
562             nsec3 = rp;
563         }
564         rp=&(*rp)->next;
565     }
566     if (!(*rp))
567     {
568         mDNSBool ret = mDNSfalse;
569         if (nsec3)
570         {
571             ret = NSEC3WildcardAnswerProof(m, ncr, dv);
572         }
573         if (!ret)
574         {
575             LogDNSSEC("WildcardAnswerProof: NSEC3 wildcard proof failed for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
576             goto error;
577         }
578         rp = nsec3;
579     }
580     else
581     {
582         ce = NSECClosestEncloser(&((*rp)->resrec), &dv->origName);
583         if (!ce)
584         {
585             LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser NULL for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
586             goto error;
587         }
588         if (!SameDomainName(ce, dv->wildcardName))
589         {
590             LogMsg("WildcardAnswerProof: ERROR!! Closest Encloser %##s does not match wildcard name %##s", q.qname.c, dv->wildcardName->c);
591             goto error;
592         }
593     }
594
595     VerifyNSEC(m, &((*rp)->resrec), mDNSNULL, dv, ncr, mDNSNULL);
596     return;
597 error:
598     dv->DVCallback(m, dv, DNSSEC_Bogus);
599 }
600
601 // We have a NSEC. Need to see if it proves that NODATA exists for the given name. Note that this
602 // function does not prove anything as proof may require more than one NSEC and this function
603 // processes only one NSEC at a time.
604 //
605 // Returns mDNSfalse if the NSEC does not prove the NODATA error
606 // Returns mDNStrue if the NSEC proves the NODATA error
607 //
608 mDNSlocal mDNSBool NSECNoDataError(mDNS *const m, ResourceRecord *rr, domainname *name, mDNSu16 qtype, domainname **wildcard)
609 {
610     const domainname *oname = rr->name; // owner name
611
612     *wildcard = mDNSNULL;
613     // RFC 4035
614     //
615     // section 3.1.3.1 : Name matches. Prove that the type does not exist and also CNAME is
616     // not set as in that case CNAME should have been returned ( CNAME part is mentioned in
617     // section 4.3 of dnssec-bis-updates.) Without the CNAME check, a positive response can
618     // be converted to a NODATA/NOERROR response.
619     //
620     // section 3.1.3.4 : No exact match for the name but there is a wildcard that could match
621     // the name but not the type. There are two NSECs in this case. One of them is a wildcard
622     // NSEC and another NSEC proving that the qname does not exist. We are called with one
623     // NSEC at a time. We return what we matched and the caller should decide whether all
624     // conditions are met for the proof.
625     if (SameDomainName(oname, name))
626     {
627         mDNSBool soa = RRAssertsExistence(rr, kDNSType_SOA);
628         mDNSBool ns = RRAssertsExistence(rr, kDNSType_NS);
629         if (qtype != kDNSType_DS)
630         {
631             // For non-DS type questions, we don't want to use the parent side records to
632             // answer it
633             if (ns && !soa)
634             {
635                 LogDNSSEC("NSECNoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)",
636                           RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
637                 return mDNSfalse;
638             }
639         }
640         else
641         {
642             if (soa)
643             {
644                 LogDNSSEC("NSECNoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)",
645                           RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
646                 return mDNSfalse;
647             }
648         }
649         if (RRAssertsExistence(rr, qtype) || RRAssertsExistence(rr, kDNSType_CNAME))
650         {
651             LogMsg("NSECNoDataError: ERROR!! qtype %s exists in %s", DNSTypeName(qtype), RRDisplayString(m, rr));
652             return mDNSfalse;
653         }
654         LogDNSSEC("NSECNoDataError: qype %s does not exist in %s", DNSTypeName(qtype), RRDisplayString(m, rr));
655         return mDNStrue;
656     }
657     else
658     {
659         // Name does not exist. Before we check for a wildcard match, make sure that
660         // this is not an ENT.
661         if (NSECAnswersENT(rr, name))
662         {
663             LogDNSSEC("NSECNoDataError: name %##s exists %s", name->c, RRDisplayString(m, rr));
664             return mDNSfalse;
665         }
666
667         // Wildcard check. If this is a wildcard NSEC, then check to see if we could
668         // have answered the question using this wildcard and it should not have the
669         // "qtype" passed in with its bitmap.
670         //
671         // See RFC 4592, on how wildcards are used to synthesize answers. Find the
672         // closest encloser and the qname should be a subdomain i.e if the wildcard
673         // is *.x.example, x.example is the closest encloser and the qname should be
674         // a subdomain e.g., y.x.example or z.y.x.example and so on.
675         if (oname->c[0] == 1 && oname->c[1] == '*')
676         {
677             int s;
678             const domainname *ce = SkipLeadingLabels(oname, 1);
679
680             DNSSECCanonicalOrder(name, ce, &s);
681             if (s)
682             {
683                 if (RRAssertsExistence(rr, qtype) || RRAssertsExistence(rr, kDNSType_CNAME))
684                 {
685                     LogMsg("NSECNoDataError: ERROR!! qtype %s exists in wildcard %s", DNSTypeName(qtype), RRDisplayString(m, rr));
686                     return mDNSfalse;
687                 }
688                 if (qtype == kDNSType_DS && RRAssertsExistence(rr, kDNSType_SOA))
689                 {
690                     LogDNSSEC("NSECNoDataError: Child side wildcard NSEC %s, can't use for parent qname %##s (%s)",
691                               RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
692                     return mDNSfalse;
693                 }
694                 else if (qtype != kDNSType_DS && RRAssertsNonexistence(rr, kDNSType_SOA) &&
695                     RRAssertsExistence(rr, kDNSType_NS))
696                 {
697                     // Don't use the parent side record for this
698                     LogDNSSEC("NSECNoDataError: Parent side wildcard NSEC %s, can't use for child qname %##s (%s)",
699                               RRDisplayString(m, rr), name->c, DNSTypeName(qtype));
700                     return mDNSfalse;
701                 }
702                 *wildcard = (domainname *)ce;
703                 LogDNSSEC("NSECNoDataError: qtype %s does not exist in wildcard %s", DNSTypeName(qtype), RRDisplayString(m, rr));
704                 return mDNStrue;
705             }
706         }
707         return mDNSfalse;
708     }
709 }
710
711 mDNSexport void NoDataNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
712 {
713     RRVerifier *rv;
714     DNSSECVerifier *pdv;
715     CacheRecord *ncr;
716
717     LogDNSSEC("NoDataNSECCallback: called");
718     if (!dv->parent)
719     {
720         LogMsg("NoDataNSECCCallback: no parent DV");
721         FreeDNSSECVerifier(m, dv);
722         return;
723     }
724
725     if (dv->ac)
726     {
727         // Before we free the "dv", we need to update the
728         // parent with our AuthChain information
729         UpdateParent(dv);
730     }
731
732     pdv = dv->parent;
733
734     // We don't care about the "dv" that was allocated in VerifyNSEC
735     // as it just verifies one of the nsecs. Get the original verifier and
736     // verify the other NSEC like we did the first time.
737     dv->parent = mDNSNULL;
738     FreeDNSSECVerifier(m, dv);
739
740     if (status != DNSSEC_Secure)
741     {
742         goto error;
743     }
744
745     ncr = NSECParentForQuestion(m, &pdv->q);
746     if (!ncr)
747     {
748         LogMsg("NoDataNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv->q.qname.c, DNSTypeName(pdv->q.qtype));
749         goto error;
750     }
751     rv = pdv->pendingNSEC;
752     pdv->pendingNSEC = rv->next;
753     // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one,
754     // we don't need to come back here; let the regular NSECCallback call the original callback.
755     rv->next = mDNSNULL;
756     LogDNSSEC("NoDataNSECCallback: Verifying %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype));
757     if (!pdv->pendingNSEC)
758         VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, mDNSNULL);
759     else
760         VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, NoDataNSECCallback);
761     return;
762
763 error:
764     pdv->DVCallback(m, pdv, status);
765 }
766
767 mDNSexport void NameErrorNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
768 {
769     RRVerifier *rv;
770     DNSSECVerifier *pdv;
771     CacheRecord *ncr;
772
773     LogDNSSEC("NameErrorNSECCallback: called");
774     if (!dv->parent)
775     {
776         LogMsg("NameErrorNSECCCallback: no parent DV");
777         FreeDNSSECVerifier(m, dv);
778         return;
779     }
780
781     if (dv->ac)
782     {
783         // Before we free the "dv", we need to update the
784         // parent with our AuthChain information
785         UpdateParent(dv);
786     }
787
788     pdv = dv->parent;
789     // We don't care about the "dv" that was allocated in VerifyNSEC
790     // as it just verifies one of the nsecs. Get the original verifier and
791     // verify the other NSEC like we did the first time.
792     dv->parent = mDNSNULL;
793     FreeDNSSECVerifier(m, dv);
794
795     if (status != DNSSEC_Secure)
796     {
797         goto error;
798     }
799
800     ncr = NSECParentForQuestion(m, &pdv->q);
801     if (!ncr)
802     {
803         LogMsg("NameErrorNSECCallback: Can't find NSEC Parent for %##s (%s)", pdv->q.qname.c, DNSTypeName(pdv->q.qtype));
804         goto error;
805     }
806     rv = pdv->pendingNSEC;
807     pdv->pendingNSEC = rv->next;
808     // We might have more than one pendingNSEC in the case of NSEC3. If this is the last one,
809     // we don't need to come back here; let the regular NSECCallback call the original callback.
810     rv->next = mDNSNULL;
811     LogDNSSEC("NameErrorNSECCallback: Verifying %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype));
812     if (!pdv->pendingNSEC)
813         VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, mDNSNULL);
814     else
815         VerifyNSEC(m, mDNSNULL, rv, pdv, ncr, NameErrorNSECCallback);
816
817     return;
818
819 error:
820     pdv->DVCallback(m, pdv, status);
821 }
822
823 // We get a NODATA error with no records in answer section. This proves
824 // that qname does not exist.
825 mDNSlocal void NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
826 {
827     CacheRecord **rp;
828     domainname *wildcard = mDNSNULL;
829     const domainname *ce = mDNSNULL;
830     ResourceRecord *nsec_wild = mDNSNULL;
831     ResourceRecord *nsec_noname = mDNSNULL;
832
833     // NODATA Error could mean two things. The name exists with no type or there is a
834     // wildcard that matches the name but no type. This is done by NSECNoDataError.
835     //
836     // If it is the case of wildcard, there are two NSECs. One is the wildcard NSEC and
837     // the other NSEC to prove that there is no other closer match.
838
839     wildcard = mDNSNULL;
840     rp = &(ncr->nsec);
841     while (*rp)
842     {
843         if ((*rp)->resrec.rrtype == kDNSType_NSEC)
844         {
845             CacheRecord *cr = *rp;
846             if (NSECNoDataError(m, &cr->resrec, &dv->q.qname, dv->q.qtype, &wildcard))
847             {
848                 if (wildcard)
849                 {
850                     dv->flags |= WILDCARD_PROVES_NONAME_EXISTS;
851                     LogDNSSEC("NoDataProof: NSEC %s proves NODATA error for %##s (%s)",
852                               RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype));
853                 }
854                 else
855                 {
856                     dv->flags |= NSEC_PROVES_NOTYPE_EXISTS;
857                     LogDNSSEC("NoDataProof: NSEC %s proves NOTYPE error for %##s (%s)",
858                               RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype));
859                 }
860                 nsec_wild = &cr->resrec;
861             }
862             if (!NSECNameExists(m, &cr->resrec, &dv->q.qname, dv->q.qtype))
863             {
864                 LogDNSSEC("NoDataProof: NSEC %s proves that  name %##s (%s) does not exist",
865                           RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype));
866                 // If we have a wildcard, then we should check to see if the closest
867                 // encloser is the same as the wildcard.
868                 ce = NSECClosestEncloser(&cr->resrec, &dv->q.qname);
869                 dv->flags |= NSEC_PROVES_NONAME_EXISTS;
870                 nsec_noname = &cr->resrec;
871             }
872         }
873         rp=&(*rp)->next;
874     }
875     if (!nsec_noname && !nsec_wild)
876     {
877         LogDNSSEC("NoDataProof: No valid NSECs for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
878         goto error;
879     }
880     // If the type exists, then we have to verify just that NSEC
881     if (!(dv->flags & NSEC_PROVES_NOTYPE_EXISTS))
882     {
883         // If we have a wildcard, then we should have a "ce" which matches the wildcard
884         // If we don't have a wildcard, then we should have proven that the name does not
885         // exist which means we would have set the "ce".
886         if (wildcard && !ce)
887         {
888             LogMsg("NoDataProof: Cannot prove that the name %##s (%s) does not exist", dv->q.qname.c, DNSTypeName(dv->q.qtype));
889             goto error;
890         }
891         if (wildcard && !SameDomainName(wildcard, ce))
892         {
893             LogMsg("NoDataProof: wildcard %##s does not match closest encloser %##s", wildcard->c, ce->c);
894             goto error;
895         }
896         // If a single NSEC can prove both, then we just have validate that one NSEC.
897         if (nsec_wild == nsec_noname)
898         {
899             nsec_noname = mDNSNULL;
900             dv->flags &= ~NSEC_PROVES_NONAME_EXISTS;
901         }
902     }
903
904     if ((dv->flags & (WILDCARD_PROVES_NONAME_EXISTS|NSEC_PROVES_NONAME_EXISTS)) ==
905         (WILDCARD_PROVES_NONAME_EXISTS|NSEC_PROVES_NONAME_EXISTS))
906     {
907         mStatus status;
908         RRVerifier *r = AllocateRRVerifier(nsec_noname, &status);
909         if (!r) goto error;
910         // First verify wildcard NSEC and then when we are done, we
911         // will verify the noname nsec
912         dv->pendingNSEC = r;
913         LogDNSSEC("NoDataProof: Verifying wild and noname %s", nsec_wild ? RRDisplayString(m, nsec_wild) : "NULL");
914         VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, NoDataNSECCallback);
915     }
916     else if ((dv->flags & WILDCARD_PROVES_NONAME_EXISTS) ||
917              (dv->flags & NSEC_PROVES_NOTYPE_EXISTS))
918     {
919         LogDNSSEC("NoDataProof: Verifying wild %s", nsec_wild ? RRDisplayString(m, nsec_wild) : "NULL");
920         VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, mDNSNULL);
921     }
922     else if (dv->flags & NSEC_PROVES_NONAME_EXISTS)
923     {
924         LogDNSSEC("NoDataProof: Verifying noname %s", nsec_noname ? RRDisplayString(m, nsec_noname) : "NULL");
925         VerifyNSEC(m, nsec_noname, mDNSNULL, dv, ncr, mDNSNULL);
926     }
927     return;
928 error:
929     LogDNSSEC("NoDataProof: Error return");
930     dv->DVCallback(m, dv, DNSSEC_Bogus);
931 }
932
933 mDNSlocal mDNSBool NSECNoWildcard(mDNS *const m, ResourceRecord *rr, domainname *qname, mDNSu16 qtype)
934 {
935     const domainname *ce;
936     domainname wild;
937
938     // If the query name is c.x.w.example and if the name does not exist, we should get
939     // get a nsec back that looks something like this:
940     //
941     //      w.example NSEC a.w.example
942     //
943     // First, we need to get the closest encloser which in this case is w.example. Wild
944     // card synthesis works by finding the closest encloser first and then look for
945     // a "*" label (assuming * label does not appear in the question). If it does not
946     // exists, it would return the NSEC at that name. And the wildcard name at the
947     // closest encloser "*.w.example" would be covered by such an NSEC. (Appending "*"
948     // makes it bigger than w.example and "* is smaller than "a" for the above NSEC)
949     //
950     ce = NSECClosestEncloser(rr, qname);
951     if (!ce) { LogMsg("NSECNoWildcard: No closest encloser for rr %s, qname %##s (%s)", qname->c, DNSTypeName(qtype)); return mDNSfalse; }
952
953     wild.c[0] = 1;
954     wild.c[1] = '*';
955     wild.c[2] = 0;
956     if (!AppendDomainName(&wild, ce))
957     {
958         LogMsg("NSECNoWildcard: ERROR!! Can't append domainname closest encloser name %##s, qname %##s (%s)", ce->c, qname->c, DNSTypeName(qtype));
959         return mDNSfalse;
960     }
961     if (NSECNameExists(m, rr, &wild, qtype) != 0)
962     {
963         LogDNSSEC("NSECNoWildcard: Wildcard name %##s exists or not valid qname %##s (%s)", wild.c, qname->c, DNSTypeName(qtype));
964         return mDNSfalse;
965     }
966     LogDNSSEC("NSECNoWildcard: Wildcard name %##s does not exist for record %s, qname %##s (%s)", wild.c,
967               RRDisplayString(m, rr), qname->c, DNSTypeName(qtype));
968     return mDNStrue;
969 }
970
971 // We get a NXDOMAIN error with no records in answer section. This proves
972 // that qname does not exist.
973 mDNSlocal void NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
974 {
975     CacheRecord **rp;
976     ResourceRecord *nsec_wild = mDNSNULL;
977     ResourceRecord *nsec_noname = mDNSNULL;
978     mStatus status;
979
980     // NXDOMAIN Error. We need to prove that the qname does not exist and there
981     // is no wildcard that can be used to answer the question.
982
983     rp = &(ncr->nsec);
984     while (*rp)
985     {
986         if ((*rp)->resrec.rrtype == kDNSType_NSEC)
987         {
988             CacheRecord *cr = *rp;
989             if (!NSECNameExists(m, &cr->resrec, &dv->q.qname, dv->q.qtype))
990             {
991                 LogDNSSEC("NameErrorProof: NSEC %s proves name does not exist for %##s (%s)",
992                           RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype));
993                 // If we have a wildcard, then we should check to see if the closest
994                 // encloser is the same as the wildcard.
995                 dv->flags |= NSEC_PROVES_NONAME_EXISTS;
996                 nsec_noname = &cr->resrec;
997             }
998             if (NSECNoWildcard(m, &cr->resrec, &dv->q.qname, dv->q.qtype))
999             {
1000                 dv->flags |= WILDCARD_PROVES_NONAME_EXISTS;
1001                 nsec_wild = &cr->resrec;
1002                 LogDNSSEC("NameErrorProof: NSEC %s proves wildcard cannot answer question for %##s (%s)",
1003                           RRDisplayString(m, &(*rp)->resrec), dv->q.qname.c, DNSTypeName(dv->q.qtype));
1004             }
1005         }
1006         rp=&(*rp)->next;
1007     }
1008     if (!nsec_noname || !nsec_wild)
1009     {
1010         LogMsg("NameErrorProof: Proof failed for %##s (%s) noname %p, wild %p", dv->q.qname.c, DNSTypeName(dv->q.qtype), nsec_noname, nsec_wild);
1011         goto error;
1012     }
1013
1014     // First verify wildcard NSEC and then when we are done, we will verify the noname nsec.
1015     // Sometimes a single NSEC can prove both that the "qname" does not exist and a wildcard
1016     // could not have produced qname. These are a few examples where this can happen.
1017     //
1018     // 1. If the zone is example.com and you look up *.example.com and if there are no wildcards,
1019     //    you will get a NSEC back "example.com NSEC a.example.com". This proves that both the
1020     //    name does not exist and *.example.com also does not exist
1021     //
1022     // 2. If the zone is example.com and it has a record like this:
1023     //
1024     //                                  example.com NSEC d.example.com
1025     //
1026     // any name you lookup in between like a.example.com,b.example.com etc. you will get a single
1027     // NSEC back. In that case we just have to verify only once.
1028     //
1029     if (nsec_wild != nsec_noname)
1030     {
1031         RRVerifier *r = AllocateRRVerifier(nsec_noname, &status);
1032         if (!r) goto error;
1033         dv->pendingNSEC = r;
1034         LogDNSSEC("NoDataProof: Verifying wild %s", RRDisplayString(m, nsec_wild));
1035         VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, NameErrorNSECCallback);
1036     }
1037     else
1038     {
1039         LogDNSSEC("NoDataProof: Verifying only one %s", RRDisplayString(m, nsec_wild));
1040         VerifyNSEC(m, nsec_wild, mDNSNULL, dv, ncr, mDNSNULL);
1041     }
1042     return;
1043 error:
1044     dv->DVCallback(m, dv, DNSSEC_Bogus);
1045 }
1046
1047 mDNSexport CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype)
1048 {
1049     CacheGroup *cg;
1050     CacheRecord *cr;
1051     mDNSu32 namehash;
1052
1053     namehash = DomainNameHashValue(name);
1054
1055     cg = CacheGroupForName(m, namehash, name);
1056     if (!cg)
1057     {
1058         LogDNSSEC("NSECRecordForName: cg NULL for %##s", name);
1059         return mDNSNULL;
1060     }
1061     for (cr = cg->members; cr; cr = cr->next)
1062     {
1063         if (cr->resrec.RecordType == kDNSRecordTypePacketNegative && cr->resrec.rrtype == qtype)
1064         {
1065             CacheRecord *ncr;
1066             for (ncr = cr->nsec; ncr; ncr = ncr->next)
1067             {
1068                 if (ncr->resrec.rrtype == kDNSType_NSEC &&
1069                     SameDomainName(ncr->resrec.name, name))
1070                 {
1071                     // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit
1072                     // should be absent
1073                     if (RRAssertsExistence(&ncr->resrec, kDNSType_SOA) ||
1074                         RRAssertsExistence(&ncr->resrec, kDNSType_DS))
1075                     {
1076                         LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but DS or SOA bit set", CRDisplayString(m, ncr), name,
1077                             DNSTypeName(qtype));
1078                         return mDNSNULL;
1079                     }
1080                     // Section 2.3 of RFC 4035 states that:
1081                     //
1082                     // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST
1083                     // have an NSEC resource record. 
1084                     //
1085                     // So, if we have an NSEC record matching the question name with the NS bit set,
1086                     // then this is a delegation.
1087                     //
1088                     if (RRAssertsExistence(&ncr->resrec, kDNSType_NS))
1089                     {
1090                         LogDNSSEC("NSECRecordForName: found record %s for %##s (%s)", CRDisplayString(m, ncr), name, DNSTypeName(qtype));
1091                         return ncr;
1092                     }
1093                     else
1094                     {
1095                         LogDNSSEC("NSECRecordForName: found record %s for %##s (%s), but NS bit is not set", CRDisplayString(m, ncr), name,
1096                             DNSTypeName(qtype));
1097                         return mDNSNULL;
1098                     }
1099                 }
1100             }
1101         }
1102     }
1103     return mDNSNULL;
1104 }
1105
1106 mDNSlocal void StartInsecureProof(mDNS * const m, DNSSECVerifier *dv)
1107 {
1108     domainname trigger;
1109     DNSSECVerifier *prevdv = mDNSNULL;
1110
1111     // Remember the name that triggered the insecure proof
1112     AssignDomainName(&trigger, &dv->q.qname);
1113     while (dv->parent)
1114     {
1115         prevdv = dv;
1116         dv = dv->parent;
1117     }
1118     if (prevdv)
1119     {
1120         prevdv->parent = mDNSNULL;
1121         FreeDNSSECVerifier(m, prevdv);
1122     }
1123     // For Optional DNSSEC, we are opportunistically verifying dnssec. We don't care
1124     // if something results in bogus as we still want to deliver results to the
1125     // application e.g., CNAME processing results in bogus because the path is broken,
1126     // but we still want to follow CNAMEs so that we can deliver the final results to
1127     // the application.
1128     if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL)
1129     {
1130         LogDNSSEC("StartInsecureProof: Aborting insecure proof for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
1131         dv->DVCallback(m, dv, DNSSEC_Bogus);
1132         return;
1133     }
1134
1135     LogDNSSEC("StartInsecureProof for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
1136     // Don't start the insecure proof again after we finish the one that we start here by
1137     // setting InsecureProofDone.
1138     dv->InsecureProofDone = 1;
1139     ProveInsecure(m, dv, mDNSNULL, &trigger);
1140     return;
1141 }
1142
1143 mDNSexport void ValidateWithNSECS(mDNS *const m, DNSSECVerifier *dv, CacheRecord *cr)
1144 {
1145     LogDNSSEC("ValidateWithNSECS: called for %s", CRDisplayString(m, cr));
1146
1147     // If we are encountering a break in the chain of trust i.e., NSEC/NSEC3s for
1148     // DS query, then do the insecure proof. This is important because if we
1149     // validate these NSECs normally and prove that they are "secure", we will
1150     // end up delivering the secure result to the original question where as
1151     // these NSEC/NSEC3s actually prove that DS does not exist and hence insecure.
1152     //
1153     // This break in the chain can happen after we have partially validated the
1154     // path (dv->ac is non-NULL) or the first time (dv->ac is NULL) after we
1155     // fetched the DNSKEY (dv->key is non-NULL). We don't want to do this
1156     // if we have just started the non-existence proof (dv->key is NULL) as
1157     // it does not indicate a break in the chain of trust.
1158     //
1159     // If we are already doing a insecurity proof, don't start another one. In
1160     // the case of NSECs, it is possible that insecurity proof starts and it
1161     // gets NSECs and as part of validating that we receive more NSECS in which
1162     // case we don't want to start another insecurity proof.
1163     if (dv->ValidationRequired != DNSSEC_VALIDATION_INSECURE &&
1164         (!dv->parent || dv->parent->ValidationRequired != DNSSEC_VALIDATION_INSECURE))
1165     {
1166          if ((dv->ac && dv->q.qtype == kDNSType_DS) ||
1167              (!dv->ac && dv->key && dv->q.qtype == kDNSType_DS))
1168         {
1169             LogDNSSEC("ValidateWithNSECS: Starting insecure proof: name %##s ac %p, key %p, parent %p", dv->q.qname.c,
1170                 dv->ac, dv->key, dv->parent);
1171             StartInsecureProof(m, dv);
1172             return;
1173         }
1174     }
1175     // "parent" is set when we are validating a NSEC and we should not be here in
1176     // the normal case when parent is set. For example, we are looking up the A
1177     // record for www.example.com and following can happen.
1178     //
1179     // a) Record does not exist and we get a NSEC
1180     // b) While validating (a), we get an NSEC for the first DS record that we look up
1181     // c) Record exists but we get NSECs for the first DS record
1182     // d) We are able to partially validate (a) or (b), but we get NSECs somewhere in
1183     //    the chain
1184     //
1185     // For (a), parent is not set as we are not validating the NSEC yet. Hence we would
1186     // start the validation now.
1187     //
1188     // For (b), the parent is set, but should be caught by the above "if" block because we 
1189     // should have gotten the DNSKEY at least. In the case of nested insecurity proof,
1190     // we would end up here and fail with bogus.
1191     //
1192     // For (c), the parent is not set and should be caught by the above "if" block because we 
1193     // should have gotten the DNSKEY at least.
1194     //
1195     // For (d), the above "if" block would catch it as "dv->ac" is non-NULL.
1196     // 
1197     // Hence, we should not come here in the normal case. Possible pathological cases are:
1198     // Insecure proof getting NSECs while validating NSECs, getting NSECs for DNSKEY for (c)
1199     // above etc.
1200     if (dv->parent)
1201     {
1202         LogDNSSEC("ValidateWithNSECS: dv parent set for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
1203         dv->DVCallback(m, dv, DNSSEC_Bogus);
1204         return;
1205     }
1206     if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
1207     {
1208         mDNSu8 rcode;
1209         CacheRecord *neg = cr->nsec;
1210         mDNSBool nsecs_seen = mDNSfalse;
1211
1212         while (neg)
1213         {
1214             // The list can only have NSEC or NSEC3s. This was checked when we added the
1215             // NSECs to the cache record.
1216             if (neg->resrec.rrtype == kDNSType_NSEC)
1217                 nsecs_seen = mDNStrue;
1218             LogDNSSEC("ValidateWithNSECS: NSECCached Record %s", CRDisplayString(m, neg));
1219             neg = neg->next;
1220         }
1221
1222         rcode = (mDNSu8)(cr->responseFlags.b[1] & kDNSFlag1_RC_Mask);
1223         if (rcode == kDNSFlag1_RC_NoErr)
1224         {
1225             if (nsecs_seen)
1226                 NoDataProof(m, dv, cr);
1227             else
1228                 NSEC3NoDataProof(m, dv, cr);
1229         }
1230         else if (rcode == kDNSFlag1_RC_NXDomain)
1231         {
1232             if (nsecs_seen)
1233                 NameErrorProof(m, dv, cr);
1234             else
1235                 NSEC3NameErrorProof(m, dv, cr);
1236         }
1237         else
1238         {
1239             LogDNSSEC("ValidateWithNSECS: Rcode %d invalid", rcode);
1240             dv->DVCallback(m, dv, DNSSEC_Bogus);
1241         }
1242     }
1243     else
1244     {
1245         LogMsg("ValidateWithNSECS: Not a valid cache record %s for NSEC proofs", CRDisplayString(m, cr));
1246         dv->DVCallback(m, dv, DNSSEC_Bogus);
1247         return;
1248     }
1249 }
1250
1251 #else // !DNSSEC_DISABLED
1252
1253 mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
1254 {
1255     (void)m;
1256     (void)crlist;
1257     (void)negcr;
1258     (void)rcode;
1259
1260     return mDNSfalse;
1261 }
1262
1263 #endif // !DNSSEC_DISABLED