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