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