1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011-2018 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // ***************************************************************************
19 // nsec3.c: This file contains support functions to validate NSEC3 records for
20 // NODATA and NXDOMAIN error.
21 // ***************************************************************************
23 #include "mDNSEmbeddedAPI.h"
24 #include "DNSCommon.h"
25 #include "CryptoAlg.h"
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
36 #define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
38 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
39 // and use the stub functions implemented later in this file.
41 #ifndef DNSSEC_DISABLED
50 //#define NSEC3_DEBUG 1
53 mDNSlocal
void PrintHash(mDNSu8
*digest
, int digestlen
, char *buffer
, int buflen
)
56 for (int j
= 0; j
< digestlen
; j
++)
58 length
+= mDNS_snprintf(buffer
+length
, buflen
-length
-1, "%x", digest
[j
]);
63 mDNSlocal mDNSBool
NSEC3OptOut(CacheRecord
*cr
)
65 const RDataBody2
*const rdb
= (RDataBody2
*)cr
->resrec
.rdata
->u
.data
;
66 rdataNSEC3
*nsec3
= (rdataNSEC3
*)rdb
->data
;
67 return (nsec3
->flags
& NSEC3_FLAGS_OPTOUT
);
70 mDNSlocal
int NSEC3SameName(const mDNSu8
*name
, int namelen
, const mDNSu8
*nsecName
, int nsecLen
)
74 // Note: With NSEC3, the lengths should always be same.
75 if (namelen
!= nsecLen
)
77 LogMsg("NSEC3SameName: ERROR!! namelen %d, nsecLen %d", namelen
, nsecLen
);
78 return ((namelen
< nsecLen
) ? -1 : 1);
81 for (i
= 0; i
< namelen
; i
++)
84 mDNSu8 bc
= *nsecName
++;
85 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
86 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
89 verbosedebugf("NSEC3SameName: returning ac %c, bc %c", ac
, bc
);
90 return ((ac
< bc
) ? -1 : 1);
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
,
104 const mDNSu8 b32nxtname
[NSEC3_MAX_B32_LEN
+1];
107 NSEC3Parse(&ncr
->resrec
, mDNSNULL
, &nxtLength
, &nxtName
, mDNSNULL
, mDNSNULL
);
109 if (nxtLength
!= hashLen
|| ncr
->resrec
.name
->c
[0] != b32len
)
112 // Compare the owner names and the "nxt" names.
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
);
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
);
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)
135 LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Normal)", CRDisplayString(m
, ncr
), b32Name
);
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
);
144 LogDNSSEC("NSEC3CoversName: baseEncode of nxtName of %s failed", CRDisplayString(m
, ncr
));
147 if (b32len
!= b32nxtlen
)
149 LogDNSSEC("NSEC3CoversName: baseEncode of nxtName for %s resulted in wrong length b32nxtlen %d, b32len %d",
150 CRDisplayString(m
, ncr
), b32len
, b32nxtlen
);
153 LogDNSSEC("NSEC3CoversName: Owner name %s, b32nxtname %s, ret1 %d, ret2 %d", &ncr
->resrec
.name
->c
[1], b32nxtname
, ret1
, ret2
);
155 // If it is the last NSEC3 in the zone nxt < "name" and NSEC3SameName returns -1.
157 // - ret1 < 0 means "name > owner"
158 // - ret2 > 0 means "name < nxt"
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]);
163 (ret1
< 0 || ret2
> 0))
165 LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Last), ret1 %d, ret2 %d", CRDisplayString(m
, ncr
), b32Name
, ret1
, ret2
);
172 mDNSlocal
const mDNSu8
*NSEC3HashName(const domainname
*name
, rdataNSEC3
*nsec3
, const mDNSu8 hash
[NSEC3_MAX_HASH_LEN
], int *dlen
)
176 unsigned int iterations
;
178 mDNSu8
*p
= (mDNSu8
*)&nsec3
->salt
;
179 const mDNSu8
*digest
;
181 mDNSBool first
= mDNStrue
;
183 if (DNSNameToLowerCase((domainname
*)name
, &lname
) != mStatus_NoError
)
185 LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
190 digestlen
= DomainNameLength(&lname
);
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
++)
197 ctx
= AlgCreate(DIGEST_ALG
, nsec3
->alg
);
200 LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
204 AlgAdd(ctx
, digest
, digestlen
);
205 if (nsec3
->saltLength
)
206 AlgAdd(ctx
, p
, nsec3
->saltLength
);
211 digestlen
= AlgLength(ctx
);
213 AlgFinal(ctx
, (void *)digest
, digestlen
);
220 // This function can be called with NSEC3ClosestEncloser, NSEC3Covers and NSEC3CEProof
222 // Passing in NSEC3ClosestEncloser means "find an exact match for the origName".
223 // Passing in NSEC3Covers means "find an NSEC3 that covers the origName".
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.
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.
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
)
241 int labelCount
= CountLabels(origName
);
245 (void) qtype
; // unused
246 // Pick the first NSEC for the iterations, salt etc.
247 for (cr
= ncr
->nsec
; cr
; cr
= cr
->next
)
249 if (cr
->resrec
.rrtype
== kDNSType_NSEC3
)
251 const RDataBody2
*const rdb
= (RDataBody2
*)cr
->resrec
.rdata
->u
.data
;
252 nsec3
= (rdataNSEC3
*)rdb
->data
;
258 LogMsg("NSEC3Find: cr NULL");
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.
266 // Section 8.3 of RFC 5155.
267 // 1. Set SNAME=QNAME. Clear the flag.
269 // closerEncloser is the "flag". "name" below is SNAME.
274 *closestEncloser
= mDNSNULL
;
277 *closerEncloser
= mDNSNULL
;
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
282 if (val
!= NSEC3CEProof
)
287 for (i
= 0; i
< labelCount
+ 1; i
++)
290 const mDNSu8 hashName
[NSEC3_MAX_HASH_LEN
];
291 const domainname
*name
;
292 const mDNSu8 b32Name
[NSEC3_MAX_B32_LEN
+1];
295 name
= SkipLeadingLabels(origName
, i
);
296 if (!NSEC3HashName(name
, nsec3
, hashName
, &hlen
))
298 LogMsg("NSEC3Find: NSEC3HashName failed for %##s", name
->c
);
302 b32len
= baseEncode((char *)b32Name
, sizeof(b32Name
), (mDNSu8
*)hashName
, hlen
, ENC_BASE32
);
305 LogMsg("NSEC3Find: baseEncode of name %##s failed", name
->c
);
310 for (cr
= ncr
->nsec
; cr
; cr
= cr
->next
)
312 const domainname
*nsecZone
;
313 int result
, subdomain
;
315 if (cr
->resrec
.rrtype
!= kDNSType_NSEC3
)
318 nsecZone
= SkipLeadingLabels(cr
->resrec
.name
, 1);
321 LogMsg("NSEC3Find: SkipLeadingLabel failed for %s, current name %##s",
322 CRDisplayString(m
, cr
), name
->c
);
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
330 result
= DNSSECCanonicalOrder(origName
, nsecZone
, &subdomain
);
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
))
337 LogMsg("NSEC3Find: NSEC3 %s not a subdomain of %##s, result %d", CRDisplayString(m
, cr
),
338 origName
->c
, result
);
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
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
352 if (val
== NSEC3ClosestEncloser
|| val
== NSEC3CEProof
)
354 if (!NSEC3SameName(&cr
->resrec
.name
->c
[1], cr
->resrec
.name
->c
[0], (const mDNSu8
*)b32Name
, b32len
))
359 // For NSEC3ClosestEncloser, we are finding an exact match and
360 // "type" specific checks should be done by the caller.
361 if (val
!= NSEC3ClosestEncloser
)
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
))
367 LogDNSSEC("NSEC3Find: DNAME bit set in %s, ignoring", CRDisplayString(m
, cr
));
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
))
374 LogDNSSEC("NSEC3Find: NS bit set without SOA bit in %s, ignoring", CRDisplayString(m
, cr
));
379 LogDNSSEC("NSEC3Find: ClosestEncloser %s found for name %##s", CRDisplayString(m
, cr
), name
->c
);
383 *closestEncloser
= cr
;
385 if (val
== NSEC3ClosestEncloser
)
392 if ((val
== NSEC3Covers
|| val
== NSEC3CEProof
) && (!closerEncloser
|| !(*closerEncloser
)))
394 if (NSEC3CoversName(m
, cr
, hashName
, hlen
, b32Name
, b32len
))
396 // 2.2) If there is an NSEC3 RR in the response that covers SNAME, set the flag.
398 *closerEncloser
= cr
;
399 if (val
== NSEC3Covers
)
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
409 if (val
== NSEC3CEProof
&& closestEncloser
&& *closestEncloser
)
411 if (closerEncloser
&& *closerEncloser
)
413 LogDNSSEC("NSEC3Find: Found closest and closer encloser");
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.
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
425 LogDNSSEC("NSEC3Find: Found closest, but not closer encloser");
429 // 3. Truncate SNAME by one label from the left, go to step 2.
431 LogDNSSEC("NSEC3Find: Cannot find name %##s (%s)", origName
->c
, DNSTypeName(qtype
));
435 mDNSlocal mDNSBool
NSEC3ClosestEncloserProof(mDNS
*const m
, CacheRecord
*ncr
, domainname
*name
, CacheRecord
**closestEncloser
, CacheRecord
**closerEncloser
,
436 const domainname
**ce
, mDNSu16 qtype
)
438 if (!NSEC3Find(m
, NSEC3CEProof
, ncr
, name
, closestEncloser
, closerEncloser
, ce
, qtype
))
440 LogDNSSEC("NSEC3ClosestEncloserProof: ERROR!! Cannot do closest encloser proof");
444 // Note: It is possible that closestEncloser and closerEncloser are the same.
445 if (!closestEncloser
|| !closerEncloser
|| !ce
)
447 LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %p or CloserEncloser %p ce %p, something is NULL", closestEncloser
, closerEncloser
, ce
);
451 // If the name exists, we should not have gotten the name error
452 if (SameDomainName((*ce
), name
))
454 LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %s same as origName %##s", CRDisplayString(m
, *closestEncloser
),
461 mDNSlocal mDNSBool
VerifyNSEC3(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*ncr
, CacheRecord
*closestEncloser
,
462 CacheRecord
*closerEncloser
, CacheRecord
*wildcard
, DNSSECVerifierCallback callback
)
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.
471 if (closestEncloser
== closerEncloser
)
472 closestEncloser
= mDNSNULL
;
473 if (closerEncloser
== wildcard
)
474 closerEncloser
= mDNSNULL
;
475 if (closestEncloser
== wildcard
)
476 closestEncloser
= mDNSNULL
;
478 dv
->pendingNSEC
= mDNSNULL
;
481 r
= AllocateRRVerifier(&closestEncloser
->resrec
, &status
);
484 r
->next
= dv
->pendingNSEC
;
489 r
= AllocateRRVerifier(&closerEncloser
->resrec
, &status
);
492 r
->next
= dv
->pendingNSEC
;
497 r
= AllocateRRVerifier(&wildcard
->resrec
, &status
);
500 r
->next
= dv
->pendingNSEC
;
503 if (!dv
->pendingNSEC
)
505 LogMsg("VerifyNSEC3: ERROR!! pending NSEC null");
509 dv
->pendingNSEC
= r
->next
;
512 LogDNSSEC("VerifyNSEC3: Verifying %##s (%s)", r
->name
.c
, DNSTypeName(r
->rrtype
));
513 if (!dv
->pendingNSEC
)
514 VerifyNSEC(m
, mDNSNULL
, r
, dv
, ncr
, mDNSNULL
);
516 VerifyNSEC(m
, mDNSNULL
, r
, dv
, ncr
, callback
);
520 mDNSexport
void NSEC3NameErrorProof(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*ncr
)
522 CacheRecord
*closerEncloser
;
523 CacheRecord
*closestEncloser
;
524 CacheRecord
*wildcard
;
525 const domainname
*ce
= mDNSNULL
;
528 if (!NSEC3ClosestEncloserProof(m
, ncr
, &dv
->q
.qname
, &closestEncloser
, &closerEncloser
, &ce
, dv
->q
.qtype
))
532 LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser %s, ce %##s", CRDisplayString(m
, closestEncloser
), ce
->c
);
533 LogDNSSEC("NSEC3NameErrorProof: CloserEncloser %s", CRDisplayString(m
, closerEncloser
));
535 // *.closestEncloser should be covered by some nsec3 which would then prove
536 // that the wildcard does not exist
540 if (!AppendDomainName(&wild
, ce
))
542 LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce
->c
);
545 if (!NSEC3Find(m
, NSEC3Covers
, ncr
, &wild
, mDNSNULL
, &wildcard
, mDNSNULL
, dv
->q
.qtype
))
547 LogMsg("NSEC3NameErrorProof: Cannot find encloser for wildcard");
552 LogDNSSEC("NSEC3NameErrorProof: Wildcard %##s covered by %s", wild
.c
, CRDisplayString(m
, wildcard
));
553 if (wildcard
== closestEncloser
)
555 LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser matching Wildcard %s", CRDisplayString(m
, wildcard
));
558 if (NSEC3OptOut(closerEncloser
))
560 dv
->flags
|= NSEC3_OPT_OUT
;
562 if (!VerifyNSEC3(m
, dv
, ncr
, closestEncloser
, closerEncloser
, wildcard
, NameErrorNSECCallback
))
568 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
)
574 const domainname
*ce
= mDNSNULL
;
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
))
584 NSEC3Parse(&(*closestEncloser
)->resrec
, mDNSNULL
, mDNSNULL
, mDNSNULL
, &bmaplen
, &bmap
);
585 if (BitmapTypeCheck(bmap
, bmaplen
, qtype
) || BitmapTypeCheck(bmap
, bmaplen
, kDNSType_CNAME
))
587 LogMsg("NSEC3NoDataError: qtype %s exists in %s", DNSTypeName(qtype
), CRDisplayString(m
, *closestEncloser
));
590 ns
= BitmapTypeCheck(bmap
, bmaplen
, kDNSType_NS
);
591 soa
= BitmapTypeCheck(bmap
, bmaplen
, kDNSType_SOA
);
592 if (qtype
!= kDNSType_DS
)
594 // For non-DS type questions, we don't want to use the parent side records to
598 LogDNSSEC("NSEC3NoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)",
599 CRDisplayString(m
, *closestEncloser
), name
->c
, DNSTypeName(qtype
));
607 LogDNSSEC("NSEC3NoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)",
608 CRDisplayString(m
, *closestEncloser
), name
->c
, DNSTypeName(qtype
));
612 LogDNSSEC("NSEC3NoDataError: Name -%##s- exists, but qtype %s does not exist in %s", name
->c
, DNSTypeName(qtype
), CRDisplayString(m
, *closestEncloser
));
618 mDNSexport
void NSEC3NoDataProof(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
*ncr
)
620 CacheRecord
*closerEncloser
= mDNSNULL
;
621 CacheRecord
*closestEncloser
= mDNSNULL
;
622 CacheRecord
*wildcard
= mDNSNULL
;
623 const domainname
*ce
= mDNSNULL
;
626 // Section 8.5, 8.6 of RFC 5155
627 if (NSEC3NoDataError(m
, ncr
, &dv
->q
.qname
, dv
->q
.qtype
, &closestEncloser
))
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
))
638 // Section 8.7: find a matching NSEC3 for *.closestEncloser
642 if (!AppendDomainName(&wild
, ce
))
644 LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce
->c
);
647 if (!NSEC3Find(m
, NSEC3ClosestEncloser
, ncr
, &wild
, &wildcard
, mDNSNULL
, &ce
, dv
->q
.qtype
))
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
))
653 LogDNSSEC("NSEC3DataProof: opt out not set for %##s (%s), bogus", dv
->q
.qname
.c
, DNSTypeName(dv
->q
.qtype
));
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
;
663 NSEC3Parse(&wildcard
->resrec
, mDNSNULL
, mDNSNULL
, mDNSNULL
, &bmaplen
, &bmap
);
664 if (BitmapTypeCheck(bmap
, bmaplen
, dv
->q
.qtype
) || BitmapTypeCheck(bmap
, bmaplen
, kDNSType_CNAME
))
666 LogDNSSEC("NSEC3NoDataProof: qtype %s exists in %s", DNSTypeName(dv
->q
.qtype
), CRDisplayString(m
, wildcard
));
669 if (dv
->q
.qtype
== kDNSType_DS
&& BitmapTypeCheck(bmap
, bmaplen
, kDNSType_SOA
))
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
));
675 else if (dv
->q
.qtype
!= kDNSType_DS
&& !BitmapTypeCheck(bmap
, bmaplen
, kDNSType_SOA
) &&
676 BitmapTypeCheck(bmap
, bmaplen
, kDNSType_NS
))
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
));
683 LogDNSSEC("NSEC3NoDataProof: Wildcard %##s matched by %s", wild
.c
, CRDisplayString(m
, wildcard
));
687 if (!VerifyNSEC3(m
, dv
, ncr
, closestEncloser
, closerEncloser
, wildcard
, NoDataNSECCallback
))
692 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
695 mDNSexport mDNSBool
NSEC3WildcardAnswerProof(mDNS
*const m
, CacheRecord
*ncr
, DNSSECVerifier
*dv
)
698 const domainname
*nc
;
699 CacheRecord
*closerEncloser
;
703 // Find the next closer name and prove that it is covered by the NSEC3
704 skip
= CountLabels(&dv
->origName
) - CountLabels(dv
->wildcardName
) - 1;
706 nc
= SkipLeadingLabels(&dv
->origName
, skip
);
710 LogDNSSEC("NSEC3WildcardAnswerProof: wildcard name %##s", nc
->c
);
712 if (!NSEC3Find(m
, NSEC3Covers
, ncr
, (domainname
*)nc
, mDNSNULL
, &closerEncloser
, mDNSNULL
, dv
->q
.qtype
))
714 LogMsg("NSEC3WildcardAnswerProof: Cannot find closer encloser");
719 LogMsg("NSEC3WildcardAnswerProof: closerEncloser NULL");
722 if (NSEC3OptOut(closerEncloser
))
724 dv
->flags
|= NSEC3_OPT_OUT
;
726 // NSEC3 Verification is done by the caller
730 mDNSexport CacheRecord
*NSEC3RecordIsDelegation(mDNS
*const m
, domainname
*name
, mDNSu16 qtype
)
737 namehash
= DomainNameHashValue(name
);
739 cg
= CacheGroupForName(m
, namehash
, name
);
742 LogDNSSEC("NSEC3RecordForName: cg NULL for %##s", name
);
745 for (ncr
= cg
->members
; ncr
; ncr
= ncr
->next
)
747 if (ncr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
||
748 ncr
->resrec
.rrtype
!= qtype
)
752 for (cr
= ncr
->nsec
; cr
; cr
= cr
->next
)
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
;
760 if (cr
->resrec
.rrtype
!= kDNSType_NSEC3
)
763 nsec3
= (rdataNSEC3
*)rdb
->data
;
765 if (!NSEC3HashName(name
, nsec3
, hashName
, &hlen
))
767 LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for %##s", name
->c
);
771 b32len
= baseEncode((char *)b32Name
, sizeof(b32Name
), (mDNSu8
*)hashName
, hlen
, ENC_BASE32
);
774 LogMsg("NSEC3RecordIsDelegation: baseEncode of name %##s failed", name
->c
);
777 // Section 2.3 of RFC 4035 states that:
779 // Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST
780 // have an NSEC resource record.
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.
785 if (!NSEC3SameName(&cr
->resrec
.name
->c
[1], cr
->resrec
.name
->c
[0], (const mDNSu8
*)b32Name
, b32len
))
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
);
793 // See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit
795 if (BitmapTypeCheck(bmap
, bmaplen
, kDNSType_SOA
) ||
796 BitmapTypeCheck(bmap
, bmaplen
, kDNSType_DS
))
798 LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s has DS or SOA bit set, ignoring", CRDisplayString(m
, cr
));
801 if (BitmapTypeCheck(bmap
, bmaplen
, kDNSType_NS
))
806 // If opt-out is not set, then it does not cover any delegations
807 if (!(nsec3
->flags
& NSEC3_FLAGS_OPTOUT
))
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
))
813 LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s covers name %##s with optout", CRDisplayString(m
, cr
), name
->c
);
821 #else // !DNSSEC_DISABLED
823 #endif // !DNSSEC_DISABLED