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