]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-dnssec.c
resolved: rework IDNA logic
[thirdparty/systemd.git] / src / resolve / resolved-dns-dnssec.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <gcrypt.h>
23
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
30
31 /* Open question:
32 *
33 * How does the DNSSEC canonical form of a hostname with a label
34 * containing a dot look like, the way DNS-SD does it?
35 *
36 * TODO:
37 *
38 * - bus calls to override DNSEC setting per interface
39 * - log all DNSSEC downgrades
40 * - log all RRs that failed validation
41 * - enable by default
42 * - Allow clients to request DNSSEC even if DNSSEC is off
43 * - make sure when getting an NXDOMAIN response through CNAME, we still process the first CNAMEs in the packet
44 * - update test-complex to also do ResolveAddress lookups
45 * - extend complex test to check "xn--kprw13d." DNAME domain
46 * - rework IDNA stuff: only to IDNA for ResolveAddress and ResolveService, and prepare a pair of lookup keys then, never do IDNA comparisons after that
47 * */
48
49 #define VERIFY_RRS_MAX 256
50 #define MAX_KEY_SIZE (32*1024)
51
52 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
53 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
54
55 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
56 #define NSEC3_ITERATIONS_MAX 2500
57
58 /*
59 * The DNSSEC Chain of trust:
60 *
61 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
62 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
63 * DS RRs are protected like normal RRs
64 *
65 * Example chain:
66 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
67 */
68
69 static void initialize_libgcrypt(void) {
70 const char *p;
71
72 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
73 return;
74
75 p = gcry_check_version("1.4.5");
76 assert(p);
77
78 gcry_control(GCRYCTL_DISABLE_SECMEM);
79 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
80 }
81
82 uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) {
83 const uint8_t *p;
84 uint32_t sum, f;
85 size_t i;
86
87 /* The algorithm from RFC 4034, Appendix B. */
88
89 assert(dnskey);
90 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
91
92 f = (uint32_t) dnskey->dnskey.flags;
93
94 if (mask_revoke)
95 f &= ~DNSKEY_FLAG_REVOKE;
96
97 sum = f + ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
98
99 p = dnskey->dnskey.key;
100
101 for (i = 0; i < dnskey->dnskey.key_size; i++)
102 sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
103
104 sum += (sum >> 16) & UINT32_C(0xFFFF);
105
106 return sum & UINT32_C(0xFFFF);
107 }
108
109 static int rr_compare(const void *a, const void *b) {
110 DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
111 size_t m;
112 int r;
113
114 /* Let's order the RRs according to RFC 4034, Section 6.3 */
115
116 assert(x);
117 assert(*x);
118 assert((*x)->wire_format);
119 assert(y);
120 assert(*y);
121 assert((*y)->wire_format);
122
123 m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
124
125 r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
126 if (r != 0)
127 return r;
128
129 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
130 return -1;
131 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
132 return 1;
133
134 return 0;
135 }
136
137 static int dnssec_rsa_verify_raw(
138 const char *hash_algorithm,
139 const void *signature, size_t signature_size,
140 const void *data, size_t data_size,
141 const void *exponent, size_t exponent_size,
142 const void *modulus, size_t modulus_size) {
143
144 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
145 gcry_mpi_t n = NULL, e = NULL, s = NULL;
146 gcry_error_t ge;
147 int r;
148
149 assert(hash_algorithm);
150
151 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
152 if (ge != 0) {
153 r = -EIO;
154 goto finish;
155 }
156
157 ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
158 if (ge != 0) {
159 r = -EIO;
160 goto finish;
161 }
162
163 ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
164 if (ge != 0) {
165 r = -EIO;
166 goto finish;
167 }
168
169 ge = gcry_sexp_build(&signature_sexp,
170 NULL,
171 "(sig-val (rsa (s %m)))",
172 s);
173
174 if (ge != 0) {
175 r = -EIO;
176 goto finish;
177 }
178
179 ge = gcry_sexp_build(&data_sexp,
180 NULL,
181 "(data (flags pkcs1) (hash %s %b))",
182 hash_algorithm,
183 (int) data_size,
184 data);
185 if (ge != 0) {
186 r = -EIO;
187 goto finish;
188 }
189
190 ge = gcry_sexp_build(&public_key_sexp,
191 NULL,
192 "(public-key (rsa (n %m) (e %m)))",
193 n,
194 e);
195 if (ge != 0) {
196 r = -EIO;
197 goto finish;
198 }
199
200 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
201 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
202 r = 0;
203 else if (ge != 0) {
204 log_debug("RSA signature check failed: %s", gpg_strerror(ge));
205 r = -EIO;
206 } else
207 r = 1;
208
209 finish:
210 if (e)
211 gcry_mpi_release(e);
212 if (n)
213 gcry_mpi_release(n);
214 if (s)
215 gcry_mpi_release(s);
216
217 if (public_key_sexp)
218 gcry_sexp_release(public_key_sexp);
219 if (signature_sexp)
220 gcry_sexp_release(signature_sexp);
221 if (data_sexp)
222 gcry_sexp_release(data_sexp);
223
224 return r;
225 }
226
227 static int dnssec_rsa_verify(
228 const char *hash_algorithm,
229 const void *hash, size_t hash_size,
230 DnsResourceRecord *rrsig,
231 DnsResourceRecord *dnskey) {
232
233 size_t exponent_size, modulus_size;
234 void *exponent, *modulus;
235
236 assert(hash_algorithm);
237 assert(hash);
238 assert(hash_size > 0);
239 assert(rrsig);
240 assert(dnskey);
241
242 if (*(uint8_t*) dnskey->dnskey.key == 0) {
243 /* exponent is > 255 bytes long */
244
245 exponent = (uint8_t*) dnskey->dnskey.key + 3;
246 exponent_size =
247 ((size_t) (((uint8_t*) dnskey->dnskey.key)[1]) << 8) |
248 ((size_t) ((uint8_t*) dnskey->dnskey.key)[2]);
249
250 if (exponent_size < 256)
251 return -EINVAL;
252
253 if (3 + exponent_size >= dnskey->dnskey.key_size)
254 return -EINVAL;
255
256 modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
257 modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
258
259 } else {
260 /* exponent is <= 255 bytes long */
261
262 exponent = (uint8_t*) dnskey->dnskey.key + 1;
263 exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
264
265 if (exponent_size <= 0)
266 return -EINVAL;
267
268 if (1 + exponent_size >= dnskey->dnskey.key_size)
269 return -EINVAL;
270
271 modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
272 modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
273 }
274
275 return dnssec_rsa_verify_raw(
276 hash_algorithm,
277 rrsig->rrsig.signature, rrsig->rrsig.signature_size,
278 hash, hash_size,
279 exponent, exponent_size,
280 modulus, modulus_size);
281 }
282
283 static int dnssec_ecdsa_verify_raw(
284 const char *hash_algorithm,
285 const char *curve,
286 const void *signature_r, size_t signature_r_size,
287 const void *signature_s, size_t signature_s_size,
288 const void *data, size_t data_size,
289 const void *key, size_t key_size) {
290
291 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
292 gcry_mpi_t q = NULL, r = NULL, s = NULL;
293 gcry_error_t ge;
294 int k;
295
296 assert(hash_algorithm);
297
298 ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
299 if (ge != 0) {
300 k = -EIO;
301 goto finish;
302 }
303
304 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
305 if (ge != 0) {
306 k = -EIO;
307 goto finish;
308 }
309
310 ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
311 if (ge != 0) {
312 k = -EIO;
313 goto finish;
314 }
315
316 ge = gcry_sexp_build(&signature_sexp,
317 NULL,
318 "(sig-val (ecdsa (r %m) (s %m)))",
319 r,
320 s);
321 if (ge != 0) {
322 k = -EIO;
323 goto finish;
324 }
325
326 ge = gcry_sexp_build(&data_sexp,
327 NULL,
328 "(data (flags rfc6979) (hash %s %b))",
329 hash_algorithm,
330 (int) data_size,
331 data);
332 if (ge != 0) {
333 k = -EIO;
334 goto finish;
335 }
336
337 ge = gcry_sexp_build(&public_key_sexp,
338 NULL,
339 "(public-key (ecc (curve %s) (q %m)))",
340 curve,
341 q);
342 if (ge != 0) {
343 k = -EIO;
344 goto finish;
345 }
346
347 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
348 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
349 k = 0;
350 else if (ge != 0) {
351 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
352 k = -EIO;
353 } else
354 k = 1;
355 finish:
356 if (r)
357 gcry_mpi_release(r);
358 if (s)
359 gcry_mpi_release(s);
360 if (q)
361 gcry_mpi_release(q);
362
363 if (public_key_sexp)
364 gcry_sexp_release(public_key_sexp);
365 if (signature_sexp)
366 gcry_sexp_release(signature_sexp);
367 if (data_sexp)
368 gcry_sexp_release(data_sexp);
369
370 return k;
371 }
372
373 static int dnssec_ecdsa_verify(
374 const char *hash_algorithm,
375 int algorithm,
376 const void *hash, size_t hash_size,
377 DnsResourceRecord *rrsig,
378 DnsResourceRecord *dnskey) {
379
380 const char *curve;
381 size_t key_size;
382 uint8_t *q;
383
384 assert(hash);
385 assert(hash_size);
386 assert(rrsig);
387 assert(dnskey);
388
389 if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
390 key_size = 32;
391 curve = "NIST P-256";
392 } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
393 key_size = 48;
394 curve = "NIST P-384";
395 } else
396 return -EOPNOTSUPP;
397
398 if (dnskey->dnskey.key_size != key_size * 2)
399 return -EINVAL;
400
401 if (rrsig->rrsig.signature_size != key_size * 2)
402 return -EINVAL;
403
404 q = alloca(key_size*2 + 1);
405 q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
406 memcpy(q+1, dnskey->dnskey.key, key_size*2);
407
408 return dnssec_ecdsa_verify_raw(
409 hash_algorithm,
410 curve,
411 rrsig->rrsig.signature, key_size,
412 (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
413 hash, hash_size,
414 q, key_size*2+1);
415 }
416
417 static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
418 gcry_md_write(md, &v, sizeof(v));
419 }
420
421 static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
422 v = htobe16(v);
423 gcry_md_write(md, &v, sizeof(v));
424 }
425
426 static void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
427 v = htobe32(v);
428 gcry_md_write(md, &v, sizeof(v));
429 }
430
431 static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) {
432 int n_key_labels, n_signer_labels;
433 const char *name;
434 int r;
435
436 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
437 * .n_skip_labels_signer fields so that we can use them later on. */
438
439 assert(rrsig);
440 assert(rrsig->key->type == DNS_TYPE_RRSIG);
441
442 /* Check if this RRSIG RR is already prepared */
443 if (rrsig->n_skip_labels_source != (unsigned) -1)
444 return 0;
445
446 if (rrsig->rrsig.inception > rrsig->rrsig.expiration)
447 return -EINVAL;
448
449 name = DNS_RESOURCE_KEY_NAME(rrsig->key);
450
451 n_key_labels = dns_name_count_labels(name);
452 if (n_key_labels < 0)
453 return n_key_labels;
454 if (rrsig->rrsig.labels > n_key_labels)
455 return -EINVAL;
456
457 n_signer_labels = dns_name_count_labels(rrsig->rrsig.signer);
458 if (n_signer_labels < 0)
459 return n_signer_labels;
460 if (n_signer_labels > rrsig->rrsig.labels)
461 return -EINVAL;
462
463 r = dns_name_skip(name, n_key_labels - n_signer_labels, &name);
464 if (r < 0)
465 return r;
466 if (r == 0)
467 return -EINVAL;
468
469 /* Check if the signer is really a suffix of us */
470 r = dns_name_equal(name, rrsig->rrsig.signer);
471 if (r < 0)
472 return r;
473 if (r == 0)
474 return -EINVAL;
475
476 rrsig->n_skip_labels_source = n_key_labels - rrsig->rrsig.labels;
477 rrsig->n_skip_labels_signer = n_key_labels - n_signer_labels;
478
479 return 0;
480 }
481
482 static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
483 usec_t expiration, inception, skew;
484
485 assert(rrsig);
486 assert(rrsig->key->type == DNS_TYPE_RRSIG);
487
488 if (realtime == USEC_INFINITY)
489 realtime = now(CLOCK_REALTIME);
490
491 expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
492 inception = rrsig->rrsig.inception * USEC_PER_SEC;
493
494 /* Consider inverted validity intervals as expired */
495 if (inception > expiration)
496 return true;
497
498 /* Permit a certain amount of clock skew of 10% of the valid
499 * time range. This takes inspiration from unbound's
500 * resolver. */
501 skew = (expiration - inception) / 10;
502 if (skew > SKEW_MAX)
503 skew = SKEW_MAX;
504
505 if (inception < skew)
506 inception = 0;
507 else
508 inception -= skew;
509
510 if (expiration + skew < expiration)
511 expiration = USEC_INFINITY;
512 else
513 expiration += skew;
514
515 return realtime < inception || realtime > expiration;
516 }
517
518 static int algorithm_to_gcrypt_md(uint8_t algorithm) {
519
520 /* Translates a DNSSEC signature algorithm into a gcrypt
521 * digest identifier.
522 *
523 * Note that we implement all algorithms listed as "Must
524 * implement" and "Recommended to Implement" in RFC6944. We
525 * don't implement any algorithms that are listed as
526 * "Optional" or "Must Not Implement". Specifically, we do not
527 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
528 * GOST-ECC. */
529
530 switch (algorithm) {
531
532 case DNSSEC_ALGORITHM_RSASHA1:
533 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
534 return GCRY_MD_SHA1;
535
536 case DNSSEC_ALGORITHM_RSASHA256:
537 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
538 return GCRY_MD_SHA256;
539
540 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
541 return GCRY_MD_SHA384;
542
543 case DNSSEC_ALGORITHM_RSASHA512:
544 return GCRY_MD_SHA512;
545
546 default:
547 return -EOPNOTSUPP;
548 }
549 }
550
551 static void dnssec_fix_rrset_ttl(
552 DnsResourceRecord *list[],
553 unsigned n,
554 DnsResourceRecord *rrsig,
555 usec_t realtime) {
556
557 unsigned k;
558
559 assert(list);
560 assert(n > 0);
561 assert(rrsig);
562
563 for (k = 0; k < n; k++) {
564 DnsResourceRecord *rr = list[k];
565
566 /* Pick the TTL as the minimum of the RR's TTL, the
567 * RR's original TTL according to the RRSIG and the
568 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
569 rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
570 rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
571
572 /* Copy over information about the signer and wildcard source of synthesis */
573 rr->n_skip_labels_source = rrsig->n_skip_labels_source;
574 rr->n_skip_labels_signer = rrsig->n_skip_labels_signer;
575 }
576
577 rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
578 }
579
580 int dnssec_verify_rrset(
581 DnsAnswer *a,
582 const DnsResourceKey *key,
583 DnsResourceRecord *rrsig,
584 DnsResourceRecord *dnskey,
585 usec_t realtime,
586 DnssecResult *result) {
587
588 uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
589 DnsResourceRecord **list, *rr;
590 const char *source, *name;
591 gcry_md_hd_t md = NULL;
592 int r, md_algorithm;
593 size_t k, n = 0;
594 size_t hash_size;
595 void *hash;
596 bool wildcard;
597
598 assert(key);
599 assert(rrsig);
600 assert(dnskey);
601 assert(result);
602 assert(rrsig->key->type == DNS_TYPE_RRSIG);
603 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
604
605 /* Verifies the the RRSet matching the specified "key" in "a",
606 * using the signature "rrsig" and the key "dnskey". It's
607 * assumed the RRSIG and DNSKEY match. */
608
609 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
610 if (md_algorithm == -EOPNOTSUPP) {
611 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
612 return 0;
613 }
614 if (md_algorithm < 0)
615 return md_algorithm;
616
617 r = dnssec_rrsig_prepare(rrsig);
618 if (r == -EINVAL) {
619 *result = DNSSEC_INVALID;
620 return r;
621 }
622 if (r < 0)
623 return r;
624
625 r = dnssec_rrsig_expired(rrsig, realtime);
626 if (r < 0)
627 return r;
628 if (r > 0) {
629 *result = DNSSEC_SIGNATURE_EXPIRED;
630 return 0;
631 }
632
633 name = DNS_RESOURCE_KEY_NAME(key);
634
635 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
636 if (dns_type_apex_only(rrsig->rrsig.type_covered)) {
637 r = dns_name_equal(rrsig->rrsig.signer, name);
638 if (r < 0)
639 return r;
640 if (r == 0) {
641 *result = DNSSEC_INVALID;
642 return 0;
643 }
644 }
645
646 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
647 if (rrsig->rrsig.type_covered == DNS_TYPE_DS) {
648 r = dns_name_equal(rrsig->rrsig.signer, name);
649 if (r < 0)
650 return r;
651 if (r > 0) {
652 *result = DNSSEC_INVALID;
653 return 0;
654 }
655 }
656
657 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
658 r = dns_name_suffix(name, rrsig->rrsig.labels, &source);
659 if (r < 0)
660 return r;
661 if (r > 0 && !dns_type_may_wildcard(rrsig->rrsig.type_covered)) {
662 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
663 *result = DNSSEC_INVALID;
664 return 0;
665 }
666 if (r == 1) {
667 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
668 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
669 r = dns_name_startswith(name, "*");
670 if (r < 0)
671 return r;
672 if (r > 0)
673 source = name;
674
675 wildcard = r == 0;
676 } else
677 wildcard = r > 0;
678
679 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
680 list = newa(DnsResourceRecord *, dns_answer_size(a));
681
682 DNS_ANSWER_FOREACH(rr, a) {
683 r = dns_resource_key_equal(key, rr->key);
684 if (r < 0)
685 return r;
686 if (r == 0)
687 continue;
688
689 /* We need the wire format for ordering, and digest calculation */
690 r = dns_resource_record_to_wire_format(rr, true);
691 if (r < 0)
692 return r;
693
694 list[n++] = rr;
695
696 if (n > VERIFY_RRS_MAX)
697 return -E2BIG;
698 }
699
700 if (n <= 0)
701 return -ENODATA;
702
703 /* Bring the RRs into canonical order */
704 qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
705
706 /* OK, the RRs are now in canonical order. Let's calculate the digest */
707 initialize_libgcrypt();
708
709 hash_size = gcry_md_get_algo_dlen(md_algorithm);
710 assert(hash_size > 0);
711
712 gcry_md_open(&md, md_algorithm, 0);
713 if (!md)
714 return -EIO;
715
716 md_add_uint16(md, rrsig->rrsig.type_covered);
717 md_add_uint8(md, rrsig->rrsig.algorithm);
718 md_add_uint8(md, rrsig->rrsig.labels);
719 md_add_uint32(md, rrsig->rrsig.original_ttl);
720 md_add_uint32(md, rrsig->rrsig.expiration);
721 md_add_uint32(md, rrsig->rrsig.inception);
722 md_add_uint16(md, rrsig->rrsig.key_tag);
723
724 r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
725 if (r < 0)
726 goto finish;
727 gcry_md_write(md, wire_format_name, r);
728
729 /* Convert the source of synthesis into wire format */
730 r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true);
731 if (r < 0)
732 goto finish;
733
734 for (k = 0; k < n; k++) {
735 size_t l;
736
737 rr = list[k];
738
739 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
740 if (wildcard)
741 gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2);
742 gcry_md_write(md, wire_format_name, r);
743
744 md_add_uint16(md, rr->key->type);
745 md_add_uint16(md, rr->key->class);
746 md_add_uint32(md, rrsig->rrsig.original_ttl);
747
748 l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
749 assert(l <= 0xFFFF);
750
751 md_add_uint16(md, (uint16_t) l);
752 gcry_md_write(md, DNS_RESOURCE_RECORD_RDATA(rr), l);
753 }
754
755 hash = gcry_md_read(md, 0);
756 if (!hash) {
757 r = -EIO;
758 goto finish;
759 }
760
761 switch (rrsig->rrsig.algorithm) {
762
763 case DNSSEC_ALGORITHM_RSASHA1:
764 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
765 case DNSSEC_ALGORITHM_RSASHA256:
766 case DNSSEC_ALGORITHM_RSASHA512:
767 r = dnssec_rsa_verify(
768 gcry_md_algo_name(md_algorithm),
769 hash, hash_size,
770 rrsig,
771 dnskey);
772 break;
773
774 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
775 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
776 r = dnssec_ecdsa_verify(
777 gcry_md_algo_name(md_algorithm),
778 rrsig->rrsig.algorithm,
779 hash, hash_size,
780 rrsig,
781 dnskey);
782 break;
783 }
784
785 if (r < 0)
786 goto finish;
787
788 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
789 if (r > 0)
790 dnssec_fix_rrset_ttl(list, n, rrsig, realtime);
791
792 if (r == 0)
793 *result = DNSSEC_INVALID;
794 else if (wildcard)
795 *result = DNSSEC_VALIDATED_WILDCARD;
796 else
797 *result = DNSSEC_VALIDATED;
798
799 r = 0;
800
801 finish:
802 gcry_md_close(md);
803 return r;
804 }
805
806 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
807
808 assert(rrsig);
809 assert(dnskey);
810
811 /* Checks if the specified DNSKEY RR matches the key used for
812 * the signature in the specified RRSIG RR */
813
814 if (rrsig->key->type != DNS_TYPE_RRSIG)
815 return -EINVAL;
816
817 if (dnskey->key->type != DNS_TYPE_DNSKEY)
818 return 0;
819 if (dnskey->key->class != rrsig->key->class)
820 return 0;
821 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
822 return 0;
823 if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
824 return 0;
825 if (dnskey->dnskey.protocol != 3)
826 return 0;
827 if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
828 return 0;
829
830 if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
831 return 0;
832
833 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
834 }
835
836 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
837 assert(key);
838 assert(rrsig);
839
840 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
841
842 if (rrsig->key->type != DNS_TYPE_RRSIG)
843 return 0;
844 if (rrsig->key->class != key->class)
845 return 0;
846 if (rrsig->rrsig.type_covered != key->type)
847 return 0;
848
849 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
850 }
851
852 int dnssec_verify_rrset_search(
853 DnsAnswer *a,
854 const DnsResourceKey *key,
855 DnsAnswer *validated_dnskeys,
856 usec_t realtime,
857 DnssecResult *result,
858 DnsResourceRecord **ret_rrsig) {
859
860 bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
861 DnsResourceRecord *rrsig;
862 int r;
863
864 assert(key);
865 assert(result);
866
867 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
868
869 if (!a || a->n_rrs <= 0)
870 return -ENODATA;
871
872 /* Iterate through each RRSIG RR. */
873 DNS_ANSWER_FOREACH(rrsig, a) {
874 DnsResourceRecord *dnskey;
875 DnsAnswerFlags flags;
876
877 /* Is this an RRSIG RR that applies to RRs matching our key? */
878 r = dnssec_key_match_rrsig(key, rrsig);
879 if (r < 0)
880 return r;
881 if (r == 0)
882 continue;
883
884 found_rrsig = true;
885
886 /* Look for a matching key */
887 DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
888 DnssecResult one_result;
889
890 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
891 continue;
892
893 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
894 r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false);
895 if (r < 0)
896 return r;
897 if (r == 0)
898 continue;
899
900 /* Take the time here, if it isn't set yet, so
901 * that we do all validations with the same
902 * time. */
903 if (realtime == USEC_INFINITY)
904 realtime = now(CLOCK_REALTIME);
905
906 /* Yay, we found a matching RRSIG with a matching
907 * DNSKEY, awesome. Now let's verify all entries of
908 * the RRSet against the RRSIG and DNSKEY
909 * combination. */
910
911 r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
912 if (r < 0)
913 return r;
914
915 switch (one_result) {
916
917 case DNSSEC_VALIDATED:
918 case DNSSEC_VALIDATED_WILDCARD:
919 /* Yay, the RR has been validated,
920 * return immediately, but fix up the expiry */
921 if (ret_rrsig)
922 *ret_rrsig = rrsig;
923
924 *result = one_result;
925 return 0;
926
927 case DNSSEC_INVALID:
928 /* If the signature is invalid, let's try another
929 key and/or signature. After all they
930 key_tags and stuff are not unique, and
931 might be shared by multiple keys. */
932 found_invalid = true;
933 continue;
934
935 case DNSSEC_UNSUPPORTED_ALGORITHM:
936 /* If the key algorithm is
937 unsupported, try another
938 RRSIG/DNSKEY pair, but remember we
939 encountered this, so that we can
940 return a proper error when we
941 encounter nothing better. */
942 found_unsupported_algorithm = true;
943 continue;
944
945 case DNSSEC_SIGNATURE_EXPIRED:
946 /* If the signature is expired, try
947 another one, but remember it, so
948 that we can return this */
949 found_expired_rrsig = true;
950 continue;
951
952 default:
953 assert_not_reached("Unexpected DNSSEC validation result");
954 }
955 }
956 }
957
958 if (found_expired_rrsig)
959 *result = DNSSEC_SIGNATURE_EXPIRED;
960 else if (found_unsupported_algorithm)
961 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
962 else if (found_invalid)
963 *result = DNSSEC_INVALID;
964 else if (found_rrsig)
965 *result = DNSSEC_MISSING_KEY;
966 else
967 *result = DNSSEC_NO_SIGNATURE;
968
969 if (ret_rrsig)
970 *ret_rrsig = NULL;
971
972 return 0;
973 }
974
975 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
976 DnsResourceRecord *rr;
977 int r;
978
979 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
980
981 DNS_ANSWER_FOREACH(rr, a) {
982 r = dnssec_key_match_rrsig(key, rr);
983 if (r < 0)
984 return r;
985 if (r > 0)
986 return 1;
987 }
988
989 return 0;
990 }
991
992 int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
993 size_t c = 0;
994 int r;
995
996 /* Converts the specified hostname into DNSSEC canonicalized
997 * form. */
998
999 if (buffer_max < 2)
1000 return -ENOBUFS;
1001
1002 for (;;) {
1003 r = dns_label_unescape(&n, buffer, buffer_max);
1004 if (r < 0)
1005 return r;
1006 if (r == 0)
1007 break;
1008
1009 if (buffer_max < (size_t) r + 2)
1010 return -ENOBUFS;
1011
1012 /* The DNSSEC canonical form is not clear on what to
1013 * do with dots appearing in labels, the way DNS-SD
1014 * does it. Refuse it for now. */
1015
1016 if (memchr(buffer, '.', r))
1017 return -EINVAL;
1018
1019 ascii_strlower_n(buffer, (size_t) r);
1020 buffer[r] = '.';
1021
1022 buffer += r + 1;
1023 c += r + 1;
1024
1025 buffer_max -= r + 1;
1026 }
1027
1028 if (c <= 0) {
1029 /* Not even a single label: this is the root domain name */
1030
1031 assert(buffer_max > 2);
1032 buffer[0] = '.';
1033 buffer[1] = 0;
1034
1035 return 1;
1036 }
1037
1038 return (int) c;
1039 }
1040
1041 static int digest_to_gcrypt_md(uint8_t algorithm) {
1042
1043 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1044
1045 switch (algorithm) {
1046
1047 case DNSSEC_DIGEST_SHA1:
1048 return GCRY_MD_SHA1;
1049
1050 case DNSSEC_DIGEST_SHA256:
1051 return GCRY_MD_SHA256;
1052
1053 case DNSSEC_DIGEST_SHA384:
1054 return GCRY_MD_SHA384;
1055
1056 default:
1057 return -EOPNOTSUPP;
1058 }
1059 }
1060
1061 int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
1062 char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
1063 gcry_md_hd_t md = NULL;
1064 size_t hash_size;
1065 int md_algorithm, r;
1066 void *result;
1067
1068 assert(dnskey);
1069 assert(ds);
1070
1071 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1072
1073 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1074 return -EINVAL;
1075 if (ds->key->type != DNS_TYPE_DS)
1076 return -EINVAL;
1077 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1078 return -EKEYREJECTED;
1079 if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
1080 return -EKEYREJECTED;
1081 if (dnskey->dnskey.protocol != 3)
1082 return -EKEYREJECTED;
1083
1084 if (dnskey->dnskey.algorithm != ds->ds.algorithm)
1085 return 0;
1086 if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
1087 return 0;
1088
1089 initialize_libgcrypt();
1090
1091 md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
1092 if (md_algorithm < 0)
1093 return md_algorithm;
1094
1095 hash_size = gcry_md_get_algo_dlen(md_algorithm);
1096 assert(hash_size > 0);
1097
1098 if (ds->ds.digest_size != hash_size)
1099 return 0;
1100
1101 r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
1102 if (r < 0)
1103 return r;
1104
1105 gcry_md_open(&md, md_algorithm, 0);
1106 if (!md)
1107 return -EIO;
1108
1109 gcry_md_write(md, owner_name, r);
1110 if (mask_revoke)
1111 md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
1112 else
1113 md_add_uint16(md, dnskey->dnskey.flags);
1114 md_add_uint8(md, dnskey->dnskey.protocol);
1115 md_add_uint8(md, dnskey->dnskey.algorithm);
1116 gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
1117
1118 result = gcry_md_read(md, 0);
1119 if (!result) {
1120 r = -EIO;
1121 goto finish;
1122 }
1123
1124 r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
1125
1126 finish:
1127 gcry_md_close(md);
1128 return r;
1129 }
1130
1131 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1132 DnsResourceRecord *ds;
1133 DnsAnswerFlags flags;
1134 int r;
1135
1136 assert(dnskey);
1137
1138 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1139 return 0;
1140
1141 DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
1142
1143 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1144 continue;
1145
1146 if (ds->key->type != DNS_TYPE_DS)
1147 continue;
1148 if (ds->key->class != dnskey->key->class)
1149 continue;
1150
1151 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
1152 if (r < 0)
1153 return r;
1154 if (r == 0)
1155 continue;
1156
1157 r = dnssec_verify_dnskey_by_ds(dnskey, ds, false);
1158 if (IN_SET(r, -EKEYREJECTED, -EOPNOTSUPP))
1159 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1160 if (r < 0)
1161 return r;
1162 if (r > 0)
1163 return 1;
1164 }
1165
1166 return 0;
1167 }
1168
1169 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
1170
1171 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1172
1173 switch (algorithm) {
1174
1175 case NSEC3_ALGORITHM_SHA1:
1176 return GCRY_MD_SHA1;
1177
1178 default:
1179 return -EOPNOTSUPP;
1180 }
1181 }
1182
1183 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1184 uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1185 gcry_md_hd_t md = NULL;
1186 size_t hash_size;
1187 int algorithm;
1188 void *result;
1189 unsigned k;
1190 int r;
1191
1192 assert(nsec3);
1193 assert(name);
1194 assert(ret);
1195
1196 if (nsec3->key->type != DNS_TYPE_NSEC3)
1197 return -EINVAL;
1198
1199 if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX) {
1200 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3));
1201 return -EOPNOTSUPP;
1202 }
1203
1204 algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
1205 if (algorithm < 0)
1206 return algorithm;
1207
1208 initialize_libgcrypt();
1209
1210 hash_size = gcry_md_get_algo_dlen(algorithm);
1211 assert(hash_size > 0);
1212
1213 if (nsec3->nsec3.next_hashed_name_size != hash_size)
1214 return -EINVAL;
1215
1216 r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1217 if (r < 0)
1218 return r;
1219
1220 gcry_md_open(&md, algorithm, 0);
1221 if (!md)
1222 return -EIO;
1223
1224 gcry_md_write(md, wire_format, r);
1225 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1226
1227 result = gcry_md_read(md, 0);
1228 if (!result) {
1229 r = -EIO;
1230 goto finish;
1231 }
1232
1233 for (k = 0; k < nsec3->nsec3.iterations; k++) {
1234 uint8_t tmp[hash_size];
1235 memcpy(tmp, result, hash_size);
1236
1237 gcry_md_reset(md);
1238 gcry_md_write(md, tmp, hash_size);
1239 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1240
1241 result = gcry_md_read(md, 0);
1242 if (!result) {
1243 r = -EIO;
1244 goto finish;
1245 }
1246 }
1247
1248 memcpy(ret, result, hash_size);
1249 r = (int) hash_size;
1250
1251 finish:
1252 gcry_md_close(md);
1253 return r;
1254 }
1255
1256 static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
1257 const char *a, *b;
1258 int r;
1259
1260 assert(rr);
1261
1262 if (rr->key->type != DNS_TYPE_NSEC3)
1263 return 0;
1264
1265 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1266 if (!IN_SET(rr->nsec3.flags, 0, 1))
1267 return 0;
1268
1269 /* Ignore NSEC3 RRs whose algorithm we don't know */
1270 if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
1271 return 0;
1272 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1273 if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1274 return 0;
1275
1276 /* Ignore NSEC3 RRs generated from wildcards */
1277 if (rr->n_skip_labels_source != 0)
1278 return 0;
1279 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1280 if (rr->n_skip_labels_signer != 1)
1281 return 0;
1282
1283 if (!nsec3)
1284 return 1;
1285
1286 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1287
1288 if (nsec3 == rr) /* Shortcut */
1289 return 1;
1290
1291 if (rr->key->class != nsec3->key->class)
1292 return 0;
1293 if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
1294 return 0;
1295 if (rr->nsec3.iterations != nsec3->nsec3.iterations)
1296 return 0;
1297 if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
1298 return 0;
1299 if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
1300 return 0;
1301
1302 a = DNS_RESOURCE_KEY_NAME(rr->key);
1303 r = dns_name_parent(&a); /* strip off hash */
1304 if (r < 0)
1305 return r;
1306 if (r == 0)
1307 return 0;
1308
1309 b = DNS_RESOURCE_KEY_NAME(nsec3->key);
1310 r = dns_name_parent(&b); /* strip off hash */
1311 if (r < 0)
1312 return r;
1313 if (r == 0)
1314 return 0;
1315
1316 /* Make sure both have the same parent */
1317 return dns_name_equal(a, b);
1318 }
1319
1320 static int nsec3_hashed_domain_format(const uint8_t *hashed, size_t hashed_size, const char *zone, char **ret) {
1321 _cleanup_free_ char *l = NULL;
1322 char *j;
1323
1324 assert(hashed);
1325 assert(hashed_size > 0);
1326 assert(zone);
1327 assert(ret);
1328
1329 l = base32hexmem(hashed, hashed_size, false);
1330 if (!l)
1331 return -ENOMEM;
1332
1333 j = strjoin(l, ".", zone, NULL);
1334 if (!j)
1335 return -ENOMEM;
1336
1337 *ret = j;
1338 return (int) hashed_size;
1339 }
1340
1341 static int nsec3_hashed_domain_make(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) {
1342 uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1343 int hashed_size;
1344
1345 assert(nsec3);
1346 assert(domain);
1347 assert(zone);
1348 assert(ret);
1349
1350 hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed);
1351 if (hashed_size < 0)
1352 return hashed_size;
1353
1354 return nsec3_hashed_domain_format(hashed, (size_t) hashed_size, zone, ret);
1355 }
1356
1357 /* See RFC 5155, Section 8
1358 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1359 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1360 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1361 * matches the wildcard domain.
1362 *
1363 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1364 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1365 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1366 * to conclude anything we indicate this by returning NO_RR. */
1367 static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1368 _cleanup_free_ char *next_closer_domain = NULL, *wildcard_domain = NULL;
1369 const char *zone, *p, *pp = NULL, *wildcard;
1370 DnsResourceRecord *rr, *enclosure_rr, *zone_rr, *wildcard_rr = NULL;
1371 DnsAnswerFlags flags;
1372 int hashed_size, r;
1373 bool a, no_closer = false, no_wildcard = false, optout = false;
1374
1375 assert(key);
1376 assert(result);
1377
1378 /* First step, find the zone name and the NSEC3 parameters of the zone.
1379 * it is sufficient to look for the longest common suffix we find with
1380 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1381 * records from a given zone in a response must use the same
1382 * parameters. */
1383 zone = DNS_RESOURCE_KEY_NAME(key);
1384 for (;;) {
1385 DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) {
1386 r = nsec3_is_good(zone_rr, NULL);
1387 if (r < 0)
1388 return r;
1389 if (r == 0)
1390 continue;
1391
1392 r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr->key), 1, zone);
1393 if (r < 0)
1394 return r;
1395 if (r > 0)
1396 goto found_zone;
1397 }
1398
1399 /* Strip one label from the front */
1400 r = dns_name_parent(&zone);
1401 if (r < 0)
1402 return r;
1403 if (r == 0)
1404 break;
1405 }
1406
1407 *result = DNSSEC_NSEC_NO_RR;
1408 return 0;
1409
1410 found_zone:
1411 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1412 p = DNS_RESOURCE_KEY_NAME(key);
1413 for (;;) {
1414 _cleanup_free_ char *hashed_domain = NULL;
1415
1416 hashed_size = nsec3_hashed_domain_make(zone_rr, p, zone, &hashed_domain);
1417 if (hashed_size == -EOPNOTSUPP) {
1418 *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1419 return 0;
1420 }
1421 if (hashed_size < 0)
1422 return hashed_size;
1423
1424 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) {
1425
1426 r = nsec3_is_good(enclosure_rr, zone_rr);
1427 if (r < 0)
1428 return r;
1429 if (r == 0)
1430 continue;
1431
1432 if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
1433 continue;
1434
1435 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain);
1436 if (r < 0)
1437 return r;
1438 if (r > 0) {
1439 a = flags & DNS_ANSWER_AUTHENTICATED;
1440 goto found_closest_encloser;
1441 }
1442 }
1443
1444 /* We didn't find the closest encloser with this name,
1445 * but let's remember this domain name, it might be
1446 * the next closer name */
1447
1448 pp = p;
1449
1450 /* Strip one label from the front */
1451 r = dns_name_parent(&p);
1452 if (r < 0)
1453 return r;
1454 if (r == 0)
1455 break;
1456 }
1457
1458 *result = DNSSEC_NSEC_NO_RR;
1459 return 0;
1460
1461 found_closest_encloser:
1462 /* We found a closest encloser in 'p'; next closer is 'pp' */
1463
1464 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1465 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME))
1466 return -EBADMSG;
1467
1468 /* Ensure that this data is from the delegated domain
1469 * (i.e. originates from the "lower" DNS server), and isn't
1470 * just glue records (i.e. doesn't originate from the "upper"
1471 * DNS server). */
1472 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1473 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1474 return -EBADMSG;
1475
1476 if (!pp) {
1477 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1478 if (bitmap_isset(enclosure_rr->nsec3.types, key->type))
1479 *result = DNSSEC_NSEC_FOUND;
1480 else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME))
1481 *result = DNSSEC_NSEC_CNAME;
1482 else
1483 *result = DNSSEC_NSEC_NODATA;
1484
1485 if (authenticated)
1486 *authenticated = a;
1487 if (ttl)
1488 *ttl = enclosure_rr->ttl;
1489
1490 return 0;
1491 }
1492
1493 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1494
1495 wildcard = strjoina("*.", p);
1496 r = nsec3_hashed_domain_make(enclosure_rr, wildcard, zone, &wildcard_domain);
1497 if (r < 0)
1498 return r;
1499 if (r != hashed_size)
1500 return -EBADMSG;
1501
1502 r = nsec3_hashed_domain_make(enclosure_rr, pp, zone, &next_closer_domain);
1503 if (r < 0)
1504 return r;
1505 if (r != hashed_size)
1506 return -EBADMSG;
1507
1508 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1509 _cleanup_free_ char *next_hashed_domain = NULL;
1510
1511 r = nsec3_is_good(rr, zone_rr);
1512 if (r < 0)
1513 return r;
1514 if (r == 0)
1515 continue;
1516
1517 r = nsec3_hashed_domain_format(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, zone, &next_hashed_domain);
1518 if (r < 0)
1519 return r;
1520
1521 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
1522 if (r < 0)
1523 return r;
1524 if (r > 0) {
1525 if (rr->nsec3.flags & 1)
1526 optout = true;
1527
1528 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1529
1530 no_closer = true;
1531 }
1532
1533 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain);
1534 if (r < 0)
1535 return r;
1536 if (r > 0) {
1537 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1538
1539 wildcard_rr = rr;
1540 }
1541
1542 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain);
1543 if (r < 0)
1544 return r;
1545 if (r > 0) {
1546 if (rr->nsec3.flags & 1)
1547 /* This only makes sense if we have a wildcard delegation, which is
1548 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1549 * this not happening, so hence cannot simply conclude NXDOMAIN as
1550 * we would wish */
1551 optout = true;
1552
1553 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1554
1555 no_wildcard = true;
1556 }
1557 }
1558
1559 if (wildcard_rr && no_wildcard)
1560 return -EBADMSG;
1561
1562 if (!no_closer) {
1563 *result = DNSSEC_NSEC_NO_RR;
1564 return 0;
1565 }
1566
1567 if (wildcard_rr) {
1568 /* A wildcard exists that matches our query. */
1569 if (optout)
1570 /* This is not specified in any RFC to the best of my knowledge, but
1571 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1572 * it means that we cannot prove that the source of synthesis is
1573 * correct, as there may be a closer match. */
1574 *result = DNSSEC_NSEC_OPTOUT;
1575 else if (bitmap_isset(wildcard_rr->nsec3.types, key->type))
1576 *result = DNSSEC_NSEC_FOUND;
1577 else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME))
1578 *result = DNSSEC_NSEC_CNAME;
1579 else
1580 *result = DNSSEC_NSEC_NODATA;
1581 } else {
1582 if (optout)
1583 /* The RFC only specifies that we have to care for optout for NODATA for
1584 * DS records. However, children of an insecure opt-out delegation should
1585 * also be considered opt-out, rather than verified NXDOMAIN.
1586 * Note that we do not require a proof of wildcard non-existence if the
1587 * next closer domain is covered by an opt-out, as that would not provide
1588 * any additional information. */
1589 *result = DNSSEC_NSEC_OPTOUT;
1590 else if (no_wildcard)
1591 *result = DNSSEC_NSEC_NXDOMAIN;
1592 else {
1593 *result = DNSSEC_NSEC_NO_RR;
1594
1595 return 0;
1596 }
1597 }
1598
1599 if (authenticated)
1600 *authenticated = a;
1601
1602 if (ttl)
1603 *ttl = enclosure_rr->ttl;
1604
1605 return 0;
1606 }
1607
1608 static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
1609 char label[DNS_LABEL_MAX];
1610 const char *n;
1611 int r;
1612
1613 assert(rr);
1614 assert(rr->key->type == DNS_TYPE_NSEC);
1615
1616 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1617
1618 if (rr->n_skip_labels_source != 1)
1619 return 0;
1620
1621 n = DNS_RESOURCE_KEY_NAME(rr->key);
1622 r = dns_label_unescape(&n, label, sizeof(label));
1623 if (r <= 0)
1624 return r;
1625 if (r != 1 || label[0] != '*')
1626 return 0;
1627
1628 return dns_name_endswith(name, n);
1629 }
1630
1631 static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
1632 const char *nn, *common_suffix;
1633 int r;
1634
1635 assert(rr);
1636 assert(rr->key->type == DNS_TYPE_NSEC);
1637
1638 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1639 *
1640 * A couple of examples:
1641 *
1642 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1643 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1644 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1645 */
1646
1647 /* First, determine parent of next domain. */
1648 nn = rr->nsec.next_domain_name;
1649 r = dns_name_parent(&nn);
1650 if (r <= 0)
1651 return r;
1652
1653 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1654 * anything at all. */
1655 r = dns_name_endswith(nn, name);
1656 if (r <= 0)
1657 return r;
1658
1659 /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */
1660 r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
1661 if (r < 0)
1662 return r;
1663
1664 return dns_name_endswith(name, common_suffix);
1665 }
1666
1667 static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name) {
1668 int r;
1669
1670 assert(rr);
1671 assert(rr->key->type == DNS_TYPE_NSEC);
1672
1673 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1674
1675 r = dns_name_parent(&name);
1676 if (r <= 0)
1677 return r;
1678
1679 r = dns_name_equal(name, DNS_RESOURCE_KEY_NAME(rr->key));
1680 if (r <= 0)
1681 return r;
1682
1683 /* DNAME, and NS without SOA is an indication for a delegation. */
1684 if (bitmap_isset(rr->nsec.types, DNS_TYPE_DNAME))
1685 return 1;
1686
1687 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) && !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1688 return 1;
1689
1690 return 0;
1691 }
1692
1693 static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
1694 const char *common_suffix, *p;
1695 int r;
1696
1697 assert(rr);
1698 assert(rr->key->type == DNS_TYPE_NSEC);
1699
1700 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1701
1702 r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
1703 if (r < 0)
1704 return r;
1705
1706 for (;;) {
1707 p = name;
1708 r = dns_name_parent(&name);
1709 if (r < 0)
1710 return r;
1711 if (r == 0)
1712 return 0;
1713
1714 r = dns_name_equal(name, common_suffix);
1715 if (r < 0)
1716 return r;
1717 if (r > 0)
1718 break;
1719 }
1720
1721 /* p is now the "Next Closer". */
1722
1723 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), p, rr->nsec.next_domain_name);
1724 }
1725
1726 static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
1727 const char *common_suffix, *wc;
1728 int r;
1729
1730 assert(rr);
1731 assert(rr->key->type == DNS_TYPE_NSEC);
1732
1733 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1734 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1735 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1736 *
1737 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1738 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1739 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1740 */
1741
1742 r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
1743 if (r < 0)
1744 return r;
1745
1746 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1747 r = dns_name_endswith(name, common_suffix);
1748 if (r <= 0)
1749 return r;
1750
1751 wc = strjoina("*.", common_suffix, NULL);
1752 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name);
1753 }
1754
1755 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1756 bool have_nsec3 = false, covering_rr_authenticated = false, wildcard_rr_authenticated = false;
1757 DnsResourceRecord *rr, *covering_rr = NULL, *wildcard_rr = NULL;
1758 DnsAnswerFlags flags;
1759 const char *name;
1760 int r;
1761
1762 assert(key);
1763 assert(result);
1764
1765 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1766
1767 name = DNS_RESOURCE_KEY_NAME(key);
1768
1769 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1770
1771 if (rr->key->class != key->class)
1772 continue;
1773
1774 have_nsec3 = have_nsec3 || (rr->key->type == DNS_TYPE_NSEC3);
1775
1776 if (rr->key->type != DNS_TYPE_NSEC)
1777 continue;
1778
1779 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1780 r = dns_resource_record_is_synthetic(rr);
1781 if (r < 0)
1782 return r;
1783 if (r > 0)
1784 continue;
1785
1786 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1787 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), name);
1788 if (r < 0)
1789 return r;
1790 if (r == 0) {
1791 /* If it's not a direct match, maybe it's a wild card match? */
1792 r = dnssec_nsec_wildcard_equal(rr, name);
1793 if (r < 0)
1794 return r;
1795 }
1796 if (r > 0) {
1797 if (key->type == DNS_TYPE_DS) {
1798 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1799 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1800 if (bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1801 continue;
1802 } else {
1803 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1804 * we got the child's NSEC. */
1805 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) &&
1806 !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1807 continue;
1808 }
1809
1810 if (bitmap_isset(rr->nsec.types, key->type))
1811 *result = DNSSEC_NSEC_FOUND;
1812 else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME))
1813 *result = DNSSEC_NSEC_CNAME;
1814 else
1815 *result = DNSSEC_NSEC_NODATA;
1816
1817 if (authenticated)
1818 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1819 if (ttl)
1820 *ttl = rr->ttl;
1821
1822 return 0;
1823 }
1824
1825 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1826 * of the NSEC RR. */
1827 r = dnssec_nsec_in_path(rr, name);
1828 if (r < 0)
1829 return r;
1830 if (r > 0) {
1831 *result = DNSSEC_NSEC_NODATA;
1832
1833 if (authenticated)
1834 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1835 if (ttl)
1836 *ttl = rr->ttl;
1837
1838 return 0;
1839 }
1840
1841 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1842 r = dnssec_nsec_from_parent_zone(rr, name);
1843 if (r < 0)
1844 return r;
1845 if (r > 0)
1846 continue;
1847
1848 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1849 r = dnssec_nsec_covers(rr, name);
1850 if (r < 0)
1851 return r;
1852 if (r > 0 && (!covering_rr || !covering_rr_authenticated)) {
1853 covering_rr = rr;
1854 covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1855 }
1856
1857 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1858 r = dnssec_nsec_covers_wildcard(rr, name);
1859 if (r < 0)
1860 return r;
1861 if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
1862 wildcard_rr = rr;
1863 wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1864 }
1865 }
1866
1867 if (covering_rr && wildcard_rr) {
1868 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1869 * proved the NXDOMAIN case. */
1870 *result = DNSSEC_NSEC_NXDOMAIN;
1871
1872 if (authenticated)
1873 *authenticated = covering_rr_authenticated && wildcard_rr_authenticated;
1874 if (ttl)
1875 *ttl = MIN(covering_rr->ttl, wildcard_rr->ttl);
1876
1877 return 0;
1878 }
1879
1880 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1881 if (have_nsec3)
1882 return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
1883
1884 /* No approproate NSEC RR found, report this. */
1885 *result = DNSSEC_NSEC_NO_RR;
1886 return 0;
1887 }
1888
1889 int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const char *name, const char *zone, bool *authenticated) {
1890 DnsResourceRecord *rr;
1891 DnsAnswerFlags flags;
1892 int r;
1893
1894 assert(name);
1895 assert(zone);
1896
1897 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1898 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1899
1900 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1901 bool found = false;
1902
1903 if (rr->key->type != type && type != DNS_TYPE_ANY)
1904 continue;
1905
1906 switch (rr->key->type) {
1907
1908 case DNS_TYPE_NSEC:
1909
1910 /* We only care for NSEC RRs from the indicated zone */
1911 r = dns_resource_record_is_signer(rr, zone);
1912 if (r < 0)
1913 return r;
1914 if (r == 0)
1915 continue;
1916
1917 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name);
1918 if (r < 0)
1919 return r;
1920
1921 found = r > 0;
1922 break;
1923
1924 case DNS_TYPE_NSEC3: {
1925 _cleanup_free_ char *hashed_domain = NULL, *next_hashed_domain = NULL;
1926
1927 /* We only care for NSEC3 RRs from the indicated zone */
1928 r = dns_resource_record_is_signer(rr, zone);
1929 if (r < 0)
1930 return r;
1931 if (r == 0)
1932 continue;
1933
1934 r = nsec3_is_good(rr, NULL);
1935 if (r < 0)
1936 return r;
1937 if (r == 0)
1938 break;
1939
1940 /* Format the domain we are testing with the NSEC3 RR's hash function */
1941 r = nsec3_hashed_domain_make(
1942 rr,
1943 name,
1944 zone,
1945 &hashed_domain);
1946 if (r < 0)
1947 return r;
1948 if ((size_t) r != rr->nsec3.next_hashed_name_size)
1949 break;
1950
1951 /* Format the NSEC3's next hashed name as proper domain name */
1952 r = nsec3_hashed_domain_format(
1953 rr->nsec3.next_hashed_name,
1954 rr->nsec3.next_hashed_name_size,
1955 zone,
1956 &next_hashed_domain);
1957 if (r < 0)
1958 return r;
1959
1960 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain, next_hashed_domain);
1961 if (r < 0)
1962 return r;
1963
1964 found = r > 0;
1965 break;
1966 }
1967
1968 default:
1969 continue;
1970 }
1971
1972 if (found) {
1973 if (authenticated)
1974 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1975 return 1;
1976 }
1977 }
1978
1979 return 0;
1980 }
1981
1982 static int dnssec_test_positive_wildcard_nsec3(
1983 DnsAnswer *answer,
1984 const char *name,
1985 const char *source,
1986 const char *zone,
1987 bool *authenticated) {
1988
1989 const char *next_closer = NULL;
1990 int r;
1991
1992 /* Run a positive NSEC3 wildcard proof. Specifically:
1993 *
1994 * A proof that the the "next closer" of the generating wildcard does not exist.
1995 *
1996 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1997 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1998 * exists for the NSEC3 RR and we are done.
1999 *
2000 * To prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f all we have to check is that
2001 * c.d.e.f does not exist. */
2002
2003 for (;;) {
2004 next_closer = name;
2005 r = dns_name_parent(&name);
2006 if (r < 0)
2007 return r;
2008 if (r == 0)
2009 return 0;
2010
2011 r = dns_name_equal(name, source);
2012 if (r < 0)
2013 return r;
2014 if (r > 0)
2015 break;
2016 }
2017
2018 return dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC3, next_closer, zone, authenticated);
2019 }
2020
2021 static int dnssec_test_positive_wildcard_nsec(
2022 DnsAnswer *answer,
2023 const char *name,
2024 const char *source,
2025 const char *zone,
2026 bool *_authenticated) {
2027
2028 bool authenticated = true;
2029 int r;
2030
2031 /* Run a positive NSEC wildcard proof. Specifically:
2032 *
2033 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2034 * a prefix of the synthesizing source "source" in the zone "zone".
2035 *
2036 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2037 *
2038 * Note that if we want to prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f, then we
2039 * have to prove that none of the following exist:
2040 *
2041 * 1) a.b.c.d.e.f
2042 * 2) *.b.c.d.e.f
2043 * 3) b.c.d.e.f
2044 * 4) *.c.d.e.f
2045 * 5) c.d.e.f
2046 *
2047 */
2048
2049 for (;;) {
2050 _cleanup_free_ char *wc = NULL;
2051 bool a = false;
2052
2053 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2054 * i.e between the owner name and the next name of an NSEC RR. */
2055 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, name, zone, &a);
2056 if (r <= 0)
2057 return r;
2058
2059 authenticated = authenticated && a;
2060
2061 /* Strip one label off */
2062 r = dns_name_parent(&name);
2063 if (r <= 0)
2064 return r;
2065
2066 /* Did we reach the source of synthesis? */
2067 r = dns_name_equal(name, source);
2068 if (r < 0)
2069 return r;
2070 if (r > 0) {
2071 /* Successful exit */
2072 *_authenticated = authenticated;
2073 return 1;
2074 }
2075
2076 /* Safety check, that the source of synthesis is still our suffix */
2077 r = dns_name_endswith(name, source);
2078 if (r < 0)
2079 return r;
2080 if (r == 0)
2081 return -EBADMSG;
2082
2083 /* Replace the label we stripped off with an asterisk */
2084 wc = strappend("*.", name);
2085 if (!wc)
2086 return -ENOMEM;
2087
2088 /* And check if the proof holds for the asterisk name, too */
2089 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, wc, zone, &a);
2090 if (r <= 0)
2091 return r;
2092
2093 authenticated = authenticated && a;
2094 /* In the next iteration we'll check the non-asterisk-prefixed version */
2095 }
2096 }
2097
2098 int dnssec_test_positive_wildcard(
2099 DnsAnswer *answer,
2100 const char *name,
2101 const char *source,
2102 const char *zone,
2103 bool *authenticated) {
2104
2105 int r;
2106
2107 assert(name);
2108 assert(source);
2109 assert(zone);
2110 assert(authenticated);
2111
2112 r = dns_answer_contains_zone_nsec3(answer, zone);
2113 if (r < 0)
2114 return r;
2115 if (r > 0)
2116 return dnssec_test_positive_wildcard_nsec3(answer, name, source, zone, authenticated);
2117 else
2118 return dnssec_test_positive_wildcard_nsec(answer, name, source, zone, authenticated);
2119 }
2120
2121 static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
2122 [DNSSEC_VALIDATED] = "validated",
2123 [DNSSEC_VALIDATED_WILDCARD] = "validated-wildcard",
2124 [DNSSEC_INVALID] = "invalid",
2125 [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
2126 [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
2127 [DNSSEC_NO_SIGNATURE] = "no-signature",
2128 [DNSSEC_MISSING_KEY] = "missing-key",
2129 [DNSSEC_UNSIGNED] = "unsigned",
2130 [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
2131 [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
2132 [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
2133 };
2134 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);