]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-dnssec.c
Merge pull request #8066 from LittleCVR/udevadm-trigger-and-settle
[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 _cleanup_(gcry_md_closep) 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 return r;
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 return r;
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 return 0;
889 default:
890 /* OK, the RRs are now in canonical order. Let's calculate the digest */
891 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
892 if (md_algorithm == -EOPNOTSUPP) {
893 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
894 return 0;
895 }
896 if (md_algorithm < 0)
897 return md_algorithm;
898
899 gcry_md_open(&md, md_algorithm, 0);
900 if (!md)
901 return -EIO;
902
903 hash_size = gcry_md_get_algo_dlen(md_algorithm);
904 assert(hash_size > 0);
905
906 gcry_md_write(md, sig_data, sig_size);
907
908 hash = gcry_md_read(md, 0);
909 if (!hash)
910 return -EIO;
911 }
912
913 switch (rrsig->rrsig.algorithm) {
914
915 case DNSSEC_ALGORITHM_RSASHA1:
916 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
917 case DNSSEC_ALGORITHM_RSASHA256:
918 case DNSSEC_ALGORITHM_RSASHA512:
919 r = dnssec_rsa_verify(
920 gcry_md_algo_name(md_algorithm),
921 hash, hash_size,
922 rrsig,
923 dnskey);
924 break;
925
926 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
927 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
928 r = dnssec_ecdsa_verify(
929 gcry_md_algo_name(md_algorithm),
930 rrsig->rrsig.algorithm,
931 hash, hash_size,
932 rrsig,
933 dnskey);
934 break;
935 #if GCRYPT_VERSION_NUMBER >= 0x010600
936 case DNSSEC_ALGORITHM_ED25519:
937 r = dnssec_eddsa_verify(
938 rrsig->rrsig.algorithm,
939 sig_data, sig_size,
940 rrsig,
941 dnskey);
942 break;
943 #endif
944 }
945 if (r < 0)
946 return r;
947
948 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
949 if (r > 0)
950 dnssec_fix_rrset_ttl(list, n, rrsig, realtime);
951
952 if (r == 0)
953 *result = DNSSEC_INVALID;
954 else if (wildcard)
955 *result = DNSSEC_VALIDATED_WILDCARD;
956 else
957 *result = DNSSEC_VALIDATED;
958
959 return 0;
960 }
961
962 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
963
964 assert(rrsig);
965 assert(dnskey);
966
967 /* Checks if the specified DNSKEY RR matches the key used for
968 * the signature in the specified RRSIG RR */
969
970 if (rrsig->key->type != DNS_TYPE_RRSIG)
971 return -EINVAL;
972
973 if (dnskey->key->type != DNS_TYPE_DNSKEY)
974 return 0;
975 if (dnskey->key->class != rrsig->key->class)
976 return 0;
977 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
978 return 0;
979 if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
980 return 0;
981 if (dnskey->dnskey.protocol != 3)
982 return 0;
983 if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
984 return 0;
985
986 if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
987 return 0;
988
989 return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer);
990 }
991
992 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
993 assert(key);
994 assert(rrsig);
995
996 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
997
998 if (rrsig->key->type != DNS_TYPE_RRSIG)
999 return 0;
1000 if (rrsig->key->class != key->class)
1001 return 0;
1002 if (rrsig->rrsig.type_covered != key->type)
1003 return 0;
1004
1005 return dns_name_equal(dns_resource_key_name(rrsig->key), dns_resource_key_name(key));
1006 }
1007
1008 int dnssec_verify_rrset_search(
1009 DnsAnswer *a,
1010 const DnsResourceKey *key,
1011 DnsAnswer *validated_dnskeys,
1012 usec_t realtime,
1013 DnssecResult *result,
1014 DnsResourceRecord **ret_rrsig) {
1015
1016 bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
1017 DnsResourceRecord *rrsig;
1018 int r;
1019
1020 assert(key);
1021 assert(result);
1022
1023 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
1024
1025 if (!a || a->n_rrs <= 0)
1026 return -ENODATA;
1027
1028 /* Iterate through each RRSIG RR. */
1029 DNS_ANSWER_FOREACH(rrsig, a) {
1030 DnsResourceRecord *dnskey;
1031 DnsAnswerFlags flags;
1032
1033 /* Is this an RRSIG RR that applies to RRs matching our key? */
1034 r = dnssec_key_match_rrsig(key, rrsig);
1035 if (r < 0)
1036 return r;
1037 if (r == 0)
1038 continue;
1039
1040 found_rrsig = true;
1041
1042 /* Look for a matching key */
1043 DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
1044 DnssecResult one_result;
1045
1046 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1047 continue;
1048
1049 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
1050 r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false);
1051 if (r < 0)
1052 return r;
1053 if (r == 0)
1054 continue;
1055
1056 /* Take the time here, if it isn't set yet, so
1057 * that we do all validations with the same
1058 * time. */
1059 if (realtime == USEC_INFINITY)
1060 realtime = now(CLOCK_REALTIME);
1061
1062 /* Yay, we found a matching RRSIG with a matching
1063 * DNSKEY, awesome. Now let's verify all entries of
1064 * the RRSet against the RRSIG and DNSKEY
1065 * combination. */
1066
1067 r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
1068 if (r < 0)
1069 return r;
1070
1071 switch (one_result) {
1072
1073 case DNSSEC_VALIDATED:
1074 case DNSSEC_VALIDATED_WILDCARD:
1075 /* Yay, the RR has been validated,
1076 * return immediately, but fix up the expiry */
1077 if (ret_rrsig)
1078 *ret_rrsig = rrsig;
1079
1080 *result = one_result;
1081 return 0;
1082
1083 case DNSSEC_INVALID:
1084 /* If the signature is invalid, let's try another
1085 key and/or signature. After all they
1086 key_tags and stuff are not unique, and
1087 might be shared by multiple keys. */
1088 found_invalid = true;
1089 continue;
1090
1091 case DNSSEC_UNSUPPORTED_ALGORITHM:
1092 /* If the key algorithm is
1093 unsupported, try another
1094 RRSIG/DNSKEY pair, but remember we
1095 encountered this, so that we can
1096 return a proper error when we
1097 encounter nothing better. */
1098 found_unsupported_algorithm = true;
1099 continue;
1100
1101 case DNSSEC_SIGNATURE_EXPIRED:
1102 /* If the signature is expired, try
1103 another one, but remember it, so
1104 that we can return this */
1105 found_expired_rrsig = true;
1106 continue;
1107
1108 default:
1109 assert_not_reached("Unexpected DNSSEC validation result");
1110 }
1111 }
1112 }
1113
1114 if (found_expired_rrsig)
1115 *result = DNSSEC_SIGNATURE_EXPIRED;
1116 else if (found_unsupported_algorithm)
1117 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
1118 else if (found_invalid)
1119 *result = DNSSEC_INVALID;
1120 else if (found_rrsig)
1121 *result = DNSSEC_MISSING_KEY;
1122 else
1123 *result = DNSSEC_NO_SIGNATURE;
1124
1125 if (ret_rrsig)
1126 *ret_rrsig = NULL;
1127
1128 return 0;
1129 }
1130
1131 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
1132 DnsResourceRecord *rr;
1133 int r;
1134
1135 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1136
1137 DNS_ANSWER_FOREACH(rr, a) {
1138 r = dnssec_key_match_rrsig(key, rr);
1139 if (r < 0)
1140 return r;
1141 if (r > 0)
1142 return 1;
1143 }
1144
1145 return 0;
1146 }
1147
1148 static int digest_to_gcrypt_md(uint8_t algorithm) {
1149
1150 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1151
1152 switch (algorithm) {
1153
1154 case DNSSEC_DIGEST_SHA1:
1155 return GCRY_MD_SHA1;
1156
1157 case DNSSEC_DIGEST_SHA256:
1158 return GCRY_MD_SHA256;
1159
1160 case DNSSEC_DIGEST_SHA384:
1161 return GCRY_MD_SHA384;
1162
1163 default:
1164 return -EOPNOTSUPP;
1165 }
1166 }
1167
1168 int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
1169 char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
1170 _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
1171 size_t hash_size;
1172 int md_algorithm, r;
1173 void *result;
1174
1175 assert(dnskey);
1176 assert(ds);
1177
1178 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1179
1180 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1181 return -EINVAL;
1182 if (ds->key->type != DNS_TYPE_DS)
1183 return -EINVAL;
1184 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1185 return -EKEYREJECTED;
1186 if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
1187 return -EKEYREJECTED;
1188 if (dnskey->dnskey.protocol != 3)
1189 return -EKEYREJECTED;
1190
1191 if (dnskey->dnskey.algorithm != ds->ds.algorithm)
1192 return 0;
1193 if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
1194 return 0;
1195
1196 initialize_libgcrypt(false);
1197
1198 md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
1199 if (md_algorithm < 0)
1200 return md_algorithm;
1201
1202 hash_size = gcry_md_get_algo_dlen(md_algorithm);
1203 assert(hash_size > 0);
1204
1205 if (ds->ds.digest_size != hash_size)
1206 return 0;
1207
1208 r = dnssec_canonicalize(dns_resource_key_name(dnskey->key), owner_name, sizeof(owner_name));
1209 if (r < 0)
1210 return r;
1211
1212 gcry_md_open(&md, md_algorithm, 0);
1213 if (!md)
1214 return -EIO;
1215
1216 gcry_md_write(md, owner_name, r);
1217 if (mask_revoke)
1218 md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
1219 else
1220 md_add_uint16(md, dnskey->dnskey.flags);
1221 md_add_uint8(md, dnskey->dnskey.protocol);
1222 md_add_uint8(md, dnskey->dnskey.algorithm);
1223 gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
1224
1225 result = gcry_md_read(md, 0);
1226 if (!result)
1227 return -EIO;
1228
1229 return memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
1230 }
1231
1232 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1233 DnsResourceRecord *ds;
1234 DnsAnswerFlags flags;
1235 int r;
1236
1237 assert(dnskey);
1238
1239 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1240 return 0;
1241
1242 DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
1243
1244 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1245 continue;
1246
1247 if (ds->key->type != DNS_TYPE_DS)
1248 continue;
1249 if (ds->key->class != dnskey->key->class)
1250 continue;
1251
1252 r = dns_name_equal(dns_resource_key_name(dnskey->key), dns_resource_key_name(ds->key));
1253 if (r < 0)
1254 return r;
1255 if (r == 0)
1256 continue;
1257
1258 r = dnssec_verify_dnskey_by_ds(dnskey, ds, false);
1259 if (IN_SET(r, -EKEYREJECTED, -EOPNOTSUPP))
1260 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1261 if (r < 0)
1262 return r;
1263 if (r > 0)
1264 return 1;
1265 }
1266
1267 return 0;
1268 }
1269
1270 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
1271
1272 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1273
1274 switch (algorithm) {
1275
1276 case NSEC3_ALGORITHM_SHA1:
1277 return GCRY_MD_SHA1;
1278
1279 default:
1280 return -EOPNOTSUPP;
1281 }
1282 }
1283
1284 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1285 uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1286 gcry_md_hd_t md = NULL;
1287 size_t hash_size;
1288 int algorithm;
1289 void *result;
1290 unsigned k;
1291 int r;
1292
1293 assert(nsec3);
1294 assert(name);
1295 assert(ret);
1296
1297 if (nsec3->key->type != DNS_TYPE_NSEC3)
1298 return -EINVAL;
1299
1300 if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX) {
1301 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3));
1302 return -EOPNOTSUPP;
1303 }
1304
1305 algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
1306 if (algorithm < 0)
1307 return algorithm;
1308
1309 initialize_libgcrypt(false);
1310
1311 hash_size = gcry_md_get_algo_dlen(algorithm);
1312 assert(hash_size > 0);
1313
1314 if (nsec3->nsec3.next_hashed_name_size != hash_size)
1315 return -EINVAL;
1316
1317 r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1318 if (r < 0)
1319 return r;
1320
1321 gcry_md_open(&md, algorithm, 0);
1322 if (!md)
1323 return -EIO;
1324
1325 gcry_md_write(md, wire_format, r);
1326 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1327
1328 result = gcry_md_read(md, 0);
1329 if (!result) {
1330 r = -EIO;
1331 goto finish;
1332 }
1333
1334 for (k = 0; k < nsec3->nsec3.iterations; k++) {
1335 uint8_t tmp[hash_size];
1336 memcpy(tmp, result, hash_size);
1337
1338 gcry_md_reset(md);
1339 gcry_md_write(md, tmp, hash_size);
1340 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1341
1342 result = gcry_md_read(md, 0);
1343 if (!result) {
1344 r = -EIO;
1345 goto finish;
1346 }
1347 }
1348
1349 memcpy(ret, result, hash_size);
1350 r = (int) hash_size;
1351
1352 finish:
1353 gcry_md_close(md);
1354 return r;
1355 }
1356
1357 static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
1358 const char *a, *b;
1359 int r;
1360
1361 assert(rr);
1362
1363 if (rr->key->type != DNS_TYPE_NSEC3)
1364 return 0;
1365
1366 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1367 if (!IN_SET(rr->nsec3.flags, 0, 1))
1368 return 0;
1369
1370 /* Ignore NSEC3 RRs whose algorithm we don't know */
1371 if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
1372 return 0;
1373 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1374 if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1375 return 0;
1376
1377 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1378 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1379 if (!IN_SET(rr->n_skip_labels_source, 0, (unsigned) -1))
1380 return 0;
1381 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1382 if (!IN_SET(rr->n_skip_labels_signer, 1, (unsigned) -1))
1383 return 0;
1384
1385 if (!nsec3)
1386 return 1;
1387
1388 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1389
1390 if (nsec3 == rr) /* Shortcut */
1391 return 1;
1392
1393 if (rr->key->class != nsec3->key->class)
1394 return 0;
1395 if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
1396 return 0;
1397 if (rr->nsec3.iterations != nsec3->nsec3.iterations)
1398 return 0;
1399 if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
1400 return 0;
1401 if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
1402 return 0;
1403
1404 a = dns_resource_key_name(rr->key);
1405 r = dns_name_parent(&a); /* strip off hash */
1406 if (r < 0)
1407 return r;
1408 if (r == 0)
1409 return 0;
1410
1411 b = dns_resource_key_name(nsec3->key);
1412 r = dns_name_parent(&b); /* strip off hash */
1413 if (r < 0)
1414 return r;
1415 if (r == 0)
1416 return 0;
1417
1418 /* Make sure both have the same parent */
1419 return dns_name_equal(a, b);
1420 }
1421
1422 static int nsec3_hashed_domain_format(const uint8_t *hashed, size_t hashed_size, const char *zone, char **ret) {
1423 _cleanup_free_ char *l = NULL;
1424 char *j;
1425
1426 assert(hashed);
1427 assert(hashed_size > 0);
1428 assert(zone);
1429 assert(ret);
1430
1431 l = base32hexmem(hashed, hashed_size, false);
1432 if (!l)
1433 return -ENOMEM;
1434
1435 j = strjoin(l, ".", zone);
1436 if (!j)
1437 return -ENOMEM;
1438
1439 *ret = j;
1440 return (int) hashed_size;
1441 }
1442
1443 static int nsec3_hashed_domain_make(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) {
1444 uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1445 int hashed_size;
1446
1447 assert(nsec3);
1448 assert(domain);
1449 assert(zone);
1450 assert(ret);
1451
1452 hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed);
1453 if (hashed_size < 0)
1454 return hashed_size;
1455
1456 return nsec3_hashed_domain_format(hashed, (size_t) hashed_size, zone, ret);
1457 }
1458
1459 /* See RFC 5155, Section 8
1460 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1461 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1462 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1463 * matches the wildcard domain.
1464 *
1465 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1466 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1467 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1468 * to conclude anything we indicate this by returning NO_RR. */
1469 static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1470 _cleanup_free_ char *next_closer_domain = NULL, *wildcard_domain = NULL;
1471 const char *zone, *p, *pp = NULL, *wildcard;
1472 DnsResourceRecord *rr, *enclosure_rr, *zone_rr, *wildcard_rr = NULL;
1473 DnsAnswerFlags flags;
1474 int hashed_size, r;
1475 bool a, no_closer = false, no_wildcard = false, optout = false;
1476
1477 assert(key);
1478 assert(result);
1479
1480 /* First step, find the zone name and the NSEC3 parameters of the zone.
1481 * it is sufficient to look for the longest common suffix we find with
1482 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1483 * records from a given zone in a response must use the same
1484 * parameters. */
1485 zone = dns_resource_key_name(key);
1486 for (;;) {
1487 DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) {
1488 r = nsec3_is_good(zone_rr, NULL);
1489 if (r < 0)
1490 return r;
1491 if (r == 0)
1492 continue;
1493
1494 r = dns_name_equal_skip(dns_resource_key_name(zone_rr->key), 1, zone);
1495 if (r < 0)
1496 return r;
1497 if (r > 0)
1498 goto found_zone;
1499 }
1500
1501 /* Strip one label from the front */
1502 r = dns_name_parent(&zone);
1503 if (r < 0)
1504 return r;
1505 if (r == 0)
1506 break;
1507 }
1508
1509 *result = DNSSEC_NSEC_NO_RR;
1510 return 0;
1511
1512 found_zone:
1513 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1514 p = dns_resource_key_name(key);
1515 for (;;) {
1516 _cleanup_free_ char *hashed_domain = NULL;
1517
1518 hashed_size = nsec3_hashed_domain_make(zone_rr, p, zone, &hashed_domain);
1519 if (hashed_size == -EOPNOTSUPP) {
1520 *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1521 return 0;
1522 }
1523 if (hashed_size < 0)
1524 return hashed_size;
1525
1526 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) {
1527
1528 r = nsec3_is_good(enclosure_rr, zone_rr);
1529 if (r < 0)
1530 return r;
1531 if (r == 0)
1532 continue;
1533
1534 if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
1535 continue;
1536
1537 r = dns_name_equal(dns_resource_key_name(enclosure_rr->key), hashed_domain);
1538 if (r < 0)
1539 return r;
1540 if (r > 0) {
1541 a = flags & DNS_ANSWER_AUTHENTICATED;
1542 goto found_closest_encloser;
1543 }
1544 }
1545
1546 /* We didn't find the closest encloser with this name,
1547 * but let's remember this domain name, it might be
1548 * the next closer name */
1549
1550 pp = p;
1551
1552 /* Strip one label from the front */
1553 r = dns_name_parent(&p);
1554 if (r < 0)
1555 return r;
1556 if (r == 0)
1557 break;
1558 }
1559
1560 *result = DNSSEC_NSEC_NO_RR;
1561 return 0;
1562
1563 found_closest_encloser:
1564 /* We found a closest encloser in 'p'; next closer is 'pp' */
1565
1566 if (!pp) {
1567 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1568 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1569 * appropriately set. */
1570
1571 if (key->type == DNS_TYPE_DS) {
1572 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1573 return -EBADMSG;
1574 } else {
1575 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1576 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1577 return -EBADMSG;
1578 }
1579
1580 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1581 if (bitmap_isset(enclosure_rr->nsec3.types, key->type))
1582 *result = DNSSEC_NSEC_FOUND;
1583 else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME))
1584 *result = DNSSEC_NSEC_CNAME;
1585 else
1586 *result = DNSSEC_NSEC_NODATA;
1587
1588 if (authenticated)
1589 *authenticated = a;
1590 if (ttl)
1591 *ttl = enclosure_rr->ttl;
1592
1593 return 0;
1594 }
1595
1596 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1597 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME))
1598 return -EBADMSG;
1599
1600 /* Ensure that this data is from the delegated domain
1601 * (i.e. originates from the "lower" DNS server), and isn't
1602 * just glue records (i.e. doesn't originate from the "upper"
1603 * DNS server). */
1604 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1605 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1606 return -EBADMSG;
1607
1608 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1609
1610 wildcard = strjoina("*.", p);
1611 r = nsec3_hashed_domain_make(enclosure_rr, wildcard, zone, &wildcard_domain);
1612 if (r < 0)
1613 return r;
1614 if (r != hashed_size)
1615 return -EBADMSG;
1616
1617 r = nsec3_hashed_domain_make(enclosure_rr, pp, zone, &next_closer_domain);
1618 if (r < 0)
1619 return r;
1620 if (r != hashed_size)
1621 return -EBADMSG;
1622
1623 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1624 _cleanup_free_ char *next_hashed_domain = NULL;
1625
1626 r = nsec3_is_good(rr, zone_rr);
1627 if (r < 0)
1628 return r;
1629 if (r == 0)
1630 continue;
1631
1632 r = nsec3_hashed_domain_format(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, zone, &next_hashed_domain);
1633 if (r < 0)
1634 return r;
1635
1636 r = dns_name_between(dns_resource_key_name(rr->key), next_closer_domain, next_hashed_domain);
1637 if (r < 0)
1638 return r;
1639 if (r > 0) {
1640 if (rr->nsec3.flags & 1)
1641 optout = true;
1642
1643 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1644
1645 no_closer = true;
1646 }
1647
1648 r = dns_name_equal(dns_resource_key_name(rr->key), wildcard_domain);
1649 if (r < 0)
1650 return r;
1651 if (r > 0) {
1652 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1653
1654 wildcard_rr = rr;
1655 }
1656
1657 r = dns_name_between(dns_resource_key_name(rr->key), wildcard_domain, next_hashed_domain);
1658 if (r < 0)
1659 return r;
1660 if (r > 0) {
1661 if (rr->nsec3.flags & 1)
1662 /* This only makes sense if we have a wildcard delegation, which is
1663 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1664 * this not happening, so hence cannot simply conclude NXDOMAIN as
1665 * we would wish */
1666 optout = true;
1667
1668 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1669
1670 no_wildcard = true;
1671 }
1672 }
1673
1674 if (wildcard_rr && no_wildcard)
1675 return -EBADMSG;
1676
1677 if (!no_closer) {
1678 *result = DNSSEC_NSEC_NO_RR;
1679 return 0;
1680 }
1681
1682 if (wildcard_rr) {
1683 /* A wildcard exists that matches our query. */
1684 if (optout)
1685 /* This is not specified in any RFC to the best of my knowledge, but
1686 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1687 * it means that we cannot prove that the source of synthesis is
1688 * correct, as there may be a closer match. */
1689 *result = DNSSEC_NSEC_OPTOUT;
1690 else if (bitmap_isset(wildcard_rr->nsec3.types, key->type))
1691 *result = DNSSEC_NSEC_FOUND;
1692 else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME))
1693 *result = DNSSEC_NSEC_CNAME;
1694 else
1695 *result = DNSSEC_NSEC_NODATA;
1696 } else {
1697 if (optout)
1698 /* The RFC only specifies that we have to care for optout for NODATA for
1699 * DS records. However, children of an insecure opt-out delegation should
1700 * also be considered opt-out, rather than verified NXDOMAIN.
1701 * Note that we do not require a proof of wildcard non-existence if the
1702 * next closer domain is covered by an opt-out, as that would not provide
1703 * any additional information. */
1704 *result = DNSSEC_NSEC_OPTOUT;
1705 else if (no_wildcard)
1706 *result = DNSSEC_NSEC_NXDOMAIN;
1707 else {
1708 *result = DNSSEC_NSEC_NO_RR;
1709
1710 return 0;
1711 }
1712 }
1713
1714 if (authenticated)
1715 *authenticated = a;
1716
1717 if (ttl)
1718 *ttl = enclosure_rr->ttl;
1719
1720 return 0;
1721 }
1722
1723 static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
1724 char label[DNS_LABEL_MAX];
1725 const char *n;
1726 int r;
1727
1728 assert(rr);
1729 assert(rr->key->type == DNS_TYPE_NSEC);
1730
1731 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1732
1733 if (rr->n_skip_labels_source != 1)
1734 return 0;
1735
1736 n = dns_resource_key_name(rr->key);
1737 r = dns_label_unescape(&n, label, sizeof(label));
1738 if (r <= 0)
1739 return r;
1740 if (r != 1 || label[0] != '*')
1741 return 0;
1742
1743 return dns_name_endswith(name, n);
1744 }
1745
1746 static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
1747 const char *nn, *common_suffix;
1748 int r;
1749
1750 assert(rr);
1751 assert(rr->key->type == DNS_TYPE_NSEC);
1752
1753 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1754 *
1755 * A couple of examples:
1756 *
1757 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1758 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1759 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1760 */
1761
1762 /* First, determine parent of next domain. */
1763 nn = rr->nsec.next_domain_name;
1764 r = dns_name_parent(&nn);
1765 if (r <= 0)
1766 return r;
1767
1768 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1769 * anything at all. */
1770 r = dns_name_endswith(nn, name);
1771 if (r <= 0)
1772 return r;
1773
1774 /* 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. */
1775 r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
1776 if (r < 0)
1777 return r;
1778
1779 return dns_name_endswith(name, common_suffix);
1780 }
1781
1782 static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name) {
1783 int r;
1784
1785 assert(rr);
1786 assert(rr->key->type == DNS_TYPE_NSEC);
1787
1788 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1789
1790 r = dns_name_parent(&name);
1791 if (r <= 0)
1792 return r;
1793
1794 r = dns_name_equal(name, dns_resource_key_name(rr->key));
1795 if (r <= 0)
1796 return r;
1797
1798 /* DNAME, and NS without SOA is an indication for a delegation. */
1799 if (bitmap_isset(rr->nsec.types, DNS_TYPE_DNAME))
1800 return 1;
1801
1802 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) && !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1803 return 1;
1804
1805 return 0;
1806 }
1807
1808 static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
1809 const char *common_suffix, *p;
1810 int r;
1811
1812 assert(rr);
1813 assert(rr->key->type == DNS_TYPE_NSEC);
1814
1815 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1816
1817 r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
1818 if (r < 0)
1819 return r;
1820
1821 for (;;) {
1822 p = name;
1823 r = dns_name_parent(&name);
1824 if (r < 0)
1825 return r;
1826 if (r == 0)
1827 return 0;
1828
1829 r = dns_name_equal(name, common_suffix);
1830 if (r < 0)
1831 return r;
1832 if (r > 0)
1833 break;
1834 }
1835
1836 /* p is now the "Next Closer". */
1837
1838 return dns_name_between(dns_resource_key_name(rr->key), p, rr->nsec.next_domain_name);
1839 }
1840
1841 static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
1842 _cleanup_free_ char *wc = NULL;
1843 const char *common_suffix;
1844 int r;
1845
1846 assert(rr);
1847 assert(rr->key->type == DNS_TYPE_NSEC);
1848
1849 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1850 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1851 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1852 *
1853 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1854 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1855 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1856 */
1857
1858 r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
1859 if (r < 0)
1860 return r;
1861
1862 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1863 r = dns_name_endswith(name, common_suffix);
1864 if (r <= 0)
1865 return r;
1866
1867 r = dns_name_concat("*", common_suffix, &wc);
1868 if (r < 0)
1869 return r;
1870
1871 return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
1872 }
1873
1874 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1875 bool have_nsec3 = false, covering_rr_authenticated = false, wildcard_rr_authenticated = false;
1876 DnsResourceRecord *rr, *covering_rr = NULL, *wildcard_rr = NULL;
1877 DnsAnswerFlags flags;
1878 const char *name;
1879 int r;
1880
1881 assert(key);
1882 assert(result);
1883
1884 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1885
1886 name = dns_resource_key_name(key);
1887
1888 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1889
1890 if (rr->key->class != key->class)
1891 continue;
1892
1893 have_nsec3 = have_nsec3 || (rr->key->type == DNS_TYPE_NSEC3);
1894
1895 if (rr->key->type != DNS_TYPE_NSEC)
1896 continue;
1897
1898 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1899 r = dns_resource_record_is_synthetic(rr);
1900 if (r < 0)
1901 return r;
1902 if (r > 0)
1903 continue;
1904
1905 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1906 r = dns_name_equal(dns_resource_key_name(rr->key), name);
1907 if (r < 0)
1908 return r;
1909 if (r == 0) {
1910 /* If it's not a direct match, maybe it's a wild card match? */
1911 r = dnssec_nsec_wildcard_equal(rr, name);
1912 if (r < 0)
1913 return r;
1914 }
1915 if (r > 0) {
1916 if (key->type == DNS_TYPE_DS) {
1917 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1918 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1919 if (bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1920 continue;
1921 } else {
1922 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1923 * we got the child's NSEC. */
1924 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) &&
1925 !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1926 continue;
1927 }
1928
1929 if (bitmap_isset(rr->nsec.types, key->type))
1930 *result = DNSSEC_NSEC_FOUND;
1931 else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME))
1932 *result = DNSSEC_NSEC_CNAME;
1933 else
1934 *result = DNSSEC_NSEC_NODATA;
1935
1936 if (authenticated)
1937 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1938 if (ttl)
1939 *ttl = rr->ttl;
1940
1941 return 0;
1942 }
1943
1944 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1945 * of the NSEC RR. */
1946 r = dnssec_nsec_in_path(rr, name);
1947 if (r < 0)
1948 return r;
1949 if (r > 0) {
1950 *result = DNSSEC_NSEC_NODATA;
1951
1952 if (authenticated)
1953 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1954 if (ttl)
1955 *ttl = rr->ttl;
1956
1957 return 0;
1958 }
1959
1960 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1961 r = dnssec_nsec_from_parent_zone(rr, name);
1962 if (r < 0)
1963 return r;
1964 if (r > 0)
1965 continue;
1966
1967 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1968 r = dnssec_nsec_covers(rr, name);
1969 if (r < 0)
1970 return r;
1971 if (r > 0 && (!covering_rr || !covering_rr_authenticated)) {
1972 covering_rr = rr;
1973 covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1974 }
1975
1976 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1977 r = dnssec_nsec_covers_wildcard(rr, name);
1978 if (r < 0)
1979 return r;
1980 if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
1981 wildcard_rr = rr;
1982 wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1983 }
1984 }
1985
1986 if (covering_rr && wildcard_rr) {
1987 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1988 * proved the NXDOMAIN case. */
1989 *result = DNSSEC_NSEC_NXDOMAIN;
1990
1991 if (authenticated)
1992 *authenticated = covering_rr_authenticated && wildcard_rr_authenticated;
1993 if (ttl)
1994 *ttl = MIN(covering_rr->ttl, wildcard_rr->ttl);
1995
1996 return 0;
1997 }
1998
1999 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
2000 if (have_nsec3)
2001 return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
2002
2003 /* No approproate NSEC RR found, report this. */
2004 *result = DNSSEC_NSEC_NO_RR;
2005 return 0;
2006 }
2007
2008 static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const char *name, const char *zone, bool *authenticated) {
2009 DnsResourceRecord *rr;
2010 DnsAnswerFlags flags;
2011 int r;
2012
2013 assert(name);
2014 assert(zone);
2015
2016 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
2017 * 'zone'. The 'zone' must be a suffix of the 'name'. */
2018
2019 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
2020 bool found = false;
2021
2022 if (rr->key->type != type && type != DNS_TYPE_ANY)
2023 continue;
2024
2025 switch (rr->key->type) {
2026
2027 case DNS_TYPE_NSEC:
2028
2029 /* We only care for NSEC RRs from the indicated zone */
2030 r = dns_resource_record_is_signer(rr, zone);
2031 if (r < 0)
2032 return r;
2033 if (r == 0)
2034 continue;
2035
2036 r = dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
2037 if (r < 0)
2038 return r;
2039
2040 found = r > 0;
2041 break;
2042
2043 case DNS_TYPE_NSEC3: {
2044 _cleanup_free_ char *hashed_domain = NULL, *next_hashed_domain = NULL;
2045
2046 /* We only care for NSEC3 RRs from the indicated zone */
2047 r = dns_resource_record_is_signer(rr, zone);
2048 if (r < 0)
2049 return r;
2050 if (r == 0)
2051 continue;
2052
2053 r = nsec3_is_good(rr, NULL);
2054 if (r < 0)
2055 return r;
2056 if (r == 0)
2057 break;
2058
2059 /* Format the domain we are testing with the NSEC3 RR's hash function */
2060 r = nsec3_hashed_domain_make(
2061 rr,
2062 name,
2063 zone,
2064 &hashed_domain);
2065 if (r < 0)
2066 return r;
2067 if ((size_t) r != rr->nsec3.next_hashed_name_size)
2068 break;
2069
2070 /* Format the NSEC3's next hashed name as proper domain name */
2071 r = nsec3_hashed_domain_format(
2072 rr->nsec3.next_hashed_name,
2073 rr->nsec3.next_hashed_name_size,
2074 zone,
2075 &next_hashed_domain);
2076 if (r < 0)
2077 return r;
2078
2079 r = dns_name_between(dns_resource_key_name(rr->key), hashed_domain, next_hashed_domain);
2080 if (r < 0)
2081 return r;
2082
2083 found = r > 0;
2084 break;
2085 }
2086
2087 default:
2088 continue;
2089 }
2090
2091 if (found) {
2092 if (authenticated)
2093 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
2094 return 1;
2095 }
2096 }
2097
2098 return 0;
2099 }
2100
2101 static int dnssec_test_positive_wildcard_nsec3(
2102 DnsAnswer *answer,
2103 const char *name,
2104 const char *source,
2105 const char *zone,
2106 bool *authenticated) {
2107
2108 const char *next_closer = NULL;
2109 int r;
2110
2111 /* Run a positive NSEC3 wildcard proof. Specifically:
2112 *
2113 * A proof that the "next closer" of the generating wildcard does not exist.
2114 *
2115 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2116 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2117 * exists for the NSEC3 RR and we are done.
2118 *
2119 * 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
2120 * c.d.e.f does not exist. */
2121
2122 for (;;) {
2123 next_closer = name;
2124 r = dns_name_parent(&name);
2125 if (r < 0)
2126 return r;
2127 if (r == 0)
2128 return 0;
2129
2130 r = dns_name_equal(name, source);
2131 if (r < 0)
2132 return r;
2133 if (r > 0)
2134 break;
2135 }
2136
2137 return dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC3, next_closer, zone, authenticated);
2138 }
2139
2140 static int dnssec_test_positive_wildcard_nsec(
2141 DnsAnswer *answer,
2142 const char *name,
2143 const char *source,
2144 const char *zone,
2145 bool *_authenticated) {
2146
2147 bool authenticated = true;
2148 int r;
2149
2150 /* Run a positive NSEC wildcard proof. Specifically:
2151 *
2152 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2153 * a prefix of the synthesizing source "source" in the zone "zone".
2154 *
2155 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2156 *
2157 * 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
2158 * have to prove that none of the following exist:
2159 *
2160 * 1) a.b.c.d.e.f
2161 * 2) *.b.c.d.e.f
2162 * 3) b.c.d.e.f
2163 * 4) *.c.d.e.f
2164 * 5) c.d.e.f
2165 *
2166 */
2167
2168 for (;;) {
2169 _cleanup_free_ char *wc = NULL;
2170 bool a = false;
2171
2172 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2173 * i.e between the owner name and the next name of an NSEC RR. */
2174 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, name, zone, &a);
2175 if (r <= 0)
2176 return r;
2177
2178 authenticated = authenticated && a;
2179
2180 /* Strip one label off */
2181 r = dns_name_parent(&name);
2182 if (r <= 0)
2183 return r;
2184
2185 /* Did we reach the source of synthesis? */
2186 r = dns_name_equal(name, source);
2187 if (r < 0)
2188 return r;
2189 if (r > 0) {
2190 /* Successful exit */
2191 *_authenticated = authenticated;
2192 return 1;
2193 }
2194
2195 /* Safety check, that the source of synthesis is still our suffix */
2196 r = dns_name_endswith(name, source);
2197 if (r < 0)
2198 return r;
2199 if (r == 0)
2200 return -EBADMSG;
2201
2202 /* Replace the label we stripped off with an asterisk */
2203 wc = strappend("*.", name);
2204 if (!wc)
2205 return -ENOMEM;
2206
2207 /* And check if the proof holds for the asterisk name, too */
2208 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, wc, zone, &a);
2209 if (r <= 0)
2210 return r;
2211
2212 authenticated = authenticated && a;
2213 /* In the next iteration we'll check the non-asterisk-prefixed version */
2214 }
2215 }
2216
2217 int dnssec_test_positive_wildcard(
2218 DnsAnswer *answer,
2219 const char *name,
2220 const char *source,
2221 const char *zone,
2222 bool *authenticated) {
2223
2224 int r;
2225
2226 assert(name);
2227 assert(source);
2228 assert(zone);
2229 assert(authenticated);
2230
2231 r = dns_answer_contains_zone_nsec3(answer, zone);
2232 if (r < 0)
2233 return r;
2234 if (r > 0)
2235 return dnssec_test_positive_wildcard_nsec3(answer, name, source, zone, authenticated);
2236 else
2237 return dnssec_test_positive_wildcard_nsec(answer, name, source, zone, authenticated);
2238 }
2239
2240 #else
2241
2242 int dnssec_verify_rrset(
2243 DnsAnswer *a,
2244 const DnsResourceKey *key,
2245 DnsResourceRecord *rrsig,
2246 DnsResourceRecord *dnskey,
2247 usec_t realtime,
2248 DnssecResult *result) {
2249
2250 return -EOPNOTSUPP;
2251 }
2252
2253 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
2254
2255 return -EOPNOTSUPP;
2256 }
2257
2258 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
2259
2260 return -EOPNOTSUPP;
2261 }
2262
2263 int dnssec_verify_rrset_search(
2264 DnsAnswer *a,
2265 const DnsResourceKey *key,
2266 DnsAnswer *validated_dnskeys,
2267 usec_t realtime,
2268 DnssecResult *result,
2269 DnsResourceRecord **ret_rrsig) {
2270
2271 return -EOPNOTSUPP;
2272 }
2273
2274 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
2275
2276 return -EOPNOTSUPP;
2277 }
2278
2279 int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
2280
2281 return -EOPNOTSUPP;
2282 }
2283
2284 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
2285
2286 return -EOPNOTSUPP;
2287 }
2288
2289 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
2290
2291 return -EOPNOTSUPP;
2292 }
2293
2294 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
2295
2296 return -EOPNOTSUPP;
2297 }
2298
2299 int dnssec_test_positive_wildcard(
2300 DnsAnswer *answer,
2301 const char *name,
2302 const char *source,
2303 const char *zone,
2304 bool *authenticated) {
2305
2306 return -EOPNOTSUPP;
2307 }
2308
2309 #endif
2310
2311 static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
2312 [DNSSEC_VALIDATED] = "validated",
2313 [DNSSEC_VALIDATED_WILDCARD] = "validated-wildcard",
2314 [DNSSEC_INVALID] = "invalid",
2315 [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
2316 [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
2317 [DNSSEC_NO_SIGNATURE] = "no-signature",
2318 [DNSSEC_MISSING_KEY] = "missing-key",
2319 [DNSSEC_UNSIGNED] = "unsigned",
2320 [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
2321 [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
2322 [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
2323 };
2324 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
2325
2326 static const char* const dnssec_verdict_table[_DNSSEC_VERDICT_MAX] = {
2327 [DNSSEC_SECURE] = "secure",
2328 [DNSSEC_INSECURE] = "insecure",
2329 [DNSSEC_BOGUS] = "bogus",
2330 [DNSSEC_INDETERMINATE] = "indeterminate",
2331 };
2332 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict, DnssecVerdict);