]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-dnssec.c
Merge pull request #2269 from poettering/dnssec11
[thirdparty/systemd.git] / src / resolve / resolved-dns-dnssec.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <gcrypt.h>
23
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
30
31 /* Open question:
32 *
33 * How does the DNSSEC canonical form of a hostname with a label
34 * containing a dot look like, the way DNS-SD does it?
35 *
36 * TODO:
37 *
38 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39 * - multi-label zone compatibility
40 * - cname/dname compatibility
41 * - nxdomain on qname
42 * - per-interface DNSSEC setting
43 *
44 * */
45
46 #define VERIFY_RRS_MAX 256
47 #define MAX_KEY_SIZE (32*1024)
48
49 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
50 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
51
52 /* Maximum number of NSEC3 iterations we'll do. */
53 #define NSEC3_ITERATIONS_MAX 2048
54
55 /*
56 * The DNSSEC Chain of trust:
57 *
58 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
59 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
60 * DS RRs are protected like normal RRs
61 *
62 * Example chain:
63 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
64 */
65
66 static void initialize_libgcrypt(void) {
67 const char *p;
68
69 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
70 return;
71
72 p = gcry_check_version("1.4.5");
73 assert(p);
74
75 gcry_control(GCRYCTL_DISABLE_SECMEM);
76 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
77 }
78
79 uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) {
80 const uint8_t *p;
81 uint32_t sum, f;
82 size_t i;
83
84 /* The algorithm from RFC 4034, Appendix B. */
85
86 assert(dnskey);
87 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
88
89 f = (uint32_t) dnskey->dnskey.flags;
90
91 if (mask_revoke)
92 f &= ~DNSKEY_FLAG_REVOKE;
93
94 sum = f + ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
95
96 p = dnskey->dnskey.key;
97
98 for (i = 0; i < dnskey->dnskey.key_size; i++)
99 sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
100
101 sum += (sum >> 16) & UINT32_C(0xFFFF);
102
103 return sum & UINT32_C(0xFFFF);
104 }
105
106 static int rr_compare(const void *a, const void *b) {
107 DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
108 size_t m;
109 int r;
110
111 /* Let's order the RRs according to RFC 4034, Section 6.3 */
112
113 assert(x);
114 assert(*x);
115 assert((*x)->wire_format);
116 assert(y);
117 assert(*y);
118 assert((*y)->wire_format);
119
120 m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
121
122 r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
123 if (r != 0)
124 return r;
125
126 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
127 return -1;
128 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
129 return 1;
130
131 return 0;
132 }
133
134 static int dnssec_rsa_verify_raw(
135 const char *hash_algorithm,
136 const void *signature, size_t signature_size,
137 const void *data, size_t data_size,
138 const void *exponent, size_t exponent_size,
139 const void *modulus, size_t modulus_size) {
140
141 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
142 gcry_mpi_t n = NULL, e = NULL, s = NULL;
143 gcry_error_t ge;
144 int r;
145
146 assert(hash_algorithm);
147
148 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
149 if (ge != 0) {
150 r = -EIO;
151 goto finish;
152 }
153
154 ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
155 if (ge != 0) {
156 r = -EIO;
157 goto finish;
158 }
159
160 ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
161 if (ge != 0) {
162 r = -EIO;
163 goto finish;
164 }
165
166 ge = gcry_sexp_build(&signature_sexp,
167 NULL,
168 "(sig-val (rsa (s %m)))",
169 s);
170
171 if (ge != 0) {
172 r = -EIO;
173 goto finish;
174 }
175
176 ge = gcry_sexp_build(&data_sexp,
177 NULL,
178 "(data (flags pkcs1) (hash %s %b))",
179 hash_algorithm,
180 (int) data_size,
181 data);
182 if (ge != 0) {
183 r = -EIO;
184 goto finish;
185 }
186
187 ge = gcry_sexp_build(&public_key_sexp,
188 NULL,
189 "(public-key (rsa (n %m) (e %m)))",
190 n,
191 e);
192 if (ge != 0) {
193 r = -EIO;
194 goto finish;
195 }
196
197 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
198 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
199 r = 0;
200 else if (ge != 0) {
201 log_debug("RSA signature check failed: %s", gpg_strerror(ge));
202 r = -EIO;
203 } else
204 r = 1;
205
206 finish:
207 if (e)
208 gcry_mpi_release(e);
209 if (n)
210 gcry_mpi_release(n);
211 if (s)
212 gcry_mpi_release(s);
213
214 if (public_key_sexp)
215 gcry_sexp_release(public_key_sexp);
216 if (signature_sexp)
217 gcry_sexp_release(signature_sexp);
218 if (data_sexp)
219 gcry_sexp_release(data_sexp);
220
221 return r;
222 }
223
224 static int dnssec_rsa_verify(
225 const char *hash_algorithm,
226 const void *hash, size_t hash_size,
227 DnsResourceRecord *rrsig,
228 DnsResourceRecord *dnskey) {
229
230 size_t exponent_size, modulus_size;
231 void *exponent, *modulus;
232
233 assert(hash_algorithm);
234 assert(hash);
235 assert(hash_size > 0);
236 assert(rrsig);
237 assert(dnskey);
238
239 if (*(uint8_t*) dnskey->dnskey.key == 0) {
240 /* exponent is > 255 bytes long */
241
242 exponent = (uint8_t*) dnskey->dnskey.key + 3;
243 exponent_size =
244 ((size_t) (((uint8_t*) dnskey->dnskey.key)[1]) << 8) |
245 ((size_t) ((uint8_t*) dnskey->dnskey.key)[2]);
246
247 if (exponent_size < 256)
248 return -EINVAL;
249
250 if (3 + exponent_size >= dnskey->dnskey.key_size)
251 return -EINVAL;
252
253 modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
254 modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
255
256 } else {
257 /* exponent is <= 255 bytes long */
258
259 exponent = (uint8_t*) dnskey->dnskey.key + 1;
260 exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
261
262 if (exponent_size <= 0)
263 return -EINVAL;
264
265 if (1 + exponent_size >= dnskey->dnskey.key_size)
266 return -EINVAL;
267
268 modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
269 modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
270 }
271
272 return dnssec_rsa_verify_raw(
273 hash_algorithm,
274 rrsig->rrsig.signature, rrsig->rrsig.signature_size,
275 hash, hash_size,
276 exponent, exponent_size,
277 modulus, modulus_size);
278 }
279
280 static int dnssec_ecdsa_verify_raw(
281 const char *hash_algorithm,
282 const char *curve,
283 const void *signature_r, size_t signature_r_size,
284 const void *signature_s, size_t signature_s_size,
285 const void *data, size_t data_size,
286 const void *key, size_t key_size) {
287
288 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
289 gcry_mpi_t q = NULL, r = NULL, s = NULL;
290 gcry_error_t ge;
291 int k;
292
293 assert(hash_algorithm);
294
295 ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
296 if (ge != 0) {
297 k = -EIO;
298 goto finish;
299 }
300
301 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
302 if (ge != 0) {
303 k = -EIO;
304 goto finish;
305 }
306
307 ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
308 if (ge != 0) {
309 k = -EIO;
310 goto finish;
311 }
312
313 ge = gcry_sexp_build(&signature_sexp,
314 NULL,
315 "(sig-val (ecdsa (r %m) (s %m)))",
316 r,
317 s);
318 if (ge != 0) {
319 k = -EIO;
320 goto finish;
321 }
322
323 ge = gcry_sexp_build(&data_sexp,
324 NULL,
325 "(data (flags rfc6979) (hash %s %b))",
326 hash_algorithm,
327 (int) data_size,
328 data);
329 if (ge != 0) {
330 k = -EIO;
331 goto finish;
332 }
333
334 ge = gcry_sexp_build(&public_key_sexp,
335 NULL,
336 "(public-key (ecc (curve %s) (q %m)))",
337 curve,
338 q);
339 if (ge != 0) {
340 k = -EIO;
341 goto finish;
342 }
343
344 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
345 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
346 k = 0;
347 else if (ge != 0) {
348 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
349 k = -EIO;
350 } else
351 k = 1;
352 finish:
353 if (r)
354 gcry_mpi_release(r);
355 if (s)
356 gcry_mpi_release(s);
357 if (q)
358 gcry_mpi_release(q);
359
360 if (public_key_sexp)
361 gcry_sexp_release(public_key_sexp);
362 if (signature_sexp)
363 gcry_sexp_release(signature_sexp);
364 if (data_sexp)
365 gcry_sexp_release(data_sexp);
366
367 return k;
368 }
369
370 static int dnssec_ecdsa_verify(
371 const char *hash_algorithm,
372 int algorithm,
373 const void *hash, size_t hash_size,
374 DnsResourceRecord *rrsig,
375 DnsResourceRecord *dnskey) {
376
377 const char *curve;
378 size_t key_size;
379 uint8_t *q;
380
381 assert(hash);
382 assert(hash_size);
383 assert(rrsig);
384 assert(dnskey);
385
386 if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
387 key_size = 32;
388 curve = "NIST P-256";
389 } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
390 key_size = 48;
391 curve = "NIST P-384";
392 } else
393 return -EOPNOTSUPP;
394
395 if (dnskey->dnskey.key_size != key_size * 2)
396 return -EINVAL;
397
398 if (rrsig->rrsig.signature_size != key_size * 2)
399 return -EINVAL;
400
401 q = alloca(key_size*2 + 1);
402 q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
403 memcpy(q+1, dnskey->dnskey.key, key_size*2);
404
405 return dnssec_ecdsa_verify_raw(
406 hash_algorithm,
407 curve,
408 rrsig->rrsig.signature, key_size,
409 (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
410 hash, hash_size,
411 q, key_size*2+1);
412 }
413
414 static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
415 gcry_md_write(md, &v, sizeof(v));
416 }
417
418 static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
419 v = htobe16(v);
420 gcry_md_write(md, &v, sizeof(v));
421 }
422
423 static void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
424 v = htobe32(v);
425 gcry_md_write(md, &v, sizeof(v));
426 }
427
428 static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
429 usec_t expiration, inception, skew;
430
431 assert(rrsig);
432 assert(rrsig->key->type == DNS_TYPE_RRSIG);
433
434 if (realtime == USEC_INFINITY)
435 realtime = now(CLOCK_REALTIME);
436
437 expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
438 inception = rrsig->rrsig.inception * USEC_PER_SEC;
439
440 if (inception > expiration)
441 return -EKEYREJECTED;
442
443 /* Permit a certain amount of clock skew of 10% of the valid
444 * time range. This takes inspiration from unbound's
445 * resolver. */
446 skew = (expiration - inception) / 10;
447 if (skew > SKEW_MAX)
448 skew = SKEW_MAX;
449
450 if (inception < skew)
451 inception = 0;
452 else
453 inception -= skew;
454
455 if (expiration + skew < expiration)
456 expiration = USEC_INFINITY;
457 else
458 expiration += skew;
459
460 return realtime < inception || realtime > expiration;
461 }
462
463 static int algorithm_to_gcrypt_md(uint8_t algorithm) {
464
465 /* Translates a DNSSEC signature algorithm into a gcrypt
466 * digest identifier.
467 *
468 * Note that we implement all algorithms listed as "Must
469 * implement" and "Recommended to Implement" in RFC6944. We
470 * don't implement any algorithms that are listed as
471 * "Optional" or "Must Not Implement". Specifically, we do not
472 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
473 * GOST-ECC. */
474
475 switch (algorithm) {
476
477 case DNSSEC_ALGORITHM_RSASHA1:
478 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
479 return GCRY_MD_SHA1;
480
481 case DNSSEC_ALGORITHM_RSASHA256:
482 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
483 return GCRY_MD_SHA256;
484
485 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
486 return GCRY_MD_SHA384;
487
488 case DNSSEC_ALGORITHM_RSASHA512:
489 return GCRY_MD_SHA512;
490
491 default:
492 return -EOPNOTSUPP;
493 }
494 }
495
496 int dnssec_verify_rrset(
497 DnsAnswer *a,
498 const DnsResourceKey *key,
499 DnsResourceRecord *rrsig,
500 DnsResourceRecord *dnskey,
501 usec_t realtime,
502 DnssecResult *result) {
503
504 uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
505 size_t hash_size;
506 void *hash;
507 DnsResourceRecord **list, *rr;
508 gcry_md_hd_t md = NULL;
509 int r, md_algorithm;
510 size_t k, n = 0;
511
512 assert(key);
513 assert(rrsig);
514 assert(dnskey);
515 assert(result);
516 assert(rrsig->key->type == DNS_TYPE_RRSIG);
517 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
518
519 /* Verifies the the RRSet matching the specified "key" in "a",
520 * using the signature "rrsig" and the key "dnskey". It's
521 * assumed the RRSIG and DNSKEY match. */
522
523 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
524 if (md_algorithm == -EOPNOTSUPP) {
525 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
526 return 0;
527 }
528 if (md_algorithm < 0)
529 return md_algorithm;
530
531 r = dnssec_rrsig_expired(rrsig, realtime);
532 if (r < 0)
533 return r;
534 if (r > 0) {
535 *result = DNSSEC_SIGNATURE_EXPIRED;
536 return 0;
537 }
538
539 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
540 list = newa(DnsResourceRecord *, a->n_rrs);
541
542 DNS_ANSWER_FOREACH(rr, a) {
543 r = dns_resource_key_equal(key, rr->key);
544 if (r < 0)
545 return r;
546 if (r == 0)
547 continue;
548
549 /* We need the wire format for ordering, and digest calculation */
550 r = dns_resource_record_to_wire_format(rr, true);
551 if (r < 0)
552 return r;
553
554 list[n++] = rr;
555
556 if (n > VERIFY_RRS_MAX)
557 return -E2BIG;
558 }
559
560 if (n <= 0)
561 return -ENODATA;
562
563 /* Bring the RRs into canonical order */
564 qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
565
566 /* OK, the RRs are now in canonical order. Let's calculate the digest */
567 initialize_libgcrypt();
568
569 hash_size = gcry_md_get_algo_dlen(md_algorithm);
570 assert(hash_size > 0);
571
572 gcry_md_open(&md, md_algorithm, 0);
573 if (!md)
574 return -EIO;
575
576 md_add_uint16(md, rrsig->rrsig.type_covered);
577 md_add_uint8(md, rrsig->rrsig.algorithm);
578 md_add_uint8(md, rrsig->rrsig.labels);
579 md_add_uint32(md, rrsig->rrsig.original_ttl);
580 md_add_uint32(md, rrsig->rrsig.expiration);
581 md_add_uint32(md, rrsig->rrsig.inception);
582 md_add_uint16(md, rrsig->rrsig.key_tag);
583
584 r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
585 if (r < 0)
586 goto finish;
587 gcry_md_write(md, wire_format_name, r);
588
589 for (k = 0; k < n; k++) {
590 const char *suffix;
591 size_t l;
592 rr = list[k];
593
594 r = dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rrsig->rrsig.labels, &suffix);
595 if (r < 0)
596 goto finish;
597 if (r > 0) /* This is a wildcard! */
598 gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2);
599
600 r = dns_name_to_wire_format(suffix, wire_format_name, sizeof(wire_format_name), true);
601 if (r < 0)
602 goto finish;
603 gcry_md_write(md, wire_format_name, r);
604
605 md_add_uint16(md, rr->key->type);
606 md_add_uint16(md, rr->key->class);
607 md_add_uint32(md, rrsig->rrsig.original_ttl);
608
609 l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
610 assert(l <= 0xFFFF);
611
612 md_add_uint16(md, (uint16_t) l);
613 gcry_md_write(md, DNS_RESOURCE_RECORD_RDATA(rr), l);
614 }
615
616 hash = gcry_md_read(md, 0);
617 if (!hash) {
618 r = -EIO;
619 goto finish;
620 }
621
622 switch (rrsig->rrsig.algorithm) {
623
624 case DNSSEC_ALGORITHM_RSASHA1:
625 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
626 case DNSSEC_ALGORITHM_RSASHA256:
627 case DNSSEC_ALGORITHM_RSASHA512:
628 r = dnssec_rsa_verify(
629 gcry_md_algo_name(md_algorithm),
630 hash, hash_size,
631 rrsig,
632 dnskey);
633 break;
634
635 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
636 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
637 r = dnssec_ecdsa_verify(
638 gcry_md_algo_name(md_algorithm),
639 rrsig->rrsig.algorithm,
640 hash, hash_size,
641 rrsig,
642 dnskey);
643 break;
644 }
645
646 if (r < 0)
647 goto finish;
648
649 *result = r ? DNSSEC_VALIDATED : DNSSEC_INVALID;
650 r = 0;
651
652 finish:
653 gcry_md_close(md);
654 return r;
655 }
656
657 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
658
659 assert(rrsig);
660 assert(dnskey);
661
662 /* Checks if the specified DNSKEY RR matches the key used for
663 * the signature in the specified RRSIG RR */
664
665 if (rrsig->key->type != DNS_TYPE_RRSIG)
666 return -EINVAL;
667
668 if (dnskey->key->type != DNS_TYPE_DNSKEY)
669 return 0;
670 if (dnskey->key->class != rrsig->key->class)
671 return 0;
672 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
673 return 0;
674 if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
675 return 0;
676 if (dnskey->dnskey.protocol != 3)
677 return 0;
678 if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
679 return 0;
680
681 if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
682 return 0;
683
684 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
685 }
686
687 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
688 int r;
689
690 assert(key);
691 assert(rrsig);
692
693 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
694
695 if (rrsig->key->type != DNS_TYPE_RRSIG)
696 return 0;
697 if (rrsig->key->class != key->class)
698 return 0;
699 if (rrsig->rrsig.type_covered != key->type)
700 return 0;
701
702 /* Make sure signer is a parent of the RRset */
703 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig->key), rrsig->rrsig.signer);
704 if (r <= 0)
705 return r;
706
707 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
708 r = dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig->key));
709 if (r < 0)
710 return r;
711 if (r < rrsig->rrsig.labels)
712 return 0;
713
714 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
715 }
716
717 static int dnssec_fix_rrset_ttl(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord *rrsig, usec_t realtime) {
718 DnsResourceRecord *rr;
719 int r;
720
721 assert(key);
722 assert(rrsig);
723
724 DNS_ANSWER_FOREACH(rr, a) {
725 r = dns_resource_key_equal(key, rr->key);
726 if (r < 0)
727 return r;
728 if (r == 0)
729 continue;
730
731 /* Pick the TTL as the minimum of the RR's TTL, the
732 * RR's original TTL according to the RRSIG and the
733 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
734 rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
735 rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
736 }
737
738 return 0;
739 }
740
741 int dnssec_verify_rrset_search(
742 DnsAnswer *a,
743 const DnsResourceKey *key,
744 DnsAnswer *validated_dnskeys,
745 usec_t realtime,
746 DnssecResult *result) {
747
748 bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
749 DnsResourceRecord *rrsig;
750 int r;
751
752 assert(key);
753 assert(result);
754
755 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
756
757 if (!a || a->n_rrs <= 0)
758 return -ENODATA;
759
760 /* Iterate through each RRSIG RR. */
761 DNS_ANSWER_FOREACH(rrsig, a) {
762 DnsResourceRecord *dnskey;
763 DnsAnswerFlags flags;
764
765 /* Is this an RRSIG RR that applies to RRs matching our key? */
766 r = dnssec_key_match_rrsig(key, rrsig);
767 if (r < 0)
768 return r;
769 if (r == 0)
770 continue;
771
772 found_rrsig = true;
773
774 /* Look for a matching key */
775 DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
776 DnssecResult one_result;
777
778 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
779 continue;
780
781 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
782 r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false);
783 if (r < 0)
784 return r;
785 if (r == 0)
786 continue;
787
788 /* Take the time here, if it isn't set yet, so
789 * that we do all validations with the same
790 * time. */
791 if (realtime == USEC_INFINITY)
792 realtime = now(CLOCK_REALTIME);
793
794 /* Yay, we found a matching RRSIG with a matching
795 * DNSKEY, awesome. Now let's verify all entries of
796 * the RRSet against the RRSIG and DNSKEY
797 * combination. */
798
799 r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
800 if (r < 0)
801 return r;
802
803 switch (one_result) {
804
805 case DNSSEC_VALIDATED:
806 /* Yay, the RR has been validated,
807 * return immediately, but fix up the expiry */
808 r = dnssec_fix_rrset_ttl(a, key, rrsig, realtime);
809 if (r < 0)
810 return r;
811
812 *result = DNSSEC_VALIDATED;
813 return 0;
814
815 case DNSSEC_INVALID:
816 /* If the signature is invalid, let's try another
817 key and/or signature. After all they
818 key_tags and stuff are not unique, and
819 might be shared by multiple keys. */
820 found_invalid = true;
821 continue;
822
823 case DNSSEC_UNSUPPORTED_ALGORITHM:
824 /* If the key algorithm is
825 unsupported, try another
826 RRSIG/DNSKEY pair, but remember we
827 encountered this, so that we can
828 return a proper error when we
829 encounter nothing better. */
830 found_unsupported_algorithm = true;
831 continue;
832
833 case DNSSEC_SIGNATURE_EXPIRED:
834 /* If the signature is expired, try
835 another one, but remember it, so
836 that we can return this */
837 found_expired_rrsig = true;
838 continue;
839
840 default:
841 assert_not_reached("Unexpected DNSSEC validation result");
842 }
843 }
844 }
845
846 if (found_expired_rrsig)
847 *result = DNSSEC_SIGNATURE_EXPIRED;
848 else if (found_unsupported_algorithm)
849 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
850 else if (found_invalid)
851 *result = DNSSEC_INVALID;
852 else if (found_rrsig)
853 *result = DNSSEC_MISSING_KEY;
854 else
855 *result = DNSSEC_NO_SIGNATURE;
856
857 return 0;
858 }
859
860 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
861 DnsResourceRecord *rr;
862 int r;
863
864 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
865
866 DNS_ANSWER_FOREACH(rr, a) {
867 r = dnssec_key_match_rrsig(key, rr);
868 if (r < 0)
869 return r;
870 if (r > 0)
871 return 1;
872 }
873
874 return 0;
875 }
876
877 int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
878 size_t c = 0;
879 int r;
880
881 /* Converts the specified hostname into DNSSEC canonicalized
882 * form. */
883
884 if (buffer_max < 2)
885 return -ENOBUFS;
886
887 for (;;) {
888 size_t i;
889
890 r = dns_label_unescape(&n, buffer, buffer_max);
891 if (r < 0)
892 return r;
893 if (r == 0)
894 break;
895 if (r > 0) {
896 int k;
897
898 /* DNSSEC validation is always done on the ASCII version of the label */
899 k = dns_label_apply_idna(buffer, r, buffer, buffer_max);
900 if (k < 0)
901 return k;
902 if (k > 0)
903 r = k;
904 }
905
906 if (buffer_max < (size_t) r + 2)
907 return -ENOBUFS;
908
909 /* The DNSSEC canonical form is not clear on what to
910 * do with dots appearing in labels, the way DNS-SD
911 * does it. Refuse it for now. */
912
913 if (memchr(buffer, '.', r))
914 return -EINVAL;
915
916 for (i = 0; i < (size_t) r; i ++) {
917 if (buffer[i] >= 'A' && buffer[i] <= 'Z')
918 buffer[i] = buffer[i] - 'A' + 'a';
919 }
920
921 buffer[r] = '.';
922
923 buffer += r + 1;
924 c += r + 1;
925
926 buffer_max -= r + 1;
927 }
928
929 if (c <= 0) {
930 /* Not even a single label: this is the root domain name */
931
932 assert(buffer_max > 2);
933 buffer[0] = '.';
934 buffer[1] = 0;
935
936 return 1;
937 }
938
939 return (int) c;
940 }
941
942 static int digest_to_gcrypt_md(uint8_t algorithm) {
943
944 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
945
946 switch (algorithm) {
947
948 case DNSSEC_DIGEST_SHA1:
949 return GCRY_MD_SHA1;
950
951 case DNSSEC_DIGEST_SHA256:
952 return GCRY_MD_SHA256;
953
954 case DNSSEC_DIGEST_SHA384:
955 return GCRY_MD_SHA384;
956
957 default:
958 return -EOPNOTSUPP;
959 }
960 }
961
962 int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
963 char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
964 gcry_md_hd_t md = NULL;
965 size_t hash_size;
966 int md_algorithm, r;
967 void *result;
968
969 assert(dnskey);
970 assert(ds);
971
972 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
973
974 if (dnskey->key->type != DNS_TYPE_DNSKEY)
975 return -EINVAL;
976 if (ds->key->type != DNS_TYPE_DS)
977 return -EINVAL;
978 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
979 return -EKEYREJECTED;
980 if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
981 return -EKEYREJECTED;
982 if (dnskey->dnskey.protocol != 3)
983 return -EKEYREJECTED;
984
985 if (dnskey->dnskey.algorithm != ds->ds.algorithm)
986 return 0;
987 if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
988 return 0;
989
990 initialize_libgcrypt();
991
992 md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
993 if (md_algorithm < 0)
994 return md_algorithm;
995
996 hash_size = gcry_md_get_algo_dlen(md_algorithm);
997 assert(hash_size > 0);
998
999 if (ds->ds.digest_size != hash_size)
1000 return 0;
1001
1002 r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
1003 if (r < 0)
1004 return r;
1005
1006 gcry_md_open(&md, md_algorithm, 0);
1007 if (!md)
1008 return -EIO;
1009
1010 gcry_md_write(md, owner_name, r);
1011 if (mask_revoke)
1012 md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
1013 else
1014 md_add_uint16(md, dnskey->dnskey.flags);
1015 md_add_uint8(md, dnskey->dnskey.protocol);
1016 md_add_uint8(md, dnskey->dnskey.algorithm);
1017 gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
1018
1019 result = gcry_md_read(md, 0);
1020 if (!result) {
1021 r = -EIO;
1022 goto finish;
1023 }
1024
1025 r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
1026
1027 finish:
1028 gcry_md_close(md);
1029 return r;
1030 }
1031
1032 int dnssec_verify_dnskey_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1033 DnsResourceRecord *ds;
1034 DnsAnswerFlags flags;
1035 int r;
1036
1037 assert(dnskey);
1038
1039 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1040 return 0;
1041
1042 DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
1043
1044 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1045 continue;
1046
1047 if (ds->key->type != DNS_TYPE_DS)
1048 continue;
1049
1050 if (ds->key->class != dnskey->key->class)
1051 continue;
1052
1053 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
1054 if (r < 0)
1055 return r;
1056 if (r == 0)
1057 continue;
1058
1059 r = dnssec_verify_dnskey(dnskey, ds, false);
1060 if (r == -EKEYREJECTED)
1061 return 0; /* The DNSKEY is revoked or otherwise invalid, we won't bless it */
1062 if (r < 0)
1063 return r;
1064 if (r > 0)
1065 return 1;
1066 }
1067
1068 return 0;
1069 }
1070
1071 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
1072
1073 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1074
1075 switch (algorithm) {
1076
1077 case NSEC3_ALGORITHM_SHA1:
1078 return GCRY_MD_SHA1;
1079
1080 default:
1081 return -EOPNOTSUPP;
1082 }
1083 }
1084
1085 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1086 uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1087 gcry_md_hd_t md = NULL;
1088 size_t hash_size;
1089 int algorithm;
1090 void *result;
1091 unsigned k;
1092 int r;
1093
1094 assert(nsec3);
1095 assert(name);
1096 assert(ret);
1097
1098 if (nsec3->key->type != DNS_TYPE_NSEC3)
1099 return -EINVAL;
1100
1101 if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX) {
1102 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3));
1103 return -EOPNOTSUPP;
1104 }
1105
1106 algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
1107 if (algorithm < 0)
1108 return algorithm;
1109
1110 initialize_libgcrypt();
1111
1112 hash_size = gcry_md_get_algo_dlen(algorithm);
1113 assert(hash_size > 0);
1114
1115 if (nsec3->nsec3.next_hashed_name_size != hash_size)
1116 return -EINVAL;
1117
1118 r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1119 if (r < 0)
1120 return r;
1121
1122 gcry_md_open(&md, algorithm, 0);
1123 if (!md)
1124 return -EIO;
1125
1126 gcry_md_write(md, wire_format, r);
1127 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1128
1129 result = gcry_md_read(md, 0);
1130 if (!result) {
1131 r = -EIO;
1132 goto finish;
1133 }
1134
1135 for (k = 0; k < nsec3->nsec3.iterations; k++) {
1136 uint8_t tmp[hash_size];
1137 memcpy(tmp, result, hash_size);
1138
1139 gcry_md_reset(md);
1140 gcry_md_write(md, tmp, hash_size);
1141 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1142
1143 result = gcry_md_read(md, 0);
1144 if (!result) {
1145 r = -EIO;
1146 goto finish;
1147 }
1148 }
1149
1150 memcpy(ret, result, hash_size);
1151 r = (int) hash_size;
1152
1153 finish:
1154 gcry_md_close(md);
1155 return r;
1156 }
1157
1158 static int nsec3_is_good(DnsResourceRecord *rr, DnsAnswerFlags flags, DnsResourceRecord *nsec3) {
1159 const char *a, *b;
1160 int r;
1161
1162 assert(rr);
1163
1164 if (rr->key->type != DNS_TYPE_NSEC3)
1165 return 0;
1166
1167 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1168 if (!IN_SET(rr->nsec3.flags, 0, 1))
1169 return 0;
1170
1171 /* Ignore NSEC3 RRs whose algorithm we don't know */
1172 if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
1173 return 0;
1174 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1175 if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1176 return 0;
1177
1178 if (!nsec3)
1179 return 1;
1180
1181 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1182
1183 if (nsec3 == rr) /* Shortcut */
1184 return 1;
1185
1186 if (rr->key->class != nsec3->key->class)
1187 return 0;
1188 if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
1189 return 0;
1190 if (rr->nsec3.iterations != nsec3->nsec3.iterations)
1191 return 0;
1192 if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
1193 return 0;
1194 if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
1195 return 0;
1196
1197 a = DNS_RESOURCE_KEY_NAME(rr->key);
1198 r = dns_name_parent(&a); /* strip off hash */
1199 if (r < 0)
1200 return r;
1201 if (r == 0)
1202 return 0;
1203
1204 b = DNS_RESOURCE_KEY_NAME(nsec3->key);
1205 r = dns_name_parent(&b); /* strip off hash */
1206 if (r < 0)
1207 return r;
1208 if (r == 0)
1209 return 0;
1210
1211 return dns_name_equal(a, b);
1212 }
1213
1214 static int nsec3_hashed_domain(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) {
1215 _cleanup_free_ char *l = NULL, *hashed_domain = NULL;
1216 uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1217 int hashed_size;
1218
1219 assert(nsec3);
1220 assert(domain);
1221 assert(zone);
1222 assert(ret);
1223
1224 hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed);
1225 if (hashed_size < 0)
1226 return hashed_size;
1227
1228 l = base32hexmem(hashed, hashed_size, false);
1229 if (!l)
1230 return -ENOMEM;
1231
1232 hashed_domain = strjoin(l, ".", zone, NULL);
1233 if (!hashed_domain)
1234 return -ENOMEM;
1235
1236 *ret = hashed_domain;
1237 hashed_domain = NULL;
1238
1239 return hashed_size;
1240 }
1241
1242 /* See RFC 5155, Section 8
1243 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1244 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1245 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1246 * matches the wildcard domain.
1247 *
1248 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1249 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1250 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1251 * to conclude anything we indicate this by returning NO_RR. */
1252 static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1253 _cleanup_free_ char *next_closer_domain = NULL, *wildcard = NULL, *wildcard_domain = NULL;
1254 const char *zone, *p, *pp = NULL;
1255 DnsResourceRecord *rr, *enclosure_rr, *suffix_rr, *wildcard_rr = NULL;
1256 DnsAnswerFlags flags;
1257 int hashed_size, r;
1258 bool a, no_closer = false, no_wildcard = false, optout = false;
1259
1260 assert(key);
1261 assert(result);
1262
1263 /* First step, find the zone name and the NSEC3 parameters of the zone.
1264 * it is sufficient to look for the longest common suffix we find with
1265 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1266 * records from a given zone in a response must use the same
1267 * parameters. */
1268 zone = DNS_RESOURCE_KEY_NAME(key);
1269 for (;;) {
1270 DNS_ANSWER_FOREACH_FLAGS(suffix_rr, flags, answer) {
1271 r = nsec3_is_good(suffix_rr, flags, NULL);
1272 if (r < 0)
1273 return r;
1274 if (r == 0)
1275 continue;
1276
1277 r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr->key), 1, zone);
1278 if (r < 0)
1279 return r;
1280 if (r > 0)
1281 goto found_zone;
1282 }
1283
1284 /* Strip one label from the front */
1285 r = dns_name_parent(&zone);
1286 if (r < 0)
1287 return r;
1288 if (r == 0)
1289 break;
1290 }
1291
1292 *result = DNSSEC_NSEC_NO_RR;
1293 return 0;
1294
1295 found_zone:
1296 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1297 p = DNS_RESOURCE_KEY_NAME(key);
1298 for (;;) {
1299 _cleanup_free_ char *hashed_domain = NULL;
1300
1301 hashed_size = nsec3_hashed_domain(suffix_rr, p, zone, &hashed_domain);
1302 if (hashed_size == -EOPNOTSUPP) {
1303 *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1304 return 0;
1305 }
1306 if (hashed_size < 0)
1307 return hashed_size;
1308
1309 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) {
1310
1311 r = nsec3_is_good(enclosure_rr, flags, suffix_rr);
1312 if (r < 0)
1313 return r;
1314 if (r == 0)
1315 continue;
1316
1317 if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
1318 continue;
1319
1320 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain);
1321 if (r < 0)
1322 return r;
1323 if (r > 0) {
1324 a = flags & DNS_ANSWER_AUTHENTICATED;
1325 goto found_closest_encloser;
1326 }
1327 }
1328
1329 /* We didn't find the closest encloser with this name,
1330 * but let's remember this domain name, it might be
1331 * the next closer name */
1332
1333 pp = p;
1334
1335 /* Strip one label from the front */
1336 r = dns_name_parent(&p);
1337 if (r < 0)
1338 return r;
1339 if (r == 0)
1340 break;
1341 }
1342
1343 *result = DNSSEC_NSEC_NO_RR;
1344 return 0;
1345
1346 found_closest_encloser:
1347 /* We found a closest encloser in 'p'; next closer is 'pp' */
1348
1349 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1350 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME))
1351 return -EBADMSG;
1352
1353 /* Ensure that this data is from the delegated domain
1354 * (i.e. originates from the "lower" DNS server), and isn't
1355 * just glue records (i.e. doesn't originate from the "upper"
1356 * DNS server). */
1357 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1358 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1359 return -EBADMSG;
1360
1361 if (!pp) {
1362 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1363 if (bitmap_isset(enclosure_rr->nsec3.types, key->type))
1364 *result = DNSSEC_NSEC_FOUND;
1365 else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME))
1366 *result = DNSSEC_NSEC_CNAME;
1367 else
1368 *result = DNSSEC_NSEC_NODATA;
1369
1370 if (authenticated)
1371 *authenticated = a;
1372 if (ttl)
1373 *ttl = enclosure_rr->ttl;
1374
1375 return 0;
1376 }
1377
1378 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1379
1380 wildcard = strappend("*.", p);
1381 if (!wildcard)
1382 return -ENOMEM;
1383
1384 r = nsec3_hashed_domain(enclosure_rr, wildcard, zone, &wildcard_domain);
1385 if (r < 0)
1386 return r;
1387 if (r != hashed_size)
1388 return -EBADMSG;
1389
1390 r = nsec3_hashed_domain(enclosure_rr, pp, zone, &next_closer_domain);
1391 if (r < 0)
1392 return r;
1393 if (r != hashed_size)
1394 return -EBADMSG;
1395
1396 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1397 _cleanup_free_ char *label = NULL, *next_hashed_domain = NULL;
1398
1399 r = nsec3_is_good(rr, flags, suffix_rr);
1400 if (r < 0)
1401 return r;
1402 if (r == 0)
1403 continue;
1404
1405 label = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1406 if (!label)
1407 return -ENOMEM;
1408
1409 next_hashed_domain = strjoin(label, ".", zone, NULL);
1410 if (!next_hashed_domain)
1411 return -ENOMEM;
1412
1413 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
1414 if (r < 0)
1415 return r;
1416 if (r > 0) {
1417 if (rr->nsec3.flags & 1)
1418 optout = true;
1419
1420 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1421
1422 no_closer = true;
1423 }
1424
1425 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain);
1426 if (r < 0)
1427 return r;
1428 if (r > 0) {
1429 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1430
1431 wildcard_rr = rr;
1432 }
1433
1434 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain);
1435 if (r < 0)
1436 return r;
1437 if (r > 0) {
1438 if (rr->nsec3.flags & 1)
1439 /* This only makes sense if we have a wildcard delegation, which is
1440 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1441 * this not happening, so hence cannot simply conclude NXDOMAIN as
1442 * we would wish */
1443 optout = true;
1444
1445 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1446
1447 no_wildcard = true;
1448 }
1449 }
1450
1451 if (wildcard_rr && no_wildcard)
1452 return -EBADMSG;
1453
1454 if (!no_closer) {
1455 *result = DNSSEC_NSEC_NO_RR;
1456 return 0;
1457 }
1458
1459 if (wildcard_rr) {
1460 /* A wildcard exists that matches our query. */
1461 if (optout)
1462 /* This is not specified in any RFC to the best of my knowledge, but
1463 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1464 * it means that we cannot prove that the source of synthesis is
1465 * correct, as there may be a closer match. */
1466 *result = DNSSEC_NSEC_OPTOUT;
1467 else if (bitmap_isset(wildcard_rr->nsec3.types, key->type))
1468 *result = DNSSEC_NSEC_FOUND;
1469 else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME))
1470 *result = DNSSEC_NSEC_CNAME;
1471 else
1472 *result = DNSSEC_NSEC_NODATA;
1473 } else {
1474 if (optout)
1475 /* The RFC only specifies that we have to care for optout for NODATA for
1476 * DS records. However, children of an insecure opt-out delegation should
1477 * also be considered opt-out, rather than verified NXDOMAIN.
1478 * Note that we do not require a proof of wildcard non-existence if the
1479 * next closer domain is covered by an opt-out, as that would not provide
1480 * any additional information. */
1481 *result = DNSSEC_NSEC_OPTOUT;
1482 else if (no_wildcard)
1483 *result = DNSSEC_NSEC_NXDOMAIN;
1484 else {
1485 *result = DNSSEC_NSEC_NO_RR;
1486
1487 return 0;
1488 }
1489 }
1490
1491 if (authenticated)
1492 *authenticated = a;
1493
1494 if (ttl)
1495 *ttl = enclosure_rr->ttl;
1496
1497 return 0;
1498 }
1499
1500 int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1501 DnsResourceRecord *rr;
1502 bool have_nsec3 = false;
1503 DnsAnswerFlags flags;
1504 int r;
1505
1506 assert(key);
1507 assert(result);
1508
1509 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1510
1511 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1512
1513 if (rr->key->class != key->class)
1514 continue;
1515
1516 switch (rr->key->type) {
1517
1518 case DNS_TYPE_NSEC:
1519
1520 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
1521 if (r < 0)
1522 return r;
1523 if (r > 0) {
1524 if (bitmap_isset(rr->nsec.types, key->type))
1525 *result = DNSSEC_NSEC_FOUND;
1526 else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME))
1527 *result = DNSSEC_NSEC_CNAME;
1528 else
1529 *result = DNSSEC_NSEC_NODATA;
1530
1531 if (authenticated)
1532 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1533 if (ttl)
1534 *ttl = rr->ttl;
1535
1536 return 0;
1537 }
1538
1539 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key), rr->nsec.next_domain_name);
1540 if (r < 0)
1541 return r;
1542 if (r > 0) {
1543 *result = DNSSEC_NSEC_NXDOMAIN;
1544
1545 if (authenticated)
1546 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1547 if (ttl)
1548 *ttl = rr->ttl;
1549
1550 return 0;
1551 }
1552 break;
1553
1554 case DNS_TYPE_NSEC3:
1555 have_nsec3 = true;
1556 break;
1557 }
1558 }
1559
1560 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1561 if (have_nsec3)
1562 return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
1563
1564 /* No approproate NSEC RR found, report this. */
1565 *result = DNSSEC_NSEC_NO_RR;
1566 return 0;
1567 }
1568
1569 static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
1570 [DNSSEC_NO] = "no",
1571 [DNSSEC_DOWNGRADE_OK] = "downgrade-ok",
1572 [DNSSEC_YES] = "yes",
1573 };
1574 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode);
1575
1576 static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
1577 [DNSSEC_VALIDATED] = "validated",
1578 [DNSSEC_INVALID] = "invalid",
1579 [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
1580 [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
1581 [DNSSEC_NO_SIGNATURE] = "no-signature",
1582 [DNSSEC_MISSING_KEY] = "missing-key",
1583 [DNSSEC_UNSIGNED] = "unsigned",
1584 [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
1585 [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
1586 [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
1587 };
1588 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);