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