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