]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/nsec3.c
mDNSResponder-576.30.4.tar.gz
[apple/mdnsresponder.git] / mDNSCore / nsec3.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 // nsec3.c: This file contains support functions to validate NSEC3 records for
20 // NODATA and NXDOMAIN error.
21 // ***************************************************************************
22
23 #include "mDNSEmbeddedAPI.h"
24 #include "DNSCommon.h"
25 #include "CryptoAlg.h"
26 #include "nsec3.h"
27 #include "nsec.h"
28
29 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
30 // and use the stub functions implemented later in this file.
31
32 #ifndef DNSSEC_DISABLED
33
34 typedef enum
35 {
36 NSEC3ClosestEncloser,
37 NSEC3Covers,
38 NSEC3CEProof
39 } NSEC3FindValues;
40
41 //#define NSEC3_DEBUG 1
42
43 #if NSEC3_DEBUG
44 mDNSlocal void PrintHash(mDNSu8 *digest, int digestlen, char *buffer, int buflen)
45 {
46 int length = 0;
47 for (int j = 0; j < digestlen; j++)
48 {
49 length += mDNS_snprintf(buffer+length, buflen-length-1, "%x", digest[j]);
50 }
51 }
52 #endif
53
54 mDNSlocal mDNSBool NSEC3OptOut(CacheRecord *cr)
55 {
56 const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
57 rdataNSEC3 *nsec3 = (rdataNSEC3 *)rdb->data;
58 return (nsec3->flags & NSEC3_FLAGS_OPTOUT);
59 }
60
61 mDNSlocal int NSEC3SameName(const mDNSu8 *name, int namelen, const mDNSu8 *nsecName, int nsecLen)
62 {
63 int i;
64
65 // Note: With NSEC3, the lengths should always be same.
66 if (namelen != nsecLen)
67 {
68 LogMsg("NSEC3SameName: ERROR!! namelen %d, nsecLen %d", namelen, nsecLen);
69 return ((namelen < nsecLen) ? -1 : 1);
70 }
71
72 for (i = 0; i < namelen; i++)
73 {
74 mDNSu8 ac = *name++;
75 mDNSu8 bc = *nsecName++;
76 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
77 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
78 if (ac != bc)
79 {
80 verbosedebugf("NSEC3SameName: returning ac %c, bc %c", ac, bc);
81 return ((ac < bc) ? -1 : 1);
82 }
83 }
84 return 0;
85 }
86
87 // Does the NSEC3 in "ncr" covers the "name" ?
88 // hashName is hash of the "name" and b32Name is the base32 encoded equivalent.
89 mDNSlocal mDNSBool NSEC3CoversName(mDNS *const m, CacheRecord *ncr, const mDNSu8 *hashName, int hashLen, const mDNSu8 *b32Name,
90 int b32len)
91 {
92 mDNSu8 *nxtName;
93 int nxtLength;
94 int ret, ret1, ret2;
95 const mDNSu8 b32nxtname[NSEC3_MAX_B32_LEN+1];
96 int b32nxtlen;
97
98 NSEC3Parse(&ncr->resrec, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
99
100 if (nxtLength != hashLen || ncr->resrec.name->c[0] != b32len)
101 return mDNSfalse;
102
103 // Compare the owner names and the "nxt" names.
104 //
105 // Owner name is base32 encoded and hence use the base32 encoded name b32name.
106 // nxt name is binary and hence use the binary value in hashName.
107 ret1 = NSEC3SameName(&ncr->resrec.name->c[1], ncr->resrec.name->c[0], b32Name, b32len);
108 ret2 = DNSMemCmp(nxtName, hashName, hashLen);
109
110 #if NSEC3_DEBUG
111 {
112 char nxtbuf1[50];
113 char nxtbuf2[50];
114
115 PrintHash(nxtName, nxtLength, nxtbuf1, sizeof(nxtbuf1));
116 PrintHash((mDNSu8 *)hashName, hashLen, nxtbuf2, sizeof(nxtbuf2));
117 LogMsg("NSEC3CoversName: Owner name %s, name %s", &ncr->resrec.name->c[1], b32Name);
118 LogMsg("NSEC3CoversName: Nxt hash name %s, name %s", nxtbuf1, nxtbuf2);
119 }
120 #endif
121
122 // "name" is greater than the owner name and smaller than nxtName. This also implies
123 // that nxtName > owner name implying that it is normal NSEC3.
124 if (ret1 < 0 && ret2 > 0)
125 {
126 LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Normal)", CRDisplayString(m, ncr), b32Name);
127 return mDNStrue;
128 }
129 // Need to compare the owner name and "nxt" to see if this is the last
130 // NSEC3 in the zone. Only the owner name is in base32 and hence we need to
131 // convert the nxtName to base32.
132 b32nxtlen = baseEncode((char *)b32nxtname, sizeof(b32nxtname), nxtName, nxtLength, ENC_BASE32);
133 if (!b32nxtlen)
134 {
135 LogDNSSEC("NSEC3CoversName: baseEncode of nxtName of %s failed", CRDisplayString(m, ncr));
136 return mDNSfalse;
137 }
138 if (b32len != b32nxtlen)
139 {
140 LogDNSSEC("NSEC3CoversName: baseEncode of nxtName for %s resulted in wrong length b32nxtlen %d, b32len %d",
141 CRDisplayString(m, ncr), b32len, b32nxtlen);
142 return mDNSfalse;
143 }
144 LogDNSSEC("NSEC3CoversName: Owner name %s, b32nxtname %s, ret1 %d, ret2 %d", &ncr->resrec.name->c[1], b32nxtname, ret1, ret2);
145
146 // If it is the last NSEC3 in the zone nxt < "name" and NSEC3SameName returns -1.
147 //
148 // - ret1 < 0 means "name > owner"
149 // - ret2 > 0 means "name < nxt"
150 //
151 // Note: We also handle the case of only NSEC3 in the zone where NSEC3SameName returns zero.
152 ret = NSEC3SameName(b32nxtname, b32nxtlen, &ncr->resrec.name->c[1], ncr->resrec.name->c[0]);
153 if (ret <= 0 &&
154 (ret1 < 0 || ret2 > 0))
155 {
156 LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Last), ret1 %d, ret2 %d", CRDisplayString(m, ncr), b32Name, ret1, ret2);
157 return mDNStrue;
158 }
159
160 return mDNSfalse;
161 }
162
163 // This function can be called with NSEC3ClosestEncloser, NSEC3Covers and NSEC3CEProof
164 //
165 // Passing in NSEC3ClosestEncloser means "find an exact match for the origName".
166 // Passing in NSEC3Covers means "find an NSEC3 that covers the origName".
167 //
168 // i.e., in both cases the nsec3 records are iterated to find the best match and returned.
169 // With NSEC3ClosestEncloser, as we are just looking for a name match, extra checks for
170 // the types being present or absent will not be checked.
171 //
172 // If NSEC3CEProof is passed, the name is tried as such first by iterating through all NSEC3s
173 // finding a ClosestEncloser or CloserEncloser and then one label skipped from the left and
174 // retried again till both the closest and closer encloser is found.
175 //
176 // ncr is the negative cache record that has the NSEC3 chain
177 // origName is the name for which we are trying to find the ClosestEncloser etc.
178 // closestEncloser and closerEncloser are the return values of the function
179 // ce is the closest encloser that will be returned if we find one
180 mDNSlocal mDNSBool NSEC3Find(mDNS *const m, NSEC3FindValues val, CacheRecord *ncr, domainname *origName, CacheRecord **closestEncloser,
181 CacheRecord **closerEncloser, const domainname **ce, mDNSu16 qtype)
182 {
183 int i;
184 int labelCount = CountLabels(origName);
185 CacheRecord *cr;
186 rdataNSEC3 *nsec3;
187
188 (void) qtype; // unused
189 // Pick the first NSEC for the iterations, salt etc.
190 for (cr = ncr->nsec; cr; cr = cr->next)
191 {
192 if (cr->resrec.rrtype == kDNSType_NSEC3)
193 {
194 const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
195 nsec3 = (rdataNSEC3 *)rdb->data;
196 break;
197 }
198 }
199 if (!cr)
200 {
201 LogMsg("NSEC3Find: cr NULL");
202 return mDNSfalse;
203 }
204
205 // Note: The steps defined in this function are for "NSEC3CEProof". As part of NSEC3CEProof,
206 // we need to find both the closestEncloser and closerEncloser which can also be found
207 // by passing NSEC3ClosestEncloser and NSEC3Covers respectively.
208 //
209 // Section 8.3 of RFC 5155.
210 // 1. Set SNAME=QNAME. Clear the flag.
211 //
212 // closerEncloser is the "flag". "name" below is SNAME.
213
214 if (closestEncloser)
215 {
216 *ce = mDNSNULL;
217 *closestEncloser = mDNSNULL;
218 }
219 if (closerEncloser)
220 *closerEncloser = mDNSNULL;
221
222 // If we are looking for a closestEncloser or a covering NSEC3, we don't have
223 // to truncate the name. For the give name, try to find the closest or closer
224 // encloser.
225 if (val != NSEC3CEProof)
226 {
227 labelCount = 0;
228 }
229
230 for (i = 0; i < labelCount + 1; i++)
231 {
232 int hlen;
233 const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
234 const domainname *name;
235 const mDNSu8 b32Name[NSEC3_MAX_B32_LEN+1];
236 int b32len;
237
238 name = SkipLeadingLabels(origName, i);
239 if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
240 {
241 LogMsg("NSEC3Find: NSEC3HashName failed for ##s", name->c);
242 continue;
243 }
244
245 b32len = baseEncode((char *)b32Name, sizeof(b32Name), (mDNSu8 *)hashName, hlen, ENC_BASE32);
246 if (!b32len)
247 {
248 LogMsg("NSEC3Find: baseEncode of name %##s failed", name->c);
249 continue;
250 }
251
252
253 for (cr = ncr->nsec; cr; cr = cr->next)
254 {
255 const domainname *nsecZone;
256 int result, subdomain;
257
258 if (cr->resrec.rrtype != kDNSType_NSEC3)
259 continue;
260
261 nsecZone = SkipLeadingLabels(cr->resrec.name, 1);
262 if (!nsecZone)
263 {
264 LogMsg("NSEC3Find: SkipLeadingLabel failed for %s, current name %##s",
265 CRDisplayString(m, cr), name->c);
266 continue;
267 }
268
269 // NSEC3 owner names are formed by hashing the owner name and then appending
270 // the zone name to it. If we skip the first label, the rest should be
271 // the zone name. See whether it is the subdomain of the name we are looking
272 // for.
273 result = DNSSECCanonicalOrder(origName, nsecZone, &subdomain);
274
275 // The check can't be a strict subdomain check. When NSEC3ClosestEncloser is
276 // passed in, there can be an exact match. If it is a subdomain or an exact
277 // match, we should continue with the proof.
278 if (!(subdomain || !result))
279 {
280 LogMsg("NSEC3Find: NSEC3 %s not a subdomain of %##s, result %d", CRDisplayString(m, cr),
281 origName->c, result);
282 continue;
283 }
284
285 // 2.1) If there is no NSEC3 RR in the response that matches SNAME
286 // (i.e., an NSEC3 RR whose owner name is the same as the hash of
287 // SNAME, prepended as a single label to the zone name), clear
288 // the flag.
289 //
290 // Note: We don't try to determine the actual zone name. We know that
291 // the labels following the hash (nsecZone) is the ancestor and we don't
292 // know where the zone cut is. Hence, we verify just the hash to be
293 // the same.
294
295 if (val == NSEC3ClosestEncloser || val == NSEC3CEProof)
296 {
297 if (!NSEC3SameName(&cr->resrec.name->c[1], cr->resrec.name->c[0], (const mDNSu8 *)b32Name, b32len))
298 {
299 int bmaplen;
300 mDNSu8 *bmap;
301
302 // For NSEC3ClosestEncloser, we are finding an exact match and
303 // "type" specific checks should be done by the caller.
304 if (val != NSEC3ClosestEncloser)
305 {
306 // DNAME bit must not be set and NS bit may be set only if SOA bit is set
307 NSEC3Parse(&cr->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
308 if (BitmapTypeCheck(bmap, bmaplen, kDNSType_DNAME))
309 {
310 LogDNSSEC("NSEC3Find: DNAME bit set in %s, ignoring", CRDisplayString(m, cr));
311 return mDNSfalse;
312 }
313 // This is the closest encloser and should come from the right zone.
314 if (BitmapTypeCheck(bmap, bmaplen, kDNSType_NS) &&
315 !BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA))
316 {
317 LogDNSSEC("NSEC3Find: NS bit set without SOA bit in %s, ignoring", CRDisplayString(m, cr));
318 return mDNSfalse;
319 }
320 }
321
322 LogDNSSEC("NSEC3Find: ClosestEncloser %s found for name %##s", CRDisplayString(m, cr), name->c);
323 if (closestEncloser)
324 {
325 *ce = name;
326 *closestEncloser = cr;
327 }
328 if (val == NSEC3ClosestEncloser)
329 return mDNStrue;
330 else
331 break;
332 }
333 }
334
335 if ((val == NSEC3Covers || val == NSEC3CEProof) && !(*closerEncloser))
336 {
337 if (NSEC3CoversName(m, cr, hashName, hlen, b32Name, b32len))
338 {
339 // 2.2) If there is an NSEC3 RR in the response that covers SNAME, set the flag.
340 if (closerEncloser)
341 *closerEncloser = cr;
342 if (val == NSEC3Covers)
343 return mDNStrue;
344 else
345 break;
346 }
347 }
348 }
349 // 2.3) If there is a matching NSEC3 RR in the response and the flag
350 // was set, then the proof is complete, and SNAME is the closest
351 // encloser.
352 if (val == NSEC3CEProof)
353 {
354 if (*closestEncloser && *closerEncloser)
355 {
356 LogDNSSEC("NSEC3Find: Found closest and closer encloser");
357 return mDNStrue;
358 }
359
360 // 2.4) If there is a matching NSEC3 RR in the response, but the flag
361 // is not set, then the response is bogus.
362 //
363 // Note: We don't have to wait till we finish trying all the names. If the matchName
364 // happens, we found the closest encloser which means we should have found the closer
365 // encloser before.
366
367 if (*closestEncloser && !(*closerEncloser))
368 {
369 LogDNSSEC("NSEC3Find: Found closest, but not closer encloser");
370 return mDNSfalse;
371 }
372 }
373 // 3. Truncate SNAME by one label from the left, go to step 2.
374 }
375 LogDNSSEC("NSEC3Find: Cannot find name %##s (%s)", origName->c, DNSTypeName(qtype));
376 return mDNSfalse;
377 }
378
379 mDNSlocal mDNSBool NSEC3ClosestEncloserProof(mDNS *const m, CacheRecord *ncr, domainname *name, CacheRecord **closestEncloser, CacheRecord **closerEncloser,
380 const domainname **ce, mDNSu16 qtype)
381 {
382 if (!NSEC3Find(m, NSEC3CEProof, ncr, name, closestEncloser, closerEncloser, ce, qtype))
383 {
384 LogDNSSEC("NSEC3ClosestEncloserProof: ERROR!! Cannot do closest encloser proof");
385 return mDNSfalse;
386 }
387
388 // Note: It is possible that closestEncloser and closerEncloser are the same.
389 if (!closestEncloser || !closerEncloser || !ce)
390 {
391 LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %p or CloserEncloser %p ce %p, something is NULL", *closestEncloser,
392 *closerEncloser, *ce);
393 return mDNSfalse;
394 }
395
396 // If the name exists, we should not have gotten the name error
397 if (SameDomainName((*ce), name))
398 {
399 LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %s same as origName %##s", CRDisplayString(m, *closestEncloser),
400 (*ce)->c);
401 return mDNSfalse;
402 }
403 return mDNStrue;
404 }
405
406 mDNSlocal mDNSBool VerifyNSEC3(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr, CacheRecord *closestEncloser,
407 CacheRecord *closerEncloser, CacheRecord *wildcard, DNSSECVerifierCallback callback)
408 {
409 mStatus status;
410 RRVerifier *r;
411
412 // We have three NSEC3s. If any of two are same, we should just prove one of them.
413 // This is just not an optimization; DNSSECNegativeValidationCB does not handle
414 // identical NSEC3s very well.
415
416 if (closestEncloser == closerEncloser)
417 closestEncloser = mDNSNULL;
418 if (closerEncloser == wildcard)
419 closerEncloser = mDNSNULL;
420 if (closestEncloser == wildcard)
421 closestEncloser = mDNSNULL;
422
423 dv->pendingNSEC = mDNSNULL;
424 if (closestEncloser)
425 {
426 r = AllocateRRVerifier(&closestEncloser->resrec, &status);
427 if (!r)
428 return mDNSfalse;
429 r->next = dv->pendingNSEC;
430 dv->pendingNSEC = r;
431 }
432 if (closerEncloser)
433 {
434 r = AllocateRRVerifier(&closerEncloser->resrec, &status);
435 if (!r)
436 return mDNSfalse;
437 r->next = dv->pendingNSEC;
438 dv->pendingNSEC = r;
439 }
440 if (wildcard)
441 {
442 r = AllocateRRVerifier(&wildcard->resrec, &status);
443 if (!r)
444 return mDNSfalse;
445 r->next = dv->pendingNSEC;
446 dv->pendingNSEC = r;
447 }
448 if (!dv->pendingNSEC)
449 {
450 LogMsg("VerifyNSEC3: ERROR!! pending NSEC null");
451 return mDNSfalse;
452 }
453 r = dv->pendingNSEC;
454 dv->pendingNSEC = r->next;
455 r->next = mDNSNULL;
456
457 LogDNSSEC("VerifyNSEC3: Verifying %##s (%s)", r->name.c, DNSTypeName(r->rrtype));
458 if (!dv->pendingNSEC)
459 VerifyNSEC(m, mDNSNULL, r, dv, ncr, mDNSNULL);
460 else
461 VerifyNSEC(m, mDNSNULL, r, dv, ncr, callback);
462 return mDNStrue;
463 }
464
465 mDNSexport void NSEC3NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
466 {
467 CacheRecord *closerEncloser;
468 CacheRecord *closestEncloser;
469 CacheRecord *wildcard;
470 const domainname *ce = mDNSNULL;
471 domainname wild;
472
473 if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype))
474 {
475 goto error;
476 }
477 LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser %s, ce %##s", CRDisplayString(m, closestEncloser), ce->c);
478 LogDNSSEC("NSEC3NameErrorProof: CloserEncloser %s", CRDisplayString(m, closerEncloser));
479
480 // *.closestEncloser should be covered by some nsec3 which would then prove
481 // that the wildcard does not exist
482 wild.c[0] = 1;
483 wild.c[1] = '*';
484 wild.c[2] = 0;
485 if (!AppendDomainName(&wild, ce))
486 {
487 LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c);
488 goto error;
489 }
490 if (!NSEC3Find(m, NSEC3Covers, ncr, &wild, mDNSNULL, &wildcard, mDNSNULL, dv->q.qtype))
491 {
492 LogMsg("NSEC3NameErrorProof: Cannot find encloser for wildcard");
493 goto error;
494 }
495 else
496 {
497 LogDNSSEC("NSEC3NameErrorProof: Wildcard %##s covered by %s", wild.c, CRDisplayString(m, wildcard));
498 if (wildcard == closestEncloser)
499 {
500 LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser matching Wildcard %s", CRDisplayString(m, wildcard));
501 }
502 }
503 if (NSEC3OptOut(closerEncloser))
504 {
505 dv->flags |= NSEC3_OPT_OUT;
506 }
507 if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NameErrorNSECCallback))
508 goto error;
509 else
510 return;
511
512 error:
513 dv->DVCallback(m, dv, DNSSEC_Bogus);
514 }
515
516 // Section 8.5, 8.6 of RFC 5155 first paragraph
517 mDNSlocal mDNSBool NSEC3NoDataError(mDNS *const m, CacheRecord *ncr, domainname *name, mDNSu16 qtype, CacheRecord **closestEncloser)
518 {
519 const domainname *ce = mDNSNULL;
520
521 *closestEncloser = mDNSNULL;
522 // Note: This also covers ENT in which case the bitmap is empty
523 if (NSEC3Find(m, NSEC3ClosestEncloser, ncr, name, closestEncloser, mDNSNULL, &ce, qtype))
524 {
525 int bmaplen;
526 mDNSu8 *bmap;
527 mDNSBool ns, soa;
528
529 NSEC3Parse(&(*closestEncloser)->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
530 if (BitmapTypeCheck(bmap, bmaplen, qtype) || BitmapTypeCheck(bmap, bmaplen, kDNSType_CNAME))
531 {
532 LogMsg("NSEC3NoDataError: qtype %s exists in %s", DNSTypeName(qtype), CRDisplayString(m, *closestEncloser));
533 return mDNSfalse;
534 }
535 ns = BitmapTypeCheck(bmap, bmaplen, kDNSType_NS);
536 soa = BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA);
537 if (qtype != kDNSType_DS)
538 {
539 // For non-DS type questions, we don't want to use the parent side records to
540 // answer it
541 if (ns && !soa)
542 {
543 LogDNSSEC("NSEC3NoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)",
544 CRDisplayString(m, *closestEncloser), name->c, DNSTypeName(qtype));
545 return mDNSfalse;
546 }
547 }
548 else
549 {
550 if (soa)
551 {
552 LogDNSSEC("NSEC3NoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)",
553 CRDisplayString(m, *closestEncloser), name->c, DNSTypeName(qtype));
554 return mDNSfalse;
555 }
556 }
557 LogDNSSEC("NSEC3NoDataError: Name -%##s- exists, but qtype %s does not exist in %s", name->c, DNSTypeName(qtype), CRDisplayString(m, *closestEncloser));
558 return mDNStrue;
559 }
560 return mDNSfalse;
561 }
562
563 mDNSexport void NSEC3NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
564 {
565 CacheRecord *closerEncloser = mDNSNULL;
566 CacheRecord *closestEncloser = mDNSNULL;
567 CacheRecord *wildcard = mDNSNULL;
568 const domainname *ce = mDNSNULL;
569 domainname wild;
570
571 // Section 8.5, 8.6 of RFC 5155
572 if (NSEC3NoDataError(m, ncr, &dv->q.qname, dv->q.qtype, &closestEncloser))
573 {
574 goto verify;
575 }
576 // Section 8.6, 8.7: if we can't find the NSEC3 RR, verify the closest encloser proof
577 // for QNAME and the "next closer" should have the opt out
578 if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype))
579 {
580 goto error;
581 }
582
583 // Section 8.7: find a matching NSEC3 for *.closestEncloser
584 wild.c[0] = 1;
585 wild.c[1] = '*';
586 wild.c[2] = 0;
587 if (!AppendDomainName(&wild, ce))
588 {
589 LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c);
590 goto error;
591 }
592 if (!NSEC3Find(m, NSEC3ClosestEncloser, ncr, &wild, &wildcard, mDNSNULL, &ce, dv->q.qtype))
593 {
594 // Not a wild card case. Section 8.6 second para applies.
595 LogDNSSEC("NSEC3NoDataProof: Cannot find encloser for wildcard, perhaps not a wildcard case");
596 if (!NSEC3OptOut(closerEncloser))
597 {
598 LogDNSSEC("NSEC3DataProof: opt out not set for %##s (%s), bogus", dv->q.qname.c, DNSTypeName(dv->q.qtype));
599 goto error;
600 }
601 LogDNSSEC("NSEC3DataProof: opt out set, proof complete for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
602 dv->flags |= NSEC3_OPT_OUT;
603 }
604 else
605 {
606 int bmaplen;
607 mDNSu8 *bmap;
608 NSEC3Parse(&wildcard->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
609 if (BitmapTypeCheck(bmap, bmaplen, dv->q.qtype) || BitmapTypeCheck(bmap, bmaplen, kDNSType_CNAME))
610 {
611 LogDNSSEC("NSEC3NoDataProof: qtype %s exists in %s", DNSTypeName(dv->q.qtype), CRDisplayString(m, wildcard));
612 goto error;
613 }
614 if (dv->q.qtype == kDNSType_DS && BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA))
615 {
616 LogDNSSEC("NSEC3NoDataProof: Child side wildcard NSEC3 %s, can't use for parent qname %##s (%s)",
617 CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype));
618 goto error;
619 }
620 else if (dv->q.qtype != kDNSType_DS && !BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) &&
621 BitmapTypeCheck(bmap, bmaplen, kDNSType_NS))
622 {
623 // Don't use the parent side record for this
624 LogDNSSEC("NSEC3NoDataProof: Parent side wildcard NSEC3 %s, can't use for child qname %##s (%s)",
625 CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype));
626 goto error;
627 }
628 LogDNSSEC("NSEC3NoDataProof: Wildcard %##s matched by %s", wild.c, CRDisplayString(m, wildcard));
629 }
630 verify:
631
632 if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NoDataNSECCallback))
633 goto error;
634 else
635 return;
636 error:
637 dv->DVCallback(m, dv, DNSSEC_Bogus);
638 }
639
640 mDNSexport mDNSBool NSEC3WildcardAnswerProof(mDNS *const m, CacheRecord *ncr, DNSSECVerifier *dv)
641 {
642 int skip;
643 const domainname *nc;
644 CacheRecord *closerEncloser;
645
646 (void) m;
647
648 // Find the next closer name and prove that it is covered by the NSEC3
649 skip = CountLabels(&dv->origName) - CountLabels(dv->wildcardName) - 1;
650 if (skip)
651 nc = SkipLeadingLabels(&dv->origName, skip);
652 else
653 nc = &dv->origName;
654
655 LogDNSSEC("NSEC3WildcardAnswerProof: wildcard name %##s", nc->c);
656
657 if (!NSEC3Find(m, NSEC3Covers, ncr, (domainname *)nc, mDNSNULL, &closerEncloser, mDNSNULL, dv->q.qtype))
658 {
659 LogMsg("NSEC3WildcardAnswerProof: Cannot find closer encloser");
660 return mDNSfalse;
661 }
662 if (!closerEncloser)
663 {
664 LogMsg("NSEC3WildcardAnswerProof: closerEncloser NULL");
665 return mDNSfalse;
666 }
667 if (NSEC3OptOut(closerEncloser))
668 {
669 dv->flags |= NSEC3_OPT_OUT;
670 }
671 // NSEC3 Verification is done by the caller
672 return mDNStrue;
673 }
674
675 mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype)
676 {
677 CacheGroup *cg;
678 CacheRecord *cr;
679 CacheRecord *ncr;
680 mDNSu32 slot, namehash;
681
682 slot = HashSlot(name);
683 namehash = DomainNameHashValue(name);
684
685 cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name);
686 if (!cg)
687 {
688 LogDNSSEC("NSEC3RecordForName: cg NULL for %##s", name);
689 return mDNSNULL;
690 }
691 for (ncr = cg->members; ncr; ncr = ncr->next)
692 {
693 if (ncr->resrec.RecordType != kDNSRecordTypePacketNegative ||
694 ncr->resrec.rrtype != qtype)
695 {
696 continue;
697 }
698 for (cr = ncr->nsec; cr; cr = cr->next)
699 {
700 int hlen, b32len;
701 const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
702 const mDNSu8 b32Name[NSEC3_MAX_B32_LEN+1];
703 const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
704 rdataNSEC3 *nsec3;
705
706 if (cr->resrec.rrtype != kDNSType_NSEC3)
707 continue;
708
709 nsec3 = (rdataNSEC3 *)rdb->data;
710
711 if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
712 {
713 LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for ##s", name->c);
714 return mDNSNULL;
715 }
716
717 b32len = baseEncode((char *)b32Name, sizeof(b32Name), (mDNSu8 *)hashName, hlen, ENC_BASE32);
718 if (!b32len)
719 {
720 LogMsg("NSEC3RecordIsDelegation: baseEncode of name %##s failed", name->c);
721 return mDNSNULL;
722 }
723 // Section 2.3 of RFC 4035 states that:
724 //
725 // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST
726 // have an NSEC resource record.
727 //
728 // This applies to NSEC3 record. So, if we have an NSEC3 record matching the question name with the
729 // NS bit set, then this is a delegation.
730 //
731 if (!NSEC3SameName(&cr->resrec.name->c[1], cr->resrec.name->c[0], (const mDNSu8 *)b32Name, b32len))
732 {
733 int bmaplen;
734 mDNSu8 *bmap;
735
736 LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s matches name %##s, b32name %s", CRDisplayString(m, cr), name->c, b32Name);
737 NSEC3Parse(&cr->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
738
739 // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit
740 // should be absent
741 if (BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) ||
742 BitmapTypeCheck(bmap, bmaplen, kDNSType_DS))
743 {
744 LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s has DS or SOA bit set, ignoring", CRDisplayString(m, cr));
745 return mDNSNULL;
746 }
747 if (BitmapTypeCheck(bmap, bmaplen, kDNSType_NS))
748 return cr;
749 else
750 return mDNSNULL;
751 }
752 // If opt-out is not set, then it does not cover any delegations
753 if (!(nsec3->flags & NSEC3_FLAGS_OPTOUT))
754 continue;
755 // Opt-out allows insecure delegations to exist without the NSEC3 RR at the
756 // hashed owner name (see RFC 5155 section 6.0).
757 if (NSEC3CoversName(m, cr, hashName, hlen, b32Name, b32len))
758 {
759 LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s covers name %##s with optout", CRDisplayString(m, cr), name->c);
760 return cr;
761 }
762 }
763 }
764 return mDNSNULL;
765 }
766
767 #else // !DNSSEC_DISABLED
768
769 #endif // !DNSSEC_DISABLED