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