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