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