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