LCOV - code coverage report
Current view: top level - resolve - resolved-dns-dnssec.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 371 1177 31.5 %
Date: 2019-08-22 15:41:25 Functions: 26 46 56.5 %

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

Generated by: LCOV version 1.14