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