]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc8.cc
rec: CVE-2023-50387 and CVE-2023-50868
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc8.cc
CommitLineData
1c2d079d 1#ifndef BOOST_TEST_DYN_LINK
86675669 2#define BOOST_TEST_DYN_LINK
1c2d079d
FM
3#endif
4
86675669
OM
5#include <boost/test/unit_test.hpp>
6
7#include "test-syncres_cc.hh"
8
9BOOST_AUTO_TEST_SUITE(syncres_cc8)
10
15e973d6
OM
11static dState getDenial(const cspmap_t& validrrsets, const DNSName& qname, uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, const OptLog& log = std::nullopt, bool needWildcardProof = true, unsigned int wildcardLabelsCount = 0)
12{
13 pdns::validation::ValidationContext context;
14 context.d_nsec3IterationsRemainingQuota = std::numeric_limits<decltype(context.d_nsec3IterationsRemainingQuota)>::max();
15 return getDenial(validrrsets, qname, qtype, referralToUnsigned, wantsNoDataProof, context, log, needWildcardProof, wildcardLabelsCount);
16}
17
42dcf516
OM
18BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap)
19{
86675669
OM
20 initSR();
21
22 testkeysset_t keys;
690b86b7 23 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
24
25 vector<DNSRecord> records;
26
c1e7b833 27 sortedRecords_t recordContents;
d06dcda4 28 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
29
30 /*
31 No wrap test case:
32 a.example.org. -> d.example.org. denies the existence of b.example.org.
33 */
da2636b6 34 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 35 recordContents.insert(records.at(0).getContent());
86675669
OM
36 addRRSIG(keys, records, DNSName("example.org."), 300);
37 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
38 records.clear();
39
40 ContentSigPair pair;
41 pair.records = recordContents;
42 pair.signatures = signatureContents;
43 cspmap_t denialMap;
faa05786 44 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
86675669
OM
45
46 /* add wildcard denial */
47 recordContents.clear();
48 signatureContents.clear();
da2636b6 49 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 50 recordContents.insert(records.at(0).getContent());
86675669
OM
51 addRRSIG(keys, records, DNSName("example.org."), 300);
52 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
53 records.clear();
54
55 pair.records = recordContents;
56 pair.signatures = signatureContents;
faa05786 57 denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair;
86675669
OM
58
59 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
98307d0f 60 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
86675669
OM
61
62 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
63 /* let's check that d.example.org. is not denied by this proof */
98307d0f 64 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
65}
66
42dcf516
OM
67BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1)
68{
86675669
OM
69 initSR();
70
71 testkeysset_t keys;
690b86b7 72 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
73
74 vector<DNSRecord> records;
75
c1e7b833 76 sortedRecords_t recordContents;
d06dcda4 77 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
78
79 /*
80 Wrap case 1 test case:
81 z.example.org. -> b.example.org. denies the existence of a.example.org.
82 */
da2636b6 83 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 84 recordContents.insert(records.at(0).getContent());
86675669
OM
85 addRRSIG(keys, records, DNSName("example.org."), 300);
86 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
87 records.clear();
88
89 ContentSigPair pair;
90 pair.records = recordContents;
91 pair.signatures = signatureContents;
92 cspmap_t denialMap;
faa05786 93 denialMap[std::pair(DNSName("z.example.org."), QType::NSEC)] = pair;
86675669
OM
94
95 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
98307d0f 96 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
86675669
OM
97
98 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
99 /* let's check that d.example.org. is not denied by this proof */
98307d0f 100 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
101}
102
42dcf516
OM
103BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2)
104{
86675669
OM
105 initSR();
106
107 testkeysset_t keys;
690b86b7 108 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
109
110 vector<DNSRecord> records;
111
c1e7b833 112 sortedRecords_t recordContents;
d06dcda4 113 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
114
115 /*
116 Wrap case 2 test case:
117 y.example.org. -> a.example.org. denies the existence of z.example.org.
118 */
da2636b6 119 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 120 recordContents.insert(records.at(0).getContent());
86675669
OM
121 addRRSIG(keys, records, DNSName("example.org."), 300);
122 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
123 records.clear();
124
125 ContentSigPair pair;
126 pair.records = recordContents;
127 pair.signatures = signatureContents;
128 cspmap_t denialMap;
faa05786 129 denialMap[std::pair(DNSName("y.example.org."), QType::NSEC)] = pair;
86675669
OM
130
131 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
98307d0f 132 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
86675669
OM
133
134 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
135 /* let's check that d.example.org. is not denied by this proof */
98307d0f 136 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
137}
138
42dcf516
OM
139BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec)
140{
86675669
OM
141 initSR();
142
143 testkeysset_t keys;
690b86b7 144 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
145
146 vector<DNSRecord> records;
147
c1e7b833 148 sortedRecords_t recordContents;
d06dcda4 149 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
150
151 /*
152 Only one NSEC in the whole zone test case:
153 a.example.org. -> a.example.org. denies the existence of b.example.org.
154 */
da2636b6 155 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 156 recordContents.insert(records.at(0).getContent());
86675669
OM
157 addRRSIG(keys, records, DNSName("example.org."), 300);
158 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
159 records.clear();
160
161 ContentSigPair pair;
162 pair.records = recordContents;
163 pair.signatures = signatureContents;
164 cspmap_t denialMap;
faa05786 165 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
86675669
OM
166
167 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
98307d0f 168 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
86675669
OM
169
170 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
171 /* let's check that d.example.org. is not denied by this proof */
98307d0f 172 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
173}
174
42dcf516
OM
175BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial)
176{
86675669
OM
177 initSR();
178
179 testkeysset_t keys;
690b86b7 180 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
181
182 vector<DNSRecord> records;
183
c1e7b833 184 sortedRecords_t recordContents;
d06dcda4 185 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
186
187 /*
188 The RRSIG from "." denies the existence of anything between a. and c.,
189 including b.
190 */
da2636b6 191 addNSECRecordToLW(DNSName("a."), DNSName("c."), {QType::NS}, 600, records);
d06dcda4 192 recordContents.insert(records.at(0).getContent());
86675669
OM
193 addRRSIG(keys, records, DNSName("."), 300);
194 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
195 records.clear();
196
197 ContentSigPair pair;
198 pair.records = recordContents;
199 pair.signatures = signatureContents;
200 cspmap_t denialMap;
faa05786 201 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
86675669
OM
202
203 /* add wildcard denial */
204 recordContents.clear();
205 signatureContents.clear();
da2636b6 206 addNSECRecordToLW(DNSName("."), DNSName("+"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 207 recordContents.insert(records.at(0).getContent());
86675669
OM
208 addRRSIG(keys, records, DNSName("."), 300);
209 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
210 records.clear();
211
212 pair.records = recordContents;
213 pair.signatures = signatureContents;
faa05786 214 denialMap[std::pair(DNSName("."), QType::NSEC)] = pair;
86675669
OM
215
216 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
98307d0f 217 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
86675669
OM
218}
219
42dcf516
OM
220BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial)
221{
86675669
OM
222 initSR();
223
224 testkeysset_t keys;
690b86b7 225 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
226
227 vector<DNSRecord> records;
228
c1e7b833 229 sortedRecords_t recordContents;
d06dcda4 230 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
231
232 /*
233 The RRSIG from "." denies the existence of any type except NS at a.
234 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
235 signer field that is shorter than the owner name of the NSEC RR) it can't
0a9dcd16
RG
236 be used to deny anything except the whole name (which does not make sense here)
237 or a DS.
86675669 238 */
da2636b6 239 addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS}, 600, records);
d06dcda4 240 recordContents.insert(records.at(0).getContent());
86675669
OM
241 addRRSIG(keys, records, DNSName("."), 300);
242 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
243 records.clear();
244
245 ContentSigPair pair;
246 pair.records = recordContents;
247 pair.signatures = signatureContents;
248 cspmap_t denialMap;
faa05786 249 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
86675669
OM
250
251 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
252 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
253 nonexistence of any RRs below that zone cut, which include all RRs at
254 that (original) owner name other than DS RRs, and all RRs below that
255 owner name regardless of type.
256 */
257
0a9dcd16 258 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
86675669
OM
259 /* no data means the qname/qtype is not denied, because an ancestor
260 delegation NSEC can only deny the DS */
98307d0f 261 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
262
263 /* it can not be used to deny any RRs below that owner name either */
264 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
98307d0f 265 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
266
267 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
98307d0f 268 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
86675669
OM
269}
270
0a9dcd16
RG
271BOOST_AUTO_TEST_CASE(test_nsec_ds_denial_from_child)
272{
273 initSR();
274
275 testkeysset_t keys;
276 generateKeyMaterial(DNSName("org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
277 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
278
279 vector<DNSRecord> records;
280
281 sortedRecords_t recordContents;
d06dcda4 282 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
0a9dcd16
RG
283
284 addNSECRecordToLW(DNSName("example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 285 recordContents.insert(records.at(0).getContent());
0a9dcd16
RG
286 addRRSIG(keys, records, DNSName("example.org."), 300);
287 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
288 records.clear();
289
290 ContentSigPair pair;
291 pair.records = recordContents;
292 pair.signatures = signatureContents;
293 cspmap_t denialMap;
faa05786 294 denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair;
0a9dcd16
RG
295
296 /* check that this NSEC from the child zone can deny a AAAA at the apex */
10971f78 297 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::AAAA, false, true, std::nullopt, true), dState::NXQTYPE);
0a9dcd16
RG
298
299 /* but not that the DS does not exist, since we need the parent for that */
10971f78 300 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::DS, false, true, std::nullopt, true), dState::NODENIAL);
0a9dcd16
RG
301}
302
42dcf516
OM
303BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial)
304{
86675669
OM
305 initSR();
306
307 testkeysset_t keys;
690b86b7 308 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
309
310 vector<DNSRecord> records;
311
c1e7b833 312 sortedRecords_t recordContents;
d06dcda4 313 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
314
315 /*
316 * RFC 5155 section 8.9:
317 * If there is an NSEC3 RR present in the response that matches the
318 * delegation name, then the validator MUST ensure that the NS bit is
319 * set and that the DS bit is not set in the Type Bit Maps field of the
320 * NSEC3 RR.
321 */
322 /*
323 The RRSIG from "." denies the existence of any type at a.
324 NS should be set if it was proving an insecure delegation, let's check that
325 we correctly detect that it's not.
326 */
da2636b6 327 addNSECRecordToLW(DNSName("a."), DNSName("b."), {}, 600, records);
d06dcda4 328 recordContents.insert(records.at(0).getContent());
86675669
OM
329 addRRSIG(keys, records, DNSName("."), 300);
330 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
331 records.clear();
332
333 ContentSigPair pair;
334 pair.records = recordContents;
335 pair.signatures = signatureContents;
336 cspmap_t denialMap;
faa05786 337 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
86675669
OM
338
339 /* Insecure because the NS is not set, so while it does
340 denies the DS, it can't prove an insecure delegation */
341 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
98307d0f 342 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
343}
344
be5d851d
RG
345BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial_soa)
346{
347 initSR();
348
349 testkeysset_t keys;
350 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
351
352 vector<DNSRecord> records;
353
354 sortedRecords_t recordContents;
d06dcda4 355 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
be5d851d
RG
356
357 /*
358 * RFC 5155 section 8.9:
359 * If there is an NSEC3 RR present in the response that matches the
360 * delegation name, then the validator MUST ensure that the NS bit is
361 * set and that the DS bit is not set in the Type Bit Maps field of the
362 * NSEC3 RR.
363 */
364 /*
365 The RRSIG from "." denies the existence of any type at a except NS and SOA.
366 NS has to be set since it is proving an insecure delegation, but SOA should NOT!
367 */
368 addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS, QType::SOA}, 600, records);
d06dcda4 369 recordContents.insert(records.at(0).getContent());
be5d851d
RG
370 addRRSIG(keys, records, DNSName("."), 300);
371 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
372 records.clear();
373
374 ContentSigPair pair;
375 pair.records = recordContents;
376 pair.signatures = signatureContents;
377 cspmap_t denialMap;
378 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
379
380 /* Insecure because both NS and SOA are set, so this is not a proper delegation */
381 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
382 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
383}
384
42dcf516
OM
385BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname)
386{
86675669
OM
387 initSR();
388
389 testkeysset_t keys;
690b86b7 390 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
391
392 vector<DNSRecord> records;
393
c1e7b833 394 sortedRecords_t recordContents;
d06dcda4 395 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669 396
da2636b6 397 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::CNAME}, 600, records);
d06dcda4 398 recordContents.insert(records.at(0).getContent());
86675669
OM
399 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
400 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
401 records.clear();
402
403 ContentSigPair pair;
404 pair.records = recordContents;
405 pair.signatures = signatureContents;
406 cspmap_t denialMap;
faa05786 407 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
86675669
OM
408
409 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
410 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
98307d0f 411 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
412}
413
0a9dcd16
RG
414BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_ds)
415{
416 initSR();
417
418 testkeysset_t keys;
419 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
420
421 vector<DNSRecord> records;
422
423 sortedRecords_t recordContents;
d06dcda4 424 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
15e973d6
OM
425 const unsigned int nbIterations = 10;
426 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A}, 600, records, nbIterations);
d06dcda4 427 recordContents.insert(records.at(0).getContent());
0a9dcd16
RG
428 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
429 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
430
431 ContentSigPair pair;
432 pair.records = recordContents;
433 pair.signatures = signatureContents;
434 cspmap_t denialMap;
faa05786 435 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
0a9dcd16
RG
436 records.clear();
437
15e973d6
OM
438 pdns::validation::ValidationContext validationContext;
439 validationContext.d_nsec3IterationsRemainingQuota = 100U;
0a9dcd16 440 /* this NSEC3 is not valid to deny the DS since it is from the child zone */
15e973d6
OM
441 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("powerdns.com."), QType::DS, false, true, validationContext), dState::NODENIAL);
442 /* the NSEC3 hash is not computed since we it is from the child zone */
443 BOOST_CHECK_EQUAL(validationContext.d_nsec3IterationsRemainingQuota, 100U);
0a9dcd16 444 /* AAAA should be fine, though */
15e973d6
OM
445 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("powerdns.com."), QType::AAAA, false, true, validationContext), dState::NXQTYPE);
446 BOOST_CHECK_EQUAL(validationContext.d_nsec3IterationsRemainingQuota, (100U - nbIterations));
0a9dcd16
RG
447}
448
42dcf516
OM
449BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname)
450{
86675669
OM
451 initSR();
452
453 testkeysset_t keys;
690b86b7 454 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
455
456 vector<DNSRecord> records;
457
c1e7b833 458 sortedRecords_t recordContents;
d06dcda4 459 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669 460
da2636b6 461 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::CNAME}, 600, records);
d06dcda4 462 recordContents.insert(records.at(0).getContent());
86675669
OM
463 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
464 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
465
466 ContentSigPair pair;
467 pair.records = recordContents;
468 pair.signatures = signatureContents;
469 cspmap_t denialMap;
faa05786 470 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
471 records.clear();
472
473 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
474 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
98307d0f 475 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
476}
477
42dcf516
OM
478BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard)
479{
86675669
OM
480 initSR();
481
482 testkeysset_t keys;
690b86b7 483 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
484
485 vector<DNSRecord> records;
486
c1e7b833 487 sortedRecords_t recordContents;
d06dcda4 488 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669 489
da2636b6 490 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 491 recordContents.insert(records.at(0).getContent());
86675669
OM
492 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
493 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
494 records.clear();
495
496 ContentSigPair pair;
497 pair.records = recordContents;
498 pair.signatures = signatureContents;
499 cspmap_t denialMap;
faa05786 500 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
86675669
OM
501
502 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
98307d0f 503 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
504}
505
42dcf516
OM
506BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard)
507{
86675669
OM
508 initSR();
509
510 testkeysset_t keys;
690b86b7 511 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
512
513 vector<DNSRecord> records;
514
c1e7b833 515 sortedRecords_t recordContents;
d06dcda4 516 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669 517
d270600b 518 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10);
d06dcda4 519 recordContents.insert(records.at(0).getContent());
86675669
OM
520 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
521 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
522
523 ContentSigPair pair;
524 pair.records = recordContents;
525 pair.signatures = signatureContents;
526 cspmap_t denialMap;
faa05786 527 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
528
529 /* Add NSEC3 for the closest encloser */
530 recordContents.clear();
531 signatureContents.clear();
532 records.clear();
d270600b 533 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10);
d06dcda4 534 recordContents.insert(records.at(0).getContent());
86675669
OM
535 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
536 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
537
538 pair.records = recordContents;
539 pair.signatures = signatureContents;
faa05786 540 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669 541
0cbcfeda
RG
542 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, false);
543 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
544}
545
399f391d
RG
546BOOST_AUTO_TEST_CASE(test_nsec_expanded_wildcard_proof)
547{
548 initSR();
549
550 testkeysset_t keys;
551 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
552
553 vector<DNSRecord> records;
554
555 sortedRecords_t recordContents;
d06dcda4 556 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
399f391d
RG
557
558 /* proves that a.example.com does exist, and has been generated from a wildcard (see the RRSIG below) */
559 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 560 recordContents.insert(records.at(0).getContent());
399f391d
RG
561 addRRSIG(keys, records, DNSName("example.org."), 300, false, boost::none, DNSName("example.org."));
562 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
563 records.clear();
564
565 ContentSigPair pair;
566 pair.records = recordContents;
567 pair.signatures = signatureContents;
568 cspmap_t denialMap;
faa05786 569 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
399f391d
RG
570
571 /* This is an expanded wildcard proof, meaning that it does prove that the exact name
572 does not exist so the wildcard can apply */
10971f78 573 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType(0).getCode(), false, false, std::nullopt, false, /* normally retrieved from the RRSIG's d_labels */ 2);
399f391d
RG
574 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
575}
576
0cbcfeda
RG
577BOOST_AUTO_TEST_CASE(test_nsec_wildcard_with_cname)
578{
579 initSR();
580
581 testkeysset_t keys;
582 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
583
584 vector<DNSRecord> records;
585
586 sortedRecords_t recordContents;
d06dcda4 587 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
0cbcfeda
RG
588
589 /* proves that b.example.com does not exist */
590 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 591 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
592 addRRSIG(keys, records, DNSName("example.org."), 300);
593 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
594 records.clear();
595
596 ContentSigPair pair;
597 pair.records = recordContents;
598 pair.signatures = signatureContents;
599 cspmap_t denialMap;
faa05786 600 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
0cbcfeda
RG
601
602 /* add a NSEC proving that a wildcard exists, without a CNAME type */
603 recordContents.clear();
604 signatureContents.clear();
45c1026d 605 addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 606 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
607 addRRSIG(keys, records, DNSName("example.org."), 300);
608 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
609 records.clear();
610
611 pair.records = recordContents;
612 pair.signatures = signatureContents;
faa05786 613 denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair;
0cbcfeda
RG
614
615 /* A does exist at the wildcard, AAAA does not */
616 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
617 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
618
619 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
620 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
621
622 /* now we replace the wildcard by one with a CNAME */
623 recordContents.clear();
624 signatureContents.clear();
45c1026d 625 addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::CNAME, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 626 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
627 addRRSIG(keys, records, DNSName("example.org."), 300);
628 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
629 records.clear();
630
631 pair.records = recordContents;
632 pair.signatures = signatureContents;
faa05786 633 denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair;
0cbcfeda
RG
634
635 /* A and AAAA do not exist but we have a CNAME so at the wildcard */
636 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
637 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
638
639 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
640 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
641}
642
643BOOST_AUTO_TEST_CASE(test_nsec3_wildcard_with_cname)
644{
645 initSR();
646
647 testkeysset_t keys;
648 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
649
650 vector<DNSRecord> records;
651
652 sortedRecords_t recordContents;
d06dcda4 653 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
0cbcfeda
RG
654
655 /* proves that b.example.com does not exist */
656 addNSEC3NarrowRecordToLW(DNSName("b.example.org"), DNSName("example.org."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
d06dcda4 657 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
658 addRRSIG(keys, records, DNSName("example.org."), 300);
659 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
660
661 ContentSigPair pair;
662 pair.records = recordContents;
663 pair.signatures = signatureContents;
664 cspmap_t denialMap;
faa05786 665 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
0cbcfeda
RG
666
667 /* Add NSEC3 for the closest encloser */
668 recordContents.clear();
669 signatureContents.clear();
670 records.clear();
671 addNSEC3UnhashedRecordToLW(DNSName("example.org."), DNSName("example.org."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
d06dcda4 672 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
673 addRRSIG(keys, records, DNSName("example.org."), 300);
674 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
675
676 pair.records = recordContents;
677 pair.signatures = signatureContents;
faa05786 678 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
0cbcfeda
RG
679
680 /* add wildcard, without a CNAME type */
681 recordContents.clear();
682 signatureContents.clear();
683 records.clear();
684 addNSEC3UnhashedRecordToLW(DNSName("*.example.org."), DNSName("example.org"), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
d06dcda4 685 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
686 addRRSIG(keys, records, DNSName("example.org."), 300);
687 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
688
689 pair.records = recordContents;
690 pair.signatures = signatureContents;
faa05786 691 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
0cbcfeda
RG
692
693 /* A does exist at the wildcard, AAAA does not */
694 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
695 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
696
697 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
698 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
699
700 /* now we replace the wildcard by one with a CNAME */
701 recordContents.clear();
702 signatureContents.clear();
703 records.clear();
704 addNSEC3UnhashedRecordToLW(DNSName("*.example.org."), DNSName("example.org"), "whatever", {QType::CNAME, QType::RRSIG, QType::NSEC3}, 600, records);
d06dcda4 705 recordContents.insert(records.at(0).getContent());
0cbcfeda
RG
706 addRRSIG(keys, records, DNSName("example.org."), 300);
707 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
708
709 pair.records = recordContents;
710 pair.signatures = signatureContents;
faa05786 711 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
0cbcfeda
RG
712
713 /* A and AAAA do not exist but we have a CNAME so at the wildcard */
714 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
715 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
716
717 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
98307d0f 718 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
719}
720
42dcf516
OM
721BOOST_AUTO_TEST_CASE(test_nsec_ent_denial)
722{
86675669
OM
723 initSR();
724
725 testkeysset_t keys;
690b86b7 726 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
727
728 vector<DNSRecord> records;
729
c1e7b833 730 sortedRecords_t recordContents;
d06dcda4 731 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669 732
da2636b6 733 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::A}, 600, records);
d06dcda4 734 recordContents.insert(records.at(0).getContent());
86675669
OM
735 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
736 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
737 records.clear();
738
739 ContentSigPair pair;
740 pair.records = recordContents;
741 pair.signatures = signatureContents;
742 cspmap_t denialMap;
faa05786 743 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
86675669
OM
744
745 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
746 it is an ENT */
747 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
98307d0f 748 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
86675669
OM
749
750 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
751 it could prove a NXDOMAIN if it had an additional wildcard denial */
752 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
98307d0f 753 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
754
755 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
756 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
98307d0f 757 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
758
759 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
760 recordContents.clear();
761 signatureContents.clear();
da2636b6 762 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), {}, 600, records);
d06dcda4 763 recordContents.insert(records.at(0).getContent());
86675669
OM
764 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
765 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
766 records.clear();
767 pair.records = recordContents;
768 pair.signatures = signatureContents;
faa05786 769 denialMap[std::pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
86675669
OM
770
771 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
98307d0f 772 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
95256c05
RG
773
774 /* this NSEC is NOT valid to prove a NXDOMAIN at c.powerdns.com because it proves that
775 it exists and is an ENT */
776 denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, false);
98307d0f 777 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
778}
779
42dcf516
OM
780BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial)
781{
86675669
OM
782 initSR();
783
784 testkeysset_t keys;
690b86b7 785 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
786
787 vector<DNSRecord> records;
788
c1e7b833 789 sortedRecords_t recordContents;
d06dcda4 790 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
791
792 /*
793 The RRSIG from "." denies the existence of any type except NS at a.
794 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
795 signer field that is shorter than the owner name of the NSEC RR) it can't
796 be used to deny anything except the whole name or a DS.
797 */
da2636b6 798 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS}, 600, records);
d06dcda4 799 recordContents.insert(records.at(0).getContent());
86675669
OM
800 addRRSIG(keys, records, DNSName("."), 300);
801 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
802
803 ContentSigPair pair;
804 pair.records = recordContents;
805 pair.signatures = signatureContents;
806 cspmap_t denialMap;
faa05786 807 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
808 records.clear();
809
810 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
811 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
812 nonexistence of any RRs below that zone cut, which include all RRs at
813 that (original) owner name other than DS RRs, and all RRs below that
814 owner name regardless of type.
815 */
816
817 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
0cbcfeda 818 /* no denial means the qname/qtype is not denied, because an ancestor
86675669 819 delegation NSEC3 can only deny the DS */
98307d0f 820 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
821
822 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
98307d0f 823 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
86675669
OM
824
825 /* it can not be used to deny any RRs below that owner name either */
826 /* Add NSEC3 for the next closer */
827 recordContents.clear();
828 signatureContents.clear();
829 records.clear();
da2636b6 830 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
d06dcda4 831 recordContents.insert(records.at(0).getContent());
86675669
OM
832 addRRSIG(keys, records, DNSName("."), 300);
833 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
834
835 pair.records = recordContents;
836 pair.signatures = signatureContents;
faa05786 837 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
838
839 /* add wildcard denial */
840 recordContents.clear();
841 signatureContents.clear();
842 records.clear();
da2636b6 843 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
d06dcda4 844 recordContents.insert(records.at(0).getContent());
86675669
OM
845 addRRSIG(keys, records, DNSName("."), 300);
846 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
847
848 pair.records = recordContents;
849 pair.signatures = signatureContents;
faa05786 850 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
851
852 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
98307d0f 853 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
0a9dcd16
RG
854
855 /* not even the DS! */
856 denialState = getDenial(denialMap, DNSName("sub.a."), QType::DS, false, true);
857 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
858}
859
42dcf516
OM
860BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations)
861{
86675669
OM
862 initSR();
863
864 testkeysset_t keys;
690b86b7 865 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
866
867 vector<DNSRecord> records;
868
c1e7b833 869 sortedRecords_t recordContents;
d06dcda4 870 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
871
872 /* adding a NSEC3 with more iterations that we support */
da2636b6 873 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::AAAA}, 600, records, g_maxNSEC3Iterations + 100);
d06dcda4 874 recordContents.insert(records.at(0).getContent());
86675669
OM
875 addRRSIG(keys, records, DNSName("."), 300);
876 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
877
878 ContentSigPair pair;
879 pair.records = recordContents;
880 pair.signatures = signatureContents;
881 cspmap_t denialMap;
faa05786 882 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
883 records.clear();
884
885 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
886 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
98307d0f 887 BOOST_CHECK_EQUAL(denialState, dState::INSECURE);
86675669
OM
888}
889
42dcf516
OM
890BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial)
891{
86675669
OM
892 initSR();
893
894 testkeysset_t keys;
690b86b7 895 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
896
897 vector<DNSRecord> records;
898
c1e7b833 899 sortedRecords_t recordContents;
d06dcda4 900 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
86675669
OM
901
902 /*
903 * RFC 5155 section 8.9:
904 * If there is an NSEC3 RR present in the response that matches the
905 * delegation name, then the validator MUST ensure that the NS bit is
906 * set and that the DS bit is not set in the Type Bit Maps field of the
907 * NSEC3 RR.
908 */
909 /*
910 The RRSIG from "." denies the existence of any type at a.
911 NS should be set if it was proving an insecure delegation, let's check that
912 we correctly detect that it's not.
913 */
da2636b6 914 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {}, 600, records);
d06dcda4 915 recordContents.insert(records.at(0).getContent());
86675669
OM
916 addRRSIG(keys, records, DNSName("."), 300);
917 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
918
919 ContentSigPair pair;
920 pair.records = recordContents;
921 pair.signatures = signatureContents;
922 cspmap_t denialMap;
faa05786 923 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
86675669
OM
924 records.clear();
925
926 /* Insecure because the NS is not set, so while it does
927 denies the DS, it can't prove an insecure delegation */
928 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
98307d0f 929 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
86675669
OM
930}
931
be5d851d
RG
932BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial_soa)
933{
934 initSR();
935
936 testkeysset_t keys;
937 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
938
939 vector<DNSRecord> records;
940
941 sortedRecords_t recordContents;
d06dcda4 942 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
be5d851d
RG
943
944 /*
945 * RFC 5155 section 8.9:
946 * If there is an NSEC3 RR present in the response that matches the
947 * delegation name, then the validator MUST ensure that the NS bit is
948 * set and that the DS bit is not set in the Type Bit Maps field of the
949 * NSEC3 RR.
950 */
951 /*
952 The RRSIG from "." denies the existence of any type at a except NS and SOA.
953 NS has to be set since it is proving an insecure delegation, but SOA should NOT!
954 */
955 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS, QType::SOA}, 600, records);
d06dcda4 956 recordContents.insert(records.at(0).getContent());
be5d851d
RG
957 addRRSIG(keys, records, DNSName("."), 300);
958 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
959
960 ContentSigPair pair;
961 pair.records = recordContents;
962 pair.signatures = signatureContents;
963 cspmap_t denialMap;
964 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
965 records.clear();
966
967 /* Insecure because both NS and SOA are set, so it is not a proper delegation */
968 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
969 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
970}
971
ce454638
RG
972BOOST_AUTO_TEST_CASE(test_nsec3_ent_opt_out)
973{
974 initSR();
975
976 testkeysset_t keys;
977 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
978
979 vector<DNSRecord> records;
980
981 sortedRecords_t recordContents;
d06dcda4 982 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
ce454638
RG
983
984 /*
985 * RFC 7129 section 5.1:
986 * A recently discovered corner case (see RFC Errata ID 3441 [Err3441])
987 * shows that not only those delegations remain insecure but also the
988 * empty non-terminal space that is derived from those delegations.
989 */
990 /*
991 We have a NSEC3 proving that was.here does exist, and a second
992 one proving that ent.was.here. does not,
993 There NSEC3 are opt-out, so the result should be insecure (and we don't need
994 a wildcard proof).
995 */
996 addNSEC3UnhashedRecordToLW(DNSName("was.here."), DNSName("."), "whatever", {}, 600, records, 10, true /* opt out */);
d06dcda4 997 recordContents.insert(records.at(0).getContent());
ce454638
RG
998 addRRSIG(keys, records, DNSName("."), 300);
999 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
1000
1001 ContentSigPair pair;
1002 pair.records = recordContents;
1003 pair.signatures = signatureContents;
1004 cspmap_t denialMap;
faa05786 1005 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
ce454638
RG
1006
1007 /* it can not be used to deny any RRs below that owner name either */
1008 /* Add NSEC3 for the next closer */
1009 recordContents.clear();
1010 signatureContents.clear();
1011 records.clear();
1012 addNSEC3NarrowRecordToLW(DNSName("ent.was.here."), DNSName("."), {QType::RRSIG, QType::NSEC3}, 600, records, 10, true /* opt-out */);
d06dcda4 1013 recordContents.insert(records.at(0).getContent());
ce454638
RG
1014 addRRSIG(keys, records, DNSName("."), 300);
1015 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
1016
1017 pair.records = recordContents;
1018 pair.signatures = signatureContents;
faa05786 1019 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
ce454638
RG
1020
1021 /* Insecure because the opt-out bit is set */
1022 dState denialState = getDenial(denialMap, DNSName("ent.was.here."), QType::A, false, true);
1023 BOOST_CHECK_EQUAL(denialState, dState::OPTOUT);
1024}
1025
42dcf516
OM
1026BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity)
1027{
86675669
OM
1028 std::unique_ptr<SyncRes> sr;
1029 initSR(sr, true);
1030
1031 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1032
1033 primeHints();
1034 const DNSName target("com.");
1035 testkeysset_t keys;
1036
1037 auto luaconfsCopy = g_luaconfs.getCopy();
1038 luaconfsCopy.dsAnchors.clear();
690b86b7
OM
1039 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1040 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
1041 g_luaconfs.setState(luaconfsCopy);
1042
1043 size_t queriesCount = 0;
1044 const time_t fixedNow = sr->getNow().tv_sec;
1045
c0f8e484 1046 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516 1047 queriesCount++;
86675669 1048
42dcf516
OM
1049 DNSName auth = domain;
1050 auth.chopOff();
86675669 1051
42dcf516
OM
1052 if (type == QType::DS || type == QType::DNSKEY) {
1053 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1054 }
c0f8e484 1055 {
42dcf516
OM
1056 setLWResult(res, RCode::NoError, true, false, true);
1057 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1058 addRRSIG(keys, res->d_records, domain, 300);
1059 addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 600, res->d_records);
1060 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow);
308f4c43 1061 return LWResult::Result::Success;
42dcf516 1062 }
86675669 1063
308f4c43 1064 return LWResult::Result::Timeout;
42dcf516 1065 });
86675669
OM
1066
1067 vector<DNSRecord> ret;
1068 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1069 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1070 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
690b86b7
OM
1071 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1072 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1073
1074 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
33433a8a 1075 NegCache::NegCacheEntry ne;
ccfadb6c
OM
1076 BOOST_CHECK_EQUAL(g_negCache->size(), 1U);
1077 BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true);
33433a8a 1078 BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + 1);
98307d0f 1079 BOOST_CHECK_EQUAL(ne.d_validationState, vState::Secure);
33433a8a
RG
1080 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
1081 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
1082 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1U);
1083 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1U);
86675669
OM
1084
1085 /* again, to test the cache */
1086 ret.clear();
1087 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1088 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1089 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
690b86b7
OM
1090 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1091 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1092}
1093
42dcf516
OM
1094BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_bogus_validity)
1095{
86675669
OM
1096 std::unique_ptr<SyncRes> sr;
1097 initSR(sr, true);
1098
1099 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1100
1101 primeHints();
1102 const DNSName target("com.");
1103 testkeysset_t keys;
1104
1105 auto luaconfsCopy = g_luaconfs.getCopy();
1106 luaconfsCopy.dsAnchors.clear();
690b86b7
OM
1107 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1108 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
1109 g_luaconfs.setState(luaconfsCopy);
1110
1111 size_t queriesCount = 0;
1112 const time_t fixedNow = sr->getNow().tv_sec;
1113
c0f8e484 1114 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516 1115 queriesCount++;
86675669 1116
42dcf516
OM
1117 DNSName auth = domain;
1118 auth.chopOff();
86675669 1119
42dcf516
OM
1120 if (type == QType::DS || type == QType::DNSKEY) {
1121 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1122 }
c0f8e484 1123 {
42dcf516
OM
1124 setLWResult(res, RCode::NoError, true, false, true);
1125 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 86400);
1126 addRRSIG(keys, res->d_records, domain, 86400);
1127 addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 86400, res->d_records);
1128 /* no RRSIG */
308f4c43 1129 return LWResult::Result::Success;
42dcf516 1130 }
86675669 1131
308f4c43 1132 return LWResult::Result::Timeout;
42dcf516 1133 });
86675669
OM
1134
1135 SyncRes::s_maxnegttl = 3600;
1136 SyncRes::s_maxbogusttl = 360;
1137
1138 vector<DNSRecord> ret;
1139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1140 BOOST_CHECK_EQUAL(res, RCode::NoError);
fd870915 1141 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
690b86b7
OM
1142 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1143 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1144
1145 /* check that the entry has been negatively cached but not longer than s_maxbogusttl */
33433a8a 1146 NegCache::NegCacheEntry ne;
ccfadb6c
OM
1147 BOOST_CHECK_EQUAL(g_negCache->size(), 1U);
1148 BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true);
33433a8a 1149 BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + SyncRes::s_maxbogusttl);
fd870915 1150 BOOST_CHECK_EQUAL(ne.d_validationState, vState::BogusNoRRSIG);
33433a8a
RG
1151 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
1152 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
1153 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1U);
1154 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0U);
86675669
OM
1155
1156 /* again, to test the cache */
1157 ret.clear();
1158 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1159 BOOST_CHECK_EQUAL(res, RCode::NoError);
fd870915 1160 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
690b86b7
OM
1161 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1162 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1163}
1164
42dcf516
OM
1165BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity)
1166{
86675669
OM
1167 std::unique_ptr<SyncRes> sr;
1168 initSR(sr, true);
1169
1170 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1171
1172 primeHints();
1173 const DNSName target("com.");
1174 const ComboAddress targetAddr("192.0.2.42");
1175 testkeysset_t keys;
1176
1177 auto luaconfsCopy = g_luaconfs.getCopy();
1178 luaconfsCopy.dsAnchors.clear();
690b86b7
OM
1179 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1180 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
86675669
OM
1181 g_luaconfs.setState(luaconfsCopy);
1182
1183 size_t queriesCount = 0;
1184 const time_t tnow = sr->getNow().tv_sec;
1185
c0f8e484 1186 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516 1187 queriesCount++;
86675669 1188
42dcf516
OM
1189 DNSName auth = domain;
1190 auth.chopOff();
86675669 1191
42dcf516
OM
1192 if (type == QType::DS || type == QType::DNSKEY) {
1193 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1194 }
c0f8e484 1195 {
42dcf516
OM
1196 setLWResult(res, RCode::NoError, true, false, true);
1197 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
1198 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, tnow);
308f4c43 1199 return LWResult::Result::Success;
42dcf516 1200 }
86675669 1201
308f4c43 1202 return LWResult::Result::Timeout;
42dcf516 1203 });
86675669
OM
1204
1205 vector<DNSRecord> ret;
1206 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1207 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1208 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
690b86b7
OM
1209 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1210 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1211
1212 /* check that the entry has not been cached for longer than the RRSIG validity */
1213 const ComboAddress who;
1214 vector<DNSRecord> cached;
d06dcda4 1215 vector<std::shared_ptr<const RRSIGRecordContent>> signatures;
171089f5 1216 BOOST_REQUIRE_EQUAL(g_recCache->get(tnow, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who, boost::none, &signatures), 1);
690b86b7
OM
1217 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1218 BOOST_REQUIRE_EQUAL(signatures.size(), 1U);
86675669
OM
1219 BOOST_CHECK_EQUAL((cached[0].d_ttl - tnow), 1);
1220
1221 /* again, to test the cache */
1222 ret.clear();
1223 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1224 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1225 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
690b86b7
OM
1226 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1227 BOOST_CHECK_EQUAL(queriesCount, 4U);
86675669
OM
1228}
1229
42dcf516
OM
1230BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure)
1231{
86675669
OM
1232 /*
1233 Validation is optional, and the first query does not ask for it,
1234 so the answer is cached as Indeterminate.
1235 The second query asks for validation, answer should be marked as
1236 Secure, after just-in-time validation.
1237 */
1238 std::unique_ptr<SyncRes> sr;
1239 initSR(sr, true);
1240
1241 setDNSSECValidation(sr, DNSSECMode::Process);
1242
1243 primeHints();
1244 const DNSName target("com.");
1245 testkeysset_t keys;
1246
1247 auto luaconfsCopy = g_luaconfs.getCopy();
1248 luaconfsCopy.dsAnchors.clear();
690b86b7 1249 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
86675669
OM
1250 g_luaconfs.setState(luaconfsCopy);
1251
1252 size_t queriesCount = 0;
1253
c0f8e484 1254 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516
OM
1255 queriesCount++;
1256
1257 if (type == QType::DS || type == QType::DNSKEY) {
1258 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1259 }
c0f8e484 1260 {
42dcf516
OM
1261 if (domain == target && type == QType::A) {
1262 setLWResult(res, 0, true, false, true);
1263 addRecordToLW(res, target, QType::A, "192.0.2.1");
1264 addRRSIG(keys, res->d_records, DNSName("."), 300);
308f4c43 1265 return LWResult::Result::Success;
86675669 1266 }
42dcf516 1267 }
86675669 1268
308f4c43 1269 return LWResult::Result::Timeout;
42dcf516 1270 });
86675669
OM
1271
1272 vector<DNSRecord> ret;
1273 /* first query does not require validation */
1274 sr->setDNSSECValidationRequested(false);
1275 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1276 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1277 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
690b86b7 1278 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
86675669
OM
1279 for (const auto& record : ret) {
1280 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1281 }
690b86b7 1282 BOOST_CHECK_EQUAL(queriesCount, 1U);
86675669 1283
86675669
OM
1284 ret.clear();
1285 /* second one _does_ require validation */
1286 sr->setDNSSECValidationRequested(true);
1287 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1288 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1289 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
690b86b7 1290 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
86675669
OM
1291 for (const auto& record : ret) {
1292 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1293 }
7c1fe83b 1294 BOOST_CHECK_EQUAL(queriesCount, 2U);
86675669
OM
1295}
1296
42dcf516
OM
1297BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure)
1298{
86675669
OM
1299 /*
1300 Validation is optional, and the first query does not ask for it,
1301 so the answer is cached as Indeterminate.
1302 The second query asks for validation, answer should be marked as
1303 Insecure.
1304 */
1305 std::unique_ptr<SyncRes> sr;
1306 initSR(sr, true);
1307
1308 setDNSSECValidation(sr, DNSSECMode::Process);
1309
1310 primeHints();
1311 const DNSName target("com.");
1312 testkeysset_t keys;
1313
1314 auto luaconfsCopy = g_luaconfs.getCopy();
1315 luaconfsCopy.dsAnchors.clear();
1316 g_luaconfs.setState(luaconfsCopy);
1317
1318 size_t queriesCount = 0;
1319
c0f8e484 1320 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516 1321 queriesCount++;
86675669 1322
42dcf516
OM
1323 if (type == QType::DS || type == QType::DNSKEY) {
1324 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1325 }
c0f8e484 1326 {
42dcf516
OM
1327 if (domain == target && type == QType::A) {
1328 setLWResult(res, 0, true, false, true);
1329 addRecordToLW(res, target, QType::A, "192.0.2.1");
308f4c43 1330 return LWResult::Result::Success;
86675669 1331 }
42dcf516 1332 }
86675669 1333
308f4c43 1334 return LWResult::Result::Timeout;
42dcf516 1335 });
86675669
OM
1336
1337 vector<DNSRecord> ret;
1338 /* first query does not require validation */
1339 sr->setDNSSECValidationRequested(false);
1340 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1341 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1342 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
690b86b7 1343 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
86675669
OM
1344 for (const auto& record : ret) {
1345 BOOST_CHECK(record.d_type == QType::A);
1346 }
690b86b7 1347 BOOST_CHECK_EQUAL(queriesCount, 1U);
86675669 1348
86675669
OM
1349 ret.clear();
1350 /* second one _does_ require validation */
1351 sr->setDNSSECValidationRequested(true);
1352 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1353 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1354 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
690b86b7 1355 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
86675669
OM
1356 for (const auto& record : ret) {
1357 BOOST_CHECK(record.d_type == QType::A);
1358 }
690b86b7 1359 BOOST_CHECK_EQUAL(queriesCount, 1U);
86675669
OM
1360}
1361
42dcf516
OM
1362BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus)
1363{
86675669
OM
1364 /*
1365 Validation is optional, and the first query does not ask for it,
1366 so the answer is cached as Indeterminate.
1367 The second query asks for validation, answer should be marked as
1368 Bogus.
1369 */
1370 std::unique_ptr<SyncRes> sr;
1371 initSR(sr, true);
1372
1373 setDNSSECValidation(sr, DNSSECMode::Process);
1374
1375 primeHints();
1376 const DNSName target("com.");
1377 testkeysset_t keys;
1378
1379 auto luaconfsCopy = g_luaconfs.getCopy();
1380 luaconfsCopy.dsAnchors.clear();
690b86b7 1381 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
86675669
OM
1382 g_luaconfs.setState(luaconfsCopy);
1383
1384 size_t queriesCount = 0;
1385
c0f8e484 1386 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
42dcf516 1387 queriesCount++;
86675669 1388
42dcf516
OM
1389 if (type == QType::DS || type == QType::DNSKEY) {
1390 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1391 }
c0f8e484 1392 {
42dcf516
OM
1393 if (domain == target && type == QType::A) {
1394 setLWResult(res, 0, true, false, true);
1395 addRecordToLW(res, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
1396 /* no RRSIG */
308f4c43 1397 return LWResult::Result::Success;
86675669 1398 }
42dcf516 1399 }
86675669 1400
308f4c43 1401 return LWResult::Result::Timeout;
42dcf516 1402 });
86675669
OM
1403
1404 SyncRes::s_maxbogusttl = 3600;
1405
1406 vector<DNSRecord> ret;
1407 /* first query does not require validation */
1408 sr->setDNSSECValidationRequested(false);
1409 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1410 BOOST_CHECK_EQUAL(res, RCode::NoError);
98307d0f 1411 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
690b86b7 1412 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
86675669
OM
1413 for (const auto& record : ret) {
1414 BOOST_CHECK(record.d_type == QType::A);
690b86b7 1415 BOOST_CHECK_EQUAL(record.d_ttl, 86400U);
86675669 1416 }
690b86b7 1417 BOOST_CHECK_EQUAL(queriesCount, 1U);
86675669 1418
86675669
OM
1419 ret.clear();
1420 /* second one _does_ require validation */
1421 sr->setDNSSECValidationRequested(true);
1422 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1423 BOOST_CHECK_EQUAL(res, RCode::NoError);
fd870915 1424 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
86675669
OM
1425 /* check that we correctly capped the TTD for a Bogus record after
1426 just-in-time validation */
690b86b7 1427 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
86675669
OM
1428 for (const auto& record : ret) {
1429 BOOST_CHECK(record.d_type == QType::A);
1430 BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
1431 }
690b86b7 1432 BOOST_CHECK_EQUAL(queriesCount, 3U);
86675669
OM
1433
1434 ret.clear();
1435 /* third time also _does_ require validation, so we
1436 can check that the cache has been updated */
1437 sr->setDNSSECValidationRequested(true);
1438 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1439 BOOST_CHECK_EQUAL(res, RCode::NoError);
fd870915 1440 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
690b86b7 1441 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
86675669
OM
1442 for (const auto& record : ret) {
1443 BOOST_CHECK(record.d_type == QType::A);
1444 BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
1445 }
690b86b7 1446 BOOST_CHECK_EQUAL(queriesCount, 3U);
86675669
OM
1447}
1448
593f56c6
RG
1449BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure_any)
1450{
1451 /*
1452 Validation is optional, and the first two queries (A, AAAA) do not ask for it,
1453 so the answer are cached as Indeterminate.
1454 The third query asks for validation, and is for ANY, so the answer should be marked as
1455 Secure, after just-in-time validation.
1456 The last query also requests validation but is for AAAA only.
1457 */
1458 std::unique_ptr<SyncRes> sr;
1459 initSR(sr, true);
1460
1461 setDNSSECValidation(sr, DNSSECMode::Process);
1462
1463 primeHints();
1464 const DNSName target("com.");
1465 testkeysset_t keys;
1466
1467 auto luaconfsCopy = g_luaconfs.getCopy();
1468 luaconfsCopy.dsAnchors.clear();
1469 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1470 g_luaconfs.setState(luaconfsCopy);
1471
1472 size_t queriesCount = 0;
1473
c0f8e484 1474 sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
593f56c6
RG
1475 queriesCount++;
1476
1477 if (type == QType::DS || type == QType::DNSKEY) {
1478 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1479 }
c0f8e484 1480 {
593f56c6
RG
1481 if (domain == target && type == QType::A) {
1482 setLWResult(res, 0, true, false, true);
1483 addRecordToLW(res, target, QType::A, "192.0.2.1");
1484 addRRSIG(keys, res->d_records, DNSName("."), 300);
308f4c43 1485 return LWResult::Result::Success;
593f56c6 1486 }
c0f8e484 1487 if (domain == target && type == QType::AAAA) {
593f56c6
RG
1488 setLWResult(res, 0, true, false, true);
1489 addRecordToLW(res, target, QType::AAAA, "2001:db8::1");
1490 addRRSIG(keys, res->d_records, DNSName("."), 300);
308f4c43 1491 return LWResult::Result::Success;
593f56c6
RG
1492 }
1493 }
1494
308f4c43 1495 return LWResult::Result::Timeout;
593f56c6
RG
1496 });
1497
1498 vector<DNSRecord> ret;
1499 /* first query does not require validation */
1500 sr->setDNSSECValidationRequested(false);
1501 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1502 BOOST_CHECK_EQUAL(res, RCode::NoError);
1503 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1504 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1505 for (const auto& record : ret) {
1506 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1507 }
1508 BOOST_CHECK_EQUAL(queriesCount, 1U);
1509
1510 ret.clear();
1511 /* second query does not require validation either */
1512 sr->setDNSSECValidationRequested(false);
1513 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
1514 BOOST_CHECK_EQUAL(res, RCode::NoError);
1515 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1516 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1517 for (const auto& record : ret) {
1518 BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1519 }
1520 BOOST_CHECK_EQUAL(queriesCount, 2U);
1521
1522 ret.clear();
1523 /* third one _does_ require validation */
1524 sr->setDNSSECValidationRequested(true);
1525 res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
1526 BOOST_CHECK_EQUAL(res, RCode::NoError);
1527 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1528 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1529 for (const auto& record : ret) {
1530 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1531 }
7c1fe83b 1532 BOOST_CHECK_EQUAL(queriesCount, 3U);
593f56c6
RG
1533
1534 ret.clear();
1535 /* last one also requires validation */
1536 sr->setDNSSECValidationRequested(true);
1537 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
1538 BOOST_CHECK_EQUAL(res, RCode::NoError);
1539 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1540 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1541 for (const auto& record : ret) {
1542 BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1543 }
7c1fe83b 1544 BOOST_CHECK_EQUAL(queriesCount, 3U);
593f56c6
RG
1545}
1546
86675669 1547BOOST_AUTO_TEST_SUITE_END()