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