]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/validate.cc
limit compression pointers to 14 bits
[thirdparty/pdns.git] / pdns / validate.cc
1 #include "validate.hh"
2 #include "misc.hh"
3 #include "dnssecinfra.hh"
4 #include "dnsseckeeper.hh"
5 #include "rec-lua-conf.hh"
6 #include "base32.hh"
7 #include "logger.hh"
8 bool g_dnssecLOG{false};
9 time_t g_signatureInceptionSkew{0};
10 uint16_t g_maxNSEC3Iterations{0};
11
12 #define LOG(x) if(g_dnssecLOG) { g_log <<Logger::Warning << x; }
13
14 const char *dStates[]={"nodata", "nxdomain", "nxqtype", "empty non-terminal", "insecure", "opt-out"};
15 const char *vStates[]={"Indeterminate", "Bogus", "Insecure", "Secure", "NTA", "TA"};
16
17 static vector<shared_ptr<DNSKEYRecordContent > > getByTag(const skeyset_t& keys, uint16_t tag, uint8_t algorithm)
18 {
19 vector<shared_ptr<DNSKEYRecordContent>> ret;
20 for(const auto& key : keys)
21 if(key->d_protocol == 3 && key->getTag() == tag && key->d_algorithm == algorithm)
22 ret.push_back(key);
23 return ret;
24 }
25
26 static bool isCoveredByNSEC3Hash(const std::string& h, const std::string& beginHash, const std::string& nextHash)
27 {
28 return ((beginHash < h && h < nextHash) || // no wrap BEGINNING --- HASH -- END
29 (nextHash > h && beginHash > nextHash) || // wrap HASH --- END --- BEGINNING
30 (nextHash < beginHash && beginHash < h) || // wrap other case END --- BEGINNING --- HASH
31 (beginHash == nextHash && h != beginHash)); // "we have only 1 NSEC3 record, LOL!"
32 }
33
34 static bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNSName& next)
35 {
36 return ((begin.canonCompare(name) && name.canonCompare(next)) || // no wrap BEGINNING --- NAME --- NEXT
37 (name.canonCompare(next) && next.canonCompare(begin)) || // wrap NAME --- NEXT --- BEGINNING
38 (next.canonCompare(begin) && begin.canonCompare(name)) || // wrap other case NEXT --- BEGINNING --- NAME
39 (begin == next && name != begin)); // "we have only 1 NSEC record, LOL!"
40 }
41
42 static bool nsecProvesENT(const DNSName& name, const DNSName& begin, const DNSName& next)
43 {
44 /* if name is an ENT:
45 - begin < name
46 - next is a child of name
47 */
48 return begin.canonCompare(name) && next != name && next.isPartOf(name);
49 }
50
51 static std::string getHashFromNSEC3(const DNSName& qname, const std::shared_ptr<NSEC3RecordContent>& nsec3)
52 {
53 std::string result;
54
55 if (g_maxNSEC3Iterations && nsec3->d_iterations > g_maxNSEC3Iterations) {
56 return result;
57 }
58
59 return hashQNameWithSalt(nsec3->d_salt, nsec3->d_iterations, qname);
60 }
61
62 /* There is no delegation at this exact point if:
63 - the name exists but the NS type is not set
64 - the name does not exist
65 One exception, if the name is covered by an opt-out NSEC3
66 it doesn't prove that an insecure delegation doesn't exist.
67 */
68 bool denialProvesNoDelegation(const DNSName& zone, const std::vector<DNSRecord>& dsrecords)
69 {
70 for (const auto& record : dsrecords) {
71 if (record.d_type == QType::NSEC) {
72 const auto nsec = getRR<NSECRecordContent>(record);
73 if (!nsec) {
74 continue;
75 }
76
77 if (record.d_name == zone) {
78 return !nsec->isSet(QType::NS);
79 }
80
81 if (isCoveredByNSEC(zone, record.d_name, nsec->d_next)) {
82 return true;
83 }
84 }
85 else if (record.d_type == QType::NSEC3) {
86 const auto nsec3 = getRR<NSEC3RecordContent>(record);
87 if (!nsec3) {
88 continue;
89 }
90
91 const string h = getHashFromNSEC3(zone, nsec3);
92 if (h.empty()) {
93 return false;
94 }
95
96 const string beginHash = fromBase32Hex(record.d_name.getRawLabels()[0]);
97 if (beginHash == h) {
98 return !nsec3->isSet(QType::NS);
99 }
100
101 if (isCoveredByNSEC3Hash(h, beginHash, nsec3->d_nexthash)) {
102 return !(nsec3->d_flags & 1);
103 }
104 }
105 }
106
107 return false;
108 }
109
110 /* RFC 4035 section-5.3.4:
111 "If the number of labels in an RRset's owner name is greater than the
112 Labels field of the covering RRSIG RR, then the RRset and its
113 covering RRSIG RR were created as a result of wildcard expansion."
114 */
115 bool isWildcardExpanded(unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign)
116 {
117 if (sign && sign->d_labels < labelCount) {
118 return true;
119 }
120
121 return false;
122 }
123
124 static bool isWildcardExpanded(const DNSName& owner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
125 {
126 if (signatures.empty()) {
127 return false;
128 }
129
130 const auto& sign = signatures.at(0);
131 unsigned int labelsCount = owner.countLabels();
132 return isWildcardExpanded(labelsCount, sign);
133 }
134
135 bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign)
136 {
137 if (owner.isWildcard() && (labelCount - 1) == sign->d_labels) {
138 /* this is a wildcard alright, but it has not been expanded */
139 return true;
140 }
141 return false;
142 }
143
144 static bool isWildcardExpandedOntoItself(const DNSName& owner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
145 {
146 if (signatures.empty()) {
147 return false;
148 }
149
150 const auto& sign = signatures.at(0);
151 unsigned int labelsCount = owner.countLabels();
152 return isWildcardExpandedOntoItself(owner, labelsCount, sign);
153 }
154
155 /* if this is a wildcard NSEC, the owner name has been modified
156 to match the name. Make sure we use the original '*' form. */
157 static DNSName getNSECOwnerName(const DNSName& initialOwner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
158 {
159 DNSName result = initialOwner;
160
161 if (signatures.empty()) {
162 return result;
163 }
164
165 const auto& sign = signatures.at(0);
166 unsigned int labelsCount = initialOwner.countLabels();
167 if (sign && sign->d_labels < labelsCount) {
168 do {
169 result.chopOff();
170 labelsCount--;
171 }
172 while (sign->d_labels < labelsCount);
173
174 result = g_wildcarddnsname + result;
175 }
176
177 return result;
178 }
179
180 static bool isNSECAncestorDelegation(const DNSName& signer, const DNSName& owner, const std::shared_ptr<NSECRecordContent>& nsec)
181 {
182 return nsec->isSet(QType::NS) &&
183 !nsec->isSet(QType::SOA) &&
184 signer.countLabels() < owner.countLabels();
185 }
186
187 static bool isNSEC3AncestorDelegation(const DNSName& signer, const DNSName& owner, const std::shared_ptr<NSEC3RecordContent>& nsec3)
188 {
189 return nsec3->isSet(QType::NS) &&
190 !nsec3->isSet(QType::SOA) &&
191 signer.countLabels() < owner.countLabels();
192 }
193
194 static bool provesNoDataWildCard(const DNSName& qname, const uint16_t qtype, const cspmap_t& validrrsets)
195 {
196 LOG("Trying to prove that there is no data in wildcard for "<<qname<<"/"<<QType(qtype).getName()<<endl);
197 for (const auto& v : validrrsets) {
198 LOG("Do have: "<<v.first.first<<"/"<<DNSRecordContent::NumberToType(v.first.second)<<endl);
199 if (v.first.second == QType::NSEC) {
200 for (const auto& r : v.second.records) {
201 LOG("\t"<<r->getZoneRepresentation()<<endl);
202 auto nsec = std::dynamic_pointer_cast<NSECRecordContent>(r);
203 if (!nsec) {
204 continue;
205 }
206
207 if (!v.first.first.isWildcard()) {
208 continue;
209 }
210 DNSName wildcard = getNSECOwnerName(v.first.first, v.second.signatures);
211 if (qname.countLabels() < wildcard.countLabels()) {
212 continue;
213 }
214
215 wildcard.chopOff();
216
217 if (qname.isPartOf(wildcard)) {
218 LOG("\tWildcard matches");
219 if (qtype == 0 || !nsec->isSet(qtype)) {
220 LOG(" and proves that the type did not exist"<<endl);
221 return true;
222 }
223 LOG(" BUT the type did exist!"<<endl);
224 return false;
225 }
226 }
227 }
228 }
229
230 return false;
231 }
232
233 /*
234 This function checks whether the non-existence of a wildcard covering qname|qtype
235 is proven by the NSEC records in validrrsets.
236 */
237 static bool provesNoWildCard(const DNSName& qname, const uint16_t qtype, const cspmap_t & validrrsets)
238 {
239 LOG("Trying to prove that there is no wildcard for "<<qname<<"/"<<QType(qtype).getName()<<endl);
240 for (const auto& v : validrrsets) {
241 LOG("Do have: "<<v.first.first<<"/"<<DNSRecordContent::NumberToType(v.first.second)<<endl);
242 if (v.first.second == QType::NSEC) {
243 for (const auto& r : v.second.records) {
244 LOG("\t"<<r->getZoneRepresentation()<<endl);
245 auto nsec = std::dynamic_pointer_cast<NSECRecordContent>(r);
246 if (!nsec) {
247 continue;
248 }
249
250 const DNSName owner = getNSECOwnerName(v.first.first, v.second.signatures);
251 /*
252 A NSEC can only prove the non-existence of a wildcard with at least the same
253 number of labels than the intersection of its owner name and next name.
254 */
255 const DNSName commonLabels = owner.getCommonLabels(nsec->d_next);
256 unsigned int commonLabelsCount = commonLabels.countLabels();
257
258 DNSName wildcard(qname);
259 unsigned int wildcardLabelsCount = wildcard.countLabels();
260 while (wildcard.chopOff() && wildcardLabelsCount >= commonLabelsCount) {
261 DNSName target = g_wildcarddnsname + wildcard;
262
263 LOG("Comparing owner: "<<owner<<" with target: "<<target<<endl);
264
265 if (isCoveredByNSEC(target, owner, nsec->d_next)) {
266 LOG("\tWildcard is covered"<<endl);
267 return true;
268 }
269 }
270 }
271 }
272 }
273
274 return false;
275 }
276
277 /*
278 This function checks whether the non-existence of a wildcard covering qname|qtype
279 is proven by the NSEC3 records in validrrsets.
280 If `wildcardExists` is not NULL, if will be set to true if a wildcard exists
281 for this qname but doesn't have this qtype.
282 */
283 static bool provesNSEC3NoWildCard(DNSName wildcard, uint16_t const qtype, const cspmap_t & validrrsets, bool * wildcardExists=nullptr)
284 {
285 wildcard = g_wildcarddnsname + wildcard;
286 LOG("Trying to prove that there is no wildcard for "<<wildcard<<"/"<<QType(qtype).getName()<<endl);
287
288 for (const auto& v : validrrsets) {
289 LOG("Do have: "<<v.first.first<<"/"<<DNSRecordContent::NumberToType(v.first.second)<<endl);
290 if (v.first.second == QType::NSEC3) {
291 for (const auto& r : v.second.records) {
292 LOG("\t"<<r->getZoneRepresentation()<<endl);
293 auto nsec3 = std::dynamic_pointer_cast<NSEC3RecordContent>(r);
294 if (!nsec3) {
295 continue;
296 }
297
298 const DNSName signer = getSigner(v.second.signatures);
299 if (!v.first.first.isPartOf(signer))
300 continue;
301
302 string h = getHashFromNSEC3(wildcard, nsec3);
303 if (h.empty()) {
304 return false;
305 }
306 LOG("\tWildcard hash: "<<toBase32Hex(h)<<endl);
307 string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
308 LOG("\tNSEC3 hash: "<<toBase32Hex(beginHash)<<" -> "<<toBase32Hex(nsec3->d_nexthash)<<endl);
309
310 if (beginHash == h) {
311 LOG("\tWildcard hash matches");
312 if (wildcardExists) {
313 *wildcardExists = true;
314 }
315 if (qtype == 0 || !nsec3->isSet(qtype)) {
316 LOG(" and proves that the type did not exist"<<endl);
317 return true;
318 }
319 LOG(" BUT the type did exist!"<<endl);
320 return false;
321 }
322
323 if (isCoveredByNSEC3Hash(h, beginHash, nsec3->d_nexthash)) {
324 LOG("\tWildcard hash is covered"<<endl);
325 return true;
326 }
327 }
328 }
329 }
330
331 return false;
332 }
333
334 /*
335 This function checks whether the existence of qname|qtype is denied by the NSEC and NSEC3
336 in validrrsets.
337 - If `referralToUnsigned` is true and qtype is QType::DS, this functions returns NODATA
338 if a NSEC or NSEC3 proves that the name exists but no NS type exists, as specified in RFC 5155 section 8.9.
339 - If `wantsNoDataProof` is set but a NSEC proves that the whole name does not exist, the function will return
340 NXQTYPE is the name is proven to be ENT and NXDOMAIN otherwise.
341 - If `needWildcardProof` is false, the proof that a wildcard covering this qname|qtype is not checked. It is
342 useful when we have a positive answer synthetized from a wildcard and we only need to prove that the exact
343 name does not exist.
344 */
345 dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, bool needWildcardProof, unsigned int wildcardLabelsCount)
346 {
347 bool nsec3Seen = false;
348 if (!needWildcardProof && wildcardLabelsCount == 0) {
349 throw PDNSException("Invalid wildcard labels count for the validation of a positive answer synthetized from a wildcard");
350 }
351
352 for(const auto& v : validrrsets) {
353 LOG("Do have: "<<v.first.first<<"/"<<DNSRecordContent::NumberToType(v.first.second)<<endl);
354
355 if(v.first.second==QType::NSEC) {
356 for(const auto& r : v.second.records) {
357 LOG("\t"<<r->getZoneRepresentation()<<endl);
358 auto nsec = std::dynamic_pointer_cast<NSECRecordContent>(r);
359 if(!nsec)
360 continue;
361
362 const DNSName signer = getSigner(v.second.signatures);
363 if (!v.first.first.isPartOf(signer))
364 continue;
365
366 const DNSName owner = getNSECOwnerName(v.first.first, v.second.signatures);
367 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
368 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
369 nonexistence of any RRs below that zone cut, which include all RRs at
370 that (original) owner name other than DS RRs, and all RRs below that
371 owner name regardless of type.
372 */
373 if (qtype != QType::DS && (qname == owner || qname.isPartOf(owner)) && isNSECAncestorDelegation(signer, owner, nsec)) {
374 LOG("type is "<<QType(qtype).getName()<<", NS is "<<std::to_string(nsec->isSet(QType::NS))<<", SOA is "<<std::to_string(nsec->isSet(QType::SOA))<<", signer is "<<signer<<", owner name is "<<owner<<endl);
375 /* this is an "ancestor delegation" NSEC RR */
376 LOG("An ancestor delegation NSEC RR can only deny the existence of a DS"<<endl);
377 return NODATA;
378 }
379
380 /* check if the type is denied */
381 if(qname == owner) {
382 if (nsec->isSet(qtype)) {
383 LOG("Does _not_ deny existence of type "<<QType(qtype).getName()<<endl);
384 return NODATA;
385 }
386
387 LOG("Denies existence of type "<<QType(qtype).getName()<<endl);
388
389 /* RFC 6840 section 4.3 */
390 if (nsec->isSet(QType::CNAME)) {
391 LOG("However a CNAME exists"<<endl);
392 return NODATA;
393 }
394
395 /*
396 * RFC 4035 Section 2.3:
397 * The bitmap for the NSEC RR at a delegation point requires special
398 * attention. Bits corresponding to the delegation NS RRset and any
399 * RRsets for which the parent zone has authoritative data MUST be set
400 */
401 if (referralToUnsigned && qtype == QType::DS && !nsec->isSet(QType::NS)) {
402 LOG("However, no NS record exists at this level!"<<endl);
403 return NODATA;
404 }
405
406 /* we know that the name exists (but this qtype doesn't) so except
407 if the answer was generated by a wildcard expansion, no wildcard
408 could have matched (rfc4035 section 5.4 bullet 1) */
409 if (!isWildcardExpanded(owner, v.second.signatures) || isWildcardExpandedOntoItself(owner, v.second.signatures)) {
410 needWildcardProof = false;
411 }
412
413 if (!needWildcardProof || provesNoWildCard(qname, qtype, validrrsets)) {
414 return NXQTYPE;
415 }
416
417 LOG("But the existence of a wildcard is not denied for "<<qname<<"/"<<endl);
418 return NODATA;
419 }
420
421 /* check if the whole NAME is denied existing */
422 if(isCoveredByNSEC(qname, owner, nsec->d_next)) {
423 LOG(qname<<" is covered ");
424 /* if the name is an ENT and we received a NODATA answer,
425 we are fine with a NSEC proving that the name does not exist. */
426 if (wantsNoDataProof && nsecProvesENT(qname, owner, nsec->d_next)) {
427 LOG("Denies existence of type "<<qname<<"/"<<QType(qtype).getName()<<" by proving that "<<qname<<" is an ENT"<<endl);
428 return NXQTYPE;
429 }
430
431 if (!needWildcardProof) {
432 LOG("and we did not need a wildcard proof"<<endl);
433 return NXDOMAIN;
434 }
435
436 LOG("but we do need a wildcard proof so ");
437 if (wantsNoDataProof) {
438 LOG("looking for NODATA proof"<<endl);
439 if (provesNoDataWildCard(qname, qtype, validrrsets)) {
440 return NXQTYPE;
441 }
442 }
443 else {
444 LOG("looking for NO wildcard proof"<<endl);
445 if (provesNoWildCard(qname, qtype, validrrsets)) {
446 return NXDOMAIN;
447 }
448 }
449
450 LOG("But the existence of a wildcard is not denied for "<<qname<<"/"<<QType(qtype).getName()<<endl);
451 return NODATA;
452 }
453
454 LOG("Did not deny existence of "<<QType(qtype).getName()<<", "<<owner<<"?="<<qname<<", "<<nsec->isSet(qtype)<<", next: "<<nsec->d_next<<endl);
455 }
456 } else if(v.first.second==QType::NSEC3) {
457 for(const auto& r : v.second.records) {
458 LOG("\t"<<r->getZoneRepresentation()<<endl);
459 auto nsec3 = std::dynamic_pointer_cast<NSEC3RecordContent>(r);
460 if(!nsec3)
461 continue;
462
463 const DNSName signer = getSigner(v.second.signatures);
464 if (!v.first.first.isPartOf(signer)) {
465 LOG("Owner "<<v.first.first<<" is not part of the signer "<<signer<<", ignoring"<<endl);
466 continue;
467 }
468
469 string h = getHashFromNSEC3(qname, nsec3);
470 if (h.empty()) {
471 LOG("Unsupported hash, ignoring"<<endl);
472 return INSECURE;
473 }
474
475 nsec3Seen = true;
476
477 // cerr<<"Salt length: "<<nsec3->d_salt.length()<<", iterations: "<<nsec3->d_iterations<<", hashed: "<<qname<<endl;
478 LOG("\tquery hash: "<<toBase32Hex(h)<<endl);
479 string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
480
481 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
482 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
483 nonexistence of any RRs below that zone cut, which include all RRs at
484 that (original) owner name other than DS RRs, and all RRs below that
485 owner name regardless of type.
486 */
487 if (qtype != QType::DS && beginHash == h && isNSEC3AncestorDelegation(signer, v.first.first, nsec3)) {
488 LOG("type is "<<QType(qtype).getName()<<", NS is "<<std::to_string(nsec3->isSet(QType::NS))<<", SOA is "<<std::to_string(nsec3->isSet(QType::SOA))<<", signer is "<<signer<<", owner name is "<<v.first.first<<endl);
489 /* this is an "ancestor delegation" NSEC3 RR */
490 LOG("An ancestor delegation NSEC3 RR can only deny the existence of a DS"<<endl);
491 return NODATA;
492 }
493
494 // If the name exists, check if the qtype is denied
495 if(beginHash == h) {
496 if (nsec3->isSet(qtype)) {
497 LOG("Does _not_ deny existence of type "<<QType(qtype).getName()<<" for name "<<qname<<" (not opt-out)."<<endl);
498 return NODATA;
499 }
500
501 LOG("Denies existence of type "<<QType(qtype).getName()<<" for name "<<qname<<" (not opt-out)."<<endl);
502
503 /* RFC 6840 section 4.3 */
504 if (nsec3->isSet(QType::CNAME)) {
505 LOG("However a CNAME exists"<<endl);
506 return NODATA;
507 }
508
509 /*
510 * RFC 5155 section 8.9:
511 * If there is an NSEC3 RR present in the response that matches the
512 * delegation name, then the validator MUST ensure that the NS bit is
513 * set and that the DS bit is not set in the Type Bit Maps field of the
514 * NSEC3 RR.
515 */
516 if (referralToUnsigned && qtype == QType::DS && !nsec3->isSet(QType::NS)) {
517 LOG("However, no NS record exists at this level!"<<endl);
518 return NODATA;
519 }
520
521 return NXQTYPE;
522 }
523 }
524 }
525 }
526
527 /* if we have no NSEC3 records, we are done */
528 if (!nsec3Seen) {
529 return NODATA;
530 }
531
532 DNSName closestEncloser(qname);
533 bool found = false;
534
535 if (needWildcardProof) {
536 /* We now need to look for a NSEC3 covering the closest (provable) encloser
537 RFC 5155 section-7.2.1
538 FRC 7129 section-5.5
539 */
540 LOG("Now looking for the closest encloser for "<<qname<<endl);
541
542 while (found == false && closestEncloser.chopOff()) {
543 for(const auto& v : validrrsets) {
544 if(v.first.second==QType::NSEC3) {
545 for(const auto& r : v.second.records) {
546 LOG("\t"<<r->getZoneRepresentation()<<endl);
547 auto nsec3 = std::dynamic_pointer_cast<NSEC3RecordContent>(r);
548 if(!nsec3)
549 continue;
550
551 const DNSName signer = getSigner(v.second.signatures);
552 if (!v.first.first.isPartOf(signer)) {
553 LOG("Owner "<<v.first.first<<" is not part of the signer "<<signer<<", ignoring"<<endl);
554 continue;
555 }
556
557 string h = getHashFromNSEC3(closestEncloser, nsec3);
558 if (h.empty()) {
559 return INSECURE;
560 }
561
562 string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
563
564 LOG("Comparing "<<toBase32Hex(h)<<" ("<<closestEncloser<<") against "<<toBase32Hex(beginHash)<<endl);
565 if(beginHash == h) {
566 if (qtype != QType::DS && isNSEC3AncestorDelegation(signer, v.first.first, nsec3)) {
567 LOG("An ancestor delegation NSEC3 RR can only deny the existence of a DS"<<endl);
568 continue;
569 }
570
571 LOG("Closest encloser for "<<qname<<" is "<<closestEncloser<<endl);
572 found = true;
573 break;
574 }
575 }
576 }
577 if (found == true) {
578 break;
579 }
580 }
581 }
582 }
583 else {
584 /* RFC 5155 section-7.2.6:
585 "It is not necessary to return an NSEC3 RR that matches the closest encloser,
586 as the existence of this closest encloser is proven by the presence of the
587 expanded wildcard in the response.
588 */
589 found = true;
590 unsigned int closestEncloserLabelsCount = closestEncloser.countLabels();
591 while (wildcardLabelsCount > 0 && closestEncloserLabelsCount > wildcardLabelsCount) {
592 closestEncloser.chopOff();
593 closestEncloserLabelsCount--;
594 }
595 }
596
597 bool nextCloserFound = false;
598 bool isOptOut = false;
599
600 if (found == true) {
601 /* now that we have found the closest (provable) encloser,
602 we can construct the next closer (FRC7129 section-5.5) name
603 and look for a NSEC3 RR covering it */
604 unsigned int labelIdx = qname.countLabels() - closestEncloser.countLabels();
605 if (labelIdx >= 1) {
606 DNSName nextCloser(closestEncloser);
607 nextCloser.prependRawLabel(qname.getRawLabel(labelIdx - 1));
608 LOG("Looking for a NSEC3 covering the next closer name "<<nextCloser<<endl);
609
610 for(const auto& v : validrrsets) {
611 if(v.first.second==QType::NSEC3) {
612 for(const auto& r : v.second.records) {
613 LOG("\t"<<r->getZoneRepresentation()<<endl);
614 auto nsec3 = std::dynamic_pointer_cast<NSEC3RecordContent>(r);
615 if(!nsec3)
616 continue;
617
618 string h = getHashFromNSEC3(nextCloser, nsec3);
619 if (h.empty()) {
620 return INSECURE;
621 }
622
623 string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
624
625 LOG("Comparing "<<toBase32Hex(h)<<" against "<<toBase32Hex(beginHash)<<" -> "<<toBase32Hex(nsec3->d_nexthash)<<endl);
626 if(isCoveredByNSEC3Hash(h, beginHash, nsec3->d_nexthash)) {
627 LOG("Denies existence of name "<<qname<<"/"<<QType(qtype).getName());
628 nextCloserFound = true;
629
630 if (qtype == QType::DS && nsec3->d_flags & 1) {
631 LOG(" but is opt-out!");
632 isOptOut = true;
633 }
634 LOG(endl);
635 break;
636 }
637 LOG("Did not cover us ("<<qname<<"), start="<<v.first.first<<", us="<<toBase32Hex(h)<<", end="<<toBase32Hex(nsec3->d_nexthash)<<endl);
638 }
639 }
640 if (nextCloserFound) {
641 break;
642 }
643 }
644 }
645 }
646
647 if (nextCloserFound) {
648 bool wildcardExists = false;
649 /* RFC 7129 section-5.6 */
650 if (needWildcardProof && !provesNSEC3NoWildCard(closestEncloser, qtype, validrrsets, &wildcardExists)) {
651 if (!isOptOut) {
652 LOG("But the existence of a wildcard is not denied for "<<qname<<"/"<<QType(qtype).getName()<<endl);
653 return NODATA;
654 }
655 }
656
657 if (isOptOut) {
658 return OPTOUT;
659 }
660 else {
661 if (wildcardExists) {
662 return NXQTYPE;
663 }
664 return NXDOMAIN;
665 }
666 }
667
668 // There were no valid NSEC(3) records
669 // XXX maybe this should be INSECURE... it depends on the semantics of this function
670 return NODATA;
671 }
672
673 /*
674 * Finds all the zone-cuts between begin (longest name) and end (shortest name),
675 * returns them all zone cuts, including end, but (possibly) not begin
676 */
677 static const vector<DNSName> getZoneCuts(const DNSName& begin, const DNSName& end, DNSRecordOracle& dro)
678 {
679 vector<DNSName> ret;
680 if(!begin.isPartOf(end))
681 throw PDNSException(end.toLogString() + "is not part of " + begin.toLogString());
682
683 DNSName qname(end);
684 vector<string> labelsToAdd = begin.makeRelative(end).getRawLabels();
685
686 // The shortest name is assumed to a zone cut
687 ret.push_back(qname);
688 while(qname != begin) {
689 bool foundCut = false;
690 if (labelsToAdd.empty())
691 break;
692
693 qname.prependRawLabel(labelsToAdd.back());
694 labelsToAdd.pop_back();
695 auto records = dro.get(qname, (uint16_t)QType::NS);
696 for (const auto record : records) {
697 if(record.d_type != QType::NS || record.d_name != qname)
698 continue;
699 foundCut = true;
700 break;
701 }
702 if (foundCut)
703 ret.push_back(qname);
704 }
705 return ret;
706 }
707
708 bool isRRSIGNotExpired(const time_t now, const shared_ptr<RRSIGRecordContent> sig)
709 {
710 return sig->d_siginception - g_signatureInceptionSkew <= now && sig->d_sigexpire >= now;
711 }
712
713 static bool checkSignatureWithKey(time_t now, const shared_ptr<RRSIGRecordContent> sig, const shared_ptr<DNSKEYRecordContent> key, const std::string& msg)
714 {
715 bool result = false;
716 try {
717 /* rfc4035:
718 - The validator's notion of the current time MUST be less than or equal to the time listed in the RRSIG RR's Expiration field.
719 - The validator's notion of the current time MUST be greater than or equal to the time listed in the RRSIG RR's Inception field.
720 */
721 if(isRRSIGNotExpired(now, sig)) {
722 std::shared_ptr<DNSCryptoKeyEngine> dke = shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromPublicKeyString(key->d_algorithm, key->d_key));
723 result = dke->verify(msg, sig->d_signature);
724 LOG("signature by key with tag "<<sig->d_tag<<" and algorithm "<<DNSSECKeeper::algorithm2name(sig->d_algorithm)<<" was " << (result ? "" : "NOT ")<<"valid"<<endl);
725 }
726 else {
727 LOG("Signature is "<<((sig->d_siginception - g_signatureInceptionSkew > now) ? "not yet valid" : "expired")<<" (inception: "<<sig->d_siginception<<", inception skew: "<<g_signatureInceptionSkew<<", expiration: "<<sig->d_sigexpire<<", now: "<<now<<")"<<endl);
728 }
729 }
730 catch(const std::exception& e) {
731 LOG("Could not make a validator for signature: "<<e.what()<<endl);
732 }
733 return result;
734 }
735
736 bool validateWithKeySet(time_t now, const DNSName& name, const vector<shared_ptr<DNSRecordContent> >& records, const vector<shared_ptr<RRSIGRecordContent> >& signatures, const skeyset_t& keys, bool validateAllSigs)
737 {
738 bool isValid = false;
739
740 for(const auto& signature : signatures) {
741 unsigned int labelCount = name.countLabels();
742 if (signature->d_labels > labelCount) {
743 LOG(name<<": Discarding invalid RRSIG whose label count is "<<signature->d_labels<<" while the RRset owner name has only "<<labelCount<<endl);
744 }
745
746 vector<shared_ptr<DNSRecordContent> > toSign = records;
747
748 auto r = getByTag(keys, signature->d_tag, signature->d_algorithm);
749
750 if(r.empty()) {
751 LOG("No key provided for "<<signature->d_tag<<" and algorithm "<<std::to_string(signature->d_algorithm)<<endl;);
752 continue;
753 }
754
755 string msg=getMessageForRRSET(name, *signature, toSign, true);
756 for(const auto& l : r) {
757 bool signIsValid = checkSignatureWithKey(now, signature, l, msg);
758 if(signIsValid) {
759 isValid = true;
760 LOG("Validated "<<name<<"/"<<DNSRecordContent::NumberToType(signature->d_type)<<endl);
761 // cerr<<"valid"<<endl;
762 // cerr<<"! validated "<<i->first.first<<"/"<<)<<endl;
763 }
764 else {
765 LOG("signature invalid"<<endl);
766 }
767 if (signIsValid && !validateAllSigs) {
768 return true;
769 }
770 }
771 }
772
773 return isValid;
774 }
775
776 void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const skeyset_t& keys)
777 {
778 validated.clear();
779 /* cerr<<"Validating an rrset with following keys: "<<endl;
780 for(auto& key : keys) {
781 cerr<<"\tTag: "<<key->getTag()<<" -> "<<key->getZoneRepresentation()<<endl;
782 }
783 */
784 time_t now = time(nullptr);
785 for(auto i=rrsets.cbegin(); i!=rrsets.cend(); i++) {
786 LOG("validating "<<(i->first.first)<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<" with "<<i->second.signatures.size()<<" sigs"<<endl);
787 if (validateWithKeySet(now, i->first.first, i->second.records, i->second.signatures, keys, true)) {
788 validated[i->first] = i->second;
789 }
790 }
791 }
792
793 // returns vState
794 // should return vState, zone cut and validated keyset
795 // i.e. www.7bits.nl -> insecure/7bits.nl/[]
796 // www.powerdnssec.org -> secure/powerdnssec.org/[keys]
797 // www.dnssec-failed.org -> bogus/dnssec-failed.org/[]
798
799 cspmap_t harvestCSPFromRecs(const vector<DNSRecord>& recs)
800 {
801 cspmap_t cspmap;
802 for(const auto& rec : recs) {
803 // cerr<<"res "<<rec.d_name<<"/"<<rec.d_type<<endl;
804 if(rec.d_type == QType::OPT) continue;
805
806 if(rec.d_type == QType::RRSIG) {
807 auto rrc = getRR<RRSIGRecordContent>(rec);
808 if (rrc) {
809 cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
810 }
811 }
812 else {
813 cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content);
814 }
815 }
816 return cspmap;
817 }
818
819 bool getTrustAnchor(const map<DNSName,dsmap_t>& anchors, const DNSName& zone, dsmap_t &res)
820 {
821 const auto& it = anchors.find(zone);
822
823 if (it == anchors.cend()) {
824 return false;
825 }
826
827 res = it->second;
828 return true;
829 }
830
831 bool haveNegativeTrustAnchor(const map<DNSName,std::string>& negAnchors, const DNSName& zone, std::string& reason)
832 {
833 const auto& it = negAnchors.find(zone);
834
835 if (it == negAnchors.cend()) {
836 return false;
837 }
838
839 reason = it->second;
840 return true;
841 }
842
843 void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, vector<shared_ptr<DNSRecordContent> >& toSign, const vector<shared_ptr<RRSIGRecordContent> >& sigs, skeyset_t& validkeys)
844 {
845 /*
846 * Check all DNSKEY records against all DS records and place all DNSKEY records
847 * that have DS records (that we support the algo for) in the tentative key storage
848 */
849 for(auto const& dsrc : dsmap)
850 {
851 auto r = getByTag(tkeys, dsrc.d_tag, dsrc.d_algorithm);
852 // cerr<<"looking at DS with tag "<<dsrc.d_tag<<", algo "<<DNSSECKeeper::algorithm2name(dsrc.d_algorithm)<<", digest "<<std::to_string(dsrc.d_digesttype)<<" for "<<zone<<", got "<<r.size()<<" DNSKEYs for tag"<<endl;
853
854 for(const auto& drc : r)
855 {
856 bool isValid = false;
857 bool dsCreated = false;
858 DSRecordContent dsrc2;
859 try {
860 dsrc2 = makeDSFromDNSKey(zone, *drc, dsrc.d_digesttype);
861 dsCreated = true;
862 isValid = dsrc == dsrc2;
863 }
864 catch(const std::exception &e) {
865 LOG("Unable to make DS from DNSKey: "<<e.what()<<endl);
866 }
867
868 if(isValid) {
869 LOG("got valid DNSKEY (it matches the DS) with tag "<<dsrc.d_tag<<" and algorithm "<<std::to_string(dsrc.d_algorithm)<<" for "<<zone<<endl);
870
871 validkeys.insert(drc);
872 }
873 else {
874 if (dsCreated) {
875 LOG("DNSKEY did not match the DS, parent DS: "<<dsrc.getZoneRepresentation() << " ! = "<<dsrc2.getZoneRepresentation()<<endl);
876 }
877 }
878 }
879 }
880
881 vector<uint16_t> toSignTags;
882 for (const auto& key : tkeys) {
883 toSignTags.push_back(key->getTag());
884 }
885
886 // cerr<<"got "<<validkeys.size()<<"/"<<tkeys.size()<<" valid/tentative keys"<<endl;
887 // these counts could be off if we somehow ended up with
888 // duplicate keys. Should switch to a type that prevents that.
889 if(validkeys.size() < tkeys.size())
890 {
891 // this should mean that we have one or more DS-validated DNSKEYs
892 // but not a fully validated DNSKEY set, yet
893 // one of these valid DNSKEYs should be able to validate the
894 // whole set
895 for(const auto& sig : sigs)
896 {
897 // cerr<<"got sig for keytag "<<i->d_tag<<" matching "<<getByTag(tkeys, i->d_tag).size()<<" keys of which "<<getByTag(validkeys, i->d_tag).size()<<" valid"<<endl;
898 auto bytag = getByTag(validkeys, sig->d_tag, sig->d_algorithm);
899
900 if (bytag.empty()) {
901 continue;
902 }
903
904 string msg = getMessageForRRSET(zone, *sig, toSign);
905 for(const auto& key : bytag) {
906 // cerr<<"validating : ";
907 bool signIsValid = checkSignatureWithKey(now, sig, key, msg);
908
909 if(signIsValid)
910 {
911 LOG("validation succeeded - whole DNSKEY set is valid"<<endl);
912 validkeys = tkeys;
913 break;
914 }
915 else {
916 LOG("Validation did not succeed!"<<endl);
917 }
918 }
919 // if(validkeys.empty()) cerr<<"did not manage to validate DNSKEY set based on DS-validated KSK, only passing KSK on"<<endl;
920 }
921 }
922 }
923
924 vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, skeyset_t& keyset)
925 {
926 auto luaLocal = g_luaconfs.getLocal();
927 const auto anchors = luaLocal->dsAnchors;
928 if (anchors.empty()) // Nothing to do here
929 return Insecure;
930
931 // Determine the lowest (i.e. with the most labels) Trust Anchor for zone
932 DNSName lowestTA(".");
933 for (auto const &anchor : anchors)
934 if (zone.isPartOf(anchor.first) && lowestTA.countLabels() < anchor.first.countLabels())
935 lowestTA = anchor.first;
936
937 // Before searching for the keys, see if we have a Negative Trust Anchor. If
938 // so, test if the NTA is valid and return an NTA state
939 const auto negAnchors = luaLocal->negAnchors;
940
941 if (!negAnchors.empty()) {
942 DNSName lowestNTA;
943
944 for (auto const &negAnchor : negAnchors)
945 if (zone.isPartOf(negAnchor.first) && lowestNTA.countLabels() <= negAnchor.first.countLabels())
946 lowestNTA = negAnchor.first;
947
948 if(!lowestNTA.empty()) {
949 LOG("Found a Negative Trust Anchor for "<<lowestNTA<<", which was added with reason '"<<negAnchors.at(lowestNTA)<<"', ");
950
951 /* RFC 7646 section 2.1 tells us that we SHOULD still validate if there
952 * is a Trust Anchor below the Negative Trust Anchor for the name we
953 * attempt validation for. However, section 3 tells us this positive
954 * Trust Anchor MUST be *below* the name and not the name itself
955 */
956 if(lowestTA.countLabels() <= lowestNTA.countLabels()) {
957 LOG("marking answer Insecure"<<endl);
958 return NTA; // Not Insecure, this way validateRecords() can shortcut
959 }
960 LOG("but a Trust Anchor for "<<lowestTA<<" is configured, continuing validation."<<endl);
961 }
962 }
963
964 skeyset_t validkeys;
965 dsmap_t dsmap;
966
967 dsmap_t* tmp = (dsmap_t*) rplookup(anchors, lowestTA);
968 if (tmp)
969 dsmap = *tmp;
970
971 auto zoneCuts = getZoneCuts(zone, lowestTA, dro);
972
973 LOG("Found the following zonecuts:")
974 for(const auto& zonecut : zoneCuts)
975 LOG(" => "<<zonecut);
976 LOG(endl);
977
978 for(auto zoneCutIter = zoneCuts.cbegin(); zoneCutIter != zoneCuts.cend(); ++zoneCutIter)
979 {
980 vector<shared_ptr<RRSIGRecordContent> > sigs;
981 vector<shared_ptr<DNSRecordContent> > toSign;
982
983 skeyset_t tkeys; // tentative keys
984 validkeys.clear();
985
986 // cerr<<"got DS for ["<<qname<<"], grabbing DNSKEYs"<<endl;
987 auto records=dro.get(*zoneCutIter, (uint16_t)QType::DNSKEY);
988 // this should use harvest perhaps
989 for(const auto& rec : records) {
990 if(rec.d_name != *zoneCutIter)
991 continue;
992
993 if(rec.d_type == QType::RRSIG)
994 {
995 auto rrc=getRR<RRSIGRecordContent> (rec);
996 if(rrc) {
997 LOG("Got signature: "<<rrc->getZoneRepresentation()<<" with tag "<<rrc->d_tag<<", for type "<<DNSRecordContent::NumberToType(rrc->d_type)<<endl);
998 if(rrc->d_type != QType::DNSKEY)
999 continue;
1000 sigs.push_back(rrc);
1001 }
1002 }
1003 else if(rec.d_type == QType::DNSKEY)
1004 {
1005 auto drc=getRR<DNSKEYRecordContent> (rec);
1006 if(drc) {
1007 tkeys.insert(drc);
1008 LOG("Inserting key with tag "<<drc->getTag()<<" and algorithm "<<DNSSECKeeper::algorithm2name(drc->d_algorithm)<<": "<<drc->getZoneRepresentation()<<endl);
1009
1010 toSign.push_back(rec.d_content);
1011 }
1012 }
1013 }
1014 LOG("got "<<tkeys.size()<<" keys and "<<sigs.size()<<" sigs from server"<<endl);
1015
1016 /*
1017 * Check all DNSKEY records against all DS records and place all DNSKEY records
1018 * that have DS records (that we support the algo for) in the tentative key storage
1019 */
1020 validateDNSKeysAgainstDS(time(nullptr), *zoneCutIter, dsmap, tkeys, toSign, sigs, validkeys);
1021
1022 if(validkeys.empty())
1023 {
1024 LOG("ended up with zero valid DNSKEYs, going Bogus"<<endl);
1025 return Bogus;
1026 }
1027 LOG("situation: we have one or more valid DNSKEYs for ["<<*zoneCutIter<<"] (want ["<<zone<<"])"<<endl);
1028
1029 if(zoneCutIter == zoneCuts.cend()-1) {
1030 LOG("requested keyset found! returning Secure for the keyset"<<endl);
1031 keyset.insert(validkeys.cbegin(), validkeys.cend());
1032 return Secure;
1033 }
1034
1035 // We now have the DNSKEYs, use them to validate the DS records at the next zonecut
1036 LOG("next name ["<<*(zoneCutIter+1)<<"], trying to get DS"<<endl);
1037
1038 dsmap_t tdsmap; // tentative DSes
1039 dsmap.clear();
1040 toSign.clear();
1041
1042 auto recs=dro.get(*(zoneCutIter+1), QType::DS);
1043
1044 cspmap_t cspmap=harvestCSPFromRecs(recs);
1045
1046 cspmap_t validrrsets;
1047 validateWithKeySet(cspmap, validrrsets, validkeys);
1048
1049 LOG("got "<<cspmap.count(make_pair(*(zoneCutIter+1),QType::DS))<<" records for DS query of which "<<validrrsets.count(make_pair(*(zoneCutIter+1),QType::DS))<<" valid "<<endl);
1050
1051 auto r = validrrsets.equal_range(make_pair(*(zoneCutIter+1), QType::DS));
1052 if(r.first == r.second) {
1053 LOG("No DS for "<<*(zoneCutIter+1)<<", now look for a secure denial"<<endl);
1054 dState res = getDenial(validrrsets, *(zoneCutIter+1), QType::DS, true, true);
1055 if (res == INSECURE || res == NXDOMAIN)
1056 return Bogus;
1057 if (res == NXQTYPE || res == OPTOUT)
1058 return Insecure;
1059 }
1060
1061 /*
1062 * Collect all DS records and add them to the dsmap for the next iteration
1063 */
1064 for(auto cspiter =r.first; cspiter!=r.second; cspiter++) {
1065 for(auto j=cspiter->second.records.cbegin(); j!=cspiter->second.records.cend(); j++)
1066 {
1067 const auto dsrc=std::dynamic_pointer_cast<DSRecordContent>(*j);
1068 if(dsrc) {
1069 dsmap.insert(*dsrc);
1070 }
1071 }
1072 }
1073 }
1074 // There were no zone cuts (aka, we should never get here)
1075 return Bogus;
1076 }
1077
1078 bool isSupportedDS(const DSRecordContent& ds)
1079 {
1080 if (!DNSCryptoKeyEngine::isAlgorithmSupported(ds.d_algorithm)) {
1081 LOG("Discarding DS "<<ds.d_tag<<" because we don't support algorithm number "<<std::to_string(ds.d_algorithm)<<endl);
1082 return false;
1083 }
1084
1085 if (!DNSCryptoKeyEngine::isDigestSupported(ds.d_digesttype)) {
1086 LOG("Discarding DS "<<ds.d_tag<<" because we don't support digest number "<<std::to_string(ds.d_digesttype)<<endl);
1087 return false;
1088 }
1089
1090 return true;
1091 }
1092
1093 DNSName getSigner(const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
1094 {
1095 for (const auto sig : signatures) {
1096 if (sig) {
1097 return sig->d_signer;
1098 }
1099 }
1100
1101 return DNSName();
1102 }